From c710063d924734cd6b9db57dd79b29808b1beff3 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 14 Apr 2026 19:32:27 +0800 Subject: [PATCH] Graph-manage camera fullscreen stage routing --- engine/CMakeLists.txt | 1 - .../Rendering/Execution/CameraFramePlan.h | 122 ++++++++++-- .../XCEngine/Rendering/RenderPipeline.h | 1 + .../Caches/FullscreenPassSurfaceCache.cpp | 5 - .../Caches/FullscreenPassSurfaceCache.h | 187 ------------------ .../Rendering/Execution/CameraRenderer.cpp | 135 +++++++++++-- .../src/Rendering/Execution/SceneRenderer.cpp | 10 - .../Planning/CameraFramePlanBuilder.cpp | 144 ++------------ .../Planning/CameraFramePlanBuilder.h | 4 - .../unit/test_camera_scene_renderer.cpp | 168 ++++++++-------- 10 files changed, 337 insertions(+), 440 deletions(-) delete mode 100644 engine/src/Rendering/Caches/FullscreenPassSurfaceCache.cpp delete mode 100644 engine/src/Rendering/Caches/FullscreenPassSurfaceCache.h diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index aba47b23..ab44ccd0 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -535,7 +535,6 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Pipelines/BuiltinForwardPipeline.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/CameraRenderer.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp - ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Caches/FullscreenPassSurfaceCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Internal/RenderPassGraphUtils.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Internal/RenderPassGraphUtils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinDepthStylePassBase.cpp diff --git a/engine/include/XCEngine/Rendering/Execution/CameraFramePlan.h b/engine/include/XCEngine/Rendering/Execution/CameraFramePlan.h index 3bdc62a3..a25335d3 100644 --- a/engine/include/XCEngine/Rendering/Execution/CameraFramePlan.h +++ b/engine/include/XCEngine/Rendering/Execution/CameraFramePlan.h @@ -6,7 +6,23 @@ namespace XCEngine { namespace Rendering { +enum class CameraFrameColorSource { + ExplicitSurface = 0, + MainSceneColor, + PostProcessColor +}; + struct CameraFramePlan { + static RenderSurface BuildGraphManagedIntermediateSurfaceTemplate( + const RenderSurface& surface) { + RenderSurface graphManagedSurface = surface; + graphManagedSurface.SetColorAttachments({}); + graphManagedSurface.SetAutoTransitionEnabled(false); + graphManagedSurface.SetColorStateBefore(RHI::ResourceStates::Common); + graphManagedSurface.SetColorStateAfter(RHI::ResourceStates::Common); + return graphManagedSurface; + } + CameraRenderRequest request = {}; ShadowCasterRenderRequest shadowCaster = {}; DirectionalShadowRenderPlan directionalShadow = {}; @@ -16,6 +32,11 @@ struct CameraFramePlan { RenderPassSequence* preScenePasses = nullptr; RenderPassSequence* postScenePasses = nullptr; RenderPassSequence* overlayPasses = nullptr; + bool usesGraphManagedMainSceneColor = false; + bool usesGraphManagedPostProcessColor = false; + CameraFrameColorSource postProcessSource = CameraFrameColorSource::ExplicitSurface; + CameraFrameColorSource finalOutputSource = CameraFrameColorSource::ExplicitSurface; + RenderSurface graphManagedMainSceneSurface = {}; static CameraFramePlan FromRequest(const CameraRenderRequest& request) { CameraFramePlan plan = {}; @@ -35,6 +56,49 @@ struct CameraFramePlan { return request.IsValid(); } + void ConfigureGraphManagedMainSceneSurface() { + graphManagedMainSceneSurface = + BuildGraphManagedIntermediateSurfaceTemplate(request.surface); + } + + bool IsPostProcessStageValid() const { + if (!postProcess.IsRequested()) { + return true; + } + + if (postProcessSource == CameraFrameColorSource::ExplicitSurface) { + return postProcess.IsValid(); + } + + const bool hasUsableDestination = + usesGraphManagedPostProcessColor || + (HasValidColorTarget(postProcess.destinationSurface) && + HasValidSurfaceSampleDescription(postProcess.destinationSurface)); + return usesGraphManagedMainSceneColor && + postProcess.passes != nullptr && + HasValidSingleSampleColorSource(request.surface) && + hasUsableDestination; + } + + bool IsFinalOutputStageValid() const { + if (!finalOutput.IsRequested()) { + return true; + } + + if (finalOutputSource == CameraFrameColorSource::ExplicitSurface) { + return finalOutput.IsValid(); + } + + const bool hasUsableSource = + finalOutputSource == CameraFrameColorSource::MainSceneColor + ? usesGraphManagedMainSceneColor + : usesGraphManagedPostProcessColor; + return hasUsableSource && + finalOutput.passes != nullptr && + HasValidColorTarget(finalOutput.destinationSurface) && + HasValidSurfaceSampleDescription(finalOutput.destinationSurface); + } + bool HasFrameStage(CameraFrameStage stage) const { switch (stage) { case CameraFrameStage::PreScenePasses: @@ -93,11 +157,19 @@ struct CameraFramePlan { } const RenderSurface& GetMainSceneSurface() const { - if (postProcess.IsRequested()) { + if (usesGraphManagedMainSceneColor && + graphManagedMainSceneSurface.GetWidth() > 0u && + graphManagedMainSceneSurface.GetHeight() > 0u) { + return graphManagedMainSceneSurface; + } + + if (postProcess.IsRequested() && + HasValidColorTarget(postProcess.sourceSurface)) { return postProcess.sourceSurface; } - if (finalOutput.IsRequested()) { + if (finalOutput.IsRequested() && + HasValidColorTarget(finalOutput.sourceSurface)) { return finalOutput.sourceSurface; } @@ -105,11 +177,13 @@ struct CameraFramePlan { } const RenderSurface& GetFinalCompositedSurface() const { - if (finalOutput.IsRequested()) { + if (finalOutput.IsRequested() && + HasValidColorTarget(finalOutput.destinationSurface)) { return finalOutput.destinationSurface; } - if (postProcess.IsRequested()) { + if (postProcess.IsRequested() && + HasValidColorTarget(postProcess.destinationSurface)) { return postProcess.destinationSurface; } @@ -126,9 +200,15 @@ struct CameraFramePlan { case CameraFrameStage::DepthOnly: return request.depthOnly.IsRequested() ? &request.depthOnly.surface : nullptr; case CameraFrameStage::PostProcess: - return postProcess.IsRequested() ? &postProcess.destinationSurface : nullptr; + return postProcess.IsRequested() && + HasValidColorTarget(postProcess.destinationSurface) + ? &postProcess.destinationSurface + : nullptr; case CameraFrameStage::FinalOutput: - return finalOutput.IsRequested() ? &finalOutput.destinationSurface : nullptr; + return finalOutput.IsRequested() && + HasValidColorTarget(finalOutput.destinationSurface) + ? &finalOutput.destinationSurface + : nullptr; case CameraFrameStage::ObjectId: return request.objectId.IsRequested() ? &request.objectId.surface : nullptr; case CameraFrameStage::PostScenePasses: @@ -142,9 +222,15 @@ struct CameraFramePlan { const RenderSurface* GetSourceSurface(CameraFrameStage stage) const { switch (stage) { case CameraFrameStage::PostProcess: - return postProcess.IsRequested() ? &postProcess.sourceSurface : nullptr; + return postProcess.IsRequested() && + postProcessSource == CameraFrameColorSource::ExplicitSurface + ? &postProcess.sourceSurface + : nullptr; case CameraFrameStage::FinalOutput: - return finalOutput.IsRequested() ? &finalOutput.sourceSurface : nullptr; + return finalOutput.IsRequested() && + finalOutputSource == CameraFrameColorSource::ExplicitSurface + ? &finalOutput.sourceSurface + : nullptr; default: return nullptr; } @@ -153,9 +239,15 @@ struct CameraFramePlan { RHI::RHIResourceView* GetSourceColorView(CameraFrameStage stage) const { switch (stage) { case CameraFrameStage::PostProcess: - return postProcess.IsRequested() ? postProcess.sourceColorView : nullptr; + return postProcess.IsRequested() && + postProcessSource == CameraFrameColorSource::ExplicitSurface + ? postProcess.sourceColorView + : nullptr; case CameraFrameStage::FinalOutput: - return finalOutput.IsRequested() ? finalOutput.sourceColorView : nullptr; + return finalOutput.IsRequested() && + finalOutputSource == CameraFrameColorSource::ExplicitSurface + ? finalOutput.sourceColorView + : nullptr; default: return nullptr; } @@ -164,9 +256,15 @@ struct CameraFramePlan { RHI::ResourceStates GetSourceColorState(CameraFrameStage stage) const { switch (stage) { case CameraFrameStage::PostProcess: - return postProcess.IsRequested() ? postProcess.sourceColorState : RHI::ResourceStates::Common; + return postProcess.IsRequested() && + postProcessSource == CameraFrameColorSource::ExplicitSurface + ? postProcess.sourceColorState + : RHI::ResourceStates::Common; case CameraFrameStage::FinalOutput: - return finalOutput.IsRequested() ? finalOutput.sourceColorState : RHI::ResourceStates::Common; + return finalOutput.IsRequested() && + finalOutputSource == CameraFrameColorSource::ExplicitSurface + ? finalOutput.sourceColorState + : RHI::ResourceStates::Common; default: return RHI::ResourceStates::Common; } diff --git a/engine/include/XCEngine/Rendering/RenderPipeline.h b/engine/include/XCEngine/Rendering/RenderPipeline.h index cd4c2779..095f4d74 100644 --- a/engine/include/XCEngine/Rendering/RenderPipeline.h +++ b/engine/include/XCEngine/Rendering/RenderPipeline.h @@ -18,6 +18,7 @@ class RenderGraphBuilder; struct CameraFrameRenderGraphResources { RenderGraphTextureHandle mainSceneColor = {}; RenderGraphTextureHandle mainSceneDepth = {}; + RenderGraphTextureHandle postProcessColor = {}; RenderGraphTextureHandle mainDirectionalShadow = {}; RenderGraphTextureHandle objectIdColor = {}; }; diff --git a/engine/src/Rendering/Caches/FullscreenPassSurfaceCache.cpp b/engine/src/Rendering/Caches/FullscreenPassSurfaceCache.cpp deleted file mode 100644 index a668ac05..00000000 --- a/engine/src/Rendering/Caches/FullscreenPassSurfaceCache.cpp +++ /dev/null @@ -1,5 +0,0 @@ -#include "Rendering/Caches/FullscreenPassSurfaceCache.h" - -// This translation unit remains intentionally light. The cache is implemented -// inline in the header so existing generated build files do not require a -// CMake regeneration just to pick up method definitions. diff --git a/engine/src/Rendering/Caches/FullscreenPassSurfaceCache.h b/engine/src/Rendering/Caches/FullscreenPassSurfaceCache.h deleted file mode 100644 index 87292d83..00000000 --- a/engine/src/Rendering/Caches/FullscreenPassSurfaceCache.h +++ /dev/null @@ -1,187 +0,0 @@ -#pragma once - -#include "Rendering/RenderSurface.h" -#include "Rendering/RenderContext.h" -#include "RHI/RHIDevice.h" -#include "RHI/RHIEnums.h" -#include "RHI/RHIResourceView.h" -#include "RHI/RHITexture.h" - -#include -#include - -namespace XCEngine { -namespace RHI { -class RHIDevice; -class RHIResourceView; -class RHITexture; -} // namespace RHI - -namespace Rendering { - -struct RenderContext; - -class FullscreenPassSurfaceCache { -public: - struct SurfaceEntry { - RenderSurface surface = {}; - RHI::RHITexture* texture = nullptr; - RHI::RHIResourceView* renderTargetView = nullptr; - RHI::RHIResourceView* shaderResourceView = nullptr; - RHI::ResourceStates currentColorState = RHI::ResourceStates::Common; - }; - - FullscreenPassSurfaceCache() = default; - FullscreenPassSurfaceCache(const FullscreenPassSurfaceCache&) = delete; - FullscreenPassSurfaceCache& operator=(const FullscreenPassSurfaceCache&) = delete; - ~FullscreenPassSurfaceCache() { - Reset(); - } - - bool EnsureSurfaces( - const RenderContext& context, - uint32_t width, - uint32_t height, - RHI::Format format, - size_t surfaceCount) { - if (!context.IsValid() || - width == 0 || - height == 0 || - format == RHI::Format::Unknown || - surfaceCount == 0) { - return false; - } - - if (Matches(context, width, height, format, surfaceCount)) { - return true; - } - - std::vector newEntries(surfaceCount); - for (size_t index = 0; index < surfaceCount; ++index) { - SurfaceEntry& entry = newEntries[index]; - - RHI::TextureDesc textureDesc = {}; - textureDesc.width = width; - textureDesc.height = height; - textureDesc.depth = 1; - textureDesc.mipLevels = 1; - textureDesc.arraySize = 1; - textureDesc.format = static_cast(format); - textureDesc.textureType = static_cast(RHI::TextureType::Texture2D); - textureDesc.sampleCount = 1; - textureDesc.sampleQuality = 0; - textureDesc.flags = 0; - - entry.texture = context.device->CreateTexture(textureDesc); - if (entry.texture == nullptr) { - for (SurfaceEntry& createdEntry : newEntries) { - DestroySurfaceEntry(createdEntry); - } - return false; - } - - RHI::ResourceViewDesc viewDesc = {}; - viewDesc.format = static_cast(format); - viewDesc.dimension = RHI::ResourceViewDimension::Texture2D; - viewDesc.mipLevel = 0; - - entry.renderTargetView = context.device->CreateRenderTargetView(entry.texture, viewDesc); - if (entry.renderTargetView == nullptr) { - for (SurfaceEntry& createdEntry : newEntries) { - DestroySurfaceEntry(createdEntry); - } - return false; - } - - entry.shaderResourceView = context.device->CreateShaderResourceView(entry.texture, viewDesc); - if (entry.shaderResourceView == nullptr) { - for (SurfaceEntry& createdEntry : newEntries) { - DestroySurfaceEntry(createdEntry); - } - return false; - } - - entry.surface = RenderSurface(width, height); - entry.surface.SetColorAttachment(entry.renderTargetView); - entry.surface.SetSampleDesc(1u, 0u); - entry.surface.SetAutoTransitionEnabled(true); - entry.surface.SetColorStateBefore(RHI::ResourceStates::Common); - entry.surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource); - entry.currentColorState = RHI::ResourceStates::Common; - } - - Reset(); - m_device = context.device; - m_width = width; - m_height = height; - m_format = format; - m_entries = std::move(newEntries); - return true; - } - - size_t GetSurfaceCount() const { return m_entries.size(); } - SurfaceEntry* GetSurfaceEntry(size_t index) { - return index < m_entries.size() ? &m_entries[index] : nullptr; - } - const SurfaceEntry* GetSurfaceEntry(size_t index) const { - return index < m_entries.size() ? &m_entries[index] : nullptr; - } - -private: - static void DestroySurfaceEntry(SurfaceEntry& entry) { - if (entry.renderTargetView != nullptr) { - entry.renderTargetView->Shutdown(); - delete entry.renderTargetView; - entry.renderTargetView = nullptr; - } - - if (entry.shaderResourceView != nullptr) { - entry.shaderResourceView->Shutdown(); - delete entry.shaderResourceView; - entry.shaderResourceView = nullptr; - } - - if (entry.texture != nullptr) { - entry.texture->Shutdown(); - delete entry.texture; - entry.texture = nullptr; - } - - entry.surface = RenderSurface(); - entry.currentColorState = RHI::ResourceStates::Common; - } - - bool Matches( - const RenderContext& context, - uint32_t width, - uint32_t height, - RHI::Format format, - size_t surfaceCount) const { - return m_device == context.device && - m_width == width && - m_height == height && - m_format == format && - m_entries.size() == surfaceCount; - } - - void Reset() { - for (SurfaceEntry& entry : m_entries) { - DestroySurfaceEntry(entry); - } - - m_entries.clear(); - m_device = nullptr; - m_width = 0; - m_height = 0; - m_format = RHI::Format::Unknown; - } - - RHI::RHIDevice* m_device = nullptr; - uint32_t m_width = 0; - uint32_t m_height = 0; - RHI::Format m_format = RHI::Format::Unknown; - std::vector m_entries; -}; - -} // namespace Rendering -} // namespace XCEngine diff --git a/engine/src/Rendering/Execution/CameraRenderer.cpp b/engine/src/Rendering/Execution/CameraRenderer.cpp index 78e6ce0d..44e2d3ad 100644 --- a/engine/src/Rendering/Execution/CameraRenderer.cpp +++ b/engine/src/Rendering/Execution/CameraRenderer.cpp @@ -530,6 +530,14 @@ RenderSurface BuildGraphManagedPassSurface( return surface; } +struct FullscreenStageGraphBinding { + const RenderSurface* sourceSurfaceTemplate = nullptr; + RHI::RHIResourceView* sourceColorView = nullptr; + RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common; + RenderGraphTextureHandle sourceColor = {}; + RenderGraphTextureHandle outputColor = {}; +}; + const RenderSurface* ResolveFrameStageOutputSurface( CameraFrameStage stage, const CameraFramePlan& plan, @@ -594,6 +602,79 @@ bool CanUseGraphManagedImportedSurface( return hasAnyTexture; } +RenderGraphTextureHandle ResolveStageOutputColorHandle( + CameraFrameStage stage, + const CameraFramePlan& plan, + const Containers::String& stageName, + const RenderPassContext& stagePassContext, + const RenderGraphImportedSurface& outputSurface, + RenderGraphBuilder& graphBuilder, + CameraFrameRenderGraphResources& frameResources) { + if (stage == CameraFrameStage::MainScene && + plan.usesGraphManagedMainSceneColor) { + return graphBuilder.CreateTransientTexture( + stageName + ".Color", + BuildImportedTextureDesc( + stagePassContext.surface, + kRenderGraphImportedColorFormat)); + } + + if (stage == CameraFrameStage::PostProcess && + plan.usesGraphManagedPostProcessColor) { + frameResources.postProcessColor = + graphBuilder.CreateTransientTexture( + stageName + ".Color", + BuildFullscreenTransientTextureDesc(stagePassContext.surface)); + return frameResources.postProcessColor; + } + + return GetPrimaryColorTexture(outputSurface); +} + +FullscreenStageGraphBinding ResolveFullscreenStageGraphBinding( + CameraFrameStage stage, + const CameraFramePlan& plan, + const RenderPassContext& stagePassContext, + const RenderGraphImportedSurface& sourceSurface, + RenderGraphTextureHandle outputColor, + CameraFrameRenderGraphResources& frameResources) { + FullscreenStageGraphBinding binding = {}; + binding.sourceSurfaceTemplate = stagePassContext.sourceSurface; + binding.sourceColorView = stagePassContext.sourceColorView; + binding.sourceColorState = stagePassContext.sourceColorState; + binding.sourceColor = GetPrimaryColorTexture(sourceSurface); + binding.outputColor = outputColor; + + if (stage == CameraFrameStage::PostProcess && + plan.postProcessSource == CameraFrameColorSource::MainSceneColor) { + binding.sourceSurfaceTemplate = &stagePassContext.surface; + binding.sourceColorView = nullptr; + binding.sourceColorState = RHI::ResourceStates::PixelShaderResource; + binding.sourceColor = frameResources.mainSceneColor; + } + + if (stage == CameraFrameStage::FinalOutput) { + if (plan.finalOutputSource == CameraFrameColorSource::MainSceneColor) { + binding.sourceSurfaceTemplate = &stagePassContext.surface; + binding.sourceColorView = nullptr; + binding.sourceColorState = RHI::ResourceStates::PixelShaderResource; + binding.sourceColor = frameResources.mainSceneColor; + } else if (plan.finalOutputSource == CameraFrameColorSource::PostProcessColor) { + binding.sourceSurfaceTemplate = &stagePassContext.surface; + binding.sourceColorView = nullptr; + binding.sourceColorState = RHI::ResourceStates::PixelShaderResource; + binding.sourceColor = frameResources.postProcessColor; + } + } + + if (binding.sourceSurfaceTemplate == nullptr && + binding.sourceColor.IsValid()) { + binding.sourceSurfaceTemplate = &stagePassContext.surface; + } + + return binding; +} + RenderPassContext BuildFrameStagePassContext( CameraFrameStage stage, const CameraFramePlan& plan, @@ -736,8 +817,7 @@ bool RecordFullscreenPassSequenceStage( CameraFrameStage stage, const Containers::String& stageName, const RenderPassContext& stagePassContext, - const RenderGraphImportedSurface& sourceSurface, - const RenderGraphImportedSurface& outputSurface, + const FullscreenStageGraphBinding& binding, const RenderSceneData& sceneData, RenderPassSequence* stageSequence, CameraFrameExecutionState& executionState, @@ -766,10 +846,8 @@ bool RecordFullscreenPassSequenceStage( return true; }; - RenderGraphTextureHandle currentSourceColor = - GetPrimaryColorTexture(sourceSurface); - const RenderGraphTextureHandle finalOutputColor = - GetPrimaryColorTexture(outputSurface); + RenderGraphTextureHandle currentSourceColor = binding.sourceColor; + const RenderGraphTextureHandle finalOutputColor = binding.outputColor; const RenderGraphTextureDesc transientDesc = BuildFullscreenTransientTextureDesc(stagePassContext.surface); @@ -792,15 +870,15 @@ bool RecordFullscreenPassSequenceStage( transientDesc); const RenderSurface* const sourceSurfaceTemplate = passIndex == 0u - ? stagePassContext.sourceSurface + ? binding.sourceSurfaceTemplate : &stagePassContext.surface; RHI::RHIResourceView* const sourceColorView = passIndex == 0u - ? stagePassContext.sourceColorView + ? binding.sourceColorView : nullptr; const RHI::ResourceStates sourceColorState = passIndex == 0u - ? stagePassContext.sourceColorState + ? binding.sourceColorState : RHI::ResourceStates::PixelShaderResource; const RenderPassRenderGraphContext passContext = { graphBuilder, @@ -879,6 +957,15 @@ bool ExecuteRenderGraphPlan( RenderGraphSurfaceImportUsage::Output, ShouldGraphOwnStageColorTransitions(stage), ShouldGraphOwnStageDepthTransitions(stage)); + const RenderGraphTextureHandle stageOutputColor = + ResolveStageOutputColorHandle( + stage, + plan, + stageName, + stagePassContext, + outputSurface, + graphBuilder, + frameResources); if (stage == CameraFrameStage::ShadowCaster && shadowState.HasShadowSampling() && outputSurface.depthTexture.IsValid()) { @@ -886,11 +973,11 @@ bool ExecuteRenderGraphPlan( frameResources.mainDirectionalShadow = outputSurface.depthTexture; } if (stage == CameraFrameStage::MainScene) { - frameResources.mainSceneColor = GetPrimaryColorTexture(outputSurface); + frameResources.mainSceneColor = stageOutputColor; frameResources.mainSceneDepth = outputSurface.depthTexture; } if (stage == CameraFrameStage::ObjectId) { - frameResources.objectIdColor = GetPrimaryColorTexture(outputSurface); + frameResources.objectIdColor = stageOutputColor; } const RenderSurface stageSurfaceTemplate = stagePassContext.surface; const bool hasStageSourceSurface = stagePassContext.sourceSurface != nullptr; @@ -908,8 +995,13 @@ bool ExecuteRenderGraphPlan( stage, stageName, stagePassContext, - sourceSurface, - outputSurface, + ResolveFullscreenStageGraphBinding( + stage, + plan, + stagePassContext, + sourceSurface, + stageOutputColor, + frameResources), sceneData, stageSequence, executionState, @@ -960,7 +1052,7 @@ bool ExecuteRenderGraphPlan( return true; }; - const RenderPassRenderGraphContext standalonePassContext = { + const RenderPassRenderGraphContext standalonePassContext = { graphBuilder, stageName, plan.request.context, @@ -970,7 +1062,7 @@ bool ExecuteRenderGraphPlan( const_cast(stageSourceColorView), stageSourceColorState, GetPrimaryColorTexture(sourceSurface), - outputSurface.colorTextures, + std::vector{ stageOutputColor }, outputSurface.depthTexture, &stageExecutionSucceeded, beginStandalonePass, @@ -999,7 +1091,7 @@ bool ExecuteRenderGraphPlan( hasStageSourceSurface ? &stageSourceSurfaceTemplate : nullptr, const_cast(stageSourceColorView), stageSourceColorState, - outputSurface.colorTextures, + std::vector{ stageOutputColor }, outputSurface.depthTexture, mainDirectionalShadowTexture, &stageExecutionSucceeded, @@ -1302,14 +1394,21 @@ bool CameraRenderer::Render( return false; } if (plan.postProcess.IsRequested() && - !plan.postProcess.IsValid()) { + !plan.IsPostProcessStageValid()) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, "CameraRenderer::Render failed: post-process request invalid"); return false; } + if (plan.usesGraphManagedMainSceneColor && + (m_pipeline == nullptr || !m_pipeline->SupportsMainSceneRenderGraph())) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + "CameraRenderer::Render failed: graph-managed main scene color requires pipeline main-scene render-graph support"); + return false; + } if (plan.finalOutput.IsRequested() && - !plan.finalOutput.IsValid()) { + !plan.IsFinalOutputStageValid()) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, "CameraRenderer::Render failed: final-output request invalid"); diff --git a/engine/src/Rendering/Execution/SceneRenderer.cpp b/engine/src/Rendering/Execution/SceneRenderer.cpp index f41c8bfb..e5b955dd 100644 --- a/engine/src/Rendering/Execution/SceneRenderer.cpp +++ b/engine/src/Rendering/Execution/SceneRenderer.cpp @@ -1,7 +1,6 @@ #include "Rendering/Execution/SceneRenderer.h" #include "Components/CameraComponent.h" -#include "Rendering/Caches/FullscreenPassSurfaceCache.h" #include "Rendering/Planning/CameraFramePlanBuilder.h" #include "Rendering/Planning/SceneRenderRequestUtils.h" @@ -83,15 +82,6 @@ bool SceneRenderer::Render(const std::vector& plans) { return false; } - if (m_framePlanBuilder != nullptr) { - m_framePlanBuilder->UpdateTrackedSurfaceState(&plan.GetMainSceneSurface()); - } - if (plan.postProcess.IsRequested()) { - if (m_framePlanBuilder != nullptr) { - m_framePlanBuilder->UpdateTrackedSurfaceState(&plan.postProcess.destinationSurface); - } - } - rendered = true; } diff --git a/engine/src/Rendering/Planning/CameraFramePlanBuilder.cpp b/engine/src/Rendering/Planning/CameraFramePlanBuilder.cpp index 5453bbe6..48a80021 100644 --- a/engine/src/Rendering/Planning/CameraFramePlanBuilder.cpp +++ b/engine/src/Rendering/Planning/CameraFramePlanBuilder.cpp @@ -2,7 +2,6 @@ #include "Components/CameraComponent.h" #include "Debug/Logger.h" -#include "Rendering/Caches/FullscreenPassSurfaceCache.h" #include "Rendering/Planning/CameraPostProcessPassFactory.h" #include "Rendering/Planning/FinalColorPassFactory.h" #include "Rendering/RenderPipelineAsset.h" @@ -10,35 +9,6 @@ namespace XCEngine { namespace Rendering { -namespace { - -RenderSurface ConfigureFullscreenStageSurface( - const FullscreenPassSurfaceCache::SurfaceEntry& entry, - const RenderSurface& templateSurface, - bool copyDepthAttachment) { - RenderSurface surface = entry.surface; - if (copyDepthAttachment) { - surface.SetDepthAttachment(templateSurface.GetDepthAttachment()); - surface.SetDepthStateBefore(templateSurface.GetDepthStateBefore()); - surface.SetDepthStateAfter(templateSurface.GetDepthStateAfter()); - if (templateSurface.HasClearColorOverride()) { - surface.SetClearColorOverride(templateSurface.GetClearColorOverride()); - } - } - - if (templateSurface.HasCustomRenderArea()) { - surface.SetRenderArea(templateSurface.GetRenderArea()); - } else { - surface.ResetRenderArea(); - } - - surface.SetColorStateBefore(entry.currentColorState); - surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource); - return surface; -} - -} // namespace - std::vector CameraFramePlanBuilder::BuildPlans( const std::vector& requests, const RenderPipelineAsset* pipelineAsset) { @@ -48,33 +18,6 @@ std::vector CameraFramePlanBuilder::BuildPlans( return plans; } -void CameraFramePlanBuilder::UpdateTrackedSurfaceState(const RenderSurface* surface) { - if (surface == nullptr || surface->GetColorAttachments().empty()) { - return; - } - - RHI::RHIResourceView* colorAttachment = surface->GetColorAttachments()[0]; - if (colorAttachment == nullptr) { - return; - } - - for (const std::unique_ptr& cache : m_ownedFullscreenStageSurfaces) { - if (cache == nullptr) { - continue; - } - - for (size_t entryIndex = 0; entryIndex < cache->GetSurfaceCount(); ++entryIndex) { - FullscreenPassSurfaceCache::SurfaceEntry* entry = cache->GetSurfaceEntry(entryIndex); - if (entry == nullptr || entry->renderTargetView != colorAttachment) { - continue; - } - - entry->currentColorState = surface->GetColorStateAfter(); - return; - } - } -} - std::vector CameraFramePlanBuilder::CreatePlansFromRequests( const std::vector& requests) const { std::vector plans = {}; @@ -86,23 +29,6 @@ std::vector CameraFramePlanBuilder::CreatePlansFromRequests( return plans; } -void CameraFramePlanBuilder::PrepareOwnedFullscreenStageState(size_t planCount) { - m_ownedPostProcessSequences.clear(); - m_ownedPostProcessSequences.resize(planCount); - m_ownedFinalOutputSequences.clear(); - m_ownedFinalOutputSequences.resize(planCount); - - if (m_ownedFullscreenStageSurfaces.size() < planCount) { - m_ownedFullscreenStageSurfaces.resize(planCount); - } - - for (size_t index = 0; index < planCount; ++index) { - if (m_ownedFullscreenStageSurfaces[index] == nullptr) { - m_ownedFullscreenStageSurfaces[index] = std::make_unique(); - } - } -} - void CameraFramePlanBuilder::ResolveCameraFinalColorPolicies( std::vector& plans, const RenderPipelineAsset* pipelineAsset) const { @@ -122,7 +48,10 @@ void CameraFramePlanBuilder::ResolveCameraFinalColorPolicies( void CameraFramePlanBuilder::AttachFullscreenStageRequests( std::vector& plans) { - PrepareOwnedFullscreenStageState(plans.size()); + m_ownedPostProcessSequences.clear(); + m_ownedPostProcessSequences.resize(plans.size()); + m_ownedFinalOutputSequences.clear(); + m_ownedFinalOutputSequences.resize(plans.size()); for (size_t index = 0; index < plans.size(); ++index) { CameraFramePlan& plan = plans[index]; @@ -152,63 +81,30 @@ void CameraFramePlanBuilder::AttachFullscreenStageRequests( continue; } - const std::vector& colorAttachments = - plan.request.surface.GetColorAttachments(); - const RHI::Format colorFormat = colorAttachments[0]->GetFormat(); - if (colorFormat == RHI::Format::Unknown) { - continue; - } - - const size_t fullscreenSurfaceCount = hasPostProcess && hasFinalOutput ? 2u : 1u; - FullscreenPassSurfaceCache* surfaceCache = m_ownedFullscreenStageSurfaces[index].get(); - if (surfaceCache == nullptr || - !surfaceCache->EnsureSurfaces( - plan.request.context, - plan.request.surface.GetWidth(), - plan.request.surface.GetHeight(), - colorFormat, - fullscreenSurfaceCount)) { - continue; - } - - const FullscreenPassSurfaceCache::SurfaceEntry* sceneColorEntry = - surfaceCache->GetSurfaceEntry(0u); - if (sceneColorEntry == nullptr || sceneColorEntry->shaderResourceView == nullptr) { - continue; - } - - const FullscreenPassSurfaceCache::SurfaceEntry* postProcessOutputEntry = - hasPostProcess && hasFinalOutput ? surfaceCache->GetSurfaceEntry(1u) : nullptr; - if (hasPostProcess && hasFinalOutput && - (postProcessOutputEntry == nullptr || postProcessOutputEntry->shaderResourceView == nullptr)) { - continue; - } - if (hasPostProcess) { - plan.postProcess.sourceSurface = - ConfigureFullscreenStageSurface(*sceneColorEntry, plan.request.surface, true); - plan.postProcess.sourceColorView = sceneColorEntry->shaderResourceView; - plan.postProcess.sourceColorState = plan.postProcess.sourceSurface.GetColorStateAfter(); - plan.postProcess.destinationSurface = - hasFinalOutput - ? ConfigureFullscreenStageSurface(*postProcessOutputEntry, plan.request.surface, false) - : plan.request.surface; m_ownedPostProcessSequences[index] = std::move(postProcessSequence); plan.postProcess.passes = m_ownedPostProcessSequences[index].get(); + plan.usesGraphManagedMainSceneColor = true; + plan.postProcessSource = CameraFrameColorSource::MainSceneColor; + plan.usesGraphManagedPostProcessColor = hasFinalOutput; + if (!hasFinalOutput) { + plan.postProcess.destinationSurface = plan.request.surface; + } } if (hasFinalOutput) { - const FullscreenPassSurfaceCache::SurfaceEntry* finalOutputSourceEntry = - hasPostProcess ? postProcessOutputEntry : sceneColorEntry; - plan.finalOutput.sourceSurface = - hasPostProcess - ? plan.postProcess.destinationSurface - : ConfigureFullscreenStageSurface(*sceneColorEntry, plan.request.surface, true); - plan.finalOutput.sourceColorView = finalOutputSourceEntry->shaderResourceView; - plan.finalOutput.sourceColorState = plan.finalOutput.sourceSurface.GetColorStateAfter(); - plan.finalOutput.destinationSurface = plan.request.surface; m_ownedFinalOutputSequences[index] = std::move(finalOutputSequence); plan.finalOutput.passes = m_ownedFinalOutputSequences[index].get(); + plan.usesGraphManagedMainSceneColor = true; + plan.finalOutputSource = + hasPostProcess + ? CameraFrameColorSource::PostProcessColor + : CameraFrameColorSource::MainSceneColor; + plan.finalOutput.destinationSurface = plan.request.surface; + } + + if (plan.usesGraphManagedMainSceneColor) { + plan.ConfigureGraphManagedMainSceneSurface(); } } } diff --git a/engine/src/Rendering/Planning/CameraFramePlanBuilder.h b/engine/src/Rendering/Planning/CameraFramePlanBuilder.h index a1ffa081..640a1060 100644 --- a/engine/src/Rendering/Planning/CameraFramePlanBuilder.h +++ b/engine/src/Rendering/Planning/CameraFramePlanBuilder.h @@ -8,7 +8,6 @@ namespace XCEngine { namespace Rendering { -class FullscreenPassSurfaceCache; class RenderPipelineAsset; class CameraFramePlanBuilder { @@ -21,12 +20,10 @@ public: std::vector BuildPlans( const std::vector& requests, const RenderPipelineAsset* pipelineAsset); - void UpdateTrackedSurfaceState(const RenderSurface* surface); private: std::vector CreatePlansFromRequests( const std::vector& requests) const; - void PrepareOwnedFullscreenStageState(size_t planCount); void ResolveCameraFinalColorPolicies( std::vector& plans, const RenderPipelineAsset* pipelineAsset) const; @@ -34,7 +31,6 @@ private: std::vector> m_ownedPostProcessSequences; std::vector> m_ownedFinalOutputSequences; - std::vector> m_ownedFullscreenStageSurfaces; }; } // namespace Rendering diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index 3b40ddcd..7ffa9e96 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -2735,9 +2735,12 @@ TEST(SceneRenderer_Test, BuildsCameraColorScalePostProcessRequestFromCameraPassS ASSERT_EQ(plans.size(), 1u); const CameraFramePlan& plan = plans[0]; EXPECT_TRUE(plan.postProcess.IsRequested()); - EXPECT_TRUE(plan.postProcess.IsValid()); + EXPECT_TRUE(plan.IsPostProcessStageValid()); EXPECT_NE(plan.postProcess.passes, nullptr); ASSERT_EQ(plan.postProcess.passes->GetPassCount(), 2u); + EXPECT_TRUE(plan.usesGraphManagedMainSceneColor); + EXPECT_FALSE(plan.usesGraphManagedPostProcessColor); + EXPECT_EQ(plan.postProcessSource, CameraFrameColorSource::MainSceneColor); EXPECT_EQ(plan.postProcess.destinationSurface.GetColorAttachments()[0], backBufferColorView); EXPECT_EQ(plan.postProcess.destinationSurface.GetDepthAttachment(), depthView); EXPECT_EQ( @@ -2746,30 +2749,28 @@ TEST(SceneRenderer_Test, BuildsCameraColorScalePostProcessRequestFromCameraPassS EXPECT_EQ( plan.postProcess.destinationSurface.GetDepthStateAfter(), XCEngine::RHI::ResourceStates::PixelShaderResource); - EXPECT_EQ(plan.postProcess.sourceSurface.GetDepthAttachment(), depthView); + EXPECT_EQ(plan.GetMainSceneSurface().GetDepthAttachment(), depthView); EXPECT_EQ( - plan.postProcess.sourceSurface.GetDepthStateBefore(), + plan.GetMainSceneSurface().GetDepthStateBefore(), XCEngine::RHI::ResourceStates::Common); EXPECT_EQ( - plan.postProcess.sourceSurface.GetDepthStateAfter(), + plan.GetMainSceneSurface().GetDepthStateAfter(), XCEngine::RHI::ResourceStates::PixelShaderResource); - EXPECT_EQ(plan.postProcess.sourceSurface.GetWidth(), 800u); - EXPECT_EQ(plan.postProcess.sourceSurface.GetHeight(), 600u); - const XCEngine::Math::RectInt sourceRenderArea = plan.postProcess.sourceSurface.GetRenderArea(); + EXPECT_EQ(plan.GetMainSceneSurface().GetWidth(), 800u); + EXPECT_EQ(plan.GetMainSceneSurface().GetHeight(), 600u); + const XCEngine::Math::RectInt sourceRenderArea = plan.GetMainSceneSurface().GetRenderArea(); EXPECT_EQ(sourceRenderArea.x, 200); EXPECT_EQ(sourceRenderArea.y, 75); EXPECT_EQ(sourceRenderArea.width, 400); EXPECT_EQ(sourceRenderArea.height, 375); - EXPECT_NE(plan.postProcess.sourceColorView, nullptr); - EXPECT_NE(plan.postProcess.sourceColorView, backBufferColorView); + EXPECT_EQ(plan.GetSourceSurface(CameraFrameStage::PostProcess), nullptr); + EXPECT_EQ(plan.GetSourceColorView(CameraFrameStage::PostProcess), nullptr); EXPECT_EQ( - plan.postProcess.sourceColorState, - XCEngine::RHI::ResourceStates::PixelShaderResource); - ASSERT_FALSE(plan.postProcess.sourceSurface.GetColorAttachments().empty()); - EXPECT_NE(plan.postProcess.sourceSurface.GetColorAttachments()[0], backBufferColorView); - EXPECT_EQ(allocationState->createTextureCalls, 1); - EXPECT_EQ(allocationState->createRenderTargetViewCalls, 1); - EXPECT_EQ(allocationState->createShaderViewCalls, 1); + plan.GetSourceColorState(CameraFrameStage::PostProcess), + XCEngine::RHI::ResourceStates::Common); + EXPECT_EQ(allocationState->createTextureCalls, 0); + EXPECT_EQ(allocationState->createRenderTargetViewCalls, 0); + EXPECT_EQ(allocationState->createShaderViewCalls, 0); delete depthView; delete backBufferColorView; @@ -2870,9 +2871,11 @@ TEST(SceneRenderer_Test, BuildsFinalOutputRequestFromResolvedFinalColorPolicy) { const CameraFramePlan& plan = plans[0]; EXPECT_FALSE(plan.postProcess.IsRequested()); EXPECT_TRUE(plan.finalOutput.IsRequested()); - EXPECT_TRUE(plan.finalOutput.IsValid()); + EXPECT_TRUE(plan.IsFinalOutputStageValid()); ASSERT_NE(plan.finalOutput.passes, nullptr); EXPECT_EQ(plan.finalOutput.passes->GetPassCount(), 1u); + EXPECT_TRUE(plan.usesGraphManagedMainSceneColor); + EXPECT_EQ(plan.finalOutputSource, CameraFrameColorSource::MainSceneColor); EXPECT_EQ(plan.finalOutput.destinationSurface.GetColorAttachments()[0], backBufferColorView); EXPECT_EQ(plan.finalOutput.destinationSurface.GetDepthAttachment(), depthView); EXPECT_EQ( @@ -2881,25 +2884,23 @@ TEST(SceneRenderer_Test, BuildsFinalOutputRequestFromResolvedFinalColorPolicy) { EXPECT_EQ( plan.finalOutput.destinationSurface.GetDepthStateAfter(), XCEngine::RHI::ResourceStates::PixelShaderResource); - EXPECT_EQ(plan.finalOutput.sourceSurface.GetDepthAttachment(), depthView); + EXPECT_EQ(plan.GetMainSceneSurface().GetDepthAttachment(), depthView); EXPECT_EQ( - plan.finalOutput.sourceSurface.GetDepthStateBefore(), + plan.GetMainSceneSurface().GetDepthStateBefore(), XCEngine::RHI::ResourceStates::Common); EXPECT_EQ( - plan.finalOutput.sourceSurface.GetDepthStateAfter(), + plan.GetMainSceneSurface().GetDepthStateAfter(), XCEngine::RHI::ResourceStates::PixelShaderResource); - EXPECT_EQ(plan.finalOutput.sourceSurface.GetWidth(), 800u); - EXPECT_EQ(plan.finalOutput.sourceSurface.GetHeight(), 600u); - EXPECT_NE(plan.finalOutput.sourceColorView, nullptr); - EXPECT_NE(plan.finalOutput.sourceColorView, backBufferColorView); + EXPECT_EQ(plan.GetMainSceneSurface().GetWidth(), 800u); + EXPECT_EQ(plan.GetMainSceneSurface().GetHeight(), 600u); + EXPECT_EQ(plan.GetSourceSurface(CameraFrameStage::FinalOutput), nullptr); + EXPECT_EQ(plan.GetSourceColorView(CameraFrameStage::FinalOutput), nullptr); EXPECT_EQ( - plan.finalOutput.sourceColorState, - XCEngine::RHI::ResourceStates::PixelShaderResource); - ASSERT_FALSE(plan.finalOutput.sourceSurface.GetColorAttachments().empty()); - EXPECT_NE(plan.finalOutput.sourceSurface.GetColorAttachments()[0], backBufferColorView); - EXPECT_EQ(allocationState->createTextureCalls, 1); - EXPECT_EQ(allocationState->createRenderTargetViewCalls, 1); - EXPECT_EQ(allocationState->createShaderViewCalls, 1); + plan.GetSourceColorState(CameraFrameStage::FinalOutput), + XCEngine::RHI::ResourceStates::Common); + EXPECT_EQ(allocationState->createTextureCalls, 0); + EXPECT_EQ(allocationState->createRenderTargetViewCalls, 0); + EXPECT_EQ(allocationState->createShaderViewCalls, 0); delete depthView; delete backBufferColorView; @@ -2956,32 +2957,21 @@ TEST(SceneRenderer_Test, RoutesPostProcessIntoIntermediateSurfaceBeforeFinalOutp const CameraFramePlan& plan = plans[0]; EXPECT_TRUE(plan.postProcess.IsRequested()); EXPECT_TRUE(plan.finalOutput.IsRequested()); + EXPECT_TRUE(plan.IsPostProcessStageValid()); + EXPECT_TRUE(plan.IsFinalOutputStageValid()); ASSERT_NE(plan.postProcess.passes, nullptr); ASSERT_NE(plan.finalOutput.passes, nullptr); EXPECT_EQ(plan.postProcess.passes->GetPassCount(), 1u); EXPECT_EQ(plan.finalOutput.passes->GetPassCount(), 1u); + EXPECT_TRUE(plan.usesGraphManagedMainSceneColor); + EXPECT_TRUE(plan.usesGraphManagedPostProcessColor); + EXPECT_EQ(plan.postProcessSource, CameraFrameColorSource::MainSceneColor); + EXPECT_EQ(plan.finalOutputSource, CameraFrameColorSource::PostProcessColor); - ASSERT_FALSE(plan.postProcess.sourceSurface.GetColorAttachments().empty()); - ASSERT_FALSE(plan.postProcess.destinationSurface.GetColorAttachments().empty()); - ASSERT_FALSE(plan.finalOutput.sourceSurface.GetColorAttachments().empty()); - - EXPECT_NE( - plan.postProcess.sourceSurface.GetColorAttachments()[0], - plan.postProcess.destinationSurface.GetColorAttachments()[0]); - EXPECT_EQ( - plan.finalOutput.sourceSurface.GetColorAttachments()[0], - plan.postProcess.destinationSurface.GetColorAttachments()[0]); + EXPECT_EQ(plan.GetSourceSurface(CameraFrameStage::PostProcess), nullptr); + EXPECT_EQ(plan.GetOutputSurface(CameraFrameStage::PostProcess), nullptr); + EXPECT_EQ(plan.GetSourceSurface(CameraFrameStage::FinalOutput), nullptr); EXPECT_EQ(plan.finalOutput.destinationSurface.GetColorAttachments()[0], backBufferColorView); - - EXPECT_EQ(plan.postProcess.sourceSurface.GetDepthAttachment(), depthView); - EXPECT_EQ( - plan.postProcess.sourceSurface.GetDepthStateBefore(), - XCEngine::RHI::ResourceStates::Common); - EXPECT_EQ( - plan.postProcess.sourceSurface.GetDepthStateAfter(), - XCEngine::RHI::ResourceStates::PixelShaderResource); - EXPECT_EQ(plan.postProcess.destinationSurface.GetDepthAttachment(), nullptr); - EXPECT_EQ(plan.finalOutput.sourceSurface.GetDepthAttachment(), nullptr); EXPECT_EQ(plan.finalOutput.destinationSurface.GetDepthAttachment(), depthView); EXPECT_EQ( plan.finalOutput.destinationSurface.GetDepthStateBefore(), @@ -2989,30 +2979,27 @@ TEST(SceneRenderer_Test, RoutesPostProcessIntoIntermediateSurfaceBeforeFinalOutp EXPECT_EQ( plan.finalOutput.destinationSurface.GetDepthStateAfter(), XCEngine::RHI::ResourceStates::PixelShaderResource); - - const XCEngine::Math::RectInt postProcessSourceArea = plan.postProcess.sourceSurface.GetRenderArea(); + const XCEngine::Math::RectInt postProcessSourceArea = plan.GetMainSceneSurface().GetRenderArea(); EXPECT_EQ(postProcessSourceArea.x, 200); EXPECT_EQ(postProcessSourceArea.y, 75); EXPECT_EQ(postProcessSourceArea.width, 400); EXPECT_EQ(postProcessSourceArea.height, 375); - const XCEngine::Math::RectInt finalOutputSourceArea = plan.finalOutput.sourceSurface.GetRenderArea(); + const XCEngine::Math::RectInt finalOutputSourceArea = plan.GetMainSceneSurface().GetRenderArea(); EXPECT_EQ(finalOutputSourceArea.x, 200); EXPECT_EQ(finalOutputSourceArea.y, 75); EXPECT_EQ(finalOutputSourceArea.width, 400); EXPECT_EQ(finalOutputSourceArea.height, 375); - - EXPECT_NE(plan.postProcess.sourceColorView, nullptr); - EXPECT_NE(plan.finalOutput.sourceColorView, nullptr); - EXPECT_NE(plan.postProcess.sourceColorView, plan.finalOutput.sourceColorView); + EXPECT_EQ(plan.GetSourceColorView(CameraFrameStage::PostProcess), nullptr); + EXPECT_EQ(plan.GetSourceColorView(CameraFrameStage::FinalOutput), nullptr); EXPECT_EQ( - plan.postProcess.sourceColorState, - XCEngine::RHI::ResourceStates::PixelShaderResource); + plan.GetSourceColorState(CameraFrameStage::PostProcess), + XCEngine::RHI::ResourceStates::Common); EXPECT_EQ( - plan.finalOutput.sourceColorState, - XCEngine::RHI::ResourceStates::PixelShaderResource); - EXPECT_EQ(allocationState->createTextureCalls, 2); - EXPECT_EQ(allocationState->createRenderTargetViewCalls, 2); - EXPECT_EQ(allocationState->createShaderViewCalls, 2); + plan.GetSourceColorState(CameraFrameStage::FinalOutput), + XCEngine::RHI::ResourceStates::Common); + EXPECT_EQ(allocationState->createTextureCalls, 0); + EXPECT_EQ(allocationState->createRenderTargetViewCalls, 0); + EXPECT_EQ(allocationState->createShaderViewCalls, 0); delete depthView; delete backBufferColorView; @@ -3074,7 +3061,7 @@ TEST(SceneRenderer_Test, DoesNotBuildFullscreenStagesForMultisampledMainSceneSur delete backBufferColorView; } -TEST(SceneRenderer_Test, ReusesTrackedSceneColorStateAcrossFramesWhenPostProcessIsEnabled) { +TEST(SceneRenderer_Test, KeepsMainSceneGraphManagedWhenPostProcessIsEnabledAcrossFrames) { Scene scene("SceneRendererTrackedSceneColorStateScene"); GameObject* cameraObject = scene.CreateGameObject("Camera"); @@ -3087,6 +3074,7 @@ TEST(SceneRenderer_Test, ReusesTrackedSceneColorStateAcrossFramesWhenPostProcess }); auto pipelineState = std::make_shared(); + pipelineState->supportsMainSceneRenderGraph = true; auto allocationState = std::make_shared(); MockShadowDevice device(allocationState); @@ -3114,6 +3102,8 @@ TEST(SceneRenderer_Test, ReusesTrackedSceneColorStateAcrossFramesWhenPostProcess renderer.BuildFramePlans(scene, nullptr, context, surface); ASSERT_EQ(firstFramePlans.size(), 1u); CameraFramePlan firstFramePlan = firstFramePlans[0]; + EXPECT_TRUE(firstFramePlan.usesGraphManagedMainSceneColor); + EXPECT_EQ(firstFramePlan.postProcessSource, CameraFrameColorSource::MainSceneColor); EXPECT_EQ( firstFramePlan.GetMainSceneSurface().GetColorStateBefore(), XCEngine::RHI::ResourceStates::Common); @@ -3123,23 +3113,31 @@ TEST(SceneRenderer_Test, ReusesTrackedSceneColorStateAcrossFramesWhenPostProcess firstFramePlans[0].postProcess.passes = &postProcessPasses; ASSERT_TRUE(renderer.Render(firstFramePlans)); + const int createTextureCallsAfterFirstRender = allocationState->createTextureCalls; + const int createRenderTargetViewCallsAfterFirstRender = + allocationState->createRenderTargetViewCalls; + const int createShaderViewCallsAfterFirstRender = allocationState->createShaderViewCalls; const std::vector secondFramePlans = renderer.BuildFramePlans(scene, nullptr, context, surface); ASSERT_EQ(secondFramePlans.size(), 1u); const CameraFramePlan secondFramePlan = secondFramePlans[0]; + EXPECT_TRUE(secondFramePlan.usesGraphManagedMainSceneColor); + EXPECT_EQ(secondFramePlan.postProcessSource, CameraFrameColorSource::MainSceneColor); EXPECT_EQ( secondFramePlan.GetMainSceneSurface().GetColorStateBefore(), - XCEngine::RHI::ResourceStates::PixelShaderResource); + XCEngine::RHI::ResourceStates::Common); + EXPECT_EQ(allocationState->createTextureCalls, createTextureCallsAfterFirstRender); EXPECT_EQ( - secondFramePlan.GetMainSceneSurface().GetColorStateAfter(), - XCEngine::RHI::ResourceStates::PixelShaderResource); + allocationState->createRenderTargetViewCalls, + createRenderTargetViewCallsAfterFirstRender); + EXPECT_EQ(allocationState->createShaderViewCalls, createShaderViewCallsAfterFirstRender); delete depthView; delete backBufferColorView; } -TEST(SceneRenderer_Test, ReusesTrackedPostProcessOutputStateAcrossFramesWhenFinalOutputIsEnabled) { +TEST(SceneRenderer_Test, KeepsPostProcessOutputGraphManagedWhenFinalOutputIsEnabledAcrossFrames) { Scene scene("SceneRendererTrackedPostProcessOutputStateScene"); GameObject* cameraObject = scene.CreateGameObject("Camera"); @@ -3157,6 +3155,7 @@ TEST(SceneRenderer_Test, ReusesTrackedPostProcessOutputStateAcrossFramesWhenFina camera->SetFinalColorOverrides(finalColorOverrides); auto pipelineState = std::make_shared(); + pipelineState->supportsMainSceneRenderGraph = true; auto allocationState = std::make_shared(); MockShadowDevice device(allocationState); @@ -3186,12 +3185,14 @@ TEST(SceneRenderer_Test, ReusesTrackedPostProcessOutputStateAcrossFramesWhenFina CameraFramePlan firstFramePlan = firstFramePlans[0]; EXPECT_TRUE(firstFramePlans[0].postProcess.IsRequested()); EXPECT_TRUE(firstFramePlans[0].finalOutput.IsRequested()); + EXPECT_TRUE(firstFramePlan.usesGraphManagedMainSceneColor); + EXPECT_TRUE(firstFramePlan.usesGraphManagedPostProcessColor); + EXPECT_EQ(firstFramePlan.postProcessSource, CameraFrameColorSource::MainSceneColor); + EXPECT_EQ(firstFramePlan.finalOutputSource, CameraFrameColorSource::PostProcessColor); EXPECT_EQ( firstFramePlan.GetMainSceneSurface().GetColorStateBefore(), XCEngine::RHI::ResourceStates::Common); - EXPECT_EQ( - firstFramePlan.postProcess.destinationSurface.GetColorStateBefore(), - XCEngine::RHI::ResourceStates::Common); + EXPECT_EQ(firstFramePlan.GetOutputSurface(CameraFrameStage::PostProcess), nullptr); RenderPassSequence postProcessPasses; postProcessPasses.AddPass(std::make_unique(pipelineState, "postProcess")); @@ -3201,20 +3202,29 @@ TEST(SceneRenderer_Test, ReusesTrackedPostProcessOutputStateAcrossFramesWhenFina firstFramePlans[0].finalOutput.passes = &finalOutputPasses; ASSERT_TRUE(renderer.Render(firstFramePlans)); + const int createTextureCallsAfterFirstRender = allocationState->createTextureCalls; + const int createRenderTargetViewCallsAfterFirstRender = + allocationState->createRenderTargetViewCalls; + const int createShaderViewCallsAfterFirstRender = allocationState->createShaderViewCalls; const std::vector secondFramePlans = renderer.BuildFramePlans(scene, nullptr, context, surface); ASSERT_EQ(secondFramePlans.size(), 1u); const CameraFramePlan secondFramePlan = secondFramePlans[0]; + EXPECT_TRUE(secondFramePlan.usesGraphManagedMainSceneColor); + EXPECT_TRUE(secondFramePlan.usesGraphManagedPostProcessColor); + EXPECT_EQ(secondFramePlan.postProcessSource, CameraFrameColorSource::MainSceneColor); + EXPECT_EQ(secondFramePlan.finalOutputSource, CameraFrameColorSource::PostProcessColor); EXPECT_EQ( secondFramePlan.GetMainSceneSurface().GetColorStateBefore(), - XCEngine::RHI::ResourceStates::PixelShaderResource); + XCEngine::RHI::ResourceStates::Common); + EXPECT_EQ(secondFramePlan.GetOutputSurface(CameraFrameStage::PostProcess), nullptr); + EXPECT_EQ(secondFramePlan.GetSourceSurface(CameraFrameStage::FinalOutput), nullptr); + EXPECT_EQ(allocationState->createTextureCalls, createTextureCallsAfterFirstRender); EXPECT_EQ( - secondFramePlan.postProcess.destinationSurface.GetColorStateBefore(), - XCEngine::RHI::ResourceStates::PixelShaderResource); - EXPECT_EQ( - secondFramePlan.finalOutput.sourceSurface.GetColorStateBefore(), - XCEngine::RHI::ResourceStates::PixelShaderResource); + allocationState->createRenderTargetViewCalls, + createRenderTargetViewCallsAfterFirstRender); + EXPECT_EQ(allocationState->createShaderViewCalls, createShaderViewCallsAfterFirstRender); delete depthView; delete backBufferColorView;