diff --git a/engine/include/XCEngine/Rendering/SceneRenderFeaturePass.h b/engine/include/XCEngine/Rendering/SceneRenderFeaturePass.h index c3525a0d..767ca73c 100644 --- a/engine/include/XCEngine/Rendering/SceneRenderFeaturePass.h +++ b/engine/include/XCEngine/Rendering/SceneRenderFeaturePass.h @@ -26,6 +26,7 @@ struct SceneRenderFeaturePassRenderGraphContext { const RenderSurface* sourceSurface = nullptr; RHI::RHIResourceView* sourceColorView = nullptr; RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common; + RenderGraphTextureHandle sourceColorTexture = {}; std::vector colorTargets = {}; RenderGraphTextureHandle depthTarget = {}; RenderGraphTextureHandle mainDirectionalShadowTexture = {}; diff --git a/engine/src/Rendering/Internal/RenderPassGraphUtils.cpp b/engine/src/Rendering/Internal/RenderPassGraphUtils.cpp index 946579b8..aabef70b 100644 --- a/engine/src/Rendering/Internal/RenderPassGraphUtils.cpp +++ b/engine/src/Rendering/Internal/RenderPassGraphUtils.cpp @@ -172,11 +172,13 @@ bool RecordRasterRenderPass( const RenderPassGraphIO& io) { RenderPass* const renderPass = &pass; const Containers::String passName = context.passName; - const RenderContext* const renderContext = &context.renderContext; + const RenderContext renderContext = context.renderContext; const std::shared_ptr sceneData = std::make_shared(context.sceneData); const RenderSurface surface = context.surface; - const RenderSurface* const sourceSurface = context.sourceSurface; + const bool hasSourceSurface = context.sourceSurface != nullptr; + const RenderSurface sourceSurface = + hasSourceSurface ? *context.sourceSurface : RenderSurface(); RHI::RHIResourceView* const sourceColorView = context.sourceColorView; const RHI::ResourceStates sourceColorState = context.sourceColorState; const RenderGraphTextureHandle sourceColorTexture = context.sourceColorTexture; @@ -192,6 +194,7 @@ bool RecordRasterRenderPass( renderContext, sceneData, surface, + hasSourceSurface, sourceSurface, sourceColorView, sourceColorState, @@ -224,6 +227,7 @@ bool RecordRasterRenderPass( renderContext, sceneData, surface, + hasSourceSurface, sourceSurface, sourceColorView, sourceColorState, @@ -239,12 +243,13 @@ bool RecordRasterRenderPass( return; } - const RenderSurface* resolvedSourceSurface = sourceSurface; + const RenderSurface* resolvedSourceSurface = + hasSourceSurface ? &sourceSurface : nullptr; RHI::RHIResourceView* resolvedSourceColorView = sourceColorView; RHI::ResourceStates resolvedSourceColorState = sourceColorState; RenderSurface graphManagedSourceSurface = {}; if (!ResolveGraphManagedSourceSurface( - sourceSurface, + hasSourceSurface ? &sourceSurface : nullptr, sourceColorView, sourceColorState, sourceColorTexture, @@ -277,7 +282,7 @@ bool RecordRasterRenderPass( } const RenderPassContext passContext = { - *renderContext, + renderContext, *resolvedSurface, *sceneData, resolvedSourceSurface, diff --git a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineFrame.cpp b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineFrame.cpp index caa239c7..57c02f8b 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineFrame.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardPipelineFrame.cpp @@ -94,11 +94,14 @@ bool BuiltinForwardPipeline::SupportsMainSceneRenderGraph() const { bool BuiltinForwardPipeline::RecordMainSceneRenderGraph( const RenderPipelineMainSceneRenderGraphContext& context) { const Containers::String passName = context.passName; - const RenderContext* const renderContext = &context.renderContext; - const RenderSceneData* const sceneData = &context.sceneData; + const RenderContext renderContext = context.renderContext; + const std::shared_ptr sceneData = + std::make_shared(context.sceneData); const RenderSurface surfaceTemplate = BuildGraphManagedForwardSceneSurface(context.surfaceTemplate); - const RenderSurface* const sourceSurface = context.sourceSurface; + const bool hasSourceSurface = context.sourceSurface != nullptr; + const RenderSurface sourceSurface = + hasSourceSurface ? *context.sourceSurface : RenderSurface(); RHI::RHIResourceView* const sourceColorView = context.sourceColorView; const RHI::ResourceStates sourceColorState = context.sourceColorState; const std::vector colorTargets = context.colorTargets; @@ -113,6 +116,7 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph( graphExecutionState, renderContext, sceneData, + hasSourceSurface, sourceSurface, sourceColorView, sourceColorState, @@ -124,7 +128,7 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph( } if (!graphExecutionState->initialized) { - if (!Initialize(*renderContext)) { + if (!Initialize(renderContext)) { Debug::Logger::Get().Error( Debug::LogCategory::Rendering, "BuiltinForwardPipeline::RecordMainSceneRenderGraph failed during execution: Initialize returned false"); @@ -135,10 +139,10 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph( } const FrameExecutionContext executionContext( - *renderContext, + renderContext, passContext.surface, *sceneData, - sourceSurface, + hasSourceSurface ? &sourceSurface : nullptr, sourceColorView, sourceColorState); if (!m_forwardSceneFeatureHost.Prepare(executionContext)) { @@ -177,12 +181,13 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph( const SceneRenderFeaturePassRenderGraphContext featureContext = { context.graphBuilder, passName, - *renderContext, + renderContext, *sceneData, surfaceTemplate, - sourceSurface, + hasSourceSurface ? &sourceSurface : nullptr, sourceColorView, sourceColorState, + {}, colorTargets, depthTarget, mainDirectionalShadowTexture, @@ -214,6 +219,7 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph( surfaceTemplate, renderContext, sceneData, + hasSourceSurface, sourceSurface, sourceColorView, sourceColorState, @@ -245,6 +251,7 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph( surfaceTemplate, renderContext, sceneData, + hasSourceSurface, sourceSurface, sourceColorView, sourceColorState, @@ -259,10 +266,10 @@ bool BuiltinForwardPipeline::RecordMainSceneRenderGraph( } const FrameExecutionContext executionContext( - *renderContext, + renderContext, surfaceTemplate, *sceneData, - sourceSurface, + hasSourceSurface ? &sourceSurface : nullptr, sourceColorView, sourceColorState); const RenderPassContext passContext = diff --git a/engine/src/Rendering/SceneRenderFeatureHost.cpp b/engine/src/Rendering/SceneRenderFeatureHost.cpp index 4977a5c3..7e70c016 100644 --- a/engine/src/Rendering/SceneRenderFeatureHost.cpp +++ b/engine/src/Rendering/SceneRenderFeatureHost.cpp @@ -131,6 +131,7 @@ bool SceneRenderFeatureHost::Record( context.sourceSurface, context.sourceColorView, context.sourceColorState, + context.sourceColorTexture, context.colorTargets, context.depthTarget, context.mainDirectionalShadowTexture, diff --git a/engine/src/Rendering/SceneRenderFeaturePass.cpp b/engine/src/Rendering/SceneRenderFeaturePass.cpp index 3a5f85a6..3078ec3a 100644 --- a/engine/src/Rendering/SceneRenderFeaturePass.cpp +++ b/engine/src/Rendering/SceneRenderFeaturePass.cpp @@ -1,98 +1,62 @@ #include "Rendering/SceneRenderFeaturePass.h" -#include "Rendering/Graph/RenderGraph.h" +#include "Rendering/Internal/RenderPassGraphUtils.h" + +#include namespace XCEngine { namespace Rendering { bool SceneRenderFeaturePass::RecordRenderGraph( const SceneRenderFeaturePassRenderGraphContext& context) { - SceneRenderFeaturePass* const featurePass = this; - const Containers::String passName = context.passName; - const RenderContext* const renderContext = &context.renderContext; - const RenderSceneData* const sceneData = &context.sceneData; - const RenderSurface surface = context.surface; - const RenderSurface* const sourceSurface = context.sourceSurface; - RHI::RHIResourceView* const sourceColorView = context.sourceColorView; - const RHI::ResourceStates sourceColorState = context.sourceColorState; - const std::vector colorTargets = context.colorTargets; - const RenderGraphTextureHandle depthTarget = context.depthTarget; - const bool clearAttachments = context.clearAttachments; - bool* const executionSucceeded = context.executionSucceeded; - const SceneRenderFeaturePassBeginCallback beginPassCallback = context.beginPassCallback; - const SceneRenderFeaturePassEndCallback endPassCallback = context.endPassCallback; - - context.graphBuilder.AddRasterPass( - passName, - [featurePass, - renderContext, - sceneData, - surface, - sourceSurface, - sourceColorView, - sourceColorState, - colorTargets, - depthTarget, - clearAttachments, - executionSucceeded, - beginPassCallback, - endPassCallback]( - RenderGraphPassBuilder& passBuilder) { - for (RenderGraphTextureHandle colorTarget : colorTargets) { - if (colorTarget.IsValid()) { - passBuilder.WriteTexture(colorTarget); - } - } - - if (depthTarget.IsValid()) { - passBuilder.WriteDepthTexture(depthTarget); - } - - passBuilder.SetExecuteCallback( - [featurePass, - renderContext, - sceneData, - surface, - sourceSurface, - sourceColorView, - sourceColorState, - clearAttachments, - executionSucceeded, - beginPassCallback, - endPassCallback]( - const RenderGraphExecutionContext&) { - if (executionSucceeded != nullptr && !(*executionSucceeded)) { - return; - } - - const FrameExecutionContext executionContext( - *renderContext, - surface, - *sceneData, - sourceSurface, - sourceColorView, - sourceColorState); - const RenderPassContext passContext = - BuildRenderPassContext(executionContext); - if (beginPassCallback && - !beginPassCallback(passContext, clearAttachments)) { - if (executionSucceeded != nullptr) { - *executionSucceeded = false; - } - return; - } - - const bool executeResult = featurePass->Execute(passContext); - if (endPassCallback) { - endPassCallback(passContext); - } - - if (executionSucceeded != nullptr) { - *executionSucceeded = executeResult; - } - }); + const bool usesSourceColor = context.sourceColorTexture.IsValid(); + const bool hasSourceSurfaceTemplate = + context.sourceSurface != nullptr || usesSourceColor; + const RenderSurface sourceSurfaceTemplate = + context.sourceSurface != nullptr + ? *context.sourceSurface + : (usesSourceColor ? context.surface : RenderSurface()); + const bool writesColor = + std::any_of( + context.colorTargets.begin(), + context.colorTargets.end(), + [](RenderGraphTextureHandle handle) { + return handle.IsValid(); + }); + const RenderPassGraphBeginCallback beginPassCallback = + context.beginPassCallback + ? RenderPassGraphBeginCallback( + [beginPass = context.beginPassCallback, + clearAttachments = context.clearAttachments]( + const RenderPassContext& passContext) { + return beginPass(passContext, clearAttachments); + }) + : RenderPassGraphBeginCallback(); + const RenderPassRenderGraphContext passContext = { + context.graphBuilder, + context.passName, + context.renderContext, + context.sceneData, + context.surface, + hasSourceSurfaceTemplate ? &sourceSurfaceTemplate : nullptr, + context.sourceColorView, + context.sourceColorState, + context.sourceColorTexture, + context.colorTargets, + context.depthTarget, + context.executionSucceeded, + beginPassCallback, + context.endPassCallback, + context.blackboard + }; + return Internal::RecordRasterRenderPass( + *this, + passContext, + { + usesSourceColor, + writesColor, + context.depthTarget.IsValid() }); - return true; } } // namespace Rendering diff --git a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp index c51b7dec..8cd22a94 100644 --- a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp +++ b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp @@ -452,8 +452,20 @@ public: return true; } - bool Execute(const RenderPassContext&) override { + bool Execute(const RenderPassContext& context) override { ++executeCallCount; + lastHasSourceSurface = context.sourceSurface != nullptr; + lastSourceColorView = context.sourceColorView; + if (context.sourceSurface != nullptr) { + lastSourceSurfaceWidth = context.sourceSurface->GetWidth(); + lastSourceSurfaceHeight = context.sourceSurface->GetHeight(); + lastSourceSurfaceRenderAreaWidth = + context.sourceSurface->GetRenderAreaWidth(); + lastSourceSurfaceRenderAreaHeight = + context.sourceSurface->GetRenderAreaHeight(); + lastSourceSurfaceAutoTransitionEnabled = + context.sourceSurface->IsAutoTransitionEnabled(); + } RecordEvent("Execute"); return true; } @@ -461,6 +473,7 @@ public: bool RecordRenderGraph( const SceneRenderFeaturePassRenderGraphContext& context) override { ++recordGraphCallCount; + lastReceivedSourceColorTextureValid = context.sourceColorTexture.IsValid(); RecordEvent("RecordGraph"); return SceneRenderFeaturePass::RecordRenderGraph(context); } @@ -471,6 +484,14 @@ public: size_t executeCallCount = 0u; size_t recordGraphCallCount = 0u; size_t shutdownCallCount = 0u; + bool lastHasSourceSurface = false; + uint32_t lastSourceSurfaceWidth = 0u; + uint32_t lastSourceSurfaceHeight = 0u; + uint32_t lastSourceSurfaceRenderAreaWidth = 0u; + uint32_t lastSourceSurfaceRenderAreaHeight = 0u; + bool lastSourceSurfaceAutoTransitionEnabled = true; + XCEngine::RHI::RHIResourceView* lastSourceColorView = nullptr; + bool lastReceivedSourceColorTextureValid = false; private: void RecordEvent(const char* suffix) { @@ -719,6 +740,7 @@ TEST(SceneRenderFeaturePass_Test, RecordsDefaultGraphPassAndExecutesWrappedCallb nullptr, nullptr, ResourceStates::Common, + {}, { colorTarget }, depthTarget, {}, @@ -756,6 +778,107 @@ TEST(SceneRenderFeaturePass_Test, RecordsDefaultGraphPassAndExecutesWrappedCallb "FeatureGraph:Execute" })); } +TEST(SceneRenderFeaturePass_Test, ReadsSourceColorTextureAndCopiesSourceSurfaceTemplateForGraphExecution) { + TestSceneRenderFeaturePass feature( + SceneRenderInjectionPoint::BeforeOpaque, + true, + nullptr, + "FeatureReadSource"); + + RenderGraph graph = {}; + RenderGraphBuilder graphBuilder(graph); + + RenderGraphTextureDesc colorDesc = {}; + colorDesc.width = 96u; + colorDesc.height = 48u; + colorDesc.format = static_cast(Format::R8G8B8A8_UNorm); + colorDesc.textureType = static_cast(XCEngine::RHI::TextureType::Texture2D); + colorDesc.sampleCount = 1u; + + TestResourceView sourceRenderTargetView( + ResourceViewType::RenderTarget, + ResourceViewDimension::Texture2D, + Format::R8G8B8A8_UNorm); + TestResourceView sourceShaderView( + ResourceViewType::ShaderResource, + ResourceViewDimension::Texture2D, + Format::R8G8B8A8_UNorm); + TestResourceView outputView( + ResourceViewType::RenderTarget, + ResourceViewDimension::Texture2D, + Format::R8G8B8A8_UNorm); + const RenderGraphImportedTextureOptions graphManagedImport = { + ResourceStates::Common, + ResourceStates::Common, + true + }; + const RenderGraphTextureHandle sourceColor = + graphBuilder.ImportTexture("SceneColor", colorDesc, &sourceRenderTargetView, graphManagedImport); + const RenderGraphTextureHandle outputColor = + graphBuilder.ImportTexture("OutputColor", colorDesc, &outputView, graphManagedImport); + + RenderContext renderContext = {}; + MockForwardCommandList commandList; + renderContext.commandList = &commandList; + + RenderSceneData sceneData = {}; + RenderSurface outputSurface(96u, 48u); + outputSurface.SetColorAttachment(&outputView); + outputSurface.SetAutoTransitionEnabled(false); + + RenderSurface sourceSurfaceTemplate(96u, 48u); + sourceSurfaceTemplate.SetColorAttachment(&sourceRenderTargetView); + sourceSurfaceTemplate.SetRenderArea(XCEngine::Math::RectInt(11, 7, 85, 41)); + + bool executionSucceeded = true; + const SceneRenderFeaturePassRenderGraphContext context = { + graphBuilder, + "FeatureReadSourcePass", + renderContext, + sceneData, + outputSurface, + &sourceSurfaceTemplate, + &sourceShaderView, + ResourceStates::Common, + sourceColor, + { outputColor }, + {}, + {}, + false, + &executionSucceeded, + {}, + {} + }; + + ASSERT_TRUE(feature.RecordRenderGraph(context)); + + sourceSurfaceTemplate = RenderSurface(8u, 8u); + sourceSurfaceTemplate.SetRenderArea(XCEngine::Math::RectInt(1, 2, 8, 8)); + + CompiledRenderGraph compiledGraph = {}; + String errorMessage; + ASSERT_TRUE(RenderGraphCompiler::Compile(graph, compiledGraph, &errorMessage)) + << errorMessage.CStr(); + + RenderGraphTextureLifetime lifetime = {}; + ASSERT_TRUE(compiledGraph.TryGetTextureLifetime(sourceColor, lifetime)); + EXPECT_TRUE(lifetime.used); + EXPECT_EQ(lifetime.firstPassIndex, 0u); + EXPECT_EQ(lifetime.lastPassIndex, 0u); + + ASSERT_TRUE(RenderGraphExecutor::Execute(compiledGraph, renderContext, &errorMessage)) + << errorMessage.CStr(); + EXPECT_TRUE(executionSucceeded); + EXPECT_TRUE(feature.lastReceivedSourceColorTextureValid); + EXPECT_TRUE(feature.lastHasSourceSurface); + EXPECT_EQ(feature.lastSourceSurfaceWidth, 96u); + EXPECT_EQ(feature.lastSourceSurfaceHeight, 48u); + EXPECT_EQ(feature.lastSourceSurfaceRenderAreaWidth, 85u); + EXPECT_EQ(feature.lastSourceSurfaceRenderAreaHeight, 41u); + EXPECT_FALSE(feature.lastSourceSurfaceAutoTransitionEnabled); + EXPECT_NE(feature.lastSourceColorView, nullptr); +} + TEST(BuiltinForwardPipeline_Test, RegistersBuiltinDefaultForwardSceneFeatures) { BuiltinForwardPipeline pipeline; @@ -920,6 +1043,7 @@ TEST(SceneRenderFeatureHost_Test, RecordsActiveInjectionPointFeaturesIntoRenderG nullptr, nullptr, ResourceStates::Common, + {}, { colorTarget }, depthTarget, {},