111 lines
3.9 KiB
C++
111 lines
3.9 KiB
C++
#include <mbgl/actor/scheduler.hpp>
|
|
#include <mbgl/gfx/uniform_buffer.hpp>
|
|
#include <mbgl/renderer/layer_group.hpp>
|
|
#include <mbgl/renderer/render_orchestrator.hpp>
|
|
#include <mbgl/renderer/renderer_observer.hpp>
|
|
#include <mbgl/renderer/retained_underlay_cache.hpp>
|
|
|
|
#include <gtest/gtest.h>
|
|
|
|
#include <stdexcept>
|
|
|
|
using namespace mbgl;
|
|
|
|
namespace {
|
|
|
|
class TestUniformBuffers final : public gfx::UniformBufferArray {
|
|
public:
|
|
void bind(gfx::RenderPass&) override {}
|
|
protected:
|
|
std::unique_ptr<gfx::UniformBuffer> copy(const gfx::UniformBuffer&) override { return nullptr; }
|
|
};
|
|
|
|
class TestLayerGroup final : public LayerGroup {
|
|
public:
|
|
explicit TestLayerGroup(int32_t index)
|
|
: LayerGroup(index, 0, "step097-error-group") {}
|
|
|
|
const gfx::UniformBufferArray& getUniformBuffers() const override { return buffers; }
|
|
gfx::UniformBufferArray& mutableUniformBuffers() override { return buffers; }
|
|
|
|
private:
|
|
TestUniformBuffers buffers;
|
|
};
|
|
|
|
class ErrorObserver final : public RendererObserver {
|
|
public:
|
|
void onRenderError(std::exception_ptr error) override {
|
|
++errors;
|
|
try {
|
|
std::rethrow_exception(error);
|
|
} catch (const std::runtime_error& e) {
|
|
message = e.what();
|
|
}
|
|
}
|
|
|
|
int errors = 0;
|
|
std::string message;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
TEST(RenderOrchestratorError, RangeVisitorReportsOpaqueAndTranslucentFailures) {
|
|
TaggedScheduler scheduler{Scheduler::GetBackground(), {}};
|
|
RenderOrchestrator orchestrator(false, scheduler, std::nullopt);
|
|
ErrorObserver observer;
|
|
orchestrator.setObserver(&observer);
|
|
ASSERT_TRUE(orchestrator.addLayerGroup(std::make_shared<TestLayerGroup>(0)));
|
|
ASSERT_TRUE(orchestrator.addLayerGroup(std::make_shared<TestLayerGroup>(1)));
|
|
|
|
bool failed = false;
|
|
orchestrator.visitLayerGroupsInRangeReversed(0, 2, [](LayerGroupBase&, size_t) {
|
|
throw std::runtime_error("opaque failure");
|
|
}, &failed);
|
|
EXPECT_TRUE(failed);
|
|
EXPECT_EQ(observer.errors, 2);
|
|
EXPECT_EQ(observer.message, "opaque failure");
|
|
|
|
failed = false;
|
|
observer.errors = 0;
|
|
orchestrator.visitLayerGroupsInRange(0, 2, [](LayerGroupBase&, size_t) {
|
|
throw std::runtime_error("translucent failure");
|
|
}, &failed);
|
|
EXPECT_TRUE(failed);
|
|
EXPECT_EQ(observer.errors, 2);
|
|
EXPECT_EQ(observer.message, "translucent failure");
|
|
|
|
failed = false;
|
|
int visits = 0;
|
|
orchestrator.visitLayerGroupsInRange(0, 2, [&](LayerGroupBase&, size_t) { ++visits; }, &failed);
|
|
EXPECT_FALSE(failed);
|
|
EXPECT_EQ(visits, 2);
|
|
}
|
|
|
|
TEST(RenderOrchestratorError, FailedRangeCannotReuseAndCleanRetryCanRecover) {
|
|
TaggedScheduler scheduler{Scheduler::GetBackground(), {}};
|
|
RenderOrchestrator orchestrator(false, scheduler, std::nullopt);
|
|
ErrorObserver observer;
|
|
orchestrator.setObserver(&observer);
|
|
ASSERT_TRUE(orchestrator.addLayerGroup(std::make_shared<TestLayerGroup>(0)));
|
|
|
|
RetainedUnderlayCache cache;
|
|
RetainedUnderlayKey key{{4, 4}, 0, 1, {}};
|
|
key.cameraMatrix[0] = key.cameraMatrix[5] = key.cameraMatrix[10] = key.cameraMatrix[15] = 1.0;
|
|
for (bool opaque : {true, false}) {
|
|
EXPECT_EQ(cache.evaluate(key, 1, true), RetainedUnderlayDecision::Build);
|
|
bool failed = false;
|
|
const auto throwOnRender = [](LayerGroupBase&, size_t) { throw std::runtime_error("render failure"); };
|
|
if (opaque) orchestrator.visitLayerGroupsInRangeReversed(0, 1, throwOnRender, &failed);
|
|
else orchestrator.visitLayerGroupsInRange(0, 1, throwOnRender, &failed);
|
|
ASSERT_TRUE(failed);
|
|
cache.markBuildFailed("layer-render-error");
|
|
EXPECT_FALSE(cache.isValid());
|
|
EXPECT_EQ(cache.evaluate(key, 1, true), RetainedUnderlayDecision::Build);
|
|
}
|
|
bool failed = false;
|
|
orchestrator.visitLayerGroupsInRange(0, 1, [](LayerGroupBase&, size_t) {}, &failed);
|
|
ASSERT_FALSE(failed);
|
|
cache.markBuildSucceeded();
|
|
EXPECT_EQ(cache.evaluate(key, 1, true), RetainedUnderlayDecision::Reuse);
|
|
}
|