refactor(rendering): formalize camera frame stage contracts

This commit is contained in:
2026-04-15 15:14:06 +08:00
parent 3937badf37
commit 795eaf80df
16 changed files with 558 additions and 296 deletions

View File

@@ -23,6 +23,7 @@
#include "Rendering/Execution/Internal/CameraFrameGraph/SurfaceResolver.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
using namespace XCEngine::Components;
@@ -428,6 +429,7 @@ public:
void Shutdown() override {
++m_state->shutdownCalls;
ShutdownCameraFrameStandalonePasses();
}
bool SupportsMainSceneRenderGraph() const override {
@@ -589,6 +591,17 @@ private:
std::shared_ptr<MockPipelineState> m_state;
};
template <typename PassT, typename... Args>
PassT* InstallStandaloneStagePass(
RenderPipeline& pipeline,
CameraFrameStage stage,
Args&&... args) {
auto pass = std::make_unique<PassT>(std::forward<Args>(args)...);
PassT* const passRaw = pass.get();
pipeline.SetCameraFrameStandalonePass(stage, std::move(pass));
return passRaw;
}
class MockPipelineAsset final : public RenderPipelineAsset {
public:
explicit MockPipelineAsset(std::shared_ptr<MockPipelineAssetState> state)
@@ -1147,11 +1160,13 @@ TEST(CameraRenderer_Test, ExecutesObjectIdPassBetweenPipelineAndPostPassesWhenRe
camera->SetDepth(3.0f);
auto state = std::make_shared<MockPipelineState>();
auto objectIdPass = std::make_unique<MockObjectIdPass>(state);
MockObjectIdPass* objectIdPassRaw = objectIdPass.get();
CameraRenderer renderer(
std::make_unique<MockPipeline>(state),
std::move(objectIdPass));
auto pipeline = std::make_unique<MockPipeline>(state);
MockObjectIdPass* objectIdPassRaw =
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
state);
CameraRenderer renderer(std::move(pipeline));
RenderPassSequence prePasses;
prePasses.AddPass(std::make_unique<TrackingPass>(state, "pre"));
@@ -1642,15 +1657,22 @@ TEST(CameraRenderer_Test, ExecutesFormalFrameStagesInDocumentedOrder) {
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");
renderer.SetShadowCasterPass(std::move(shadowPass));
auto depthPass = std::make_unique<MockScenePass>(state, "depthOnly");
renderer.SetDepthOnlyPass(std::move(depthPass));
auto pipeline = std::make_unique<MockPipeline>(state);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
state);
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
state,
"shadowCaster");
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::DepthOnly,
state,
"depthOnly");
CameraRenderer renderer(std::move(pipeline));
RenderPassSequence prePasses;
prePasses.AddPass(std::make_unique<TrackingPass>(state, "pre"));
@@ -1933,17 +1955,24 @@ TEST(CameraRenderer_Test, ExecutesShadowCasterAndDepthOnlyRequestsBeforeMainPipe
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));
auto pipeline = std::make_unique<MockPipeline>(state);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
state);
MockScenePass* shadowPassRaw =
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
state,
"shadowCaster");
MockScenePass* depthPassRaw =
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::DepthOnly,
state,
"depthOnly");
CameraRenderer renderer(std::move(pipeline));
CameraRenderRequest request;
request.scene = &scene;
@@ -1997,17 +2026,32 @@ TEST(CameraRenderer_Test, RecordsGraphCapableStandalonePassStagesBeforeExecution
camera->SetDepth(3.0f);
auto state = std::make_shared<MockPipelineState>();
CameraRenderer renderer(
std::make_unique<MockPipeline>(state),
std::make_unique<MockObjectIdPass>(state, true, true));
auto shadowPass = std::make_unique<MockScenePass>(state, "shadowCaster", true, true, true);
MockScenePass* shadowPassRaw = shadowPass.get();
renderer.SetShadowCasterPass(std::move(shadowPass));
auto depthPass = std::make_unique<MockScenePass>(state, "depthOnly", true, true, true);
MockScenePass* depthPassRaw = depthPass.get();
renderer.SetDepthOnlyPass(std::move(depthPass));
auto pipeline = std::make_unique<MockPipeline>(state);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
state,
true,
true);
MockScenePass* shadowPassRaw =
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
state,
"shadowCaster",
true,
true,
true);
MockScenePass* depthPassRaw =
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::DepthOnly,
state,
"depthOnly",
true,
true,
true);
CameraRenderer renderer(std::move(pipeline));
CameraRenderRequest request;
request.scene = &scene;
@@ -2139,13 +2183,18 @@ TEST(CameraRenderer_Test, AutoAllocatesDirectionalShadowSurfaceFromShadowPlan) {
context.device = &device;
{
CameraRenderer renderer(
std::make_unique<MockPipeline>(pipelineState),
std::make_unique<MockObjectIdPass>(pipelineState));
auto shadowPass = std::make_unique<MockScenePass>(pipelineState, "shadowCaster");
MockScenePass* shadowPassRaw = shadowPass.get();
renderer.SetShadowCasterPass(std::move(shadowPass));
auto pipeline = std::make_unique<MockPipeline>(pipelineState);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
pipelineState);
MockScenePass* shadowPassRaw =
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
pipelineState,
"shadowCaster");
CameraRenderer renderer(std::move(pipeline));
CameraRenderRequest request;
request.scene = &scene;
@@ -2227,12 +2276,17 @@ TEST(CameraRenderer_Test, PassesShadowDependencyToPipelineRecordedMainScene) {
RenderContext context = CreateValidContext();
context.device = &device;
CameraRenderer renderer(
std::make_unique<MockPipeline>(pipelineState),
std::make_unique<MockObjectIdPass>(pipelineState));
auto shadowPass = std::make_unique<MockScenePass>(pipelineState, "shadowCaster");
renderer.SetShadowCasterPass(std::move(shadowPass));
auto pipeline = std::make_unique<MockPipeline>(pipelineState);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
pipelineState);
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
pipelineState,
"shadowCaster");
CameraRenderer renderer(std::move(pipeline));
CameraRenderRequest request;
request.scene = &scene;
@@ -2284,12 +2338,17 @@ TEST(CameraRenderer_Test, ReusesDirectionalShadowSurfaceWhenPlanMatches) {
RenderContext context = CreateValidContext();
context.device = &device;
CameraRenderer renderer(
std::make_unique<MockPipeline>(pipelineState),
std::make_unique<MockObjectIdPass>(pipelineState));
auto shadowPass = std::make_unique<MockScenePass>(pipelineState, "shadowCaster");
renderer.SetShadowCasterPass(std::move(shadowPass));
auto pipeline = std::make_unique<MockPipeline>(pipelineState);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
pipelineState);
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
pipelineState,
"shadowCaster");
CameraRenderer renderer(std::move(pipeline));
CameraRenderRequest request;
request.scene = &scene;
@@ -2342,12 +2401,17 @@ TEST(CameraRenderer_Test, RecreatesDirectionalShadowSurfaceWhenPlanSizeChanges)
context.device = &device;
{
CameraRenderer renderer(
std::make_unique<MockPipeline>(pipelineState),
std::make_unique<MockObjectIdPass>(pipelineState));
auto shadowPass = std::make_unique<MockScenePass>(pipelineState, "shadowCaster");
renderer.SetShadowCasterPass(std::move(shadowPass));
auto pipeline = std::make_unique<MockPipeline>(pipelineState);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
pipelineState);
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
pipelineState,
"shadowCaster");
CameraRenderer renderer(std::move(pipeline));
CameraRenderRequest request;
request.scene = &scene;
@@ -2411,12 +2475,17 @@ TEST(CameraRenderer_Test, EnablesDirectionalShadowSurfaceAfterInitialFrameWithou
context.device = &device;
{
CameraRenderer renderer(
std::make_unique<MockPipeline>(pipelineState),
std::make_unique<MockObjectIdPass>(pipelineState));
auto shadowPass = std::make_unique<MockScenePass>(pipelineState, "shadowCaster");
renderer.SetShadowCasterPass(std::move(shadowPass));
auto pipeline = std::make_unique<MockPipeline>(pipelineState);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
pipelineState);
InstallStandaloneStagePass<MockScenePass>(
*pipeline,
CameraFrameStage::ShadowCaster,
pipelineState,
"shadowCaster");
CameraRenderer renderer(std::move(pipeline));
CameraRenderRequest request;
request.scene = &scene;
@@ -2554,9 +2623,13 @@ TEST(CameraRenderer_Test, StopsRenderingWhenObjectIdPassFails) {
camera->SetDepth(2.0f);
auto state = std::make_shared<MockPipelineState>();
CameraRenderer renderer(
std::make_unique<MockPipeline>(state),
std::make_unique<MockObjectIdPass>(state, false));
auto pipeline = std::make_unique<MockPipeline>(state);
InstallStandaloneStagePass<MockObjectIdPass>(
*pipeline,
CameraFrameStage::ObjectId,
state,
false);
CameraRenderer renderer(std::move(pipeline));
RenderPassSequence prePasses;
prePasses.AddPass(std::make_unique<TrackingPass>(state, "pre"));