From a3efcda550ffbcc6d58a0e9a1eab5e50ced74450 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 14 Apr 2026 22:00:03 +0800 Subject: [PATCH] Unify camera frame graph resource binding helpers --- .../XCEngine/Rendering/RenderPipeline.h | 80 ++++++++++++ .../Rendering/Execution/CameraRenderer.cpp | 57 +++------ .../unit/test_camera_scene_renderer.cpp | 115 ++++++++++++++++++ 3 files changed, 211 insertions(+), 41 deletions(-) diff --git a/engine/include/XCEngine/Rendering/RenderPipeline.h b/engine/include/XCEngine/Rendering/RenderPipeline.h index ebff0164..5d217060 100644 --- a/engine/include/XCEngine/Rendering/RenderPipeline.h +++ b/engine/include/XCEngine/Rendering/RenderPipeline.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include #include @@ -27,6 +28,50 @@ struct CameraFrameRenderGraphResources { RenderGraphTextureHandle mainDirectionalShadow = {}; }; +inline CameraFrameRenderGraphSurfaceResources* ResolveCameraFrameRenderGraphStageSurfaceResources( + CameraFrameRenderGraphResources& frameResources, + CameraFrameStage stage) { + switch (stage) { + case CameraFrameStage::MainScene: + return &frameResources.mainScene; + case CameraFrameStage::PostProcess: + return &frameResources.postProcess; + case CameraFrameStage::ObjectId: + return &frameResources.objectId; + default: + return nullptr; + } +} + +inline const CameraFrameRenderGraphSurfaceResources* ResolveCameraFrameRenderGraphStageSurfaceResources( + const CameraFrameRenderGraphResources& frameResources, + CameraFrameStage stage) { + switch (stage) { + case CameraFrameStage::MainScene: + return &frameResources.mainScene; + case CameraFrameStage::PostProcess: + return &frameResources.postProcess; + case CameraFrameStage::ObjectId: + return &frameResources.objectId; + default: + return nullptr; + } +} + +inline const CameraFrameRenderGraphSurfaceResources* ResolveCameraFrameRenderGraphColorSourceResources( + const CameraFrameRenderGraphResources& frameResources, + CameraFrameColorSource source) { + switch (source) { + case CameraFrameColorSource::MainSceneColor: + return &frameResources.mainScene; + case CameraFrameColorSource::PostProcessColor: + return &frameResources.postProcess; + case CameraFrameColorSource::ExplicitSurface: + default: + return nullptr; + } +} + inline CameraFrameRenderGraphResources* TryGetCameraFrameRenderGraphResources( RenderGraphBlackboard* blackboard) { return blackboard != nullptr @@ -41,6 +86,41 @@ inline const CameraFrameRenderGraphResources* TryGetCameraFrameRenderGraphResour : nullptr; } +inline RenderGraphTextureHandle ResolveCameraFrameRenderGraphColorSource( + const CameraFrameRenderGraphResources& frameResources, + CameraFrameColorSource source) { + const CameraFrameRenderGraphSurfaceResources* const surfaceResources = + ResolveCameraFrameRenderGraphColorSourceResources(frameResources, source); + return surfaceResources != nullptr + ? surfaceResources->color + : RenderGraphTextureHandle{}; +} + +inline RenderGraphTextureHandle ResolveCameraFrameRenderGraphColorSource( + const RenderGraphBlackboard* blackboard, + CameraFrameColorSource source) { + const CameraFrameRenderGraphResources* const frameResources = + TryGetCameraFrameRenderGraphResources(blackboard); + return frameResources != nullptr + ? ResolveCameraFrameRenderGraphColorSource(*frameResources, source) + : RenderGraphTextureHandle{}; +} + +inline void WriteCameraFrameRenderGraphStageSurfaceResources( + CameraFrameRenderGraphResources& frameResources, + CameraFrameStage stage, + RenderGraphTextureHandle color, + RenderGraphTextureHandle depth) { + CameraFrameRenderGraphSurfaceResources* const surfaceResources = + ResolveCameraFrameRenderGraphStageSurfaceResources(frameResources, stage); + if (surfaceResources == nullptr) { + return; + } + + surfaceResources->color = color; + surfaceResources->depth = depth; +} + struct RenderPipelineMainSceneRenderGraphContext { RenderGraphBuilder& graphBuilder; Containers::String passName = {}; diff --git a/engine/src/Rendering/Execution/CameraRenderer.cpp b/engine/src/Rendering/Execution/CameraRenderer.cpp index 28eb9fcd..4586b7cd 100644 --- a/engine/src/Rendering/Execution/CameraRenderer.cpp +++ b/engine/src/Rendering/Execution/CameraRenderer.cpp @@ -608,8 +608,7 @@ RenderGraphTextureHandle ResolveStageOutputColorHandle( const Containers::String& stageName, const RenderPassContext& stagePassContext, const RenderGraphImportedSurface& outputSurface, - RenderGraphBuilder& graphBuilder, - CameraFrameRenderGraphResources& frameResources) { + RenderGraphBuilder& graphBuilder) { if (stage == CameraFrameStage::MainScene && plan.usesGraphManagedMainSceneColor) { return graphBuilder.CreateTransientTexture( @@ -621,37 +620,21 @@ RenderGraphTextureHandle ResolveStageOutputColorHandle( if (stage == CameraFrameStage::PostProcess && plan.usesGraphManagedPostProcessColor) { - frameResources.postProcess.color = - graphBuilder.CreateTransientTexture( - stageName + ".Color", - BuildFullscreenTransientTextureDesc(stagePassContext.surface)); - return frameResources.postProcess.color; + return graphBuilder.CreateTransientTexture( + stageName + ".Color", + BuildFullscreenTransientTextureDesc(stagePassContext.surface)); } return GetPrimaryColorTexture(outputSurface); } -RenderGraphTextureHandle ResolveFrameResourceColorSource( - const CameraFrameRenderGraphResources& frameResources, - CameraFrameColorSource source) { - switch (source) { - case CameraFrameColorSource::MainSceneColor: - return frameResources.mainScene.color; - case CameraFrameColorSource::PostProcessColor: - return frameResources.postProcess.color; - case CameraFrameColorSource::ExplicitSurface: - default: - return {}; - } -} - FullscreenStageGraphBinding ResolveFullscreenStageGraphBinding( CameraFrameStage stage, const CameraFramePlan& plan, const RenderPassContext& stagePassContext, const RenderGraphImportedSurface& sourceSurface, RenderGraphTextureHandle outputColor, - CameraFrameRenderGraphResources& frameResources) { + const RenderGraphBlackboard* blackboard) { FullscreenStageGraphBinding binding = {}; binding.sourceSurfaceTemplate = stagePassContext.sourceSurface; binding.sourceColorView = stagePassContext.sourceColorView; @@ -665,8 +648,8 @@ FullscreenStageGraphBinding ResolveFullscreenStageGraphBinding( binding.sourceColorView = nullptr; binding.sourceColorState = RHI::ResourceStates::PixelShaderResource; binding.sourceColor = - ResolveFrameResourceColorSource( - frameResources, + ResolveCameraFrameRenderGraphColorSource( + blackboard, plan.postProcessSource); } @@ -677,8 +660,8 @@ FullscreenStageGraphBinding ResolveFullscreenStageGraphBinding( binding.sourceColorView = nullptr; binding.sourceColorState = RHI::ResourceStates::PixelShaderResource; binding.sourceColor = - ResolveFrameResourceColorSource( - frameResources, + ResolveCameraFrameRenderGraphColorSource( + blackboard, plan.finalOutputSource); } } @@ -979,25 +962,17 @@ bool ExecuteRenderGraphPlan( stageName, stagePassContext, outputSurface, - graphBuilder, - frameResources); + graphBuilder); if (stage == CameraFrameStage::ShadowCaster && shadowState.HasShadowSampling() && outputSurface.depthTexture.IsValid()) { frameResources.mainDirectionalShadow = outputSurface.depthTexture; } - if (stage == CameraFrameStage::MainScene) { - frameResources.mainScene.color = stageOutputColor; - frameResources.mainScene.depth = outputSurface.depthTexture; - } - if (stage == CameraFrameStage::PostProcess) { - frameResources.postProcess.color = stageOutputColor; - frameResources.postProcess.depth = outputSurface.depthTexture; - } - if (stage == CameraFrameStage::ObjectId) { - frameResources.objectId.color = stageOutputColor; - frameResources.objectId.depth = outputSurface.depthTexture; - } + WriteCameraFrameRenderGraphStageSurfaceResources( + frameResources, + stage, + stageOutputColor, + outputSurface.depthTexture); const RenderSurface stageSurfaceTemplate = stagePassContext.surface; const bool hasStageSourceSurface = stagePassContext.sourceSurface != nullptr; const RenderSurface stageSourceSurfaceTemplate = @@ -1020,7 +995,7 @@ bool ExecuteRenderGraphPlan( stagePassContext, sourceSurface, stageOutputColor, - frameResources), + &blackboard), sceneData, stageSequence, executionState, diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index d01f2dde..67fb8d7f 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -759,6 +759,18 @@ public: bool RecordRenderGraph(const RenderPassRenderGraphContext& context) override { m_state->eventLog.push_back(std::string("record:") + m_label); + lastRecordedSourceColorTextureValid = context.sourceColorTexture.IsValid(); + lastRecordedRenderGraphBlackboard = context.blackboard != nullptr; + if (const CameraFrameRenderGraphResources* frameResources = + TryGetCameraFrameRenderGraphResources(context.blackboard)) { + lastRecordedBlackboardMainSceneColorValid = + frameResources->mainScene.color.IsValid(); + lastRecordedBlackboardPostProcessColorValid = + frameResources->postProcess.color.IsValid(); + } else { + lastRecordedBlackboardMainSceneColorValid = false; + lastRecordedBlackboardPostProcessColorValid = false; + } const bool writesColor = context.sourceSurface != nullptr || !context.colorTargets.empty(); @@ -815,6 +827,10 @@ public: bool lastSourceSurfaceAutoTransitionEnabled = true; XCEngine::RHI::RHIResourceView* lastSourceColorView = nullptr; XCEngine::RHI::ResourceStates lastSourceColorState = XCEngine::RHI::ResourceStates::Common; + bool lastRecordedSourceColorTextureValid = false; + bool lastRecordedRenderGraphBlackboard = false; + bool lastRecordedBlackboardMainSceneColorValid = false; + bool lastRecordedBlackboardPostProcessColorValid = false; }; RenderContext CreateValidContext() { @@ -1791,6 +1807,105 @@ TEST(CameraRenderer_Test, RecordsGraphCapableSinglePassSequenceStagesInDocumente EXPECT_FALSE(overlayPassRaw->lastSurfaceAutoTransitionEnabled); } +TEST(CameraRenderer_Test, ResolvesGraphManagedFullscreenSequenceSourcesFromFrameResources) { + Scene scene("CameraRendererGraphManagedFullscreenSources"); + + GameObject* cameraObject = scene.CreateGameObject("Camera"); + auto* camera = cameraObject->AddComponent(); + camera->SetPrimary(true); + camera->SetDepth(3.0f); + + auto state = std::make_shared(); + state->supportsMainSceneRenderGraph = true; + CameraRenderer renderer(std::make_unique(state)); + auto allocationState = std::make_shared(); + MockShadowDevice device(allocationState); + MockShadowView colorView( + allocationState, + XCEngine::RHI::ResourceViewType::RenderTarget, + XCEngine::RHI::Format::R8G8B8A8_UNorm, + XCEngine::RHI::ResourceViewDimension::Texture2D); + MockShadowView depthView( + allocationState, + XCEngine::RHI::ResourceViewType::DepthStencil, + XCEngine::RHI::Format::D24_UNorm_S8_UInt, + XCEngine::RHI::ResourceViewDimension::Texture2D); + + auto postProcessPass = std::make_unique(state, "postProcess", true, true, true); + TrackingPass* postProcessPassRaw = postProcessPass.get(); + RenderPassSequence postProcessPasses; + postProcessPasses.AddPass(std::move(postProcessPass)); + + auto finalOutputPass = std::make_unique(state, "finalOutput", true, true, true); + TrackingPass* finalOutputPassRaw = finalOutputPass.get(); + RenderPassSequence finalOutputPasses; + finalOutputPasses.AddPass(std::move(finalOutputPass)); + + CameraRenderRequest request; + request.scene = &scene; + request.camera = camera; + request.context = CreateValidContext(); + request.context.device = &device; + request.surface = RenderSurface(320, 180); + request.surface.SetColorAttachment(&colorView); + request.surface.SetDepthAttachment(&depthView); + request.cameraDepth = camera->GetDepth(); + request.postProcess.passes = &postProcessPasses; + request.finalOutput.passes = &finalOutputPasses; + request.finalOutput.destinationSurface = request.surface; + + CameraFramePlan plan = CameraFramePlan::FromRequest(request); + plan.usesGraphManagedMainSceneColor = true; + plan.ConfigureGraphManagedMainSceneSurface(); + plan.usesGraphManagedPostProcessColor = true; + plan.postProcessSource = CameraFrameColorSource::MainSceneColor; + plan.finalOutputSource = CameraFrameColorSource::PostProcessColor; + + ASSERT_TRUE(plan.IsPostProcessStageValid()); + ASSERT_TRUE(plan.IsFinalOutputStageValid()); + const bool renderResult = renderer.Render(plan); + EXPECT_TRUE(renderResult); + EXPECT_EQ(state->recordMainSceneCalls, 1); + EXPECT_EQ(state->executeRecordedMainSceneCalls, 1); + + EXPECT_EQ( + state->eventLog, + (std::vector{ + "record:postProcess", + "record:finalOutput", + "pipelineGraph", + "init:postProcess", + "postProcess", + "init:finalOutput", + "finalOutput" })); + + ASSERT_NE(postProcessPassRaw, nullptr); + EXPECT_TRUE(postProcessPassRaw->lastRecordedRenderGraphBlackboard); + EXPECT_TRUE(postProcessPassRaw->lastRecordedSourceColorTextureValid); + EXPECT_TRUE(postProcessPassRaw->lastRecordedBlackboardMainSceneColorValid); + EXPECT_NE(postProcessPassRaw->lastSourceColorView, nullptr); + EXPECT_TRUE(postProcessPassRaw->lastHasSourceSurface); + EXPECT_EQ(postProcessPassRaw->lastSourceSurfaceWidth, 320u); + EXPECT_EQ(postProcessPassRaw->lastSourceSurfaceHeight, 180u); + EXPECT_FALSE(postProcessPassRaw->lastSourceSurfaceAutoTransitionEnabled); + EXPECT_EQ( + postProcessPassRaw->lastSourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); + + ASSERT_NE(finalOutputPassRaw, nullptr); + EXPECT_TRUE(finalOutputPassRaw->lastRecordedRenderGraphBlackboard); + EXPECT_TRUE(finalOutputPassRaw->lastRecordedSourceColorTextureValid); + EXPECT_TRUE(finalOutputPassRaw->lastRecordedBlackboardPostProcessColorValid); + EXPECT_NE(finalOutputPassRaw->lastSourceColorView, nullptr); + EXPECT_TRUE(finalOutputPassRaw->lastHasSourceSurface); + EXPECT_EQ(finalOutputPassRaw->lastSourceSurfaceWidth, 320u); + EXPECT_EQ(finalOutputPassRaw->lastSourceSurfaceHeight, 180u); + EXPECT_FALSE(finalOutputPassRaw->lastSourceSurfaceAutoTransitionEnabled); + EXPECT_EQ( + finalOutputPassRaw->lastSourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); +} + TEST(CameraRenderer_Test, ExecutesShadowCasterAndDepthOnlyRequestsBeforeMainPipeline) { Scene scene("CameraRendererDepthAndShadowScene");