From 31a979f779d467bec0d46e6dc67376add7f4d421 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 15 Apr 2026 08:51:40 +0800 Subject: [PATCH] refactor(rendering): route camera-stage graph pass recording through contract --- .../CameraFrameRenderGraphStageContract.cpp | 70 +++++++ .../CameraFrameRenderGraphStageContract.h | 23 +++ ...meraFrameRenderGraphStagePassRecording.cpp | 44 +--- ...mera_frame_render_graph_stage_contract.cpp | 190 ++++++++++++++++++ 4 files changed, 293 insertions(+), 34 deletions(-) diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.cpp index 3387c784..b77632b8 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.cpp @@ -3,6 +3,7 @@ #include "Rendering/Execution/Internal/CameraFrameRenderGraphBuilderContext.h" #include "Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRuntime.h" #include "Rendering/Graph/RenderGraph.h" +#include namespace XCEngine { namespace Rendering { @@ -35,6 +36,52 @@ RenderPassContext BuildCameraFrameStageGraphPassContext( }; } +RenderPassRenderGraphContext BuildCameraFrameStandaloneStageRenderGraphContext( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + const RenderSceneData& sceneData, + RenderPass& pass, + bool& stageExecutionSucceeded) { + bool* const stageExecutionSucceededPtr = &stageExecutionSucceeded; + RenderPass* const passPtr = &pass; + const RenderPassGraphBeginCallback beginPass = + [stageExecutionSucceededPtr, passPtr, renderContext = &context.plan.request.context]( + const RenderPassContext&) -> bool { + if (!InitializeCameraFrameStandalonePass( + passPtr, + *renderContext)) { + *stageExecutionSucceededPtr = false; + return false; + } + + return true; + }; + return BuildRenderPassRenderGraphContext( + BuildCameraFrameStageGraphRecordingContext( + context, + stageState, + stageState.stageName, + sceneData, + std::vector{ stageState.outputColor }, + stageState.outputSurface.depthTexture), + beginPass); +} + +bool RecordCameraFrameStandaloneStageRenderGraphPass( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + const RenderSceneData& sceneData, + RenderPass& pass, + bool& stageExecutionSucceeded) { + return pass.RecordRenderGraph( + BuildCameraFrameStandaloneStageRenderGraphContext( + context, + stageState, + sceneData, + pass, + stageExecutionSucceeded)); +} + CameraFrameRenderGraphSourceBinding ResolveCameraFrameFullscreenStageGraphSourceBinding( const CameraFramePlan& plan, CameraFrameStage stage, @@ -158,6 +205,29 @@ RenderPassContext BuildCameraFrameStageFallbackPassContext( }; } +RenderPipelineMainSceneRenderGraphContext BuildCameraFrameMainSceneStageRenderGraphContext( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState) { + return BuildRenderPipelineMainSceneRenderGraphContext( + BuildCameraFrameStageGraphRecordingContext( + context, + stageState, + stageState.stageName, + context.sceneData, + std::vector{ stageState.outputColor }, + stageState.outputSurface.depthTexture)); +} + +bool RecordCameraFrameMainSceneGraphPass( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + RenderPipelineRenderer& pipeline) { + return pipeline.RecordMainSceneRenderGraph( + BuildCameraFrameMainSceneStageRenderGraphContext( + context, + stageState)); +} + void RecordCameraFrameStageFallbackPassIO( const CameraFrameStageGraphBuildState& stageState, RenderGraphPassBuilder& passBuilder) { diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.h b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.h index a4e14339..c86cc0e3 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.h +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.h @@ -28,6 +28,20 @@ RenderPassContext BuildCameraFrameStageGraphPassContext( const CameraFrameStageGraphBuildState& stageState, const RenderSceneData& sceneData); +RenderPassRenderGraphContext BuildCameraFrameStandaloneStageRenderGraphContext( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + const RenderSceneData& sceneData, + RenderPass& pass, + bool& stageExecutionSucceeded); + +bool RecordCameraFrameStandaloneStageRenderGraphPass( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + const RenderSceneData& sceneData, + RenderPass& pass, + bool& stageExecutionSucceeded); + CameraFrameRenderGraphSourceBinding ResolveCameraFrameFullscreenStageGraphSourceBinding( const CameraFramePlan& plan, CameraFrameStage stage, @@ -65,6 +79,15 @@ RenderPassContext BuildCameraFrameStageFallbackPassContext( const RenderContext& renderContext, const RenderSceneData& sceneData); +RenderPipelineMainSceneRenderGraphContext BuildCameraFrameMainSceneStageRenderGraphContext( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState); + +bool RecordCameraFrameMainSceneGraphPass( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + RenderPipelineRenderer& pipeline); + void RecordCameraFrameStageFallbackPassIO( const CameraFrameStageGraphBuildState& stageState, RenderGraphPassBuilder& passBuilder); diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp index 78d266d2..a5ee8c48 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp @@ -33,30 +33,12 @@ bool TryRecordCameraFrameStageStandaloneRenderGraphPass( stageState.stage, context, stageState.surfaceTemplate); - bool* const stageExecutionSucceeded = &builder.stageExecutionSucceeded; - const RenderPassGraphBeginCallback beginStandalonePass = - [stageExecutionSucceeded, standaloneStagePass, renderContext = &context.plan.request.context]( - const RenderPassContext&) -> bool { - if (!InitializeCameraFrameStandalonePass( - standaloneStagePass, - *renderContext)) { - *stageExecutionSucceeded = false; - return false; - } - - return true; - }; - const RenderPassRenderGraphContext standalonePassContext = - BuildRenderPassRenderGraphContext( - BuildCameraFrameStageGraphRecordingContext( - context, - stageState, - stageState.stageName, - stageSceneData, - std::vector{ stageState.outputColor }, - stageState.outputSurface.depthTexture), - beginStandalonePass); - if (!standaloneStagePass->RecordRenderGraph(standalonePassContext)) { + if (!RecordCameraFrameStandaloneStageRenderGraphPass( + context, + stageState, + stageSceneData, + *standaloneStagePass, + builder.stageExecutionSucceeded)) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, Containers::String("CameraRenderer::Render failed: RenderPass::RecordRenderGraph returned false for ") + @@ -80,16 +62,10 @@ bool TryRecordCameraFrameMainSceneGraphPass( } handled = true; - const RenderPipelineMainSceneRenderGraphContext mainSceneContext = - BuildRenderPipelineMainSceneRenderGraphContext( - BuildCameraFrameStageGraphRecordingContext( - context, - stageState, - stageState.stageName, - context.sceneData, - std::vector{ stageState.outputColor }, - stageState.outputSurface.depthTexture)); - if (!builder.executionState.pipeline->RecordMainSceneRenderGraph(mainSceneContext)) { + if (!RecordCameraFrameMainSceneGraphPass( + context, + stageState, + *builder.executionState.pipeline)) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, "CameraRenderer::Render failed: RenderPipeline::RecordMainSceneRenderGraph returned false"); diff --git a/tests/Rendering/unit/test_camera_frame_render_graph_stage_contract.cpp b/tests/Rendering/unit/test_camera_frame_render_graph_stage_contract.cpp index 8bc744bc..c30779b5 100644 --- a/tests/Rendering/unit/test_camera_frame_render_graph_stage_contract.cpp +++ b/tests/Rendering/unit/test_camera_frame_render_graph_stage_contract.cpp @@ -14,6 +14,88 @@ using namespace XCEngine::Rendering; namespace { +class RecordingRenderPass final : public RenderPass { +public: + const char* GetName() const override { + return "RecordingRenderPass"; + } + + bool Initialize(const RenderContext&) override { + ++initializeCalls; + return initializeResult; + } + + bool SupportsRenderGraph() const override { + return true; + } + + bool RecordRenderGraph(const RenderPassRenderGraphContext& context) override { + ++recordCalls; + lastPassName = context.passName.CStr(); + lastBeginPassCallback = context.beginPassCallback; + lastColorTargets = context.colorTargets; + lastDepthTarget = context.depthTarget; + lastExecutionSucceeded = context.executionSucceeded; + lastBlackboard = context.blackboard; + return recordResult; + } + + bool Execute(const RenderPassContext&) override { + return true; + } + + bool initializeResult = true; + bool recordResult = true; + int initializeCalls = 0; + int recordCalls = 0; + std::string lastPassName = {}; + RenderPassGraphBeginCallback lastBeginPassCallback = {}; + std::vector lastColorTargets = {}; + RenderGraphTextureHandle lastDepthTarget = {}; + bool* lastExecutionSucceeded = nullptr; + RenderGraphBlackboard* lastBlackboard = nullptr; +}; + +class RecordingPipeline final : public RenderPipeline { +public: + bool Initialize(const RenderContext&) override { + return true; + } + + void Shutdown() override { + } + + bool SupportsMainSceneRenderGraph() const override { + return true; + } + + bool RecordMainSceneRenderGraph( + const RenderPipelineMainSceneRenderGraphContext& context) override { + ++recordCalls; + lastPassName = context.passName.CStr(); + lastColorTargets = context.colorTargets; + lastDepthTarget = context.depthTarget; + lastExecutionSucceeded = context.executionSucceeded; + lastBlackboard = context.blackboard; + return recordResult; + } + + bool Render( + const RenderContext&, + const RenderSurface&, + const RenderSceneData&) override { + return true; + } + + bool recordResult = true; + int recordCalls = 0; + std::string lastPassName = {}; + std::vector lastColorTargets = {}; + RenderGraphTextureHandle lastDepthTarget = {}; + bool* lastExecutionSucceeded = nullptr; + RenderGraphBlackboard* lastBlackboard = nullptr; +}; + RenderGraphTextureDesc BuildTestRenderGraphTextureDesc() { RenderGraphTextureDesc desc = {}; desc.width = 320u; @@ -183,6 +265,114 @@ TEST(CameraFrameRenderGraphStageContract_Test, BuildsRecordingContextFromStageSt EXPECT_EQ(recordingContext.blackboard, &blackboard); } +TEST(CameraFrameRenderGraphStageContract_Test, RecordsStandaloneStageGraphPassWithDeferredInitializeCallback) { + RenderGraph graph = {}; + RenderGraphBuilder graphBuilder(graph); + RenderGraphBlackboard blackboard = {}; + CameraFrameRenderGraphFrameData& frameData = + EmplaceCameraFrameRenderGraphFrameData(blackboard); + RenderGraphImportedTextureRegistry importedTextures = {}; + CameraFrameExecutionState executionState = {}; + bool stageExecutionSucceeded = true; + CameraFrameRenderGraphBuilderContext builderContext = { + graphBuilder, + blackboard, + frameData, + importedTextures, + executionState, + stageExecutionSucceeded + }; + CameraFramePlan plan = {}; + plan.request.context.backendType = XCEngine::RHI::RHIType::D3D12; + DirectionalShadowExecutionState shadowState = {}; + RenderSceneData sceneData = {}; + const CameraFrameRenderGraphStageContext context = { + plan, + shadowState, + sceneData, + builderContext + }; + + CameraFrameStageGraphBuildState stageState = {}; + stageState.stageName = "ObjectId"; + stageState.surfaceTemplate = RenderSurface(800, 600); + stageState.outputColor = RenderGraphTextureHandle{ 19u }; + stageState.outputSurface.depthTexture = RenderGraphTextureHandle{ 23u }; + + RecordingRenderPass pass = {}; + ASSERT_TRUE(RecordCameraFrameStandaloneStageRenderGraphPass( + context, + stageState, + sceneData, + pass, + stageExecutionSucceeded)); + ASSERT_EQ(pass.recordCalls, 1); + EXPECT_STREQ(pass.lastPassName.c_str(), "ObjectId"); + ASSERT_TRUE(pass.lastBeginPassCallback); + ASSERT_EQ(pass.lastColorTargets.size(), 1u); + EXPECT_EQ(pass.lastColorTargets[0].index, 19u); + EXPECT_EQ(pass.lastDepthTarget.index, 23u); + EXPECT_EQ(pass.lastExecutionSucceeded, &stageExecutionSucceeded); + EXPECT_EQ(pass.lastBlackboard, &blackboard); + + const RenderPassContext passContext = + BuildCameraFrameStageGraphPassContext( + context, + stageState, + sceneData); + EXPECT_TRUE(pass.lastBeginPassCallback(passContext)); + EXPECT_EQ(pass.initializeCalls, 1); + EXPECT_TRUE(stageExecutionSucceeded); +} + +TEST(CameraFrameRenderGraphStageContract_Test, RecordsMainSceneGraphPassFromStageContract) { + RenderGraph graph = {}; + RenderGraphBuilder graphBuilder(graph); + RenderGraphBlackboard blackboard = {}; + CameraFrameRenderGraphFrameData& frameData = + EmplaceCameraFrameRenderGraphFrameData(blackboard); + RenderGraphImportedTextureRegistry importedTextures = {}; + CameraFrameExecutionState executionState = {}; + bool stageExecutionSucceeded = true; + CameraFrameRenderGraphBuilderContext builderContext = { + graphBuilder, + blackboard, + frameData, + importedTextures, + executionState, + stageExecutionSucceeded + }; + CameraFramePlan plan = {}; + plan.request.context.backendType = XCEngine::RHI::RHIType::D3D12; + DirectionalShadowExecutionState shadowState = {}; + RenderSceneData sceneData = {}; + const CameraFrameRenderGraphStageContext context = { + plan, + shadowState, + sceneData, + builderContext + }; + + CameraFrameStageGraphBuildState stageState = {}; + stageState.stageName = "MainScene"; + stageState.surfaceTemplate = RenderSurface(1280, 720); + stageState.outputColor = RenderGraphTextureHandle{ 41u }; + stageState.outputSurface.depthTexture = RenderGraphTextureHandle{ 43u }; + + RecordingPipeline pipeline = {}; + ASSERT_TRUE(RecordCameraFrameMainSceneGraphPass( + context, + stageState, + pipeline)); + ASSERT_EQ(pipeline.recordCalls, 1); + EXPECT_STREQ(pipeline.lastPassName.c_str(), "MainScene"); + ASSERT_EQ(pipeline.lastColorTargets.size(), 1u); + EXPECT_EQ(pipeline.lastColorTargets[0].index, 41u); + EXPECT_EQ(pipeline.lastDepthTarget.index, 43u); + EXPECT_EQ(pipeline.lastExecutionSucceeded, &stageExecutionSucceeded); + EXPECT_EQ(pipeline.lastBlackboard, &blackboard); +} + TEST(CameraFrameRenderGraphStageContract_Test, KeepsExplicitFullscreenSourceBindingUntouched) { CameraFramePlan plan = {}; RenderSurface stageSurface(320, 180);