diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index ac07e6fc..bc0bc9e1 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -506,6 +506,7 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraphTypes.h ${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/Graph/RenderGraphCompiler.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Graph/RenderGraphExecutor.h ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Materials/RenderMaterialResolve.h diff --git a/engine/src/Rendering/Internal/RenderGraphRecordingContextBuilders.h b/engine/include/XCEngine/Rendering/Graph/RenderGraphRecordingContext.h similarity index 93% rename from engine/src/Rendering/Internal/RenderGraphRecordingContextBuilders.h rename to engine/include/XCEngine/Rendering/Graph/RenderGraphRecordingContext.h index bd31e8c1..e31d4fbd 100644 --- a/engine/src/Rendering/Internal/RenderGraphRecordingContextBuilders.h +++ b/engine/include/XCEngine/Rendering/Graph/RenderGraphRecordingContext.h @@ -5,9 +5,8 @@ namespace XCEngine { namespace Rendering { -namespace Internal { -struct RenderGraphRecordingContextCommon { +struct RenderGraphRecordingContext { RenderGraphBuilder& graphBuilder; Containers::String passName = {}; const RenderContext& renderContext; @@ -24,7 +23,7 @@ struct RenderGraphRecordingContextCommon { }; inline RenderPassRenderGraphContext BuildRenderPassRenderGraphContext( - const RenderGraphRecordingContextCommon& common, + const RenderGraphRecordingContext& common, RenderPassGraphBeginCallback beginPassCallback = {}, RenderPassGraphEndCallback endPassCallback = {}) { return { @@ -47,7 +46,7 @@ inline RenderPassRenderGraphContext BuildRenderPassRenderGraphContext( } inline SceneRenderFeaturePassRenderGraphContext BuildSceneRenderFeaturePassRenderGraphContext( - const RenderGraphRecordingContextCommon& common, + const RenderGraphRecordingContext& common, bool clearAttachments = false, SceneRenderFeaturePassBeginCallback beginPassCallback = {}, SceneRenderFeaturePassEndCallback endPassCallback = {}) { @@ -72,7 +71,7 @@ inline SceneRenderFeaturePassRenderGraphContext BuildSceneRenderFeaturePassRende } inline RenderPipelineMainSceneRenderGraphContext BuildRenderPipelineMainSceneRenderGraphContext( - const RenderGraphRecordingContextCommon& common) { + const RenderGraphRecordingContext& common) { return { common.graphBuilder, common.passName, @@ -113,6 +112,5 @@ inline SceneRenderFeaturePassRenderGraphContext CloneSceneRenderFeaturePassRende }; } -} // namespace Internal } // namespace Rendering } // namespace XCEngine diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp index 9394cd8e..c7102045 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp @@ -8,7 +8,7 @@ #include "Rendering/Execution/Internal/CameraFrameRenderGraphStageState.h" #include "Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h" #include "Rendering/Graph/RenderGraph.h" -#include "Rendering/Internal/RenderGraphRecordingContextBuilders.h" +#include namespace XCEngine { namespace Rendering { @@ -47,7 +47,7 @@ bool TryRecordCameraFrameStageStandaloneRenderGraphPass( return true; }; - const Internal::RenderGraphRecordingContextCommon commonContext = { + const RenderGraphRecordingContext commonContext = { session.graphBuilder, stageState.stageName, context.plan.request.context, @@ -65,7 +65,7 @@ bool TryRecordCameraFrameStageStandaloneRenderGraphPass( &session.blackboard }; const RenderPassRenderGraphContext standalonePassContext = - Internal::BuildRenderPassRenderGraphContext( + BuildRenderPassRenderGraphContext( commonContext, beginStandalonePass); if (!standaloneStagePass->RecordRenderGraph(standalonePassContext)) { @@ -92,7 +92,7 @@ bool TryRecordCameraFrameMainSceneGraphPass( } handled = true; - const Internal::RenderGraphRecordingContextCommon commonContext = { + const RenderGraphRecordingContext commonContext = { session.graphBuilder, stageState.stageName, context.plan.request.context, @@ -110,7 +110,7 @@ bool TryRecordCameraFrameMainSceneGraphPass( &session.blackboard }; const RenderPipelineMainSceneRenderGraphContext mainSceneContext = - Internal::BuildRenderPipelineMainSceneRenderGraphContext( + BuildRenderPipelineMainSceneRenderGraphContext( commonContext); if (!session.executionState.pipeline->RecordMainSceneRenderGraph(mainSceneContext)) { Debug::Logger::Get().Error( diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp index d2825503..d2312ebc 100644 --- a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp @@ -7,7 +7,7 @@ #include "Rendering/Execution/Internal/CameraFrameRenderGraphStageState.h" #include "Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h" #include "Rendering/Graph/RenderGraph.h" -#include "Rendering/Internal/RenderGraphRecordingContextBuilders.h" +#include #include "Rendering/Internal/RenderPassGraphUtils.h" namespace XCEngine { @@ -104,7 +104,7 @@ bool RecordRegularPassSequenceStage( stageSequence->GetPassCount() == 1u ? stageName : BuildRenderGraphSequencePassName(stageName, passIndex); - const Internal::RenderGraphRecordingContextCommon commonContext = { + const RenderGraphRecordingContext commonContext = { graphBuilder, passName, stagePassContext.renderContext, @@ -120,7 +120,7 @@ bool RecordRegularPassSequenceStage( &blackboard }; const RenderPassRenderGraphContext passContext = - Internal::BuildRenderPassRenderGraphContext( + BuildRenderPassRenderGraphContext( commonContext, beginSequencePass); if (!RecordSequencePass( @@ -209,7 +209,7 @@ bool RecordFullscreenPassSequenceStage( passIndex == 0u ? binding.sourceColorState : RHI::ResourceStates::PixelShaderResource; - const Internal::RenderGraphRecordingContextCommon commonContext = { + const RenderGraphRecordingContext commonContext = { graphBuilder, passName, stagePassContext.renderContext, @@ -225,7 +225,7 @@ bool RecordFullscreenPassSequenceStage( &blackboard }; const RenderPassRenderGraphContext passContext = - Internal::BuildRenderPassRenderGraphContext( + BuildRenderPassRenderGraphContext( commonContext, beginSequencePass); if (!RecordSequencePass( diff --git a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.cpp b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.cpp index 15f9d2f4..7bcac1d0 100644 --- a/engine/src/Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.cpp +++ b/engine/src/Rendering/Pipelines/Internal/BuiltinForwardMainSceneGraphBuilder.cpp @@ -2,8 +2,8 @@ #include "Debug/Logger.h" #include "Rendering/Graph/RenderGraph.h" +#include #include "Rendering/Internal/RenderPassGraphUtils.h" -#include "Rendering/Internal/RenderGraphRecordingContextBuilders.h" #include "Rendering/Pipelines/BuiltinForwardPipeline.h" #include "Rendering/Pipelines/Internal/BuiltinForwardSceneSetup.h" #include "Rendering/RenderSurface.h" @@ -132,7 +132,7 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( [&pipeline](const RenderPassContext& passContext) { pipeline.EndForwardScenePass(passContext); }; - const ::XCEngine::Rendering::Internal::RenderGraphRecordingContextCommon commonContext = { + const ::XCEngine::Rendering::RenderGraphRecordingContext commonContext = { context.graphBuilder, passName, renderContext, @@ -152,7 +152,7 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( for (const ForwardSceneStep& step : GetBuiltinForwardSceneSteps()) { if (step.type == ForwardSceneStepType::InjectionPoint) { const SceneRenderFeaturePassRenderGraphContext featureContext = - ::XCEngine::Rendering::Internal::BuildSceneRenderFeaturePassRenderGraphContext( + ::XCEngine::Rendering::BuildSceneRenderFeaturePassRenderGraphContext( commonContext, clearAttachments, beginRecordedPass, @@ -182,10 +182,10 @@ bool BuiltinForwardMainSceneGraphBuilder::Record( mainDirectionalShadowTexture.IsValid() ? std::vector{ mainDirectionalShadowTexture } : std::vector{}; - ::XCEngine::Rendering::Internal::RenderGraphRecordingContextCommon phaseCommonContext = commonContext; + ::XCEngine::Rendering::RenderGraphRecordingContext phaseCommonContext = commonContext; phaseCommonContext.passName = phasePassName; const RenderPassRenderGraphContext phaseContext = - ::XCEngine::Rendering::Internal::BuildRenderPassRenderGraphContext( + ::XCEngine::Rendering::BuildRenderPassRenderGraphContext( phaseCommonContext, beginPhasePass, endRecordedPass); diff --git a/engine/src/Rendering/SceneRenderFeatureHost.cpp b/engine/src/Rendering/SceneRenderFeatureHost.cpp index 14dd196b..8f7675d8 100644 --- a/engine/src/Rendering/SceneRenderFeatureHost.cpp +++ b/engine/src/Rendering/SceneRenderFeatureHost.cpp @@ -1,7 +1,7 @@ #include "Rendering/SceneRenderFeatureHost.h" #include "Debug/Logger.h" -#include "Rendering/Internal/RenderGraphRecordingContextBuilders.h" +#include #include @@ -120,7 +120,7 @@ bool SceneRenderFeatureHost::Record( } const SceneRenderFeaturePassRenderGraphContext featureContext = - Internal::CloneSceneRenderFeaturePassRenderGraphContext( + CloneSceneRenderFeaturePassRenderGraphContext( context, BuildFeatureGraphPassName( context.passName, diff --git a/tests/Rendering/unit/CMakeLists.txt b/tests/Rendering/unit/CMakeLists.txt index 3a97fc6f..76cd5ddb 100644 --- a/tests/Rendering/unit/CMakeLists.txt +++ b/tests/Rendering/unit/CMakeLists.txt @@ -15,6 +15,7 @@ set(RENDERING_UNIT_TEST_SOURCES test_render_scene_extractor.cpp test_render_resource_cache.cpp test_render_graph.cpp + test_render_graph_recording_context.cpp ) add_executable(rendering_unit_tests ${RENDERING_UNIT_TEST_SOURCES}) diff --git a/tests/Rendering/unit/test_render_graph_recording_context.cpp b/tests/Rendering/unit/test_render_graph_recording_context.cpp new file mode 100644 index 00000000..b5f0ab58 --- /dev/null +++ b/tests/Rendering/unit/test_render_graph_recording_context.cpp @@ -0,0 +1,206 @@ +#include + +#include +#include +#include + +namespace { + +using namespace XCEngine::Rendering; + +RenderGraphRecordingContext BuildCommonContext( + RenderGraphBuilder& builder, + RenderGraphBlackboard& blackboard, + RenderContext& renderContext, + RenderSceneData& sceneData, + RenderSurface& surface, + RenderSurface& sourceSurface, + bool& executionSucceeded) { + return { + builder, + XCEngine::Containers::String("Recording.Pass"), + renderContext, + sceneData, + surface, + &sourceSurface, + reinterpret_cast(0x1234), + XCEngine::RHI::ResourceStates::PixelShaderResource, + { 3u }, + { { 4u }, { 5u } }, + { 6u }, + &executionSucceeded, + &blackboard + }; +} + +RenderPassContext BuildPassContext( + const RenderContext& renderContext, + const RenderSurface& surface, + const RenderSceneData& sceneData, + const RenderSurface& sourceSurface) { + return { + renderContext, + surface, + sceneData, + &sourceSurface, + reinterpret_cast(0x1234), + XCEngine::RHI::ResourceStates::PixelShaderResource + }; +} + +} // namespace + +TEST(RenderGraphRecordingContext_Test, BuildsRenderPassContextFromSharedRecordingData) { + RenderGraph graph = {}; + RenderGraphBuilder builder(graph); + RenderGraphBlackboard blackboard = {}; + RenderContext renderContext = {}; + RenderSceneData sceneData = {}; + RenderSurface surface(1280u, 720u); + surface.SetAutoTransitionEnabled(false); + RenderSurface sourceSurface(640u, 360u); + bool executionSucceeded = true; + const RenderGraphRecordingContext commonContext = + BuildCommonContext( + builder, + blackboard, + renderContext, + sceneData, + surface, + sourceSurface, + executionSucceeded); + + bool beginCalled = false; + bool endCalled = false; + const RenderPassRenderGraphContext passContext = + BuildRenderPassRenderGraphContext( + commonContext, + [&](const RenderPassContext&) { + beginCalled = true; + return true; + }, + [&](const RenderPassContext&) { + endCalled = true; + }); + + EXPECT_EQ(&passContext.graphBuilder, &builder); + EXPECT_EQ(passContext.passName, XCEngine::Containers::String("Recording.Pass")); + EXPECT_EQ(&passContext.renderContext, &renderContext); + EXPECT_EQ(&passContext.sceneData, &sceneData); + EXPECT_EQ(passContext.surface.GetWidth(), 1280u); + EXPECT_EQ(passContext.surface.GetHeight(), 720u); + ASSERT_NE(passContext.sourceSurface, nullptr); + EXPECT_EQ(passContext.sourceSurface->GetWidth(), 640u); + EXPECT_EQ(passContext.sourceColorTexture.index, 3u); + ASSERT_EQ(passContext.colorTargets.size(), 2u); + EXPECT_EQ(passContext.colorTargets[0].index, 4u); + EXPECT_EQ(passContext.depthTarget.index, 6u); + EXPECT_EQ(passContext.executionSucceeded, &executionSucceeded); + EXPECT_EQ(passContext.blackboard, &blackboard); + + const RenderPassContext callbackContext = + BuildPassContext(renderContext, surface, sceneData, sourceSurface); + ASSERT_TRUE(passContext.beginPassCallback); + ASSERT_TRUE(passContext.beginPassCallback(callbackContext)); + ASSERT_TRUE(passContext.endPassCallback); + passContext.endPassCallback(callbackContext); + EXPECT_TRUE(beginCalled); + EXPECT_TRUE(endCalled); +} + +TEST(RenderGraphRecordingContext_Test, BuildsFeaturePassContextAndCloneOverridesOnlyPassMetadata) { + RenderGraph graph = {}; + RenderGraphBuilder builder(graph); + RenderGraphBlackboard blackboard = {}; + RenderContext renderContext = {}; + RenderSceneData sceneData = {}; + RenderSurface surface(960u, 540u); + RenderSurface sourceSurface(320u, 180u); + bool executionSucceeded = true; + const RenderGraphRecordingContext commonContext = + BuildCommonContext( + builder, + blackboard, + renderContext, + sceneData, + surface, + sourceSurface, + executionSucceeded); + + bool beginCalled = false; + bool endCalled = false; + const SceneRenderFeaturePassRenderGraphContext featureContext = + BuildSceneRenderFeaturePassRenderGraphContext( + commonContext, + true, + [&](const RenderPassContext&, bool clearAttachments) { + beginCalled = clearAttachments; + return true; + }, + [&](const RenderPassContext&) { + endCalled = true; + }); + const SceneRenderFeaturePassRenderGraphContext clonedContext = + CloneSceneRenderFeaturePassRenderGraphContext( + featureContext, + XCEngine::Containers::String("Recording.Cloned"), + false); + + EXPECT_EQ(featureContext.passName, XCEngine::Containers::String("Recording.Pass")); + EXPECT_TRUE(featureContext.clearAttachments); + EXPECT_EQ(clonedContext.passName, XCEngine::Containers::String("Recording.Cloned")); + EXPECT_FALSE(clonedContext.clearAttachments); + EXPECT_EQ(clonedContext.sourceColorTexture.index, featureContext.sourceColorTexture.index); + EXPECT_EQ(clonedContext.colorTargets.size(), featureContext.colorTargets.size()); + EXPECT_EQ(clonedContext.blackboard, featureContext.blackboard); + + const RenderPassContext callbackContext = + BuildPassContext(renderContext, surface, sceneData, sourceSurface); + ASSERT_TRUE(clonedContext.beginPassCallback); + ASSERT_TRUE(clonedContext.beginPassCallback(callbackContext, false)); + ASSERT_TRUE(clonedContext.endPassCallback); + clonedContext.endPassCallback(callbackContext); + EXPECT_FALSE(beginCalled); + EXPECT_TRUE(endCalled); +} + +TEST(RenderGraphRecordingContext_Test, BuildsPipelineMainSceneContextFromSharedRecordingData) { + RenderGraph graph = {}; + RenderGraphBuilder builder(graph); + RenderGraphBlackboard blackboard = {}; + RenderContext renderContext = {}; + RenderSceneData sceneData = {}; + RenderSurface surface(800u, 600u); + RenderSurface sourceSurface(400u, 300u); + bool executionSucceeded = false; + const RenderGraphRecordingContext commonContext = + BuildCommonContext( + builder, + blackboard, + renderContext, + sceneData, + surface, + sourceSurface, + executionSucceeded); + + const RenderPipelineMainSceneRenderGraphContext pipelineContext = + BuildRenderPipelineMainSceneRenderGraphContext(commonContext); + + EXPECT_EQ(&pipelineContext.graphBuilder, &builder); + EXPECT_EQ(pipelineContext.passName, XCEngine::Containers::String("Recording.Pass")); + EXPECT_EQ(&pipelineContext.renderContext, &renderContext); + EXPECT_EQ(&pipelineContext.sceneData, &sceneData); + EXPECT_EQ(pipelineContext.surfaceTemplate.GetWidth(), 800u); + EXPECT_EQ(pipelineContext.surfaceTemplate.GetHeight(), 600u); + ASSERT_NE(pipelineContext.sourceSurface, nullptr); + EXPECT_EQ(pipelineContext.sourceSurface->GetWidth(), 400u); + EXPECT_EQ(pipelineContext.sourceColorView, reinterpret_cast(0x1234)); + EXPECT_EQ( + pipelineContext.sourceColorState, + XCEngine::RHI::ResourceStates::PixelShaderResource); + ASSERT_EQ(pipelineContext.colorTargets.size(), 2u); + EXPECT_EQ(pipelineContext.colorTargets[1].index, 5u); + EXPECT_EQ(pipelineContext.depthTarget.index, 6u); + EXPECT_EQ(pipelineContext.executionSucceeded, &executionSucceeded); + EXPECT_EQ(pipelineContext.blackboard, &blackboard); +}