test(step097): add A1 renderer regression entry points
This commit is contained in:
@@ -29,6 +29,7 @@ add_library(
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/pattern_atlas.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/particle_viewport_reseed.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/retained_underlay_cache.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/render_orchestrator_error.test.cpp
|
||||
${PROJECT_SOURCE_DIR}/test/renderer/shader_registry.test.cpp
|
||||
$<$<BOOL:${MLN_WITH_WEBGPU}>:${PROJECT_SOURCE_DIR}/test/renderer/wgsl_preprocessor.test.cpp>
|
||||
${PROJECT_SOURCE_DIR}/test/sprite/sprite_loader.test.cpp
|
||||
@@ -160,6 +161,10 @@ if(MLN_WITH_OPENGL)
|
||||
)
|
||||
endif()
|
||||
|
||||
if(MLN_WITH_METAL)
|
||||
target_sources(mbgl-test PRIVATE ${PROJECT_SOURCE_DIR}/test/renderer/mtl_retained_attachments.test.cpp)
|
||||
endif()
|
||||
|
||||
|
||||
if(MLN_WITH_VULKAN)
|
||||
target_sources(
|
||||
|
||||
101
test/renderer/mtl_retained_attachments.test.cpp
Normal file
101
test/renderer/mtl_retained_attachments.test.cpp
Normal file
@@ -0,0 +1,101 @@
|
||||
#if MLN_RENDER_BACKEND_METAL
|
||||
|
||||
#include <mbgl/mtl/context.hpp>
|
||||
#include <mbgl/mtl/offscreen_texture.hpp>
|
||||
#include <mbgl/mtl/render_pass.hpp>
|
||||
#include <mbgl/mtl/renderable_resource.hpp>
|
||||
#include <mbgl/mtl/renderer_backend.hpp>
|
||||
|
||||
#include <Foundation/Foundation.hpp>
|
||||
#include <Metal/Metal.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
#include <cstdlib>
|
||||
|
||||
using namespace mbgl;
|
||||
|
||||
namespace {
|
||||
|
||||
class TestMetalBackend final : public mtl::RendererBackend {
|
||||
public:
|
||||
TestMetalBackend() : RendererBackend(gfx::ContextMode::Unique) {}
|
||||
|
||||
gfx::Renderable& getDefaultRenderable() override { std::abort(); }
|
||||
void updateAssumedState() override {}
|
||||
|
||||
private:
|
||||
void activate() override {}
|
||||
void deactivate() override {}
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
TEST(MetalRetainedAttachments, ClearActionsApplyToCombinedDepthStencil) {
|
||||
auto pool = NS::TransferPtr(NS::AutoreleasePool::alloc()->init());
|
||||
auto device = NS::TransferPtr(MTL::CreateSystemDefaultDevice());
|
||||
if (!device) GTEST_SKIP() << "Metal device unavailable";
|
||||
|
||||
auto colorDescriptor = MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatRGBA8Unorm, 4, 4, false);
|
||||
auto combinedDescriptor =
|
||||
MTL::TextureDescriptor::texture2DDescriptor(MTL::PixelFormatDepth32Float_Stencil8, 4, 4, false);
|
||||
colorDescriptor->setUsage(MTL::TextureUsageRenderTarget);
|
||||
combinedDescriptor->setUsage(MTL::TextureUsageRenderTarget);
|
||||
auto colorTexture = NS::TransferPtr(device->newTexture(colorDescriptor));
|
||||
auto combinedTexture = NS::TransferPtr(device->newTexture(combinedDescriptor));
|
||||
if (!combinedTexture) GTEST_SKIP() << "Combined depth-stencil texture unavailable";
|
||||
ASSERT_TRUE(colorTexture);
|
||||
|
||||
auto descriptor = NS::TransferPtr(MTL::RenderPassDescriptor::alloc()->init());
|
||||
descriptor->colorAttachments()->object(0)->setTexture(colorTexture.get());
|
||||
descriptor->depthAttachment()->setTexture(combinedTexture.get());
|
||||
descriptor->stencilAttachment()->setTexture(combinedTexture.get());
|
||||
|
||||
const auto applied = mtl::detail::applyRenderPassClears(
|
||||
*descriptor, Color{0.2f, 0.3f, 0.4f, 0.5f}, 1.0f, 0);
|
||||
EXPECT_TRUE(applied.color);
|
||||
EXPECT_TRUE(applied.depth);
|
||||
EXPECT_TRUE(applied.stencil);
|
||||
EXPECT_EQ(descriptor->colorAttachments()->object(0)->loadAction(), MTL::LoadActionClear);
|
||||
EXPECT_EQ(descriptor->depthAttachment()->loadAction(), MTL::LoadActionClear);
|
||||
EXPECT_EQ(descriptor->stencilAttachment()->loadAction(), MTL::LoadActionClear);
|
||||
EXPECT_EQ(descriptor->colorAttachments()->object(0)->storeAction(), MTL::StoreActionStore);
|
||||
EXPECT_EQ(descriptor->depthAttachment()->storeAction(), MTL::StoreActionStore);
|
||||
EXPECT_EQ(descriptor->stencilAttachment()->storeAction(), MTL::StoreActionStore);
|
||||
EXPECT_DOUBLE_EQ(descriptor->depthAttachment()->clearDepth(), 1.0);
|
||||
EXPECT_EQ(descriptor->stencilAttachment()->clearStencil(), 0u);
|
||||
EXPECT_EQ(descriptor->depthAttachment()->texture(), descriptor->stencilAttachment()->texture());
|
||||
}
|
||||
|
||||
TEST(MetalRetainedAttachments, OffscreenBindsRequestedAttachmentsAndSkipsAbsentOnes) {
|
||||
auto pool = NS::TransferPtr(NS::AutoreleasePool::alloc()->init());
|
||||
TestMetalBackend backend;
|
||||
mtl::Context context{backend};
|
||||
|
||||
mtl::OffscreenTexture retained(context, {4, 4}, gfx::TextureChannelDataType::UnsignedByte, true, true);
|
||||
ASSERT_TRUE(retained.isRenderable());
|
||||
auto& retainedResource = retained.getResource<mtl::RenderableResource>();
|
||||
retainedResource.bind();
|
||||
const auto& retainedDescriptor = retainedResource.getRenderPassDescriptor();
|
||||
ASSERT_TRUE(retainedDescriptor);
|
||||
ASSERT_NE(retainedDescriptor->colorAttachments()->object(0)->texture(), nullptr);
|
||||
ASSERT_NE(retainedDescriptor->depthAttachment()->texture(), nullptr);
|
||||
ASSERT_NE(retainedDescriptor->stencilAttachment()->texture(), nullptr);
|
||||
#if TARGET_OS_SIMULATOR || defined(__x86_64__)
|
||||
EXPECT_EQ(retainedDescriptor->depthAttachment()->texture(), retainedDescriptor->stencilAttachment()->texture());
|
||||
#else
|
||||
EXPECT_NE(retainedDescriptor->depthAttachment()->texture(), retainedDescriptor->stencilAttachment()->texture());
|
||||
#endif
|
||||
|
||||
mtl::OffscreenTexture colorOnly(context, {4, 4}, gfx::TextureChannelDataType::UnsignedByte, false, false);
|
||||
ASSERT_TRUE(colorOnly.isRenderable());
|
||||
auto& colorResource = colorOnly.getResource<mtl::RenderableResource>();
|
||||
colorResource.bind();
|
||||
const auto& colorDescriptor = colorResource.getRenderPassDescriptor();
|
||||
ASSERT_TRUE(colorDescriptor);
|
||||
EXPECT_EQ(colorDescriptor->depthAttachment()->texture(), nullptr);
|
||||
EXPECT_EQ(colorDescriptor->stencilAttachment()->texture(), nullptr);
|
||||
const auto applied = mtl::detail::applyRenderPassClears(*colorDescriptor, std::nullopt, 1.0f, 0);
|
||||
EXPECT_FALSE(applied.depth);
|
||||
EXPECT_FALSE(applied.stencil);
|
||||
}
|
||||
|
||||
#endif // MLN_RENDER_BACKEND_METAL
|
||||
110
test/renderer/render_orchestrator_error.test.cpp
Normal file
110
test/renderer/render_orchestrator_error.test.cpp
Normal file
@@ -0,0 +1,110 @@
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user