diff --git a/engine/include/XCEngine/Rendering/Graph/RenderGraph.h b/engine/include/XCEngine/Rendering/Graph/RenderGraph.h index 809bb23c..a89d0eb1 100644 --- a/engine/include/XCEngine/Rendering/Graph/RenderGraph.h +++ b/engine/include/XCEngine/Rendering/Graph/RenderGraph.h @@ -84,6 +84,9 @@ public: const RenderGraphTextureDesc& desc, RHI::RHIResourceView* importedView = nullptr, const RenderGraphImportedTextureOptions& importedOptions = {}); + void MergeImportedTextureOptions( + RenderGraphTextureHandle handle, + const RenderGraphImportedTextureOptions& importedOptions); RenderGraphTextureHandle CreateTransientTexture( const Containers::String& name, diff --git a/engine/include/XCEngine/Rendering/Graph/RenderGraphTypes.h b/engine/include/XCEngine/Rendering/Graph/RenderGraphTypes.h index a14ad2fa..e1161261 100644 --- a/engine/include/XCEngine/Rendering/Graph/RenderGraphTypes.h +++ b/engine/include/XCEngine/Rendering/Graph/RenderGraphTypes.h @@ -106,6 +106,7 @@ struct RenderGraphExecutionContext { RenderGraphTextureHandle handle, RenderGraphTextureDesc& outDesc) const; bool IsTransientTexture(RenderGraphTextureHandle handle) const; + bool OwnsTextureTransitions(RenderGraphTextureHandle handle) const; }; using RenderGraphExecuteCallback = std::function; diff --git a/engine/src/Rendering/Execution/CameraRenderer.cpp b/engine/src/Rendering/Execution/CameraRenderer.cpp index 824f88f1..c02fa993 100644 --- a/engine/src/Rendering/Execution/CameraRenderer.cpp +++ b/engine/src/Rendering/Execution/CameraRenderer.cpp @@ -98,7 +98,8 @@ RenderGraphTextureDesc BuildImportedTextureDesc( RenderGraphImportedTextureOptions BuildImportedTextureOptions( const RenderSurface& surface, bool isDepth, - RenderGraphSurfaceImportUsage usage) { + RenderGraphSurfaceImportUsage usage, + bool graphOwnsTransitions) { const RHI::ResourceStates beforeState = isDepth ? surface.GetDepthStateBefore() : surface.GetColorStateBefore(); const RHI::ResourceStates afterState = @@ -113,7 +114,7 @@ RenderGraphImportedTextureOptions BuildImportedTextureOptions( usage == RenderGraphSurfaceImportUsage::Output ? afterState : options.initialState; - options.graphOwnsTransitions = false; + options.graphOwnsTransitions = graphOwnsTransitions; return options; } @@ -130,6 +131,7 @@ RenderGraphTextureHandle ImportRenderGraphTexture( const auto existing = registry.find(view); if (existing != registry.end()) { + builder.MergeImportedTextureOptions(existing->second, importedOptions); return existing->second; } @@ -144,7 +146,8 @@ RenderGraphImportedSurface ImportRenderGraphSurface( RenderGraphImportedTextureRegistry& registry, const Containers::String& surfaceName, const RenderSurface* surface, - RenderGraphSurfaceImportUsage usage) { + RenderGraphSurfaceImportUsage usage, + bool graphOwnsColorTransitions = false) { RenderGraphImportedSurface importedSurface = {}; if (surface == nullptr) { return importedSurface; @@ -170,7 +173,8 @@ RenderGraphImportedSurface ImportRenderGraphSurface( BuildImportedTextureOptions( *surface, false, - usage))); + usage, + graphOwnsColorTransitions))); } if (RHI::RHIResourceView* depthAttachment = surface->GetDepthAttachment(); @@ -185,7 +189,8 @@ RenderGraphImportedSurface ImportRenderGraphSurface( BuildImportedTextureOptions( *surface, true, - usage)); + usage, + false)); } return importedSurface; @@ -565,6 +570,17 @@ bool TryBuildRenderGraphTransientSurface( return true; } +RenderSurface BuildGraphManagedImportedSurface( + const RenderSurface& templateSurface, + RHI::ResourceStates stateBefore, + RHI::ResourceStates stateAfter) { + RenderSurface surface = templateSurface; + surface.SetAutoTransitionEnabled(false); + surface.SetColorStateBefore(stateBefore); + surface.SetColorStateAfter(stateAfter); + return surface; +} + bool ExecuteFullscreenPassSequencePass( RenderPassSequence* sequence, size_t passIndex, @@ -694,14 +710,16 @@ bool ExecuteRenderGraphPlan( importedTextures, stageName + ".Source", stagePassContext.sourceSurface, - RenderGraphSurfaceImportUsage::Source); + RenderGraphSurfaceImportUsage::Source, + true); const RenderGraphImportedSurface outputSurface = ImportRenderGraphSurface( graphBuilder, importedTextures, stageName + ".Output", &stagePassContext.surface, - RenderGraphSurfaceImportUsage::Output); + RenderGraphSurfaceImportUsage::Output, + true); RenderGraphTextureHandle currentSourceColor = GetPrimaryColorTexture(sourceSurface); const RenderGraphTextureHandle finalOutputColor = GetPrimaryColorTexture(outputSurface); @@ -1017,7 +1035,9 @@ bool ExecuteFullscreenPassSequencePass( RHI::RHIResourceView* currentSourceColorView = passContext.sourceColorView; RHI::ResourceStates currentSourceColorState = passContext.sourceColorState; RenderSurface transientSourceSurface = {}; + RenderSurface graphManagedImportedSourceSurface = {}; if (sourceColorHandle.IsValid() && + graphContext.OwnsTextureTransitions(sourceColorHandle) && graphContext.IsTransientTexture(sourceColorHandle)) { if (!TryBuildRenderGraphTransientSurface( passContext.surface, @@ -1036,11 +1056,23 @@ bool ExecuteFullscreenPassSequencePass( return false; } currentSourceColorState = RHI::ResourceStates::PixelShaderResource; + } else if (sourceColorHandle.IsValid() && + graphContext.OwnsTextureTransitions(sourceColorHandle) && + currentSourceSurface != nullptr) { + graphManagedImportedSourceSurface = + BuildGraphManagedImportedSurface( + *currentSourceSurface, + RHI::ResourceStates::PixelShaderResource, + RHI::ResourceStates::PixelShaderResource); + currentSourceSurface = &graphManagedImportedSourceSurface; + currentSourceColorState = RHI::ResourceStates::PixelShaderResource; } const RenderSurface* outputSurface = &passContext.surface; RenderSurface transientOutputSurface = {}; + RenderSurface graphManagedImportedOutputSurface = {}; if (outputColorHandle.IsValid() && + graphContext.OwnsTextureTransitions(outputColorHandle) && graphContext.IsTransientTexture(outputColorHandle)) { if (!TryBuildRenderGraphTransientSurface( passContext.surface, @@ -1051,6 +1083,14 @@ bool ExecuteFullscreenPassSequencePass( } outputSurface = &transientOutputSurface; + } else if (outputColorHandle.IsValid() && + graphContext.OwnsTextureTransitions(outputColorHandle)) { + graphManagedImportedOutputSurface = + BuildGraphManagedImportedSurface( + passContext.surface, + RHI::ResourceStates::RenderTarget, + RHI::ResourceStates::PixelShaderResource); + outputSurface = &graphManagedImportedOutputSurface; } const RenderPassContext chainedContext = { diff --git a/engine/src/Rendering/Graph/RenderGraph.cpp b/engine/src/Rendering/Graph/RenderGraph.cpp index 6be68113..accfba71 100644 --- a/engine/src/Rendering/Graph/RenderGraph.cpp +++ b/engine/src/Rendering/Graph/RenderGraph.cpp @@ -84,6 +84,24 @@ RenderGraphTextureHandle RenderGraphBuilder::CreateTransientTexture( return handle; } +void RenderGraphBuilder::MergeImportedTextureOptions( + RenderGraphTextureHandle handle, + const RenderGraphImportedTextureOptions& importedOptions) { + if (!handle.IsValid() || handle.index >= m_graph.m_textures.size()) { + return; + } + + RenderGraph::TextureResource& resource = m_graph.m_textures[handle.index]; + if (resource.kind != RenderGraphTextureKind::Imported) { + return; + } + + resource.importedOptions.graphOwnsTransitions = + resource.importedOptions.graphOwnsTransitions || + importedOptions.graphOwnsTransitions; + resource.importedOptions.finalState = importedOptions.finalState; +} + RenderGraphPassHandle RenderGraphBuilder::AddRasterPass( const Containers::String& name, const std::function& setup) { diff --git a/engine/src/Rendering/Graph/RenderGraphExecutor.cpp b/engine/src/Rendering/Graph/RenderGraphExecutor.cpp index 26729460..1f812b33 100644 --- a/engine/src/Rendering/Graph/RenderGraphExecutor.cpp +++ b/engine/src/Rendering/Graph/RenderGraphExecutor.cpp @@ -116,6 +116,10 @@ public: m_graph.m_textures[handle.index].kind == RenderGraphTextureKind::Transient; } + bool OwnsTextureTransitions(RenderGraphTextureHandle handle) const { + return ShouldGraphManageTransitions(handle); + } + bool TransitionGraphOwnedImportsToFinalStates( const RenderContext& renderContext, Containers::String* outErrorMessage) { @@ -317,6 +321,11 @@ bool RenderGraphExecutionContext::IsTransientTexture(RenderGraphTextureHandle ha runtimeResources->IsTransientTexture(handle); } +bool RenderGraphExecutionContext::OwnsTextureTransitions(RenderGraphTextureHandle handle) const { + return runtimeResources != nullptr && + runtimeResources->OwnsTextureTransitions(handle); +} + bool RenderGraphExecutor::Execute( const CompiledRenderGraph& graph, const RenderContext& renderContext, diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index 014a456d..ed35979d 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -517,10 +517,13 @@ public: lastWorldPosition = context.sceneData.cameraData.worldPosition; lastSurfaceWidth = context.surface.GetRenderAreaWidth(); lastSurfaceHeight = context.surface.GetRenderAreaHeight(); + lastSurfaceAutoTransitionEnabled = context.surface.IsAutoTransitionEnabled(); lastHasSourceSurface = context.sourceSurface != nullptr; if (context.sourceSurface != nullptr) { lastSourceSurfaceWidth = context.sourceSurface->GetRenderAreaWidth(); lastSourceSurfaceHeight = context.sourceSurface->GetRenderAreaHeight(); + lastSourceSurfaceAutoTransitionEnabled = + context.sourceSurface->IsAutoTransitionEnabled(); } lastSourceColorView = context.sourceColorView; lastSourceColorState = context.sourceColorState; @@ -538,9 +541,11 @@ public: XCEngine::Math::Vector3 lastWorldPosition = XCEngine::Math::Vector3::Zero(); uint32_t lastSurfaceWidth = 0; uint32_t lastSurfaceHeight = 0; + bool lastSurfaceAutoTransitionEnabled = true; bool lastHasSourceSurface = false; uint32_t lastSourceSurfaceWidth = 0; uint32_t lastSourceSurfaceHeight = 0; + bool lastSourceSurfaceAutoTransitionEnabled = true; XCEngine::RHI::RHIResourceView* lastSourceColorView = nullptr; XCEngine::RHI::ResourceStates lastSourceColorState = XCEngine::RHI::ResourceStates::Common; @@ -1071,18 +1076,28 @@ TEST(CameraRenderer_Test, ChainsMultiPassPostProcessThroughIntermediateSurface) EXPECT_TRUE(firstPassRaw->lastHasSourceSurface); EXPECT_EQ(firstPassRaw->lastSourceSurfaceWidth, 256u); EXPECT_EQ(firstPassRaw->lastSourceSurfaceHeight, 128u); + EXPECT_FALSE(firstPassRaw->lastSourceSurfaceAutoTransitionEnabled); EXPECT_EQ(firstPassRaw->lastSourceColorView, sourceColorShaderView); + EXPECT_EQ( + firstPassRaw->lastSourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); EXPECT_EQ(firstPassRaw->lastSurfaceWidth, 512u); EXPECT_EQ(firstPassRaw->lastSurfaceHeight, 256u); + EXPECT_FALSE(firstPassRaw->lastSurfaceAutoTransitionEnabled); ASSERT_NE(secondPassRaw, nullptr); EXPECT_TRUE(secondPassRaw->lastHasSourceSurface); EXPECT_EQ(secondPassRaw->lastSourceSurfaceWidth, 512u); EXPECT_EQ(secondPassRaw->lastSourceSurfaceHeight, 256u); + EXPECT_FALSE(secondPassRaw->lastSourceSurfaceAutoTransitionEnabled); EXPECT_NE(secondPassRaw->lastSourceColorView, nullptr); EXPECT_NE(secondPassRaw->lastSourceColorView, sourceColorShaderView); + EXPECT_EQ( + secondPassRaw->lastSourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); EXPECT_EQ(secondPassRaw->lastSurfaceWidth, 512u); EXPECT_EQ(secondPassRaw->lastSurfaceHeight, 256u); + EXPECT_FALSE(secondPassRaw->lastSurfaceAutoTransitionEnabled); EXPECT_EQ(allocationState->createTextureCalls, 1); EXPECT_EQ(allocationState->createRenderTargetViewCalls, 1); @@ -1182,15 +1197,30 @@ TEST(CameraRenderer_Test, KeepsPostProcessAndFinalOutputScratchSurfacesIndepende ASSERT_NE(postSecondPassRaw, nullptr); EXPECT_EQ(postSecondPassRaw->lastSourceSurfaceWidth, 512u); EXPECT_EQ(postSecondPassRaw->lastSourceSurfaceHeight, 256u); + EXPECT_FALSE(postSecondPassRaw->lastSourceSurfaceAutoTransitionEnabled); + EXPECT_EQ( + postSecondPassRaw->lastSourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); + EXPECT_FALSE(postSecondPassRaw->lastSurfaceAutoTransitionEnabled); ASSERT_NE(finalFirstPassRaw, nullptr); EXPECT_EQ(finalFirstPassRaw->lastSourceSurfaceWidth, 512u); EXPECT_EQ(finalFirstPassRaw->lastSourceSurfaceHeight, 256u); + EXPECT_FALSE(finalFirstPassRaw->lastSourceSurfaceAutoTransitionEnabled); EXPECT_EQ(finalFirstPassRaw->lastSourceColorView, finalOutputSource); + EXPECT_EQ( + finalFirstPassRaw->lastSourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); + EXPECT_FALSE(finalFirstPassRaw->lastSurfaceAutoTransitionEnabled); ASSERT_NE(finalSecondPassRaw, nullptr); EXPECT_EQ(finalSecondPassRaw->lastSourceSurfaceWidth, 800u); EXPECT_EQ(finalSecondPassRaw->lastSourceSurfaceHeight, 600u); + EXPECT_FALSE(finalSecondPassRaw->lastSourceSurfaceAutoTransitionEnabled); EXPECT_NE(finalSecondPassRaw->lastSourceColorView, nullptr); EXPECT_NE(finalSecondPassRaw->lastSourceColorView, finalOutputSource); + EXPECT_EQ( + finalSecondPassRaw->lastSourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); + EXPECT_FALSE(finalSecondPassRaw->lastSurfaceAutoTransitionEnabled); EXPECT_EQ(allocationState->createTextureCalls, 2); EXPECT_EQ(allocationState->createRenderTargetViewCalls, 2);