From e42b0dc50bd7ba9c1fe3b193b8c630952fe21b79 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Wed, 15 Apr 2026 10:30:04 +0800 Subject: [PATCH] refactor(rendering): move sequence graph pass authoring into contract --- .../CameraFrameRenderGraphStageContract.cpp | 96 ++++++++ .../CameraFrameRenderGraphStageContract.h | 20 ++ ...FrameRenderGraphStageSequenceRecording.cpp | 226 +++++------------- ...mera_frame_render_graph_stage_contract.cpp | 175 ++++++++++++++ 4 files changed, 346 insertions(+), 171 deletions(-) diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.cpp index b77632b8..b363a4bc 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.cpp @@ -2,12 +2,27 @@ #include "Rendering/Execution/Internal/CameraFrameRenderGraphBuilderContext.h" #include "Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRuntime.h" +#include "Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h" #include "Rendering/Graph/RenderGraph.h" +#include #include namespace XCEngine { namespace Rendering { +namespace { + +bool RecordCameraFrameCompatibleGraphPass( + RenderPass& pass, + const RenderPassRenderGraphContext& context, + const RenderPassGraphIO& io) { + return pass.SupportsRenderGraph() + ? pass.RecordRenderGraph(context) + : RecordRasterRenderPass(pass, context, io); +} + +} // namespace + CameraFrameRenderGraphSourceBinding BuildCameraFrameStageGraphSourceBinding( const CameraFrameStageGraphBuildState& stageState) { return { @@ -82,6 +97,32 @@ bool RecordCameraFrameStandaloneStageRenderGraphPass( stageExecutionSucceeded)); } +bool RecordCameraFrameRegularSequenceStageRenderGraphPass( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + const Containers::String& passName, + const RenderGraphImportedSurface& outputSurface, + const RenderPassGraphBeginCallback& beginPassCallback, + RenderPass& pass) { + return RecordCameraFrameCompatibleGraphPass( + pass, + BuildRenderPassRenderGraphContext( + BuildCameraFrameStageGraphRecordingContext( + context, + stageState, + passName, + context.sceneData, + BuildCameraFrameStageGraphSourceBinding(stageState), + outputSurface.colorTextures, + outputSurface.depthTexture), + beginPassCallback), + { + false, + GetPrimaryColorTexture(outputSurface).IsValid(), + outputSurface.depthTexture.IsValid() + }); +} + CameraFrameRenderGraphSourceBinding ResolveCameraFrameFullscreenStageGraphSourceBinding( const CameraFramePlan& plan, CameraFrameStage stage, @@ -159,6 +200,61 @@ RenderGraphRecordingContext BuildCameraFrameStageGraphRecordingContext( depthTarget); } +bool RecordCameraFrameFullscreenSequenceStageGraphPass( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + const Containers::String& passName, + const CameraFrameRenderGraphSourceBinding& binding, + RenderGraphTextureHandle finalOutputColor, + size_t passIndex, + size_t passCount, + RenderGraphTextureHandle& currentSourceColor, + const RenderPassGraphBeginCallback& beginPassCallback, + RenderPass& pass) { + const bool isLastPass = (passIndex + 1u) == passCount; + const RenderGraphTextureHandle passOutputColor = + isLastPass + ? finalOutputColor + : context.builder.graphBuilder.CreateTransientTexture( + passName + ".Color", + BuildFullscreenTransientTextureDesc(stageState.surfaceTemplate)); + const CameraFrameRenderGraphSourceBinding passSourceBinding = { + passIndex == 0u + ? binding.sourceSurfaceTemplate + : &stageState.surfaceTemplate, + passIndex == 0u + ? binding.sourceColorView + : nullptr, + passIndex == 0u + ? binding.sourceColorState + : RHI::ResourceStates::PixelShaderResource, + currentSourceColor + }; + const bool recordSucceeded = + RecordCameraFrameCompatibleGraphPass( + pass, + BuildRenderPassRenderGraphContext( + BuildCameraFrameStageGraphRecordingContext( + context, + stageState, + passName, + context.sceneData, + passSourceBinding, + std::vector{ passOutputColor }, + {}), + beginPassCallback), + { + true, + true, + false + }); + if (recordSucceeded) { + currentSourceColor = passOutputColor; + } + + return recordSucceeded; +} + CameraFrameStageFallbackSurfaceResolution ResolveCameraFrameStageFallbackSurfaceResolution( const CameraFrameStageGraphBuildState& stageState, bool graphOwnsSourceTransitions, diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.h b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.h index c86cc0e3..470e873d 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.h +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageContract.h @@ -42,6 +42,14 @@ bool RecordCameraFrameStandaloneStageRenderGraphPass( RenderPass& pass, bool& stageExecutionSucceeded); +bool RecordCameraFrameRegularSequenceStageRenderGraphPass( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + const Containers::String& passName, + const RenderGraphImportedSurface& outputSurface, + const RenderPassGraphBeginCallback& beginPassCallback, + RenderPass& pass); + CameraFrameRenderGraphSourceBinding ResolveCameraFrameFullscreenStageGraphSourceBinding( const CameraFramePlan& plan, CameraFrameStage stage, @@ -69,6 +77,18 @@ RenderGraphRecordingContext BuildCameraFrameStageGraphRecordingContext( std::vector colorTargets, RenderGraphTextureHandle depthTarget); +bool RecordCameraFrameFullscreenSequenceStageGraphPass( + const CameraFrameRenderGraphStageContext& context, + const CameraFrameStageGraphBuildState& stageState, + const Containers::String& passName, + const CameraFrameRenderGraphSourceBinding& binding, + RenderGraphTextureHandle finalOutputColor, + size_t passIndex, + size_t passCount, + RenderGraphTextureHandle& currentSourceColor, + const RenderPassGraphBeginCallback& beginPassCallback, + RenderPass& pass); + CameraFrameStageFallbackSurfaceResolution ResolveCameraFrameStageFallbackSurfaceResolution( const CameraFrameStageGraphBuildState& stageState, bool graphOwnsSourceTransitions, diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp index 3dab97ed..cd111b62 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp @@ -7,7 +7,6 @@ #include "Rendering/Execution/Internal/CameraFrameRenderGraphStageState.h" #include "Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h" #include "Rendering/Graph/RenderGraph.h" -#include namespace XCEngine { namespace Rendering { @@ -45,15 +44,6 @@ std::unique_ptr* ResolveStageSequenceState( } } -bool RecordSequencePass( - RenderPass& pass, - const RenderPassRenderGraphContext& context, - const RenderPassGraphIO& io) { - return pass.SupportsRenderGraph() - ? pass.RecordRenderGraph(context) - : RecordRasterRenderPass(pass, context, io); -} - RenderPassGraphBeginCallback BuildSequenceBeginCallback( CameraFrameStage stage, RenderPassSequence* stageSequence, @@ -129,135 +119,6 @@ bool RecordStageSequencePasses( return true; } -bool RecordRegularPassSequenceStage( - CameraFrameStage stage, - const Containers::String& stageName, - const CameraFrameRenderGraphStageContext& stageContext, - const CameraFrameStageGraphBuildState& stageState, - const RenderPassContext& stagePassContext, - const RenderGraphImportedSurface& outputSurface, - const RenderSceneData& sceneData, - RenderPassSequence* stageSequence, - CameraFrameExecutionState& executionState, - bool& stageExecutionSucceeded) { - const bool writesColor = GetPrimaryColorTexture(outputSurface).IsValid(); - const bool writesDepth = outputSurface.depthTexture.IsValid(); - - return RecordStageSequencePasses( - stage, - stageName, - stageSequence, - executionState, - stagePassContext.renderContext, - stageExecutionSucceeded, - [&stageContext, &stageState, &sceneData, &outputSurface, writesColor, writesDepth]( - RenderPass& pass, - size_t, - const Containers::String& passName, - const RenderPassGraphBeginCallback& beginSequencePass) { - const RenderPassRenderGraphContext passContext = - BuildRenderPassRenderGraphContext( - BuildCameraFrameStageGraphRecordingContext( - stageContext, - stageState, - passName, - sceneData, - BuildCameraFrameStageGraphSourceBinding(stageState), - outputSurface.colorTextures, - outputSurface.depthTexture), - beginSequencePass); - return RecordSequencePass( - pass, - passContext, - { - false, - writesColor, - writesDepth - }); - }); -} - -bool RecordFullscreenPassSequenceStage( - CameraFrameStage stage, - const Containers::String& stageName, - const CameraFrameRenderGraphStageContext& stageContext, - const CameraFrameStageGraphBuildState& stageState, - const RenderPassContext& stagePassContext, - const CameraFrameRenderGraphSourceBinding& binding, - RenderGraphTextureHandle finalOutputColor, - const RenderSceneData& sceneData, - RenderPassSequence* stageSequence, - CameraFrameExecutionState& executionState, - RenderGraphBuilder& graphBuilder, - bool& stageExecutionSucceeded) { - RenderGraphTextureHandle currentSourceColor = binding.sourceColor; - const RenderGraphTextureDesc transientDesc = - BuildFullscreenTransientTextureDesc(stagePassContext.surface); - - return RecordStageSequencePasses( - stage, - stageName, - stageSequence, - executionState, - stagePassContext.renderContext, - stageExecutionSucceeded, - [&stageContext, &stageState, &stagePassContext, &sceneData, &graphBuilder, &transientDesc, &binding, finalOutputColor, ¤tSourceColor, stageSequence]( - RenderPass& pass, - size_t passIndex, - const Containers::String& passName, - const RenderPassGraphBeginCallback& beginSequencePass) { - const bool isLastPass = (passIndex + 1u) == stageSequence->GetPassCount(); - const RenderGraphTextureHandle passOutputColor = - isLastPass - ? finalOutputColor - : graphBuilder.CreateTransientTexture( - passName + ".Color", - transientDesc); - const RenderSurface* const sourceSurfaceTemplate = - passIndex == 0u - ? binding.sourceSurfaceTemplate - : &stagePassContext.surface; - RHI::RHIResourceView* const sourceColorView = - passIndex == 0u - ? binding.sourceColorView - : nullptr; - const RHI::ResourceStates sourceColorState = - passIndex == 0u - ? binding.sourceColorState - : RHI::ResourceStates::PixelShaderResource; - const RenderPassRenderGraphContext passContext = - BuildRenderPassRenderGraphContext( - BuildCameraFrameStageGraphRecordingContext( - stageContext, - stageState, - passName, - sceneData, - { - sourceSurfaceTemplate, - sourceColorView, - sourceColorState, - currentSourceColor - }, - std::vector{ passOutputColor }, - {}), - beginSequencePass); - const bool recordSucceeded = - RecordSequencePass( - pass, - passContext, - { - true, - true, - false - }); - if (recordSucceeded) { - currentSourceColor = passOutputColor; - } - - return recordSucceeded; - }); -} - } // namespace bool TryRecordCameraFrameStageSequence( @@ -271,45 +132,68 @@ bool TryRecordCameraFrameStageSequence( } handled = true; - const RenderPassContext stagePassContext = - BuildCameraFrameStageGraphPassContext( - context, - stageState, - context.sceneData); + const CameraFrameRenderGraphSourceBinding sourceBinding = + BuildCameraFrameStageGraphSourceBinding(stageState); const bool recordResult = IsCameraFrameFullscreenSequenceStage(stageState.stage) - ? RecordFullscreenPassSequenceStage( - stageState.stage, - stageState.stageName, - context, - stageState, - stagePassContext, - ResolveCameraFrameFullscreenStageGraphSourceBinding( - context.plan, + ? [&]() { + RenderGraphTextureHandle currentSourceColor = {}; + const CameraFrameRenderGraphSourceBinding fullscreenBinding = + ResolveCameraFrameFullscreenStageGraphSourceBinding( + context.plan, + stageState.stage, + stageState.surfaceTemplate, + sourceBinding.sourceSurfaceTemplate, + sourceBinding.sourceColorView, + sourceBinding.sourceColorState, + sourceBinding.sourceColor, + &builder.blackboard); + currentSourceColor = fullscreenBinding.sourceColor; + return RecordStageSequencePasses( stageState.stage, - stageState.surfaceTemplate, - stagePassContext.sourceSurface, - stagePassContext.sourceColorView, - stagePassContext.sourceColorState, - GetPrimaryColorTexture(stageState.sourceSurface), - &builder.blackboard), - stageState.outputColor, - context.sceneData, - stageState.stageSequence, - builder.executionState, - builder.graphBuilder, - builder.stageExecutionSucceeded) - : RecordRegularPassSequenceStage( + stageState.stageName, + stageState.stageSequence, + builder.executionState, + context.plan.request.context, + builder.stageExecutionSucceeded, + [&context, &stageState, &fullscreenBinding, ¤tSourceColor]( + RenderPass& pass, + size_t passIndex, + const Containers::String& passName, + const RenderPassGraphBeginCallback& beginSequencePass) { + return RecordCameraFrameFullscreenSequenceStageGraphPass( + context, + stageState, + passName, + fullscreenBinding, + stageState.outputColor, + passIndex, + stageState.stageSequence->GetPassCount(), + currentSourceColor, + beginSequencePass, + pass); + }); + }() + : RecordStageSequencePasses( stageState.stage, stageState.stageName, - context, - stageState, - stagePassContext, - stageState.outputSurface, - context.sceneData, stageState.stageSequence, builder.executionState, - builder.stageExecutionSucceeded); + context.plan.request.context, + builder.stageExecutionSucceeded, + [&context, &stageState]( + RenderPass& pass, + size_t, + const Containers::String& passName, + const RenderPassGraphBeginCallback& beginSequencePass) { + return RecordCameraFrameRegularSequenceStageRenderGraphPass( + context, + stageState, + passName, + stageState.outputSurface, + beginSequencePass, + pass); + }); if (!recordResult) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, 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 c30779b5..4001dfee 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 @@ -33,6 +33,11 @@ public: ++recordCalls; lastPassName = context.passName.CStr(); lastBeginPassCallback = context.beginPassCallback; + lastSurface = context.surface; + lastSourceSurface = context.sourceSurface; + lastSourceColorView = context.sourceColorView; + lastSourceColorState = context.sourceColorState; + lastSourceColorTexture = context.sourceColorTexture; lastColorTargets = context.colorTargets; lastDepthTarget = context.depthTarget; lastExecutionSucceeded = context.executionSucceeded; @@ -50,6 +55,12 @@ public: int recordCalls = 0; std::string lastPassName = {}; RenderPassGraphBeginCallback lastBeginPassCallback = {}; + RenderSurface lastSurface = {}; + const RenderSurface* lastSourceSurface = nullptr; + XCEngine::RHI::RHIResourceView* lastSourceColorView = nullptr; + XCEngine::RHI::ResourceStates lastSourceColorState = + XCEngine::RHI::ResourceStates::Common; + RenderGraphTextureHandle lastSourceColorTexture = {}; std::vector lastColorTargets = {}; RenderGraphTextureHandle lastDepthTarget = {}; bool* lastExecutionSucceeded = nullptr; @@ -373,6 +384,170 @@ TEST(CameraFrameRenderGraphStageContract_Test, RecordsMainSceneGraphPassFromStag EXPECT_EQ(pipeline.lastBlackboard, &blackboard); } +TEST(CameraFrameRenderGraphStageContract_Test, RecordsRegularSequenceStageGraphPassFromStageContract) { + 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.stage = CameraFrameStage::OverlayPasses; + stageState.stageName = "OverlayPasses"; + stageState.surfaceTemplate = RenderSurface(1280, 720); + stageState.hasSourceSurface = true; + stageState.sourceSurfaceTemplate = RenderSurface(960, 540); + stageState.sourceColorView = + reinterpret_cast(71); + stageState.sourceColorState = XCEngine::RHI::ResourceStates::CopySrc; + stageState.sourceSurface.colorTextures.push_back(RenderGraphTextureHandle{ 72u }); + stageState.outputSurface.colorTextures.push_back(RenderGraphTextureHandle{ 73u }); + stageState.outputSurface.depthTexture = RenderGraphTextureHandle{ 74u }; + + RecordingRenderPass pass = {}; + const RenderPassGraphBeginCallback beginPass = + [](const RenderPassContext&) { return true; }; + + ASSERT_TRUE(RecordCameraFrameRegularSequenceStageRenderGraphPass( + context, + stageState, + "OverlayPasses.Pass0", + stageState.outputSurface, + beginPass, + pass)); + ASSERT_EQ(pass.recordCalls, 1); + EXPECT_STREQ(pass.lastPassName.c_str(), "OverlayPasses.Pass0"); + EXPECT_EQ(pass.lastSurface.GetWidth(), 1280u); + EXPECT_EQ(pass.lastSurface.GetHeight(), 720u); + EXPECT_EQ(pass.lastSourceSurface, &stageState.sourceSurfaceTemplate); + EXPECT_EQ(pass.lastSourceColorView, stageState.sourceColorView); + EXPECT_EQ(pass.lastSourceColorState, XCEngine::RHI::ResourceStates::CopySrc); + EXPECT_EQ(pass.lastSourceColorTexture.index, 72u); + ASSERT_EQ(pass.lastColorTargets.size(), 1u); + EXPECT_EQ(pass.lastColorTargets[0].index, 73u); + EXPECT_EQ(pass.lastDepthTarget.index, 74u); + ASSERT_TRUE(pass.lastBeginPassCallback); + EXPECT_TRUE(pass.lastBeginPassCallback( + BuildCameraFrameStageGraphPassContext( + context, + stageState, + sceneData))); +} + +TEST(CameraFrameRenderGraphStageContract_Test, RecordsFullscreenSequenceStageGraphPassAndAdvancesSourceColor) { + 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.stage = CameraFrameStage::PostProcess; + stageState.stageName = "PostProcess"; + stageState.surfaceTemplate = RenderSurface(1280, 720); + stageState.outputColor = RenderGraphTextureHandle{ 85u }; + + RenderSurface explicitSourceSurface(1280, 720); + const CameraFrameRenderGraphSourceBinding binding = { + &explicitSourceSurface, + reinterpret_cast(81), + XCEngine::RHI::ResourceStates::CopySrc, + RenderGraphTextureHandle{ 82u } + }; + RenderGraphTextureHandle currentSourceColor = binding.sourceColor; + + RecordingRenderPass firstPass = {}; + ASSERT_TRUE(RecordCameraFrameFullscreenSequenceStageGraphPass( + context, + stageState, + "PostProcess.Pass0", + binding, + stageState.outputColor, + 0u, + 2u, + currentSourceColor, + {}, + firstPass)); + ASSERT_EQ(firstPass.recordCalls, 1); + EXPECT_STREQ(firstPass.lastPassName.c_str(), "PostProcess.Pass0"); + EXPECT_EQ(firstPass.lastSourceSurface, &explicitSourceSurface); + EXPECT_EQ(firstPass.lastSourceColorView, binding.sourceColorView); + EXPECT_EQ(firstPass.lastSourceColorState, XCEngine::RHI::ResourceStates::CopySrc); + EXPECT_EQ(firstPass.lastSourceColorTexture.index, 82u); + ASSERT_EQ(firstPass.lastColorTargets.size(), 1u); + const RenderGraphTextureHandle firstPassOutput = firstPass.lastColorTargets[0]; + EXPECT_TRUE(firstPassOutput.IsValid()); + EXPECT_NE(firstPassOutput.index, stageState.outputColor.index); + EXPECT_EQ(currentSourceColor.index, firstPassOutput.index); + EXPECT_FALSE(firstPass.lastDepthTarget.IsValid()); + + RecordingRenderPass secondPass = {}; + ASSERT_TRUE(RecordCameraFrameFullscreenSequenceStageGraphPass( + context, + stageState, + "PostProcess.Pass1", + binding, + stageState.outputColor, + 1u, + 2u, + currentSourceColor, + {}, + secondPass)); + ASSERT_EQ(secondPass.recordCalls, 1); + EXPECT_STREQ(secondPass.lastPassName.c_str(), "PostProcess.Pass1"); + EXPECT_EQ(secondPass.lastSourceSurface, &stageState.surfaceTemplate); + EXPECT_EQ(secondPass.lastSourceColorView, nullptr); + EXPECT_EQ( + secondPass.lastSourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); + EXPECT_EQ(secondPass.lastSourceColorTexture.index, firstPassOutput.index); + ASSERT_EQ(secondPass.lastColorTargets.size(), 1u); + EXPECT_EQ(secondPass.lastColorTargets[0].index, stageState.outputColor.index); + EXPECT_EQ(currentSourceColor.index, stageState.outputColor.index); +} + TEST(CameraFrameRenderGraphStageContract_Test, KeepsExplicitFullscreenSourceBindingUntouched) { CameraFramePlan plan = {}; RenderSurface stageSurface(320, 180);