diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 372d7d54..4d521f84 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -507,6 +507,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraph.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraphBlackboard.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraphRecordingContext.h + ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/RenderPipelineMainSceneGraphContract.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Execution/CameraFrameRenderGraphFrameData.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraphCompiler.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraphExecutor.h @@ -562,6 +563,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderPassGraphContract.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/RenderPipelineMainSceneGraphContract.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinDepthStylePassBase.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinDepthStylePassBaseResources.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Passes/BuiltinDepthOnlyPass.cpp diff --git a/engine/include/XCEngine/Rendering/Graph/RenderGraphRecordingContext.h b/engine/include/XCEngine/Rendering/Graph/RenderGraphRecordingContext.h index e31d4fbd..f11409dc 100644 --- a/engine/include/XCEngine/Rendering/Graph/RenderGraphRecordingContext.h +++ b/engine/include/XCEngine/Rendering/Graph/RenderGraphRecordingContext.h @@ -81,6 +81,7 @@ inline RenderPipelineMainSceneRenderGraphContext BuildRenderPipelineMainSceneRen common.sourceSurface, common.sourceColorView, common.sourceColorState, + common.sourceColorTexture, common.colorTargets, common.depthTarget, common.executionSucceeded, diff --git a/engine/include/XCEngine/Rendering/RenderPipeline.h b/engine/include/XCEngine/Rendering/RenderPipeline.h index 0b9e1040..9a43edcb 100644 --- a/engine/include/XCEngine/Rendering/RenderPipeline.h +++ b/engine/include/XCEngine/Rendering/RenderPipeline.h @@ -24,6 +24,7 @@ struct RenderPipelineMainSceneRenderGraphContext { const RenderSurface* sourceSurface = nullptr; RHI::RHIResourceView* sourceColorView = nullptr; RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common; + RenderGraphTextureHandle sourceColorTexture = {}; std::vector colorTargets = {}; RenderGraphTextureHandle depthTarget = {}; bool* executionSucceeded = nullptr; diff --git a/engine/include/XCEngine/Rendering/RenderPipelineMainSceneGraphContract.h b/engine/include/XCEngine/Rendering/RenderPipelineMainSceneGraphContract.h new file mode 100644 index 00000000..f85917bf --- /dev/null +++ b/engine/include/XCEngine/Rendering/RenderPipelineMainSceneGraphContract.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace XCEngine { +namespace Rendering { + +class SceneRenderFeatureHost; + +Containers::String BuildRenderPipelineMainScenePhasePassName( + const Containers::String& baseName, + ScenePhase scenePhase); + +bool RecordRenderPipelineMainSceneFeaturePasses( + const RenderPipelineMainSceneRenderGraphContext& context, + SceneRenderFeatureHost& featureHost, + SceneRenderInjectionPoint injectionPoint, + bool clearAttachments, + SceneRenderFeaturePassBeginCallback beginPassCallback = {}, + SceneRenderFeaturePassEndCallback endPassCallback = {}, + bool* recordedAnyPass = nullptr); + +bool RecordRenderPipelineMainScenePhasePass( + const RenderPipelineMainSceneRenderGraphContext& context, + ScenePhase scenePhase, + RenderPassGraphExecutePassCallback executePassCallback, + RenderPassGraphBeginCallback beginPassCallback = {}, + RenderPassGraphEndCallback endPassCallback = {}, + std::vector additionalReadTextures = {}); + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.cpp b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.cpp index e0004cd0..7ed9ba0d 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.cpp @@ -2,14 +2,12 @@ #include "Debug/Logger.h" #include "Rendering/Graph/RenderGraph.h" -#include -#include #include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/Pipelines/Internal/BuiltinForwardSceneSetup.h" #include "Rendering/RenderSurface.h" +#include #include -#include namespace XCEngine { namespace Rendering { @@ -28,15 +26,6 @@ struct ForwardSceneGraphExecutionState { bool initialized = false; }; -Containers::String BuildForwardScenePhasePassName( - const Containers::String& baseName, - ScenePhase scenePhase) { - std::string name = baseName.CStr(); - name += '.'; - name += ToString(scenePhase); - return Containers::String(name.c_str()); -} - bool ScenePhaseSamplesMainDirectionalShadow(ScenePhase scenePhase) { return scenePhase == ScenePhase::Opaque || scenePhase == ScenePhase::Transparent; @@ -47,10 +36,7 @@ bool ScenePhaseSamplesMainDirectionalShadow(ScenePhase scenePhase) { bool BuiltinForwardMainSceneGraphBuilder::Record( BuiltinForwardPipeline& pipeline, const RenderPipelineMainSceneRenderGraphContext& context) { - const Containers::String passName = context.passName; const RenderContext renderContext = context.renderContext; - const std::shared_ptr sceneData = - std::make_shared(context.sceneData); const RenderSurface surfaceTemplate = BuildGraphManagedForwardSceneSurface(context.surfaceTemplate); const bool hasSourceSurface = context.sourceSurface != nullptr; @@ -58,8 +44,6 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( hasSourceSurface ? *context.sourceSurface : RenderSurface(); RHI::RHIResourceView* const sourceColorView = context.sourceColorView; const RHI::ResourceStates sourceColorState = context.sourceColorState; - const std::vector colorTargets = context.colorTargets; - const RenderGraphTextureHandle depthTarget = context.depthTarget; const CameraFrameRenderGraphResources* const frameResources = TryGetCameraFrameRenderGraphResources(context.blackboard); const RenderGraphTextureHandle mainDirectionalShadowTexture = @@ -67,13 +51,27 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( ? frameResources->mainDirectionalShadow : RenderGraphTextureHandle{}; bool* const executionSucceeded = context.executionSucceeded; + const RenderPipelineMainSceneRenderGraphContext graphContext = { + context.graphBuilder, + context.passName, + renderContext, + context.sceneData, + surfaceTemplate, + hasSourceSurface ? &sourceSurface : nullptr, + sourceColorView, + sourceColorState, + context.sourceColorTexture, + context.colorTargets, + context.depthTarget, + executionSucceeded, + context.blackboard + }; const std::shared_ptr graphExecutionState = std::make_shared(); const SceneRenderFeaturePassBeginCallback beginRecordedPass = [&pipeline, graphExecutionState, renderContext, - sceneData, hasSourceSurface, sourceSurface, sourceColorView, @@ -97,9 +95,9 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( } const FrameExecutionContext executionContext( - renderContext, + passContext.renderContext, passContext.surface, - *sceneData, + passContext.sceneData, hasSourceSurface ? &sourceSurface : nullptr, sourceColorView, sourceColorState); @@ -132,35 +130,18 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( [&pipeline](const RenderPassContext& passContext) { pipeline.EndForwardScenePass(passContext); }; - const ::XCEngine::Rendering::RenderGraphRecordingContext commonContext = { - context.graphBuilder, - passName, - renderContext, - *sceneData, - surfaceTemplate, - hasSourceSurface ? &sourceSurface : nullptr, - sourceColorView, - sourceColorState, - {}, - colorTargets, - depthTarget, - executionSucceeded, - context.blackboard - }; bool clearAttachments = true; for (const ForwardSceneStep& step : GetBuiltinForwardSceneSteps()) { if (step.type == ForwardSceneStepType::InjectionPoint) { - const SceneRenderFeaturePassRenderGraphContext featureContext = - ::XCEngine::Rendering::BuildSceneRenderFeaturePassRenderGraphContext( - commonContext, + bool recordedAnyPass = false; + if (!::XCEngine::Rendering::RecordRenderPipelineMainSceneFeaturePasses( + graphContext, + pipeline.m_forwardSceneFeatureHost, + step.injectionPoint, clearAttachments, beginRecordedPass, - endRecordedPass); - bool recordedAnyPass = false; - if (!pipeline.m_forwardSceneFeatureHost.Record( - featureContext, - step.injectionPoint, + endRecordedPass, &recordedAnyPass)) { return false; } @@ -171,8 +152,6 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( continue; } - const Containers::String phasePassName = - BuildForwardScenePhasePassName(passName, step.scenePhase); const RenderPassGraphBeginCallback beginPhasePass = [beginRecordedPass, clearAttachments](const RenderPassContext& passContext) { return beginRecordedPass(passContext, clearAttachments); @@ -182,20 +161,9 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( mainDirectionalShadowTexture.IsValid() ? std::vector{ mainDirectionalShadowTexture } : std::vector{}; - ::XCEngine::Rendering::RenderGraphRecordingContext phaseCommonContext = commonContext; - phaseCommonContext.passName = phasePassName; - const RenderPassRenderGraphContext phaseContext = - ::XCEngine::Rendering::BuildRenderPassRenderGraphContext( - phaseCommonContext, - beginPhasePass, - endRecordedPass); - if (!::XCEngine::Rendering::RecordCallbackRasterRenderPass( - phaseContext, - { - false, - true, - depthTarget.IsValid() - }, + if (!::XCEngine::Rendering::RecordRenderPipelineMainScenePhasePass( + graphContext, + step.scenePhase, [&pipeline, scenePhase = step.scenePhase](const RenderPassContext& passContext) { const FrameExecutionContext executionContext( passContext.renderContext, @@ -208,6 +176,8 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( pipeline.BuildScenePhaseExecutionContext(executionContext, scenePhase); return pipeline.ExecuteBuiltinScenePhase(scenePhaseExecutionContext); }, + beginPhasePass, + endRecordedPass, additionalReadTextures)) { return false; } diff --git a/engine/src/Rendering/RenderPipelineMainSceneGraphContract.cpp b/engine/src/Rendering/RenderPipelineMainSceneGraphContract.cpp new file mode 100644 index 00000000..0618e9af --- /dev/null +++ b/engine/src/Rendering/RenderPipelineMainSceneGraphContract.cpp @@ -0,0 +1,95 @@ +#include + +#include +#include + +#include +#include + +namespace XCEngine { +namespace Rendering { +namespace { + +RenderGraphRecordingContext BuildCommonContext( + const RenderPipelineMainSceneRenderGraphContext& context, + Containers::String passName) { + return { + context.graphBuilder, + passName, + context.renderContext, + context.sceneData, + context.surfaceTemplate, + context.sourceSurface, + context.sourceColorView, + context.sourceColorState, + context.sourceColorTexture, + context.colorTargets, + context.depthTarget, + context.executionSucceeded, + context.blackboard + }; +} + +} // namespace + +Containers::String BuildRenderPipelineMainScenePhasePassName( + const Containers::String& baseName, + ScenePhase scenePhase) { + std::string name = baseName.CStr(); + if (!name.empty()) { + name += '.'; + } + + name += ToString(scenePhase); + return Containers::String(name.c_str()); +} + +bool RecordRenderPipelineMainSceneFeaturePasses( + const RenderPipelineMainSceneRenderGraphContext& context, + SceneRenderFeatureHost& featureHost, + SceneRenderInjectionPoint injectionPoint, + bool clearAttachments, + SceneRenderFeaturePassBeginCallback beginPassCallback, + SceneRenderFeaturePassEndCallback endPassCallback, + bool* recordedAnyPass) { + const SceneRenderFeaturePassRenderGraphContext featureContext = + BuildSceneRenderFeaturePassRenderGraphContext( + BuildCommonContext(context, context.passName), + clearAttachments, + beginPassCallback, + endPassCallback); + return featureHost.Record( + featureContext, + injectionPoint, + recordedAnyPass); +} + +bool RecordRenderPipelineMainScenePhasePass( + const RenderPipelineMainSceneRenderGraphContext& context, + ScenePhase scenePhase, + RenderPassGraphExecutePassCallback executePassCallback, + RenderPassGraphBeginCallback beginPassCallback, + RenderPassGraphEndCallback endPassCallback, + std::vector additionalReadTextures) { + const RenderPassRenderGraphContext passContext = + BuildRenderPassRenderGraphContext( + BuildCommonContext( + context, + BuildRenderPipelineMainScenePhasePassName( + context.passName, + scenePhase)), + beginPassCallback, + endPassCallback); + return RecordCallbackRasterRenderPass( + passContext, + { + false, + true, + context.depthTarget.IsValid() + }, + std::move(executePassCallback), + std::move(additionalReadTextures)); +} + +} // namespace Rendering +} // namespace XCEngine diff --git a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp index 0814cccb..d073c93c 100644 --- a/tests/Rendering/unit/test_builtin_forward_pipeline.cpp +++ b/tests/Rendering/unit/test_builtin_forward_pipeline.cpp @@ -643,6 +643,7 @@ TEST(BuiltinForwardPipeline_Test, RecordsMainSceneGraphPassWithSampledShadowDepe nullptr, nullptr, ResourceStates::Common, + {}, { colorTarget }, depthTarget, &executionSucceeded, @@ -1181,6 +1182,7 @@ TEST(BuiltinForwardPipeline_Test, RecordsActiveFeatureInjectionPassesIntoMainSce nullptr, nullptr, ResourceStates::Common, + {}, { colorTarget }, depthTarget, &executionSucceeded, @@ -1201,6 +1203,112 @@ TEST(BuiltinForwardPipeline_Test, RecordsActiveFeatureInjectionPassesIntoMainSce EXPECT_STREQ(compiledGraph.GetPassName(4).CStr(), "MainScene.Transparent"); } +TEST(BuiltinForwardPipeline_Test, ForwardsSourceColorTextureIntoFeatureInjectionGraphContext) { + BuiltinForwardPipeline pipeline; + pipeline.m_forwardSceneFeatureHost.m_featurePasses.clear(); + + auto feature = std::make_unique( + SceneRenderInjectionPoint::BeforeOpaque, + true, + nullptr, + "SourceAware"); + TestSceneRenderFeaturePass* featureRaw = feature.get(); + pipeline.AddForwardSceneFeaturePass(std::move(feature)); + + RenderGraph graph = {}; + RenderGraphBuilder graphBuilder(graph); + + RenderGraphTextureDesc colorDesc = {}; + colorDesc.width = 320u; + colorDesc.height = 180u; + colorDesc.format = static_cast(Format::R8G8B8A8_UNorm); + colorDesc.textureType = static_cast(XCEngine::RHI::TextureType::Texture2D); + colorDesc.sampleCount = 1u; + + RenderGraphTextureDesc depthDesc = {}; + depthDesc.width = 320u; + depthDesc.height = 180u; + depthDesc.format = static_cast(Format::D24_UNorm_S8_UInt); + depthDesc.textureType = static_cast(XCEngine::RHI::TextureType::Texture2D); + depthDesc.sampleCount = 1u; + + TestResourceView sourceRenderTargetView( + ResourceViewType::RenderTarget, + ResourceViewDimension::Texture2D, + Format::R8G8B8A8_UNorm); + TestResourceView sourceShaderView( + ResourceViewType::ShaderResource, + ResourceViewDimension::Texture2D, + Format::R8G8B8A8_UNorm); + TestResourceView colorView( + ResourceViewType::RenderTarget, + ResourceViewDimension::Texture2D, + Format::R8G8B8A8_UNorm); + TestResourceView depthView( + ResourceViewType::DepthStencil, + ResourceViewDimension::Texture2D, + Format::D24_UNorm_S8_UInt); + + const RenderGraphImportedTextureOptions graphManagedImport = { + ResourceStates::Common, + ResourceStates::Common, + true + }; + const RenderGraphTextureHandle sourceColor = + graphBuilder.ImportTexture("SourceColor", colorDesc, &sourceRenderTargetView, graphManagedImport); + const RenderGraphTextureHandle colorTarget = + graphBuilder.ImportTexture("MainColor", colorDesc, &colorView, graphManagedImport); + const RenderGraphTextureHandle depthTarget = + graphBuilder.ImportTexture("MainDepth", depthDesc, &depthView, graphManagedImport); + + RenderSurface surface(320u, 180u); + surface.SetColorAttachment(&colorView); + surface.SetDepthAttachment(&depthView); + + RenderSurface sourceSurface(320u, 180u); + sourceSurface.SetColorAttachment(&sourceRenderTargetView); + + RenderContext renderContext = {}; + RenderSceneData sceneData = {}; + RenderGraphBlackboard blackboard = {}; + bool executionSucceeded = true; + const RenderPipelineMainSceneRenderGraphContext context = { + graphBuilder, + "MainScene", + renderContext, + sceneData, + surface, + &sourceSurface, + &sourceShaderView, + ResourceStates::Common, + sourceColor, + { colorTarget }, + depthTarget, + &executionSucceeded, + &blackboard + }; + + ASSERT_TRUE(pipeline.RecordMainSceneRenderGraph(context)); + EXPECT_EQ(featureRaw->recordGraphCallCount, 1u); + EXPECT_TRUE(featureRaw->lastReceivedSourceColorTextureValid); + + CompiledRenderGraph compiledGraph = {}; + String errorMessage; + ASSERT_TRUE(RenderGraphCompiler::Compile(graph, compiledGraph, &errorMessage)) + << errorMessage.CStr(); + ASSERT_EQ(compiledGraph.GetPassCount(), 4u); + EXPECT_STREQ(compiledGraph.GetPassName(0).CStr(), "MainScene.BeforeOpaque.SourceAware.0"); + EXPECT_STREQ(compiledGraph.GetPassName(1).CStr(), "MainScene.Opaque"); + EXPECT_STREQ(compiledGraph.GetPassName(2).CStr(), "MainScene.Skybox"); + EXPECT_STREQ(compiledGraph.GetPassName(3).CStr(), "MainScene.Transparent"); + + RenderGraphTextureLifetime sourceLifetime = {}; + ASSERT_TRUE(compiledGraph.TryGetTextureLifetime(sourceColor, sourceLifetime)); + EXPECT_TRUE(sourceLifetime.used); + EXPECT_EQ(sourceLifetime.firstPassIndex, 0u); + EXPECT_EQ(sourceLifetime.lastPassIndex, 0u); +} + TEST(BuiltinForwardPipeline_Test, PropagatesForwardDrawFailureWhenPipelineStateCreationFails) { ShaderLoader loader; LoadResult result = loader.Load(GetBuiltinForwardLitShaderPath()); diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index d5afdc22..7a1e2713 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -3676,6 +3676,7 @@ TEST(ScriptableRenderPipelineHost_Test, ForwardsRendererLifetimeAndFrameRenderin XCEngine::RHI::ResourceStates::Common, {}, {}, + {}, &executionSucceeded, &blackboard }; diff --git a/tests/Rendering/unit/test_render_graph_recording_context.cpp b/tests/Rendering/unit/test_render_graph_recording_context.cpp index b5f0ab58..8e799fb3 100644 --- a/tests/Rendering/unit/test_render_graph_recording_context.cpp +++ b/tests/Rendering/unit/test_render_graph_recording_context.cpp @@ -198,6 +198,7 @@ TEST(RenderGraphRecordingContext_Test, BuildsPipelineMainSceneContextFromSharedR EXPECT_EQ( pipelineContext.sourceColorState, XCEngine::RHI::ResourceStates::PixelShaderResource); + EXPECT_EQ(pipelineContext.sourceColorTexture.index, 3u); ASSERT_EQ(pipelineContext.colorTargets.size(), 2u); EXPECT_EQ(pipelineContext.colorTargets[1].index, 5u); EXPECT_EQ(pipelineContext.depthTarget.index, 6u);