Wire depth and shadow requests through camera renderer

This commit is contained in:
2026-04-04 14:41:01 +08:00
parent 9e8810e593
commit 1a236b866d
6 changed files with 323 additions and 7 deletions

View File

@@ -131,6 +131,59 @@ private:
bool m_renderResult = true;
};
class MockScenePass final : public RenderPass {
public:
MockScenePass(
std::shared_ptr<MockPipelineState> state,
const char* label,
bool initializeResult = true,
bool executeResult = true)
: m_state(std::move(state))
, m_label(label)
, m_initializeResult(initializeResult)
, m_executeResult(executeResult) {
}
const char* GetName() const override {
return m_label;
}
bool Initialize(const RenderContext&) override {
m_state->eventLog.push_back(std::string("init:") + m_label);
return m_initializeResult;
}
bool Execute(const RenderPassContext& context) override {
m_state->eventLog.push_back(m_label);
lastViewportWidth = context.sceneData.cameraData.viewportWidth;
lastViewportHeight = context.sceneData.cameraData.viewportHeight;
lastClearFlags = context.sceneData.cameraData.clearFlags;
lastClearColor = context.sceneData.cameraData.clearColor;
lastWorldPosition = context.sceneData.cameraData.worldPosition;
lastSurfaceWidth = context.surface.GetRenderAreaWidth();
lastSurfaceHeight = context.surface.GetRenderAreaHeight();
return m_executeResult;
}
void Shutdown() override {
m_state->eventLog.push_back(std::string("shutdown:") + m_label);
}
uint32_t lastViewportWidth = 0;
uint32_t lastViewportHeight = 0;
RenderClearFlags lastClearFlags = RenderClearFlags::All;
XCEngine::Math::Color lastClearColor = XCEngine::Math::Color::Black();
XCEngine::Math::Vector3 lastWorldPosition = XCEngine::Math::Vector3::Zero();
uint32_t lastSurfaceWidth = 0;
uint32_t lastSurfaceHeight = 0;
private:
std::shared_ptr<MockPipelineState> m_state;
const char* m_label = "";
bool m_initializeResult = true;
bool m_executeResult = true;
};
class TrackingPass final : public RenderPass {
public:
TrackingPass(
@@ -334,6 +387,92 @@ TEST(CameraRenderer_Test, ExecutesObjectIdPassBetweenPipelineAndPostPassesWhenRe
"shutdown:pre" }));
}
TEST(CameraRenderer_Test, ExecutesShadowCasterAndDepthOnlyRequestsBeforeMainPipeline) {
Scene scene("CameraRendererDepthAndShadowScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(3.0f);
auto state = std::make_shared<MockPipelineState>();
CameraRenderer renderer(
std::make_unique<MockPipeline>(state),
std::make_unique<MockObjectIdPass>(state));
auto shadowPass = std::make_unique<MockScenePass>(state, "shadowCaster");
MockScenePass* shadowPassRaw = shadowPass.get();
renderer.SetShadowCasterPass(std::move(shadowPass));
auto depthPass = std::make_unique<MockScenePass>(state, "depthOnly");
MockScenePass* depthPassRaw = depthPass.get();
renderer.SetDepthOnlyPass(std::move(depthPass));
CameraRenderRequest request;
request.scene = &scene;
request.camera = camera;
request.context = CreateValidContext();
request.surface = RenderSurface(320, 180);
request.cameraDepth = camera->GetDepth();
request.shadowCaster.surface = RenderSurface(128, 64);
request.shadowCaster.surface.SetColorAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(1));
request.shadowCaster.surface.SetDepthAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(2));
request.shadowCaster.hasCameraDataOverride = true;
request.shadowCaster.cameraDataOverride.worldPosition = XCEngine::Math::Vector3(7.0f, 8.0f, 9.0f);
request.depthOnly.surface = RenderSurface(96, 48);
request.depthOnly.surface.SetColorAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(3));
request.depthOnly.surface.SetDepthAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(4));
request.depthOnly.hasClearColorOverride = true;
request.depthOnly.clearColorOverride = XCEngine::Math::Color(0.3f, 0.2f, 0.1f, 1.0f);
ASSERT_TRUE(renderer.Render(request));
EXPECT_EQ(
state->eventLog,
(std::vector<std::string>{
"init:shadowCaster",
"shadowCaster",
"init:depthOnly",
"depthOnly",
"pipeline" }));
EXPECT_EQ(shadowPassRaw->lastViewportWidth, 128u);
EXPECT_EQ(shadowPassRaw->lastViewportHeight, 64u);
EXPECT_EQ(shadowPassRaw->lastSurfaceWidth, 128u);
EXPECT_EQ(shadowPassRaw->lastSurfaceHeight, 64u);
EXPECT_EQ(shadowPassRaw->lastClearFlags, RenderClearFlags::Depth);
EXPECT_EQ(shadowPassRaw->lastWorldPosition, XCEngine::Math::Vector3(7.0f, 8.0f, 9.0f));
EXPECT_EQ(depthPassRaw->lastViewportWidth, 96u);
EXPECT_EQ(depthPassRaw->lastViewportHeight, 48u);
EXPECT_EQ(depthPassRaw->lastClearFlags, RenderClearFlags::Depth);
EXPECT_FLOAT_EQ(depthPassRaw->lastClearColor.r, 0.3f);
EXPECT_FLOAT_EQ(depthPassRaw->lastClearColor.g, 0.2f);
EXPECT_FLOAT_EQ(depthPassRaw->lastClearColor.b, 0.1f);
EXPECT_FLOAT_EQ(depthPassRaw->lastClearColor.a, 1.0f);
}
TEST(CameraRenderer_Test, StopsRenderingWhenShadowCasterRequestIsInvalid) {
Scene scene("CameraRendererInvalidShadowScene");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
auto state = std::make_shared<MockPipelineState>();
CameraRenderer renderer(std::make_unique<MockPipeline>(state));
CameraRenderRequest request;
request.scene = &scene;
request.camera = camera;
request.context = CreateValidContext();
request.surface = RenderSurface(320, 180);
request.shadowCaster.surface = RenderSurface(64, 64);
request.shadowCaster.surface.SetColorAttachment(reinterpret_cast<XCEngine::RHI::RHIResourceView*>(1));
EXPECT_FALSE(renderer.Render(request));
EXPECT_TRUE(state->eventLog.empty());
}
TEST(CameraRenderer_Test, ShutsDownInitializedPassesWhenPipelineRenderFails) {
Scene scene("CameraRendererFailureScene");