From 795eaf80dfbe0c9b2c58fd43cf5ad48671ad2f09 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 15 Apr 2026 15:14:06 +0800 Subject: [PATCH] refactor(rendering): formalize camera frame stage contracts --- .../Rendering/Execution/CameraFrameStage.h | 69 ++++++ .../Rendering/Execution/CameraRenderer.h | 15 -- .../XCEngine/Rendering/RenderPipeline.h | 61 +++++ .../Rendering/Execution/CameraFramePlan.cpp | 45 ++-- .../Rendering/Execution/CameraRenderer.cpp | 86 +------ .../CameraFrameGraph/ExecutionState.h | 11 +- .../Internal/CameraFrameGraph/Executor.cpp | 8 +- .../Internal/CameraFrameGraph/Executor.h | 5 +- .../CameraFrameGraph/SequenceRecorder.cpp | 15 +- .../CameraFrameGraph/StageContract.cpp | 112 +++++---- .../Internal/CameraFrameGraph/StageContract.h | 8 + .../BuiltinForwardPipelineLifecycle.cpp | 1 + .../ScriptableRenderPipelineHost.cpp | 18 ++ ...test_camera_frame_graph_stage_contract.cpp | 152 ++++++++++--- .../test_camera_frame_graph_stage_policy.cpp | 35 +++ .../unit/test_camera_scene_renderer.cpp | 213 ++++++++++++------ 16 files changed, 558 insertions(+), 296 deletions(-) diff --git a/engine/include/XCEngine/Rendering/Execution/CameraFrameStage.h b/engine/include/XCEngine/Rendering/Execution/CameraFrameStage.h index 6e1c0212..ef753ae4 100644 --- a/engine/include/XCEngine/Rendering/Execution/CameraFrameStage.h +++ b/engine/include/XCEngine/Rendering/Execution/CameraFrameStage.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include namespace XCEngine { @@ -18,6 +19,19 @@ enum class CameraFrameStage : uint8_t { OverlayPasses }; +enum class CameraFrameStageExecutionKind : uint8_t { + Sequence, + StandalonePass, + MainScenePipeline +}; + +enum class CameraFrameStageRequestKind : uint8_t { + None, + ShadowCaster, + DepthOnly, + ObjectId +}; + struct CameraFrameStageInfo { CameraFrameStage stage = CameraFrameStage::MainScene; const char* name = ""; @@ -36,6 +50,61 @@ inline constexpr std::array kOrderedCameraFrameStages = { CameraFrameStage::OverlayPasses, "OverlayPasses", false } } }; +inline constexpr size_t kCameraFrameStageCount = kOrderedCameraFrameStages.size(); + +inline constexpr size_t GetCameraFrameStageIndex(CameraFrameStage stage) { + return static_cast(stage); +} + +inline constexpr CameraFrameStageExecutionKind GetCameraFrameStageExecutionKind( + CameraFrameStage stage) { + switch (stage) { + case CameraFrameStage::PreScenePasses: + case CameraFrameStage::PostProcess: + case CameraFrameStage::FinalOutput: + case CameraFrameStage::PostScenePasses: + case CameraFrameStage::OverlayPasses: + return CameraFrameStageExecutionKind::Sequence; + case CameraFrameStage::ShadowCaster: + case CameraFrameStage::DepthOnly: + case CameraFrameStage::ObjectId: + return CameraFrameStageExecutionKind::StandalonePass; + default: + return CameraFrameStageExecutionKind::MainScenePipeline; + } +} + +inline constexpr CameraFrameStageRequestKind GetCameraFrameStageRequestKind( + CameraFrameStage stage) { + switch (stage) { + case CameraFrameStage::ShadowCaster: + return CameraFrameStageRequestKind::ShadowCaster; + case CameraFrameStage::DepthOnly: + return CameraFrameStageRequestKind::DepthOnly; + case CameraFrameStage::ObjectId: + return CameraFrameStageRequestKind::ObjectId; + default: + return CameraFrameStageRequestKind::None; + } +} + +inline constexpr bool IsCameraFrameSequenceStage(CameraFrameStage stage) { + return GetCameraFrameStageExecutionKind(stage) == + CameraFrameStageExecutionKind::Sequence; +} + +inline constexpr bool SupportsCameraFrameStandalonePass(CameraFrameStage stage) { + return GetCameraFrameStageExecutionKind(stage) == + CameraFrameStageExecutionKind::StandalonePass; +} + +inline constexpr bool IsCameraFrameScenePassRequestStage(CameraFrameStage stage) { + const CameraFrameStageRequestKind requestKind = + GetCameraFrameStageRequestKind(stage); + return requestKind == CameraFrameStageRequestKind::ShadowCaster || + requestKind == CameraFrameStageRequestKind::DepthOnly; +} + inline constexpr const char* GetCameraFrameStageName(CameraFrameStage stage) { switch (stage) { case CameraFrameStage::PreScenePasses: diff --git a/engine/include/XCEngine/Rendering/Execution/CameraRenderer.h b/engine/include/XCEngine/Rendering/Execution/CameraRenderer.h index 588b5069..255fa019 100644 --- a/engine/include/XCEngine/Rendering/Execution/CameraRenderer.h +++ b/engine/include/XCEngine/Rendering/Execution/CameraRenderer.h @@ -2,7 +2,6 @@ #include #include -#include #include #include @@ -30,23 +29,12 @@ public: CameraRenderer(); explicit CameraRenderer(std::unique_ptr pipeline); explicit CameraRenderer(std::shared_ptr pipelineAsset); - CameraRenderer( - std::unique_ptr pipeline, - std::unique_ptr objectIdPass, - std::unique_ptr depthOnlyPass = nullptr, - std::unique_ptr shadowCasterPass = nullptr); ~CameraRenderer(); void SetPipeline(std::unique_ptr pipeline); void SetPipelineAsset(std::shared_ptr pipelineAsset); - void SetObjectIdPass(std::unique_ptr objectIdPass); - void SetDepthOnlyPass(std::unique_ptr depthOnlyPass); - void SetShadowCasterPass(std::unique_ptr shadowCasterPass); RenderPipeline* GetPipeline() const { return m_pipeline.get(); } const RenderPipelineAsset* GetPipelineAsset() const { return m_pipelineAsset.get(); } - RenderPass* GetObjectIdPass() const { return m_objectIdPass.get(); } - RenderPass* GetDepthOnlyPass() const { return m_depthOnlyPass.get(); } - RenderPass* GetShadowCasterPass() const { return m_shadowCasterPass.get(); } bool Render(const CameraFramePlan& plan); @@ -64,9 +52,6 @@ private: RenderSceneExtractor m_sceneExtractor; std::shared_ptr m_pipelineAsset; std::unique_ptr m_pipeline; - std::unique_ptr m_objectIdPass; - std::unique_ptr m_depthOnlyPass; - std::unique_ptr m_shadowCasterPass; std::unique_ptr m_directionalShadowRuntime; }; diff --git a/engine/include/XCEngine/Rendering/RenderPipeline.h b/engine/include/XCEngine/Rendering/RenderPipeline.h index 9a43edcb..0a771110 100644 --- a/engine/include/XCEngine/Rendering/RenderPipeline.h +++ b/engine/include/XCEngine/Rendering/RenderPipeline.h @@ -1,13 +1,17 @@ #pragma once #include +#include #include #include #include #include #include +#include #include +#include +#include #include namespace XCEngine { @@ -61,6 +65,63 @@ public: using RenderPipelineRenderer::Render; ~RenderPipeline() override = default; + + void SetCameraFrameStandalonePass( + CameraFrameStage stage, + std::unique_ptr pass) { + std::unique_ptr* const passSlot = + ResolveCameraFrameStandalonePassSlot(stage); + if (passSlot == nullptr) { + return; + } + + if (*passSlot != nullptr) { + (*passSlot)->Shutdown(); + } + + *passSlot = std::move(pass); + } + + RenderPass* GetCameraFrameStandalonePass(CameraFrameStage stage) const { + const std::unique_ptr* const passSlot = + ResolveCameraFrameStandalonePassSlot(stage); + return passSlot != nullptr + ? passSlot->get() + : nullptr; + } + +protected: + void ShutdownCameraFrameStandalonePasses() { + for (std::unique_ptr& pass : m_cameraFrameStandalonePasses) { + if (pass != nullptr) { + pass->Shutdown(); + } + } + } + +private: + using CameraFrameStandalonePassStorage = + std::array, kCameraFrameStageCount>; + + std::unique_ptr* ResolveCameraFrameStandalonePassSlot( + CameraFrameStage stage) { + if (!SupportsCameraFrameStandalonePass(stage)) { + return nullptr; + } + + return &m_cameraFrameStandalonePasses[GetCameraFrameStageIndex(stage)]; + } + + const std::unique_ptr* ResolveCameraFrameStandalonePassSlot( + CameraFrameStage stage) const { + if (!SupportsCameraFrameStandalonePass(stage)) { + return nullptr; + } + + return &m_cameraFrameStandalonePasses[GetCameraFrameStageIndex(stage)]; + } + + CameraFrameStandalonePassStorage m_cameraFrameStandalonePasses = {}; }; } // namespace Rendering diff --git a/engine/src/Rendering/Execution/CameraFramePlan.cpp b/engine/src/Rendering/Execution/CameraFramePlan.cpp index 63da37d9..ac85563c 100644 --- a/engine/src/Rendering/Execution/CameraFramePlan.cpp +++ b/engine/src/Rendering/Execution/CameraFramePlan.cpp @@ -102,31 +102,31 @@ bool CameraFramePlan::IsFinalOutputStageValid() const { } bool CameraFramePlan::HasFrameStage(CameraFrameStage stage) const { - switch (stage) { - case CameraFrameStage::PreScenePasses: - return preScenePasses != nullptr; - case CameraFrameStage::ShadowCaster: - return shadowCaster.IsRequested() || directionalShadow.IsValid(); - case CameraFrameStage::DepthOnly: - return request.depthOnly.IsRequested(); - case CameraFrameStage::MainScene: + if (stage == CameraFrameStage::MainScene) { return true; - case CameraFrameStage::PostProcess: - return postProcess.IsRequested(); - case CameraFrameStage::FinalOutput: - return finalOutput.IsRequested(); - case CameraFrameStage::ObjectId: + } + + if (IsCameraFrameSequenceStage(stage)) { + return GetPassSequence(stage) != nullptr; + } + + switch (GetCameraFrameStageRequestKind(stage)) { + case CameraFrameStageRequestKind::ShadowCaster: + return shadowCaster.IsRequested() || directionalShadow.IsValid(); + case CameraFrameStageRequestKind::DepthOnly: + return request.depthOnly.IsRequested(); + case CameraFrameStageRequestKind::ObjectId: return request.objectId.IsRequested(); - case CameraFrameStage::PostScenePasses: - return postScenePasses != nullptr; - case CameraFrameStage::OverlayPasses: - return overlayPasses != nullptr; default: return false; } } RenderPassSequence* CameraFramePlan::GetPassSequence(CameraFrameStage stage) const { + if (!IsCameraFrameSequenceStage(stage)) { + return nullptr; + } + switch (stage) { case CameraFrameStage::PreScenePasses: return preScenePasses; @@ -144,10 +144,10 @@ RenderPassSequence* CameraFramePlan::GetPassSequence(CameraFrameStage stage) con } const ScenePassRenderRequest* CameraFramePlan::GetScenePassRequest(CameraFrameStage stage) const { - switch (stage) { - case CameraFrameStage::ShadowCaster: + switch (GetCameraFrameStageRequestKind(stage)) { + case CameraFrameStageRequestKind::ShadowCaster: return &shadowCaster; - case CameraFrameStage::DepthOnly: + case CameraFrameStageRequestKind::DepthOnly: return &request.depthOnly; default: return nullptr; @@ -155,7 +155,10 @@ const ScenePassRenderRequest* CameraFramePlan::GetScenePassRequest(CameraFrameSt } const ObjectIdRenderRequest* CameraFramePlan::GetObjectIdRequest(CameraFrameStage stage) const { - return stage == CameraFrameStage::ObjectId ? &request.objectId : nullptr; + return GetCameraFrameStageRequestKind(stage) == + CameraFrameStageRequestKind::ObjectId + ? &request.objectId + : nullptr; } const RenderSurface& CameraFramePlan::GetMainSceneSurface() const { diff --git a/engine/src/Rendering/Execution/CameraRenderer.cpp b/engine/src/Rendering/Execution/CameraRenderer.cpp index fe6caee8..b004f56e 100644 --- a/engine/src/Rendering/Execution/CameraRenderer.cpp +++ b/engine/src/Rendering/Execution/CameraRenderer.cpp @@ -3,10 +3,6 @@ #include "Components/CameraComponent.h" #include "Rendering/Execution/DirectionalShadowExecutionState.h" #include "Rendering/Execution/Internal/CameraFrameGraph/Executor.h" -#include "Rendering/Passes/BuiltinDepthOnlyPass.h" -#include "Rendering/Passes/BuiltinObjectIdPass.h" -#include "Rendering/Passes/BuiltinShadowCasterPass.h" -#include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h" #include "Rendering/Pipelines/ScriptableRenderPipelineHost.h" #include "Rendering/RenderPipelineAsset.h" @@ -23,14 +19,6 @@ std::shared_ptr CreateDefaultPipelineAsset() { return Pipelines::CreateManagedOrDefaultScriptableRenderPipelineAsset(); } -std::unique_ptr CreateDefaultDepthOnlyPass() { - return std::make_unique(); -} - -std::unique_ptr CreateDefaultShadowCasterPass() { - return std::make_unique(); -} - std::unique_ptr CreatePipelineFromAsset( const std::shared_ptr& pipelineAsset) { if (pipelineAsset != nullptr) { @@ -85,40 +73,13 @@ CameraRenderer::CameraRenderer() } CameraRenderer::CameraRenderer(std::unique_ptr pipeline) - : CameraRenderer( - std::move(pipeline), - std::make_unique(), - CreateDefaultDepthOnlyPass(), - CreateDefaultShadowCasterPass()) { -} - -CameraRenderer::CameraRenderer( - std::unique_ptr pipeline, - std::unique_ptr objectIdPass, - std::unique_ptr depthOnlyPass, - std::unique_ptr shadowCasterPass) : m_pipelineAsset(nullptr) - , m_objectIdPass(std::move(objectIdPass)) - , m_depthOnlyPass(std::move(depthOnlyPass)) - , m_shadowCasterPass(std::move(shadowCasterPass)) , m_directionalShadowRuntime(std::make_unique()) { - if (m_objectIdPass == nullptr) { - m_objectIdPass = std::make_unique(); - } - if (m_depthOnlyPass == nullptr) { - m_depthOnlyPass = CreateDefaultDepthOnlyPass(); - } - if (m_shadowCasterPass == nullptr) { - m_shadowCasterPass = CreateDefaultShadowCasterPass(); - } ResetPipeline(std::move(pipeline)); } CameraRenderer::CameraRenderer(std::shared_ptr pipelineAsset) : m_pipelineAsset(std::move(pipelineAsset)) - , m_objectIdPass(std::make_unique()) - , m_depthOnlyPass(CreateDefaultDepthOnlyPass()) - , m_shadowCasterPass(CreateDefaultShadowCasterPass()) , m_directionalShadowRuntime(std::make_unique()) { SetPipelineAsset(m_pipelineAsset); } @@ -127,15 +88,6 @@ CameraRenderer::~CameraRenderer() { if (m_pipeline) { m_pipeline->Shutdown(); } - if (m_objectIdPass != nullptr) { - m_objectIdPass->Shutdown(); - } - if (m_depthOnlyPass != nullptr) { - m_depthOnlyPass->Shutdown(); - } - if (m_shadowCasterPass != nullptr) { - m_shadowCasterPass->Shutdown(); - } } void CameraRenderer::SetPipeline(std::unique_ptr pipeline) { @@ -148,39 +100,6 @@ void CameraRenderer::SetPipelineAsset(std::shared_ptr ResetPipeline(CreatePipelineFromAsset(m_pipelineAsset)); } -void CameraRenderer::SetObjectIdPass(std::unique_ptr objectIdPass) { - if (m_objectIdPass != nullptr) { - m_objectIdPass->Shutdown(); - } - - m_objectIdPass = std::move(objectIdPass); - if (m_objectIdPass == nullptr) { - m_objectIdPass = std::make_unique(); - } -} - -void CameraRenderer::SetDepthOnlyPass(std::unique_ptr depthOnlyPass) { - if (m_depthOnlyPass != nullptr) { - m_depthOnlyPass->Shutdown(); - } - - m_depthOnlyPass = std::move(depthOnlyPass); - if (m_depthOnlyPass == nullptr) { - m_depthOnlyPass = CreateDefaultDepthOnlyPass(); - } -} - -void CameraRenderer::SetShadowCasterPass(std::unique_ptr shadowCasterPass) { - if (m_shadowCasterPass != nullptr) { - m_shadowCasterPass->Shutdown(); - } - - m_shadowCasterPass = std::move(shadowCasterPass); - if (m_shadowCasterPass == nullptr) { - m_shadowCasterPass = CreateDefaultShadowCasterPass(); - } -} - void CameraRenderer::ResetPipeline(std::unique_ptr pipeline) { if (m_pipeline != nullptr) { m_pipeline->Shutdown(); @@ -227,10 +146,7 @@ bool CameraRenderer::ExecuteRenderPlan( plan, shadowState, sceneData, - m_pipeline.get(), - m_objectIdPass.get(), - m_depthOnlyPass.get(), - m_shadowCasterPass.get()); + m_pipeline.get()); } bool CameraRenderer::Render( diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/ExecutionState.h b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/ExecutionState.h index ea2ecedf..3d79b456 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/ExecutionState.h +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/ExecutionState.h @@ -3,6 +3,7 @@ #include #include +#include #include namespace XCEngine { @@ -46,14 +47,8 @@ private: struct CameraFrameExecutionState { RenderPipeline* pipeline = nullptr; - RenderPass* objectIdPass = nullptr; - RenderPass* depthOnlyPass = nullptr; - RenderPass* shadowCasterPass = nullptr; - std::unique_ptr preScenePasses; - std::unique_ptr postProcessPasses; - std::unique_ptr finalOutputPasses; - std::unique_ptr postScenePasses; - std::unique_ptr overlayPasses; + std::array, kCameraFrameStageCount> + sequenceStates = {}; }; } // namespace Rendering diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/Executor.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/Executor.cpp index 61a138e6..f78297b2 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/Executor.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/Executor.cpp @@ -16,19 +16,13 @@ bool ExecuteCameraFrameRenderGraphPlan( const CameraFramePlan& plan, const DirectionalShadowExecutionState& shadowState, const RenderSceneData& sceneData, - RenderPipeline* pipeline, - RenderPass* objectIdPass, - RenderPass* depthOnlyPass, - RenderPass* shadowCasterPass) { + RenderPipeline* pipeline) { RenderGraph graph = {}; RenderGraphBuilder graphBuilder(graph); RenderGraphBlackboard blackboard = {}; CameraFrameExecutionState executionState = {}; executionState.pipeline = pipeline; - executionState.objectIdPass = objectIdPass; - executionState.depthOnlyPass = depthOnlyPass; - executionState.shadowCasterPass = shadowCasterPass; bool stageExecutionSucceeded = true; if (!RecordCameraFrameRenderGraphStages( diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/Executor.h b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/Executor.h index 8b4ecad8..d99a14dd 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/Executor.h +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/Executor.h @@ -13,10 +13,7 @@ bool ExecuteCameraFrameRenderGraphPlan( const CameraFramePlan& plan, const DirectionalShadowExecutionState& shadowState, const RenderSceneData& sceneData, - RenderPipeline* pipeline, - RenderPass* objectIdPass, - RenderPass* depthOnlyPass, - RenderPass* shadowCasterPass); + RenderPipeline* pipeline); } // namespace Rendering } // namespace XCEngine diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/SequenceRecorder.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/SequenceRecorder.cpp index addfb707..50259e28 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/SequenceRecorder.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/SequenceRecorder.cpp @@ -28,20 +28,11 @@ bool EnsureInitializedPassSequence( std::unique_ptr* ResolveStageSequenceState( CameraFrameStage stage, CameraFrameExecutionState& executionState) { - switch (stage) { - case CameraFrameStage::PreScenePasses: - return &executionState.preScenePasses; - case CameraFrameStage::PostProcess: - return &executionState.postProcessPasses; - case CameraFrameStage::FinalOutput: - return &executionState.finalOutputPasses; - case CameraFrameStage::PostScenePasses: - return &executionState.postScenePasses; - case CameraFrameStage::OverlayPasses: - return &executionState.overlayPasses; - default: + if (!IsCameraFrameSequenceStage(stage)) { return nullptr; } + + return &executionState.sequenceStates[GetCameraFrameStageIndex(stage)]; } RenderPassGraphBeginCallback BuildSequenceBeginCallback( diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.cpp index 418878f8..3382a282 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.cpp @@ -90,6 +90,33 @@ CameraFrameRenderGraphSourceBinding BuildCameraFrameStageGraphSourceBinding( }; } +const ScenePassRenderRequest* ResolveCameraFrameStageScenePassRequest( + CameraFrameStage stage, + const CameraFrameRenderGraphStageContext& context) { + switch (GetCameraFrameStageRequestKind(stage)) { + case CameraFrameStageRequestKind::ShadowCaster: + return context.shadowState.shadowCasterRequest.IsRequested() + ? &context.shadowState.shadowCasterRequest + : nullptr; + case CameraFrameStageRequestKind::DepthOnly: + return context.plan.request.depthOnly.IsRequested() + ? &context.plan.request.depthOnly + : nullptr; + default: + return nullptr; + } +} + +const ObjectIdRenderRequest* ResolveCameraFrameStageObjectIdRequest( + CameraFrameStage stage, + const CameraFrameRenderGraphStageContext& context) { + return GetCameraFrameStageRequestKind(stage) == + CameraFrameStageRequestKind::ObjectId && + context.plan.request.objectId.IsRequested() + ? &context.plan.request.objectId + : nullptr; +} + RenderSceneData BuildCameraFrameScenePassRequestSceneData( const ScenePassRenderRequest& request, const RenderSurface& requestSurface, @@ -130,15 +157,10 @@ RenderSceneData BuildCameraFrameStandaloneStageSceneData( CameraFrameStage stage, const CameraFrameRenderGraphStageContext& context, const RenderSurface& stageSurface) { - if (stage == CameraFrameStage::ShadowCaster && - context.shadowState.shadowCasterRequest.IsRequested()) { - return BuildCameraFrameScenePassRequestSceneData( - context.shadowState.shadowCasterRequest, - stageSurface, - context.sceneData); - } - - if (const ScenePassRenderRequest* request = context.plan.GetScenePassRequest(stage); + if (const ScenePassRenderRequest* request = + ResolveCameraFrameStageScenePassRequest( + stage, + context); request != nullptr) { return BuildCameraFrameScenePassRequestSceneData( *request, @@ -152,16 +174,9 @@ RenderSceneData BuildCameraFrameStandaloneStageSceneData( RenderPass* ResolveCameraFrameStandaloneStagePass( CameraFrameStage stage, CameraFrameExecutionState& executionState) { - switch (stage) { - case CameraFrameStage::ShadowCaster: - return executionState.shadowCasterPass; - case CameraFrameStage::DepthOnly: - return executionState.depthOnlyPass; - case CameraFrameStage::ObjectId: - return executionState.objectIdPass; - default: - return nullptr; - } + return executionState.pipeline != nullptr + ? executionState.pipeline->GetCameraFrameStandalonePass(stage) + : nullptr; } bool InitializeCameraFrameStandaloneStagePass( @@ -184,22 +199,29 @@ bool ExecuteCameraFrameRecordedStagePass( const CameraFrameRenderGraphStageContext& context, CameraFrameExecutionState& executionState, const RenderPassContext& passContext) { - switch (stage) { - case CameraFrameStage::ShadowCaster: + if (IsCameraFrameScenePassRequestStage(stage)) { + const ScenePassRenderRequest* const request = + ResolveCameraFrameStageScenePassRequest( + stage, + context); + if (request == nullptr) { + return true; + } + + RenderPass* const standaloneStagePass = + ResolveCameraFrameStandaloneStagePass( + stage, + executionState); return ExecuteCameraFrameScenePassRequestStage( - executionState.shadowCasterPass, - context.shadowState.shadowCasterRequest, + standaloneStagePass, + *request, context.plan.request.context, context.sceneData, passContext.surface); - case CameraFrameStage::DepthOnly: - return ExecuteCameraFrameScenePassRequestStage( - executionState.depthOnlyPass, - context.plan.request.depthOnly, - context.plan.request.context, - context.sceneData, - passContext.surface); - case CameraFrameStage::MainScene: + } + + if (GetCameraFrameStageExecutionKind(stage) == + CameraFrameStageExecutionKind::MainScenePipeline) { return executionState.pipeline != nullptr && executionState.pipeline->Render( FrameExecutionContext( @@ -209,16 +231,26 @@ bool ExecuteCameraFrameRecordedStagePass( passContext.sourceSurface, passContext.sourceColorView, passContext.sourceColorState)); - case CameraFrameStage::ObjectId: - return !context.plan.request.objectId.IsRequested() || - ExecuteCameraFrameStandaloneStagePass( - executionState.objectIdPass, - context.plan.request.context, - passContext.surface, - context.sceneData); - default: - return false; } + + if (GetCameraFrameStageRequestKind(stage) == + CameraFrameStageRequestKind::ObjectId) { + if (ResolveCameraFrameStageObjectIdRequest(stage, context) == nullptr) { + return true; + } + + RenderPass* const standaloneStagePass = + ResolveCameraFrameStandaloneStagePass( + stage, + executionState); + return ExecuteCameraFrameStandaloneStagePass( + standaloneStagePass, + context.plan.request.context, + passContext.surface, + context.sceneData); + } + + return false; } RenderPassContext BuildCameraFrameStageGraphPassContext( diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.h b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.h index 4409a9b9..269d9bce 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.h +++ b/engine/src/Rendering/Execution/Internal/CameraFrameGraph/StageContract.h @@ -23,6 +23,14 @@ struct CameraFrameStageFallbackSurfaceResolution { CameraFrameRenderGraphSourceBinding BuildCameraFrameStageGraphSourceBinding( const CameraFrameStageGraphBuildState& stageState); +const ScenePassRenderRequest* ResolveCameraFrameStageScenePassRequest( + CameraFrameStage stage, + const CameraFrameRenderGraphStageContext& context); + +const ObjectIdRenderRequest* ResolveCameraFrameStageObjectIdRequest( + CameraFrameStage stage, + const CameraFrameRenderGraphStageContext& context); + RenderSceneData BuildCameraFrameScenePassRequestSceneData( const ScenePassRenderRequest& request, const RenderSurface& requestSurface, diff --git a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineLifecycle.cpp b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineLifecycle.cpp index 10172e6b..5e4a3932 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineLifecycle.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineLifecycle.cpp @@ -16,6 +16,7 @@ bool BuiltinForwardPipeline::Initialize(const RenderContext& context) { void BuiltinForwardPipeline::Shutdown() { m_forwardSceneFeatureHost.Shutdown(); DestroyPipelineResources(); + ShutdownCameraFrameStandalonePasses(); } bool BuiltinForwardPipeline::EnsureInitialized(const RenderContext& context) { diff --git a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp index b6e4037a..3b76da18 100644 --- a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp +++ b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp @@ -1,5 +1,8 @@ #include "Rendering/Pipelines/ScriptableRenderPipelineHost.h" +#include "Rendering/Passes/BuiltinDepthOnlyPass.h" +#include "Rendering/Passes/BuiltinObjectIdPass.h" +#include "Rendering/Passes/BuiltinShadowCasterPass.h" #include "Rendering/Pipelines/BuiltinForwardPipeline.h" namespace XCEngine { @@ -29,6 +32,18 @@ std::unique_ptr CreateMainSceneRendererFromAsset( return std::make_unique(); } +void InstallDefaultStandaloneStagePasses(RenderPipeline& pipeline) { + pipeline.SetCameraFrameStandalonePass( + CameraFrameStage::ObjectId, + std::make_unique()); + pipeline.SetCameraFrameStandalonePass( + CameraFrameStage::DepthOnly, + std::make_unique()); + pipeline.SetCameraFrameStandalonePass( + CameraFrameStage::ShadowCaster, + std::make_unique()); +} + } // namespace ScriptableRenderPipelineHost::ScriptableRenderPipelineHost() @@ -37,6 +52,7 @@ ScriptableRenderPipelineHost::ScriptableRenderPipelineHost() ScriptableRenderPipelineHost::ScriptableRenderPipelineHost( std::unique_ptr mainSceneRenderer) { + InstallDefaultStandaloneStagePasses(*this); ResetMainSceneRenderer(std::move(mainSceneRenderer)); } @@ -46,6 +62,7 @@ ScriptableRenderPipelineHost::ScriptableRenderPipelineHost( mainSceneRendererAsset != nullptr ? std::move(mainSceneRendererAsset) : CreateDefaultMainSceneRendererAsset()) { + InstallDefaultStandaloneStagePasses(*this); ResetMainSceneRenderer( CreateMainSceneRendererFromAsset(m_mainSceneRendererAsset)); } @@ -79,6 +96,7 @@ void ScriptableRenderPipelineHost::Shutdown() { if (m_mainSceneRenderer != nullptr) { m_mainSceneRenderer->Shutdown(); } + ShutdownCameraFrameStandalonePasses(); } bool ScriptableRenderPipelineHost::SupportsMainSceneRenderGraph() const { diff --git a/tests/Rendering/unit/test_camera_frame_graph_stage_contract.cpp b/tests/Rendering/unit/test_camera_frame_graph_stage_contract.cpp index c1489356..dd9c0721 100644 --- a/tests/Rendering/unit/test_camera_frame_graph_stage_contract.cpp +++ b/tests/Rendering/unit/test_camera_frame_graph_stage_contract.cpp @@ -10,6 +10,8 @@ #include "Rendering/Execution/Internal/CameraFrameGraph/ExecutionState.h" #include "Rendering/Graph/RenderGraph.h" +#include + using namespace XCEngine::Rendering; namespace { @@ -95,6 +97,7 @@ public: } void Shutdown() override { + ShutdownCameraFrameStandalonePasses(); } bool SupportsMainSceneRenderGraph() const override { @@ -149,6 +152,17 @@ public: XCEngine::RHI::ResourceStates::Common; }; +template +PassT* InstallStandaloneStagePass( + RenderPipeline& pipeline, + CameraFrameStage stage, + Args&&... args) { + auto pass = std::make_unique(std::forward(args)...); + PassT* const passRaw = pass.get(); + pipeline.SetCameraFrameStandalonePass(stage, std::move(pass)); + return passRaw; +} + RenderGraphTextureDesc BuildTestRenderGraphTextureDesc() { RenderGraphTextureDesc desc = {}; desc.width = 320u; @@ -407,29 +421,37 @@ TEST(CameraFrameRenderGraphStageContract_Test, BuildsStandaloneShadowStageSceneD } TEST(CameraFrameRenderGraphStageContract_Test, ResolvesStandaloneStagePassFromExecutionState) { - RecordingRenderPass objectIdPass = {}; - RecordingRenderPass depthOnlyPass = {}; - RecordingRenderPass shadowCasterPass = {}; + RecordingPipeline pipeline = {}; CameraFrameExecutionState executionState = {}; - executionState.objectIdPass = &objectIdPass; - executionState.depthOnlyPass = &depthOnlyPass; - executionState.shadowCasterPass = &shadowCasterPass; + executionState.pipeline = &pipeline; + RecordingRenderPass* const objectIdPass = + InstallStandaloneStagePass( + pipeline, + CameraFrameStage::ObjectId); + RecordingRenderPass* const depthOnlyPass = + InstallStandaloneStagePass( + pipeline, + CameraFrameStage::DepthOnly); + RecordingRenderPass* const shadowCasterPass = + InstallStandaloneStagePass( + pipeline, + CameraFrameStage::ShadowCaster); EXPECT_EQ( ResolveCameraFrameStandaloneStagePass( CameraFrameStage::ObjectId, executionState), - &objectIdPass); + objectIdPass); EXPECT_EQ( ResolveCameraFrameStandaloneStagePass( CameraFrameStage::DepthOnly, executionState), - &depthOnlyPass); + depthOnlyPass); EXPECT_EQ( ResolveCameraFrameStandaloneStagePass( CameraFrameStage::ShadowCaster, executionState), - &shadowCasterPass); + shadowCasterPass); EXPECT_EQ( ResolveCameraFrameStandaloneStagePass( CameraFrameStage::MainScene, @@ -437,6 +459,56 @@ TEST(CameraFrameRenderGraphStageContract_Test, ResolvesStandaloneStagePassFromEx nullptr); } +TEST(CameraFrameRenderGraphStageContract_Test, ResolvesScenePassRequestsFromRuntimeContext) { + StageContractTestContext testContext = {}; + testContext.shadowState.shadowCasterRequest.surface = RenderSurface(256, 128); + testContext.shadowState.shadowCasterRequest.surface.SetDepthAttachment( + reinterpret_cast(141)); + testContext.plan.request.depthOnly.surface = RenderSurface(320, 180); + testContext.plan.request.depthOnly.surface.SetDepthAttachment( + reinterpret_cast(142)); + + const CameraFrameRenderGraphStageContext context = testContext.BuildStageContext(); + + EXPECT_EQ( + ResolveCameraFrameStageScenePassRequest( + CameraFrameStage::ShadowCaster, + context), + &testContext.shadowState.shadowCasterRequest); + EXPECT_EQ( + ResolveCameraFrameStageScenePassRequest( + CameraFrameStage::DepthOnly, + context), + &testContext.plan.request.depthOnly); + EXPECT_EQ( + ResolveCameraFrameStageScenePassRequest( + CameraFrameStage::ObjectId, + context), + nullptr); +} + +TEST(CameraFrameRenderGraphStageContract_Test, ResolvesObjectIdRequestFromRuntimeContext) { + StageContractTestContext testContext = {}; + testContext.plan.request.objectId.surface = RenderSurface(400, 240); + testContext.plan.request.objectId.surface.SetColorAttachment( + reinterpret_cast(151)); + testContext.plan.request.objectId.surface.SetDepthAttachment( + reinterpret_cast(152)); + + const CameraFrameRenderGraphStageContext context = testContext.BuildStageContext(); + + EXPECT_EQ( + ResolveCameraFrameStageObjectIdRequest( + CameraFrameStage::ObjectId, + context), + &testContext.plan.request.objectId); + EXPECT_EQ( + ResolveCameraFrameStageObjectIdRequest( + CameraFrameStage::DepthOnly, + context), + nullptr); +} + TEST(CameraFrameRenderGraphStageContract_Test, PublishesShadowCasterDepthAliasOnlyWhenShadowSamplingIsValid) { RenderGraph graph = {}; RenderGraphBuilder graphBuilder(graph); @@ -1131,8 +1203,12 @@ TEST(CameraFrameRenderGraphStageContract_Test, InitializesStandaloneStagePassAnd TEST(CameraFrameRenderGraphStageContract_Test, ExecutesShadowCasterRecordedStageUsingFallbackSurfaceExtent) { StageContractTestContext testContext = {}; - RecordingRenderPass shadowPass = {}; - testContext.executionState.shadowCasterPass = &shadowPass; + RecordingPipeline pipeline = {}; + testContext.executionState.pipeline = &pipeline; + RecordingRenderPass* const shadowPass = + InstallStandaloneStagePass( + pipeline, + CameraFrameStage::ShadowCaster); testContext.shadowState.shadowCasterRequest.surface = RenderSurface(256, 128); testContext.shadowState.shadowCasterRequest.surface.SetDepthAttachment( reinterpret_cast(301)); @@ -1157,16 +1233,16 @@ TEST(CameraFrameRenderGraphStageContract_Test, ExecutesShadowCasterRecordedStage context, testContext.executionState, passContext)); - EXPECT_EQ(shadowPass.initializeCalls, 1); - EXPECT_EQ(shadowPass.executeCalls, 1); - ASSERT_NE(shadowPass.lastExecuteRenderContext, nullptr); - EXPECT_EQ(shadowPass.lastExecuteRenderContext, &testContext.plan.request.context); - EXPECT_EQ(shadowPass.lastExecuteSurface.GetWidth(), 1024u); - EXPECT_EQ(shadowPass.lastExecuteSurface.GetHeight(), 512u); - EXPECT_FLOAT_EQ(shadowPass.lastExecuteSceneData.cameraData.aspectRatio, 1.75f); - EXPECT_EQ(shadowPass.lastExecuteSceneData.cameraData.viewportWidth, 1024u); - EXPECT_EQ(shadowPass.lastExecuteSceneData.cameraData.viewportHeight, 512u); - EXPECT_EQ(shadowPass.lastExecuteSceneData.cameraData.clearFlags, RenderClearFlags::All); + EXPECT_EQ(shadowPass->initializeCalls, 1); + EXPECT_EQ(shadowPass->executeCalls, 1); + ASSERT_NE(shadowPass->lastExecuteRenderContext, nullptr); + EXPECT_EQ(shadowPass->lastExecuteRenderContext, &testContext.plan.request.context); + EXPECT_EQ(shadowPass->lastExecuteSurface.GetWidth(), 1024u); + EXPECT_EQ(shadowPass->lastExecuteSurface.GetHeight(), 512u); + EXPECT_FLOAT_EQ(shadowPass->lastExecuteSceneData.cameraData.aspectRatio, 1.75f); + EXPECT_EQ(shadowPass->lastExecuteSceneData.cameraData.viewportWidth, 1024u); + EXPECT_EQ(shadowPass->lastExecuteSceneData.cameraData.viewportHeight, 512u); + EXPECT_EQ(shadowPass->lastExecuteSceneData.cameraData.clearFlags, RenderClearFlags::All); } TEST(CameraFrameRenderGraphStageContract_Test, ExecutesMainSceneRecordedStageWithForwardedFrameExecutionContext) { @@ -1213,8 +1289,12 @@ TEST(CameraFrameRenderGraphStageContract_Test, ExecutesMainSceneRecordedStageWit TEST(CameraFrameRenderGraphStageContract_Test, SkipsObjectIdRecordedStageWhenRequestIsMissing) { StageContractTestContext testContext = {}; - RecordingRenderPass objectIdPass = {}; - testContext.executionState.objectIdPass = &objectIdPass; + RecordingPipeline pipeline = {}; + testContext.executionState.pipeline = &pipeline; + RecordingRenderPass* const objectIdPass = + InstallStandaloneStagePass( + pipeline, + CameraFrameStage::ObjectId); const CameraFrameRenderGraphStageContext context = testContext.BuildStageContext(); const RenderSurface outputSurface(800, 600); @@ -1232,14 +1312,18 @@ TEST(CameraFrameRenderGraphStageContract_Test, SkipsObjectIdRecordedStageWhenReq context, testContext.executionState, passContext)); - EXPECT_EQ(objectIdPass.initializeCalls, 0); - EXPECT_EQ(objectIdPass.executeCalls, 0); + EXPECT_EQ(objectIdPass->initializeCalls, 0); + EXPECT_EQ(objectIdPass->executeCalls, 0); } TEST(CameraFrameRenderGraphStageContract_Test, ExecutesDepthOnlyFallbackPassUsingResolvedFallbackSurface) { StageContractTestContext testContext = {}; - RecordingRenderPass depthOnlyPass = {}; - testContext.executionState.depthOnlyPass = &depthOnlyPass; + RecordingPipeline pipeline = {}; + testContext.executionState.pipeline = &pipeline; + RecordingRenderPass* const depthOnlyPass = + InstallStandaloneStagePass( + pipeline, + CameraFrameStage::DepthOnly); testContext.plan.request.depthOnly.surface = RenderSurface(320, 180); testContext.plan.request.depthOnly.surface.SetDepthAttachment( reinterpret_cast(501)); @@ -1261,12 +1345,12 @@ TEST(CameraFrameRenderGraphStageContract_Test, ExecutesDepthOnlyFallbackPassUsin context, testContext.executionState, graphContext)); - EXPECT_EQ(depthOnlyPass.initializeCalls, 1); - EXPECT_EQ(depthOnlyPass.executeCalls, 1); - EXPECT_EQ(depthOnlyPass.lastExecuteSurface.GetWidth(), 960u); - EXPECT_EQ(depthOnlyPass.lastExecuteSurface.GetHeight(), 540u); - EXPECT_EQ(depthOnlyPass.lastExecuteSceneData.cameraData.viewportWidth, 960u); - EXPECT_EQ(depthOnlyPass.lastExecuteSceneData.cameraData.viewportHeight, 540u); - EXPECT_EQ(depthOnlyPass.lastExecuteSceneData.cameraData.clearFlags, RenderClearFlags::Color); + EXPECT_EQ(depthOnlyPass->initializeCalls, 1); + EXPECT_EQ(depthOnlyPass->executeCalls, 1); + EXPECT_EQ(depthOnlyPass->lastExecuteSurface.GetWidth(), 960u); + EXPECT_EQ(depthOnlyPass->lastExecuteSurface.GetHeight(), 540u); + EXPECT_EQ(depthOnlyPass->lastExecuteSceneData.cameraData.viewportWidth, 960u); + EXPECT_EQ(depthOnlyPass->lastExecuteSceneData.cameraData.viewportHeight, 540u); + EXPECT_EQ(depthOnlyPass->lastExecuteSceneData.cameraData.clearFlags, RenderClearFlags::Color); } diff --git a/tests/Rendering/unit/test_camera_frame_graph_stage_policy.cpp b/tests/Rendering/unit/test_camera_frame_graph_stage_policy.cpp index c5ba5495..30d5da9f 100644 --- a/tests/Rendering/unit/test_camera_frame_graph_stage_policy.cpp +++ b/tests/Rendering/unit/test_camera_frame_graph_stage_policy.cpp @@ -8,6 +8,35 @@ TEST(CameraFrameRenderGraphStagePolicy_Test, ReportsStageFullscreenAndTransition EXPECT_TRUE(IsCameraFrameFullscreenSequenceStage(CameraFrameStage::PostProcess)); EXPECT_TRUE(IsCameraFrameFullscreenSequenceStage(CameraFrameStage::FinalOutput)); EXPECT_FALSE(IsCameraFrameFullscreenSequenceStage(CameraFrameStage::MainScene)); + EXPECT_TRUE(IsCameraFrameSequenceStage(CameraFrameStage::PreScenePasses)); + EXPECT_TRUE(IsCameraFrameSequenceStage(CameraFrameStage::OverlayPasses)); + EXPECT_FALSE(IsCameraFrameSequenceStage(CameraFrameStage::MainScene)); + + EXPECT_EQ( + GetCameraFrameStageExecutionKind(CameraFrameStage::PostProcess), + CameraFrameStageExecutionKind::Sequence); + EXPECT_EQ( + GetCameraFrameStageExecutionKind(CameraFrameStage::ObjectId), + CameraFrameStageExecutionKind::StandalonePass); + EXPECT_EQ( + GetCameraFrameStageExecutionKind(CameraFrameStage::MainScene), + CameraFrameStageExecutionKind::MainScenePipeline); + + EXPECT_EQ( + GetCameraFrameStageRequestKind(CameraFrameStage::ShadowCaster), + CameraFrameStageRequestKind::ShadowCaster); + EXPECT_EQ( + GetCameraFrameStageRequestKind(CameraFrameStage::DepthOnly), + CameraFrameStageRequestKind::DepthOnly); + EXPECT_EQ( + GetCameraFrameStageRequestKind(CameraFrameStage::ObjectId), + CameraFrameStageRequestKind::ObjectId); + EXPECT_EQ( + GetCameraFrameStageRequestKind(CameraFrameStage::MainScene), + CameraFrameStageRequestKind::None); + EXPECT_TRUE(IsCameraFrameScenePassRequestStage(CameraFrameStage::ShadowCaster)); + EXPECT_TRUE(IsCameraFrameScenePassRequestStage(CameraFrameStage::DepthOnly)); + EXPECT_FALSE(IsCameraFrameScenePassRequestStage(CameraFrameStage::ObjectId)); EXPECT_TRUE(DoesCameraFrameStageGraphOwnColorTransitions(CameraFrameStage::MainScene)); EXPECT_TRUE(DoesCameraFrameStageGraphOwnColorTransitions(CameraFrameStage::FinalOutput)); @@ -16,6 +45,12 @@ TEST(CameraFrameRenderGraphStagePolicy_Test, ReportsStageFullscreenAndTransition EXPECT_TRUE(DoesCameraFrameStageGraphOwnDepthTransitions(CameraFrameStage::MainScene)); EXPECT_TRUE(DoesCameraFrameStageGraphOwnDepthTransitions(CameraFrameStage::ShadowCaster)); EXPECT_FALSE(DoesCameraFrameStageGraphOwnDepthTransitions(CameraFrameStage::FinalOutput)); + + EXPECT_TRUE(SupportsCameraFrameStandalonePass(CameraFrameStage::ShadowCaster)); + EXPECT_TRUE(SupportsCameraFrameStandalonePass(CameraFrameStage::DepthOnly)); + EXPECT_TRUE(SupportsCameraFrameStandalonePass(CameraFrameStage::ObjectId)); + EXPECT_FALSE(SupportsCameraFrameStandalonePass(CameraFrameStage::MainScene)); + EXPECT_FALSE(SupportsCameraFrameStandalonePass(CameraFrameStage::OverlayPasses)); } TEST(CameraFrameRenderGraphStagePolicy_Test, ReportsGraphManagedOutputColorStagesFromPlan) { diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index 4dc660f2..2e5c5cda 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -23,6 +23,7 @@ #include "Rendering/Execution/Internal/CameraFrameGraph/SurfaceResolver.h" #include #include +#include #include 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 m_state; }; +template +PassT* InstallStandaloneStagePass( + RenderPipeline& pipeline, + CameraFrameStage stage, + Args&&... args) { + auto pass = std::make_unique(std::forward(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 state) @@ -1147,11 +1160,13 @@ TEST(CameraRenderer_Test, ExecutesObjectIdPassBetweenPipelineAndPostPassesWhenRe camera->SetDepth(3.0f); auto state = std::make_shared(); - auto objectIdPass = std::make_unique(state); - MockObjectIdPass* objectIdPassRaw = objectIdPass.get(); - CameraRenderer renderer( - std::make_unique(state), - std::move(objectIdPass)); + auto pipeline = std::make_unique(state); + MockObjectIdPass* objectIdPassRaw = + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + state); + CameraRenderer renderer(std::move(pipeline)); RenderPassSequence prePasses; prePasses.AddPass(std::make_unique(state, "pre")); @@ -1642,15 +1657,22 @@ TEST(CameraRenderer_Test, ExecutesFormalFrameStagesInDocumentedOrder) { camera->SetDepth(3.0f); auto state = std::make_shared(); - CameraRenderer renderer( - std::make_unique(state), - std::make_unique(state)); - - auto shadowPass = std::make_unique(state, "shadowCaster"); - renderer.SetShadowCasterPass(std::move(shadowPass)); - - auto depthPass = std::make_unique(state, "depthOnly"); - renderer.SetDepthOnlyPass(std::move(depthPass)); + auto pipeline = std::make_unique(state); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + state); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ShadowCaster, + state, + "shadowCaster"); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::DepthOnly, + state, + "depthOnly"); + CameraRenderer renderer(std::move(pipeline)); RenderPassSequence prePasses; prePasses.AddPass(std::make_unique(state, "pre")); @@ -1933,17 +1955,24 @@ TEST(CameraRenderer_Test, ExecutesShadowCasterAndDepthOnlyRequestsBeforeMainPipe camera->SetDepth(3.0f); auto state = std::make_shared(); - CameraRenderer renderer( - std::make_unique(state), - std::make_unique(state)); - - auto shadowPass = std::make_unique(state, "shadowCaster"); - MockScenePass* shadowPassRaw = shadowPass.get(); - renderer.SetShadowCasterPass(std::move(shadowPass)); - - auto depthPass = std::make_unique(state, "depthOnly"); - MockScenePass* depthPassRaw = depthPass.get(); - renderer.SetDepthOnlyPass(std::move(depthPass)); + auto pipeline = std::make_unique(state); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + state); + MockScenePass* shadowPassRaw = + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ShadowCaster, + state, + "shadowCaster"); + MockScenePass* depthPassRaw = + InstallStandaloneStagePass( + *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(); - CameraRenderer renderer( - std::make_unique(state), - std::make_unique(state, true, true)); - - auto shadowPass = std::make_unique(state, "shadowCaster", true, true, true); - MockScenePass* shadowPassRaw = shadowPass.get(); - renderer.SetShadowCasterPass(std::move(shadowPass)); - - auto depthPass = std::make_unique(state, "depthOnly", true, true, true); - MockScenePass* depthPassRaw = depthPass.get(); - renderer.SetDepthOnlyPass(std::move(depthPass)); + auto pipeline = std::make_unique(state); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + state, + true, + true); + MockScenePass* shadowPassRaw = + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ShadowCaster, + state, + "shadowCaster", + true, + true, + true); + MockScenePass* depthPassRaw = + InstallStandaloneStagePass( + *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(pipelineState), - std::make_unique(pipelineState)); - - auto shadowPass = std::make_unique(pipelineState, "shadowCaster"); - MockScenePass* shadowPassRaw = shadowPass.get(); - renderer.SetShadowCasterPass(std::move(shadowPass)); + auto pipeline = std::make_unique(pipelineState); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + pipelineState); + MockScenePass* shadowPassRaw = + InstallStandaloneStagePass( + *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(pipelineState), - std::make_unique(pipelineState)); - - auto shadowPass = std::make_unique(pipelineState, "shadowCaster"); - renderer.SetShadowCasterPass(std::move(shadowPass)); + auto pipeline = std::make_unique(pipelineState); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + pipelineState); + InstallStandaloneStagePass( + *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(pipelineState), - std::make_unique(pipelineState)); - - auto shadowPass = std::make_unique(pipelineState, "shadowCaster"); - renderer.SetShadowCasterPass(std::move(shadowPass)); + auto pipeline = std::make_unique(pipelineState); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + pipelineState); + InstallStandaloneStagePass( + *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(pipelineState), - std::make_unique(pipelineState)); - - auto shadowPass = std::make_unique(pipelineState, "shadowCaster"); - renderer.SetShadowCasterPass(std::move(shadowPass)); + auto pipeline = std::make_unique(pipelineState); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + pipelineState); + InstallStandaloneStagePass( + *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(pipelineState), - std::make_unique(pipelineState)); - - auto shadowPass = std::make_unique(pipelineState, "shadowCaster"); - renderer.SetShadowCasterPass(std::move(shadowPass)); + auto pipeline = std::make_unique(pipelineState); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + pipelineState); + InstallStandaloneStagePass( + *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(); - CameraRenderer renderer( - std::make_unique(state), - std::make_unique(state, false)); + auto pipeline = std::make_unique(state); + InstallStandaloneStagePass( + *pipeline, + CameraFrameStage::ObjectId, + state, + false); + CameraRenderer renderer(std::move(pipeline)); RenderPassSequence prePasses; prePasses.AddPass(std::make_unique(state, "pre"));