diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index b021f1b6..f7986b8d 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -534,6 +534,8 @@ add_library(XCEngine STATIC ${CMAKE_CURRENT_SOURCE_DIR}/include/XCEngine/Rendering/Features/BuiltinVolumetricPass.h ${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/Execution/Internal/CameraFrameRenderGraphExecution.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphExecution.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.cpp ${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Caches/DirectionalShadowSurfaceCache.cpp diff --git a/engine/src/Rendering/Execution/CameraRenderer.cpp b/engine/src/Rendering/Execution/CameraRenderer.cpp index 715deeb4..dc6d45ee 100644 --- a/engine/src/Rendering/Execution/CameraRenderer.cpp +++ b/engine/src/Rendering/Execution/CameraRenderer.cpp @@ -1,13 +1,8 @@ #include "Rendering/Execution/CameraRenderer.h" #include "Components/CameraComponent.h" -#include "Rendering/Execution/CameraFrameRenderGraphStagePolicy.h" -#include "Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h" #include "Rendering/Execution/DirectionalShadowExecutionState.h" -#include "Rendering/Graph/RenderGraph.h" -#include "Rendering/Graph/RenderGraphCompiler.h" -#include "Rendering/Graph/RenderGraphExecutor.h" -#include "Rendering/Internal/RenderPassGraphUtils.h" +#include "Rendering/Execution/Internal/CameraFrameRenderGraphExecution.h" #include "Rendering/Passes/BuiltinDepthOnlyPass.h" #include "Rendering/Passes/BuiltinObjectIdPass.h" #include "Rendering/Passes/BuiltinShadowCasterPass.h" @@ -59,942 +54,6 @@ Resources::ShaderKeywordSet BuildSceneGlobalShaderKeywords( return keywords; } -bool InitializeStandalonePass( - RenderPass* pass, - const RenderContext& context) { - if (pass == nullptr) { - return false; - } - - if (pass->Initialize(context)) { - return true; - } - - pass->Shutdown(); - return false; -} - -RenderSceneData BuildScenePassRequestSceneData( - const ScenePassRenderRequest& request, - const RenderSurface& requestSurface, - const RenderSceneData& baseSceneData) { - RenderSceneData sceneData = baseSceneData; - if (request.hasCameraDataOverride) { - sceneData.cameraData = request.cameraDataOverride; - } - - sceneData.cameraData.viewportWidth = requestSurface.GetRenderAreaWidth(); - sceneData.cameraData.viewportHeight = requestSurface.GetRenderAreaHeight(); - sceneData.cameraData.clearFlags = request.clearFlags; - if (request.hasClearColorOverride) { - sceneData.cameraData.clearColor = request.clearColorOverride; - } - - return sceneData; -} - -bool ExecuteScenePassRequest( - RenderPass* pass, - const ScenePassRenderRequest& request, - const RenderContext& context, - const RenderSceneData& baseSceneData, - const RenderSurface* surfaceOverride = nullptr) { - if (!request.IsRequested()) { - return true; - } - - if (!InitializeStandalonePass(pass, context)) { - return false; - } - - const RenderSurface& requestSurface = - surfaceOverride != nullptr ? *surfaceOverride : request.surface; - const RenderSceneData sceneData = - BuildScenePassRequestSceneData( - request, - requestSurface, - baseSceneData); - - const RenderPassContext passContext = { - context, - requestSurface, - sceneData, - nullptr, - nullptr, - RHI::ResourceStates::Common - }; - return pass->Execute(passContext); -} - -bool ExecuteStandalonePass( - RenderPass* pass, - const RenderContext& context, - const RenderSurface& surface, - const RenderSceneData& sceneData) { - if (pass == nullptr) { - return false; - } - - if (!InitializeStandalonePass(pass, context)) { - return false; - } - - const RenderPassContext passContext = { - context, - surface, - sceneData, - nullptr, - nullptr, - RHI::ResourceStates::Common - }; - return pass->Execute(passContext); -} - -RenderSceneData BuildStandaloneStageSceneData( - CameraFrameStage stage, - const CameraFramePlan& plan, - const DirectionalShadowExecutionState& shadowState, - const RenderSceneData& baseSceneData, - const RenderSurface& stageSurface) { - if (stage == CameraFrameStage::ShadowCaster && - shadowState.shadowCasterRequest.IsRequested()) { - return BuildScenePassRequestSceneData( - shadowState.shadowCasterRequest, - stageSurface, - baseSceneData); - } - - if (const ScenePassRenderRequest* request = plan.GetScenePassRequest(stage); - request != nullptr) { - return BuildScenePassRequestSceneData( - *request, - stageSurface, - baseSceneData); - } - - return baseSceneData; -} - -class ScopedInitializedPassSequence { -public: - ScopedInitializedPassSequence( - RenderPassSequence* sequence, - const RenderContext& context) - : m_sequence(sequence) { - if (m_sequence == nullptr) { - return; - } - - if (!m_sequence->Initialize(context)) { - m_failed = true; - m_sequence->Shutdown(); - m_sequence = nullptr; - } - } - - ScopedInitializedPassSequence(const ScopedInitializedPassSequence&) = delete; - ScopedInitializedPassSequence& operator=(const ScopedInitializedPassSequence&) = delete; - - ~ScopedInitializedPassSequence() { - // Request-owned pass sequences may record GPU work that executes only after the - // caller closes/submits the command list. Do not destroy sequence-owned GPU - // resources here; the sequence owner must shut them down explicitly when the - // sequence is no longer needed. - } - - bool IsReady() const { - return !m_failed; - } - -private: - RenderPassSequence* m_sequence = nullptr; - bool m_failed = false; -}; - -bool EnsureInitializedPassSequence( - std::unique_ptr& activeSequence, - RenderPassSequence* sequence, - const RenderContext& context) { - if (activeSequence == nullptr) { - activeSequence = std::make_unique(sequence, context); - } - - return activeSequence->IsReady(); -} - -struct CameraFrameExecutionState { - RenderPipeline* pipeline = nullptr; - RenderPass* objectIdPass = nullptr; - RenderPass* depthOnlyPass = nullptr; - RenderPass* shadowCasterPass = nullptr; - std::unique_ptr preScenePasses; - std::unique_ptr postProcessPasses; - std::unique_ptr finalOutputPasses; - std::unique_ptr postScenePasses; - std::unique_ptr overlayPasses; -}; - -RenderPass* ResolveStandaloneStagePass( - CameraFrameStage stage, - CameraFrameExecutionState& executionState) { - switch (stage) { - case CameraFrameStage::ShadowCaster: - return executionState.shadowCasterPass; - case CameraFrameStage::DepthOnly: - return executionState.depthOnlyPass; - case CameraFrameStage::ObjectId: - return executionState.objectIdPass; - default: - return nullptr; - } -} - -std::unique_ptr* ResolveStageSequenceState( - CameraFrameStage stage, - CameraFrameExecutionState& executionState) { - switch (stage) { - case CameraFrameStage::PreScenePasses: - return &executionState.preScenePasses; - case CameraFrameStage::PostProcess: - return &executionState.postProcessPasses; - case CameraFrameStage::FinalOutput: - return &executionState.finalOutputPasses; - case CameraFrameStage::PostScenePasses: - return &executionState.postScenePasses; - case CameraFrameStage::OverlayPasses: - return &executionState.overlayPasses; - default: - return nullptr; - } -} - -bool RecordSequencePass( - RenderPass& pass, - const RenderPassRenderGraphContext& context, - const Internal::RenderPassGraphIO& io) { - return pass.SupportsRenderGraph() - ? pass.RecordRenderGraph(context) - : Internal::RecordRasterRenderPass(pass, context, io); -} - -const RenderSurface* ResolveFrameStageOutputSurface( - CameraFrameStage stage, - const CameraFramePlan& plan, - const DirectionalShadowExecutionState& shadowState) { - switch (stage) { - case CameraFrameStage::ShadowCaster: - return shadowState.shadowCasterRequest.IsRequested() - ? &shadowState.shadowCasterRequest.surface - : nullptr; - case CameraFrameStage::DepthOnly: - return plan.request.depthOnly.IsRequested() - ? &plan.request.depthOnly.surface - : nullptr; - case CameraFrameStage::ObjectId: - return plan.request.objectId.IsRequested() - ? &plan.request.objectId.surface - : nullptr; - default: - return plan.GetOutputSurface(stage); - } -} - -RenderPassContext BuildFrameStagePassContext( - CameraFrameStage stage, - const CameraFramePlan& plan, - const DirectionalShadowExecutionState& shadowState, - const RenderSceneData& sceneData) { - const RenderSurface* outputSurface = - ResolveFrameStageOutputSurface(stage, plan, shadowState); - return { - plan.request.context, - outputSurface != nullptr ? *outputSurface : plan.request.surface, - sceneData, - plan.GetSourceSurface(stage), - plan.GetSourceColorView(stage), - plan.GetSourceColorState(stage) - }; -} - -bool ExecuteRecordedFrameStage( - CameraFrameStage stage, - const CameraFramePlan& plan, - const DirectionalShadowExecutionState& shadowState, - const RenderSceneData& sceneData, - CameraFrameExecutionState& executionState, - const RenderPassContext& passContext) { - switch (stage) { - case CameraFrameStage::ShadowCaster: - return ExecuteScenePassRequest( - executionState.shadowCasterPass, - shadowState.shadowCasterRequest, - plan.request.context, - sceneData, - &passContext.surface); - case CameraFrameStage::DepthOnly: - return ExecuteScenePassRequest( - executionState.depthOnlyPass, - plan.request.depthOnly, - plan.request.context, - sceneData, - &passContext.surface); - case CameraFrameStage::MainScene: - return executionState.pipeline != nullptr && - executionState.pipeline->Render( - FrameExecutionContext( - plan.request.context, - passContext.surface, - sceneData, - passContext.sourceSurface, - passContext.sourceColorView, - passContext.sourceColorState)); - case CameraFrameStage::ObjectId: - return !plan.request.objectId.IsRequested() || - ExecuteStandalonePass( - executionState.objectIdPass, - plan.request.context, - passContext.surface, - sceneData); - default: - return false; - } -} - -bool RecordRegularPassSequenceStage( - CameraFrameStage stage, - const Containers::String& stageName, - const RenderPassContext& stagePassContext, - const RenderGraphImportedSurface& outputSurface, - const RenderSceneData& sceneData, - RenderPassSequence* stageSequence, - CameraFrameExecutionState& executionState, - RenderGraphBuilder& graphBuilder, - RenderGraphBlackboard& blackboard, - bool& stageExecutionSucceeded) { - if (stageSequence == nullptr || stageSequence->GetPassCount() == 0u) { - return true; - } - - std::unique_ptr* const activeSequence = - ResolveStageSequenceState(stage, executionState); - RenderPassSequence* const sequence = stageSequence; - const RenderContext* const renderContext = &stagePassContext.renderContext; - const RenderPassGraphBeginCallback beginSequencePass = - [&, activeSequence, sequence, renderContext](const RenderPassContext&) -> bool { - if (activeSequence == nullptr || - !EnsureInitializedPassSequence( - *activeSequence, - sequence, - *renderContext)) { - stageExecutionSucceeded = false; - return false; - } - - return true; - }; - const bool writesColor = GetPrimaryColorTexture(outputSurface).IsValid(); - const bool writesDepth = outputSurface.depthTexture.IsValid(); - - for (size_t passIndex = 0u; passIndex < stageSequence->GetPassCount(); ++passIndex) { - RenderPass* const pass = stageSequence->GetPass(passIndex); - if (pass == nullptr) { - continue; - } - - const Containers::String passName = - stageSequence->GetPassCount() == 1u - ? stageName - : BuildRenderGraphSequencePassName(stageName, passIndex); - const RenderPassRenderGraphContext passContext = { - graphBuilder, - passName, - stagePassContext.renderContext, - sceneData, - stagePassContext.surface, - stagePassContext.sourceSurface, - stagePassContext.sourceColorView, - stagePassContext.sourceColorState, - {}, - outputSurface.colorTextures, - outputSurface.depthTexture, - &stageExecutionSucceeded, - beginSequencePass, - {}, - &blackboard - }; - if (!RecordSequencePass( - *pass, - passContext, - { - false, - writesColor, - writesDepth - })) { - return false; - } - } - - return true; -} - -bool RecordFullscreenPassSequenceStage( - CameraFrameStage stage, - const Containers::String& stageName, - const RenderPassContext& stagePassContext, - const CameraFrameRenderGraphSourceBinding& binding, - RenderGraphTextureHandle finalOutputColor, - const RenderSceneData& sceneData, - RenderPassSequence* stageSequence, - CameraFrameExecutionState& executionState, - RenderGraphBuilder& graphBuilder, - RenderGraphBlackboard& blackboard, - bool& stageExecutionSucceeded) { - if (stageSequence == nullptr || stageSequence->GetPassCount() == 0u) { - return true; - } - - std::unique_ptr* const activeSequence = - ResolveStageSequenceState(stage, executionState); - RenderPassSequence* const sequence = stageSequence; - const RenderContext* const renderContext = &stagePassContext.renderContext; - const RenderPassGraphBeginCallback beginSequencePass = - [&, activeSequence, sequence, renderContext](const RenderPassContext&) -> bool { - if (activeSequence == nullptr || - !EnsureInitializedPassSequence( - *activeSequence, - sequence, - *renderContext)) { - stageExecutionSucceeded = false; - return false; - } - - return true; - }; - - RenderGraphTextureHandle currentSourceColor = binding.sourceColor; - const RenderGraphTextureDesc transientDesc = - BuildFullscreenTransientTextureDesc(stagePassContext.surface); - - for (size_t passIndex = 0u; passIndex < stageSequence->GetPassCount(); ++passIndex) { - RenderPass* const pass = stageSequence->GetPass(passIndex); - if (pass == nullptr) { - continue; - } - - const bool isLastPass = (passIndex + 1u) == stageSequence->GetPassCount(); - const Containers::String passName = - stageSequence->GetPassCount() == 1u - ? stageName - : BuildRenderGraphSequencePassName(stageName, passIndex); - const RenderGraphTextureHandle passOutputColor = - isLastPass - ? finalOutputColor - : graphBuilder.CreateTransientTexture( - passName + ".Color", - transientDesc); - const RenderSurface* const sourceSurfaceTemplate = - passIndex == 0u - ? binding.sourceSurfaceTemplate - : &stagePassContext.surface; - RHI::RHIResourceView* const sourceColorView = - passIndex == 0u - ? binding.sourceColorView - : nullptr; - const RHI::ResourceStates sourceColorState = - passIndex == 0u - ? binding.sourceColorState - : RHI::ResourceStates::PixelShaderResource; - const RenderPassRenderGraphContext passContext = { - graphBuilder, - passName, - stagePassContext.renderContext, - sceneData, - stagePassContext.surface, - sourceSurfaceTemplate, - sourceColorView, - sourceColorState, - currentSourceColor, - std::vector{ passOutputColor }, - {}, - &stageExecutionSucceeded, - beginSequencePass, - {}, - &blackboard - }; - if (!RecordSequencePass( - *pass, - passContext, - { - true, - true, - false - })) { - return false; - } - - currentSourceColor = passOutputColor; - } - - return true; -} - -struct CameraFrameStageGraphBuildState { - CameraFrameStage stage = CameraFrameStage::MainScene; - Containers::String stageName = {}; - RenderPassSequence* stageSequence = nullptr; - RenderSurface surfaceTemplate = {}; - bool hasSourceSurface = false; - RenderSurface sourceSurfaceTemplate = {}; - RHI::RHIResourceView* sourceColorView = nullptr; - RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common; - RenderGraphImportedSurface sourceSurface = {}; - RenderGraphImportedSurface outputSurface = {}; - RenderGraphTextureHandle outputColor = {}; -}; - -RenderPassContext BuildCameraFrameStageGraphPassContext( - const CameraFramePlan& plan, - const CameraFrameStageGraphBuildState& stageState, - const RenderSceneData& sceneData) { - return { - plan.request.context, - stageState.surfaceTemplate, - sceneData, - stageState.hasSourceSurface - ? &stageState.sourceSurfaceTemplate - : nullptr, - stageState.sourceColorView, - stageState.sourceColorState - }; -} - -CameraFrameStageGraphBuildState BuildCameraFrameStageGraphBuildState( - CameraFrameStage stage, - const CameraFramePlan& plan, - const DirectionalShadowExecutionState& shadowState, - const RenderSceneData& sceneData, - RenderGraphBuilder& graphBuilder, - RenderGraphImportedTextureRegistry& importedTextures) { - CameraFrameStageGraphBuildState stageState = {}; - stageState.stage = stage; - stageState.stageName = Containers::String(GetCameraFrameStageName(stage)); - stageState.stageSequence = plan.GetPassSequence(stage); - - const RenderPassContext stagePassContext = - BuildFrameStagePassContext(stage, plan, shadowState, sceneData); - stageState.surfaceTemplate = stagePassContext.surface; - stageState.hasSourceSurface = stagePassContext.sourceSurface != nullptr; - if (stageState.hasSourceSurface) { - stageState.sourceSurfaceTemplate = *stagePassContext.sourceSurface; - } - stageState.sourceColorView = stagePassContext.sourceColorView; - stageState.sourceColorState = stagePassContext.sourceColorState; - stageState.sourceSurface = - ImportRenderGraphSurface( - graphBuilder, - importedTextures, - stageState.stageName + ".Source", - stagePassContext.sourceSurface, - RenderGraphSurfaceImportUsage::Source, - IsCameraFrameFullscreenSequenceStage(stage)); - stageState.outputSurface = - ImportRenderGraphSurface( - graphBuilder, - importedTextures, - stageState.stageName + ".Output", - &stagePassContext.surface, - RenderGraphSurfaceImportUsage::Output, - DoesCameraFrameStageGraphOwnColorTransitions(stage), - DoesCameraFrameStageGraphOwnDepthTransitions(stage)); - stageState.outputColor = - ResolveStageOutputColorHandle( - stage, - plan, - stageState.stageName, - stagePassContext, - stageState.outputSurface, - graphBuilder); - return stageState; -} - -void PublishCameraFrameStageGraphBuildState( - const CameraFrameStageGraphBuildState& stageState, - const DirectionalShadowExecutionState& shadowState, - CameraFrameRenderGraphResources& frameResources) { - if (stageState.stage == CameraFrameStage::ShadowCaster && - shadowState.HasShadowSampling() && - stageState.outputSurface.depthTexture.IsValid()) { - frameResources.mainDirectionalShadow = stageState.outputSurface.depthTexture; - } - - WriteCameraFrameRenderGraphStageSurfaceResources( - frameResources, - stageState.stage, - stageState.outputColor, - stageState.outputSurface.depthTexture); -} - -bool TryRecordCameraFrameStageSequence( - const CameraFrameStageGraphBuildState& stageState, - const CameraFramePlan& plan, - const RenderSceneData& sceneData, - CameraFrameExecutionState& executionState, - RenderGraphBuilder& graphBuilder, - RenderGraphBlackboard& blackboard, - bool& stageExecutionSucceeded, - bool& handled) { - if (stageState.stageSequence == nullptr) { - handled = false; - return true; - } - - handled = true; - const RenderPassContext stagePassContext = - BuildCameraFrameStageGraphPassContext(plan, stageState, sceneData); - const bool recordResult = - IsCameraFrameFullscreenSequenceStage(stageState.stage) - ? RecordFullscreenPassSequenceStage( - stageState.stage, - stageState.stageName, - stagePassContext, - ResolveCameraFrameFullscreenStageGraphSourceBinding( - plan, - stageState.stage, - stageState.surfaceTemplate, - stagePassContext.sourceSurface, - stagePassContext.sourceColorView, - stagePassContext.sourceColorState, - GetPrimaryColorTexture(stageState.sourceSurface), - &blackboard), - stageState.outputColor, - sceneData, - stageState.stageSequence, - executionState, - graphBuilder, - blackboard, - stageExecutionSucceeded) - : RecordRegularPassSequenceStage( - stageState.stage, - stageState.stageName, - stagePassContext, - stageState.outputSurface, - sceneData, - stageState.stageSequence, - executionState, - graphBuilder, - blackboard, - stageExecutionSucceeded); - if (!recordResult) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - Containers::String("CameraRenderer::Render failed: pass-sequence graph recording returned false for ") + - stageState.stageName); - return false; - } - - return true; -} - -bool TryRecordCameraFrameStageStandaloneRenderGraphPass( - const CameraFrameStageGraphBuildState& stageState, - const CameraFramePlan& plan, - const DirectionalShadowExecutionState& shadowState, - const RenderSceneData& sceneData, - CameraFrameExecutionState& executionState, - RenderGraphBuilder& graphBuilder, - RenderGraphBlackboard& blackboard, - bool& stageExecutionSucceeded, - bool& handled) { - RenderPass* const standaloneStagePass = - ResolveStandaloneStagePass(stageState.stage, executionState); - if (standaloneStagePass == nullptr || - !standaloneStagePass->SupportsRenderGraph()) { - handled = false; - return true; - } - - handled = true; - const RenderSceneData stageSceneData = - BuildStandaloneStageSceneData( - stageState.stage, - plan, - shadowState, - sceneData, - stageState.surfaceTemplate); - const RenderPassGraphBeginCallback beginStandalonePass = - [&, standaloneStagePass](const RenderPassContext&) -> bool { - if (!InitializeStandalonePass( - standaloneStagePass, - plan.request.context)) { - stageExecutionSucceeded = false; - return false; - } - - return true; - }; - const RenderPassRenderGraphContext standalonePassContext = { - graphBuilder, - stageState.stageName, - plan.request.context, - stageSceneData, - stageState.surfaceTemplate, - stageState.hasSourceSurface - ? &stageState.sourceSurfaceTemplate - : nullptr, - stageState.sourceColorView, - stageState.sourceColorState, - GetPrimaryColorTexture(stageState.sourceSurface), - std::vector{ stageState.outputColor }, - stageState.outputSurface.depthTexture, - &stageExecutionSucceeded, - beginStandalonePass, - {}, - &blackboard - }; - if (!standaloneStagePass->RecordRenderGraph(standalonePassContext)) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - Containers::String("CameraRenderer::Render failed: RenderPass::RecordRenderGraph returned false for ") + - stageState.stageName); - return false; - } - - return true; -} - -bool TryRecordCameraFrameMainSceneGraphPass( - const CameraFrameStageGraphBuildState& stageState, - const CameraFramePlan& plan, - const RenderSceneData& sceneData, - CameraFrameExecutionState& executionState, - RenderGraphBuilder& graphBuilder, - RenderGraphBlackboard& blackboard, - bool& stageExecutionSucceeded, - bool& handled) { - if (stageState.stage != CameraFrameStage::MainScene || - executionState.pipeline == nullptr || - !executionState.pipeline->SupportsMainSceneRenderGraph()) { - handled = false; - return true; - } - - handled = true; - const RenderPipelineMainSceneRenderGraphContext mainSceneContext = { - graphBuilder, - stageState.stageName, - plan.request.context, - sceneData, - stageState.surfaceTemplate, - stageState.hasSourceSurface - ? &stageState.sourceSurfaceTemplate - : nullptr, - stageState.sourceColorView, - stageState.sourceColorState, - std::vector{ stageState.outputColor }, - stageState.outputSurface.depthTexture, - &stageExecutionSucceeded, - &blackboard - }; - if (!executionState.pipeline->RecordMainSceneRenderGraph(mainSceneContext)) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - "CameraRenderer::Render failed: RenderPipeline::RecordMainSceneRenderGraph returned false"); - return false; - } - - return true; -} - -void AddCameraFrameStageFallbackRasterPass( - const CameraFrameStageGraphBuildState& stageState, - const CameraFramePlan& plan, - const DirectionalShadowExecutionState& shadowState, - const RenderSceneData& sceneData, - CameraFrameExecutionState& executionState, - RenderGraphBuilder& graphBuilder, - bool& stageExecutionSucceeded) { - const CameraFrameStageGraphBuildState capturedStageState = stageState; - graphBuilder.AddRasterPass( - capturedStageState.stageName, - [&, capturedStageState](RenderGraphPassBuilder& passBuilder) { - if (IsCameraFrameFullscreenSequenceStage(capturedStageState.stage)) { - ReadRenderGraphColorSurface(passBuilder, capturedStageState.sourceSurface); - WriteRenderGraphColorSurface(passBuilder, capturedStageState.outputSurface); - } else { - ReadRenderGraphSurface(passBuilder, capturedStageState.sourceSurface); - WriteRenderGraphSurface(passBuilder, capturedStageState.outputSurface); - } - passBuilder.SetExecuteCallback( - [&, capturedStageState]( - const RenderGraphExecutionContext& executionContext) { - if (!stageExecutionSucceeded) { - return; - } - - const RenderSurface* resolvedSourceSurface = - capturedStageState.hasSourceSurface - ? &capturedStageState.sourceSurfaceTemplate - : nullptr; - RHI::RHIResourceView* resolvedSourceColorView = - capturedStageState.sourceColorView; - RHI::ResourceStates resolvedSourceColorState = - capturedStageState.sourceColorState; - RenderSurface graphManagedSourceSurface = {}; - if (IsCameraFrameFullscreenSequenceStage(capturedStageState.stage) && - capturedStageState.hasSourceSurface && - CanUseGraphManagedImportedSurface( - capturedStageState.sourceSurface, - executionContext)) { - graphManagedSourceSurface = - BuildGraphManagedImportedSurface( - capturedStageState.sourceSurfaceTemplate, - RHI::ResourceStates::PixelShaderResource, - RHI::ResourceStates::PixelShaderResource); - resolvedSourceSurface = &graphManagedSourceSurface; - resolvedSourceColorState = RHI::ResourceStates::PixelShaderResource; - } - - const RenderSurface* resolvedOutputSurface = - &capturedStageState.surfaceTemplate; - RenderSurface graphManagedOutputSurface = {}; - if (CanUseGraphManagedImportedSurface( - capturedStageState.outputSurface, - executionContext)) { - graphManagedOutputSurface = - BuildGraphManagedPassSurface( - capturedStageState.surfaceTemplate); - resolvedOutputSurface = &graphManagedOutputSurface; - } - - const RenderPassContext passContextOverride = { - plan.request.context, - *resolvedOutputSurface, - sceneData, - resolvedSourceSurface, - resolvedSourceColorView, - resolvedSourceColorState - }; - stageExecutionSucceeded = ExecuteRecordedFrameStage( - capturedStageState.stage, - plan, - shadowState, - sceneData, - executionState, - passContextOverride); - }); - }); -} - -bool ExecuteRenderGraphPlan( - const CameraFramePlan& plan, - const DirectionalShadowExecutionState& shadowState, - const RenderSceneData& sceneData, - CameraFrameExecutionState& executionState) { - RenderGraph graph = {}; - RenderGraphBuilder graphBuilder(graph); - RenderGraphBlackboard blackboard = {}; - RenderGraphImportedTextureRegistry importedTextures = {}; - CameraFrameRenderGraphResources& frameResources = - blackboard.Emplace(); - - bool stageExecutionSucceeded = true; - for (const CameraFrameStageInfo& stageInfo : kOrderedCameraFrameStages) { - if (!plan.HasFrameStage(stageInfo.stage) && - stageInfo.stage != CameraFrameStage::MainScene) { - continue; - } - - const CameraFrameStageGraphBuildState stageState = - BuildCameraFrameStageGraphBuildState( - stageInfo.stage, - plan, - shadowState, - sceneData, - graphBuilder, - importedTextures); - PublishCameraFrameStageGraphBuildState( - stageState, - shadowState, - frameResources); - - bool stageHandled = false; - if (!TryRecordCameraFrameStageSequence( - stageState, - plan, - sceneData, - executionState, - graphBuilder, - blackboard, - stageExecutionSucceeded, - stageHandled)) { - return false; - } - if (stageHandled) { - continue; - } - - if (!TryRecordCameraFrameStageStandaloneRenderGraphPass( - stageState, - plan, - shadowState, - sceneData, - executionState, - graphBuilder, - blackboard, - stageExecutionSucceeded, - stageHandled)) { - return false; - } - if (stageHandled) { - continue; - } - - if (!TryRecordCameraFrameMainSceneGraphPass( - stageState, - plan, - sceneData, - executionState, - graphBuilder, - blackboard, - stageExecutionSucceeded, - stageHandled)) { - return false; - } - if (stageHandled) { - continue; - } - - AddCameraFrameStageFallbackRasterPass( - stageState, - plan, - shadowState, - sceneData, - executionState, - graphBuilder, - stageExecutionSucceeded); - } - - CompiledRenderGraph compiledGraph = {}; - Containers::String errorMessage; - if (!RenderGraphCompiler::Compile(graph, compiledGraph, &errorMessage)) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - Containers::String("CameraRenderer::Render failed: RenderGraph compile failed: ") + - errorMessage); - return false; - } - - if (!RenderGraphExecutor::Execute(compiledGraph, plan.request.context, &errorMessage)) { - Debug::Logger::Get().Error( - Debug::LogCategory::Rendering, - Containers::String("CameraRenderer::Render failed: RenderGraph execute failed: ") + - errorMessage); - return false; - } - - return stageExecutionSucceeded; -} - RenderEnvironmentData BuildEnvironmentData(const CameraFramePlan& plan) { RenderEnvironmentData environment = {}; const RenderSurface& mainSceneSurface = plan.GetMainSceneSurface(); @@ -1164,12 +223,14 @@ bool CameraRenderer::ExecuteRenderPlan( const CameraFramePlan& plan, const DirectionalShadowExecutionState& shadowState, const RenderSceneData& sceneData) { - CameraFrameExecutionState executionState = {}; - executionState.pipeline = m_pipeline.get(); - executionState.objectIdPass = m_objectIdPass.get(); - executionState.depthOnlyPass = m_depthOnlyPass.get(); - executionState.shadowCasterPass = m_shadowCasterPass.get(); - return ExecuteRenderGraphPlan(plan, shadowState, sceneData, executionState); + return ExecuteCameraFrameRenderGraphPlan( + plan, + shadowState, + sceneData, + m_pipeline.get(), + m_objectIdPass.get(), + m_depthOnlyPass.get(), + m_shadowCasterPass.get()); } bool CameraRenderer::Render( @@ -1254,3 +315,4 @@ bool CameraRenderer::Render( } // namespace Rendering } // namespace XCEngine + diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphExecution.cpp b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphExecution.cpp new file mode 100644 index 00000000..c3271116 --- /dev/null +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphExecution.cpp @@ -0,0 +1,972 @@ +#include "Rendering/Execution/Internal/CameraFrameRenderGraphExecution.h" + +#include "Debug/Logger.h" +#include "Rendering/Execution/CameraFrameRenderGraphStagePolicy.h" +#include "Rendering/Execution/DirectionalShadowExecutionState.h" +#include "Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h" +#include "Rendering/Graph/RenderGraph.h" +#include "Rendering/Graph/RenderGraphCompiler.h" +#include "Rendering/Graph/RenderGraphExecutor.h" +#include "Rendering/Internal/RenderPassGraphUtils.h" + +namespace XCEngine { +namespace Rendering { + +namespace { + +bool InitializeStandalonePass( + RenderPass* pass, + const RenderContext& context) { + if (pass == nullptr) { + return false; + } + + if (pass->Initialize(context)) { + return true; + } + + pass->Shutdown(); + return false; +} + +RenderSceneData BuildScenePassRequestSceneData( + const ScenePassRenderRequest& request, + const RenderSurface& requestSurface, + const RenderSceneData& baseSceneData) { + RenderSceneData sceneData = baseSceneData; + if (request.hasCameraDataOverride) { + sceneData.cameraData = request.cameraDataOverride; + } + + sceneData.cameraData.viewportWidth = requestSurface.GetRenderAreaWidth(); + sceneData.cameraData.viewportHeight = requestSurface.GetRenderAreaHeight(); + sceneData.cameraData.clearFlags = request.clearFlags; + if (request.hasClearColorOverride) { + sceneData.cameraData.clearColor = request.clearColorOverride; + } + + return sceneData; +} + +bool ExecuteScenePassRequest( + RenderPass* pass, + const ScenePassRenderRequest& request, + const RenderContext& context, + const RenderSceneData& baseSceneData, + const RenderSurface* surfaceOverride = nullptr) { + if (!request.IsRequested()) { + return true; + } + + if (!InitializeStandalonePass(pass, context)) { + return false; + } + + const RenderSurface& requestSurface = + surfaceOverride != nullptr ? *surfaceOverride : request.surface; + const RenderSceneData sceneData = + BuildScenePassRequestSceneData( + request, + requestSurface, + baseSceneData); + + const RenderPassContext passContext = { + context, + requestSurface, + sceneData, + nullptr, + nullptr, + RHI::ResourceStates::Common + }; + return pass->Execute(passContext); +} + +bool ExecuteStandalonePass( + RenderPass* pass, + const RenderContext& context, + const RenderSurface& surface, + const RenderSceneData& sceneData) { + if (pass == nullptr) { + return false; + } + + if (!InitializeStandalonePass(pass, context)) { + return false; + } + + const RenderPassContext passContext = { + context, + surface, + sceneData, + nullptr, + nullptr, + RHI::ResourceStates::Common + }; + return pass->Execute(passContext); +} + +RenderSceneData BuildStandaloneStageSceneData( + CameraFrameStage stage, + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& baseSceneData, + const RenderSurface& stageSurface) { + if (stage == CameraFrameStage::ShadowCaster && + shadowState.shadowCasterRequest.IsRequested()) { + return BuildScenePassRequestSceneData( + shadowState.shadowCasterRequest, + stageSurface, + baseSceneData); + } + + if (const ScenePassRenderRequest* request = plan.GetScenePassRequest(stage); + request != nullptr) { + return BuildScenePassRequestSceneData( + *request, + stageSurface, + baseSceneData); + } + + return baseSceneData; +} + +class ScopedInitializedPassSequence { +public: + ScopedInitializedPassSequence( + RenderPassSequence* sequence, + const RenderContext& context) + : m_sequence(sequence) { + if (m_sequence == nullptr) { + return; + } + + if (!m_sequence->Initialize(context)) { + m_failed = true; + m_sequence->Shutdown(); + m_sequence = nullptr; + } + } + + ScopedInitializedPassSequence(const ScopedInitializedPassSequence&) = delete; + ScopedInitializedPassSequence& operator=(const ScopedInitializedPassSequence&) = delete; + + ~ScopedInitializedPassSequence() { + // Request-owned pass sequences may record GPU work that executes only after the + // caller closes/submits the command list. Do not destroy sequence-owned GPU + // resources here; the sequence owner must shut them down explicitly when the + // sequence is no longer needed. + } + + bool IsReady() const { + return !m_failed; + } + +private: + RenderPassSequence* m_sequence = nullptr; + bool m_failed = false; +}; + +bool EnsureInitializedPassSequence( + std::unique_ptr& activeSequence, + RenderPassSequence* sequence, + const RenderContext& context) { + if (activeSequence == nullptr) { + activeSequence = std::make_unique(sequence, context); + } + + return activeSequence->IsReady(); +} + +struct CameraFrameExecutionState { + RenderPipeline* pipeline = nullptr; + RenderPass* objectIdPass = nullptr; + RenderPass* depthOnlyPass = nullptr; + RenderPass* shadowCasterPass = nullptr; + std::unique_ptr preScenePasses; + std::unique_ptr postProcessPasses; + std::unique_ptr finalOutputPasses; + std::unique_ptr postScenePasses; + std::unique_ptr overlayPasses; +}; + +RenderPass* ResolveStandaloneStagePass( + CameraFrameStage stage, + CameraFrameExecutionState& executionState) { + switch (stage) { + case CameraFrameStage::ShadowCaster: + return executionState.shadowCasterPass; + case CameraFrameStage::DepthOnly: + return executionState.depthOnlyPass; + case CameraFrameStage::ObjectId: + return executionState.objectIdPass; + default: + return nullptr; + } +} + +std::unique_ptr* ResolveStageSequenceState( + CameraFrameStage stage, + CameraFrameExecutionState& executionState) { + switch (stage) { + case CameraFrameStage::PreScenePasses: + return &executionState.preScenePasses; + case CameraFrameStage::PostProcess: + return &executionState.postProcessPasses; + case CameraFrameStage::FinalOutput: + return &executionState.finalOutputPasses; + case CameraFrameStage::PostScenePasses: + return &executionState.postScenePasses; + case CameraFrameStage::OverlayPasses: + return &executionState.overlayPasses; + default: + return nullptr; + } +} + +bool RecordSequencePass( + RenderPass& pass, + const RenderPassRenderGraphContext& context, + const Internal::RenderPassGraphIO& io) { + return pass.SupportsRenderGraph() + ? pass.RecordRenderGraph(context) + : Internal::RecordRasterRenderPass(pass, context, io); +} + +const RenderSurface* ResolveFrameStageOutputSurface( + CameraFrameStage stage, + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState) { + switch (stage) { + case CameraFrameStage::ShadowCaster: + return shadowState.shadowCasterRequest.IsRequested() + ? &shadowState.shadowCasterRequest.surface + : nullptr; + case CameraFrameStage::DepthOnly: + return plan.request.depthOnly.IsRequested() + ? &plan.request.depthOnly.surface + : nullptr; + case CameraFrameStage::ObjectId: + return plan.request.objectId.IsRequested() + ? &plan.request.objectId.surface + : nullptr; + default: + return plan.GetOutputSurface(stage); + } +} + +RenderPassContext BuildFrameStagePassContext( + CameraFrameStage stage, + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& sceneData) { + const RenderSurface* outputSurface = + ResolveFrameStageOutputSurface(stage, plan, shadowState); + return { + plan.request.context, + outputSurface != nullptr ? *outputSurface : plan.request.surface, + sceneData, + plan.GetSourceSurface(stage), + plan.GetSourceColorView(stage), + plan.GetSourceColorState(stage) + }; +} + +bool ExecuteRecordedFrameStage( + CameraFrameStage stage, + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& sceneData, + CameraFrameExecutionState& executionState, + const RenderPassContext& passContext) { + switch (stage) { + case CameraFrameStage::ShadowCaster: + return ExecuteScenePassRequest( + executionState.shadowCasterPass, + shadowState.shadowCasterRequest, + plan.request.context, + sceneData, + &passContext.surface); + case CameraFrameStage::DepthOnly: + return ExecuteScenePassRequest( + executionState.depthOnlyPass, + plan.request.depthOnly, + plan.request.context, + sceneData, + &passContext.surface); + case CameraFrameStage::MainScene: + return executionState.pipeline != nullptr && + executionState.pipeline->Render( + FrameExecutionContext( + plan.request.context, + passContext.surface, + sceneData, + passContext.sourceSurface, + passContext.sourceColorView, + passContext.sourceColorState)); + case CameraFrameStage::ObjectId: + return !plan.request.objectId.IsRequested() || + ExecuteStandalonePass( + executionState.objectIdPass, + plan.request.context, + passContext.surface, + sceneData); + default: + return false; + } +} + +bool RecordRegularPassSequenceStage( + CameraFrameStage stage, + const Containers::String& stageName, + const RenderPassContext& stagePassContext, + const RenderGraphImportedSurface& outputSurface, + const RenderSceneData& sceneData, + RenderPassSequence* stageSequence, + CameraFrameExecutionState& executionState, + RenderGraphBuilder& graphBuilder, + RenderGraphBlackboard& blackboard, + bool& stageExecutionSucceeded) { + if (stageSequence == nullptr || stageSequence->GetPassCount() == 0u) { + return true; + } + + std::unique_ptr* const activeSequence = + ResolveStageSequenceState(stage, executionState); + RenderPassSequence* const sequence = stageSequence; + const RenderContext* const renderContext = &stagePassContext.renderContext; + const RenderPassGraphBeginCallback beginSequencePass = + [&, activeSequence, sequence, renderContext](const RenderPassContext&) -> bool { + if (activeSequence == nullptr || + !EnsureInitializedPassSequence( + *activeSequence, + sequence, + *renderContext)) { + stageExecutionSucceeded = false; + return false; + } + + return true; + }; + const bool writesColor = GetPrimaryColorTexture(outputSurface).IsValid(); + const bool writesDepth = outputSurface.depthTexture.IsValid(); + + for (size_t passIndex = 0u; passIndex < stageSequence->GetPassCount(); ++passIndex) { + RenderPass* const pass = stageSequence->GetPass(passIndex); + if (pass == nullptr) { + continue; + } + + const Containers::String passName = + stageSequence->GetPassCount() == 1u + ? stageName + : BuildRenderGraphSequencePassName(stageName, passIndex); + const RenderPassRenderGraphContext passContext = { + graphBuilder, + passName, + stagePassContext.renderContext, + sceneData, + stagePassContext.surface, + stagePassContext.sourceSurface, + stagePassContext.sourceColorView, + stagePassContext.sourceColorState, + {}, + outputSurface.colorTextures, + outputSurface.depthTexture, + &stageExecutionSucceeded, + beginSequencePass, + {}, + &blackboard + }; + if (!RecordSequencePass( + *pass, + passContext, + { + false, + writesColor, + writesDepth + })) { + return false; + } + } + + return true; +} + +bool RecordFullscreenPassSequenceStage( + CameraFrameStage stage, + const Containers::String& stageName, + const RenderPassContext& stagePassContext, + const CameraFrameRenderGraphSourceBinding& binding, + RenderGraphTextureHandle finalOutputColor, + const RenderSceneData& sceneData, + RenderPassSequence* stageSequence, + CameraFrameExecutionState& executionState, + RenderGraphBuilder& graphBuilder, + RenderGraphBlackboard& blackboard, + bool& stageExecutionSucceeded) { + if (stageSequence == nullptr || stageSequence->GetPassCount() == 0u) { + return true; + } + + std::unique_ptr* const activeSequence = + ResolveStageSequenceState(stage, executionState); + RenderPassSequence* const sequence = stageSequence; + const RenderContext* const renderContext = &stagePassContext.renderContext; + const RenderPassGraphBeginCallback beginSequencePass = + [&, activeSequence, sequence, renderContext](const RenderPassContext&) -> bool { + if (activeSequence == nullptr || + !EnsureInitializedPassSequence( + *activeSequence, + sequence, + *renderContext)) { + stageExecutionSucceeded = false; + return false; + } + + return true; + }; + + RenderGraphTextureHandle currentSourceColor = binding.sourceColor; + const RenderGraphTextureDesc transientDesc = + BuildFullscreenTransientTextureDesc(stagePassContext.surface); + + for (size_t passIndex = 0u; passIndex < stageSequence->GetPassCount(); ++passIndex) { + RenderPass* const pass = stageSequence->GetPass(passIndex); + if (pass == nullptr) { + continue; + } + + const bool isLastPass = (passIndex + 1u) == stageSequence->GetPassCount(); + const Containers::String passName = + stageSequence->GetPassCount() == 1u + ? stageName + : BuildRenderGraphSequencePassName(stageName, passIndex); + const RenderGraphTextureHandle passOutputColor = + isLastPass + ? finalOutputColor + : graphBuilder.CreateTransientTexture( + passName + ".Color", + transientDesc); + const RenderSurface* const sourceSurfaceTemplate = + passIndex == 0u + ? binding.sourceSurfaceTemplate + : &stagePassContext.surface; + RHI::RHIResourceView* const sourceColorView = + passIndex == 0u + ? binding.sourceColorView + : nullptr; + const RHI::ResourceStates sourceColorState = + passIndex == 0u + ? binding.sourceColorState + : RHI::ResourceStates::PixelShaderResource; + const RenderPassRenderGraphContext passContext = { + graphBuilder, + passName, + stagePassContext.renderContext, + sceneData, + stagePassContext.surface, + sourceSurfaceTemplate, + sourceColorView, + sourceColorState, + currentSourceColor, + std::vector{ passOutputColor }, + {}, + &stageExecutionSucceeded, + beginSequencePass, + {}, + &blackboard + }; + if (!RecordSequencePass( + *pass, + passContext, + { + true, + true, + false + })) { + return false; + } + + currentSourceColor = passOutputColor; + } + + return true; +} + +struct CameraFrameStageGraphBuildState { + CameraFrameStage stage = CameraFrameStage::MainScene; + Containers::String stageName = {}; + RenderPassSequence* stageSequence = nullptr; + RenderSurface surfaceTemplate = {}; + bool hasSourceSurface = false; + RenderSurface sourceSurfaceTemplate = {}; + RHI::RHIResourceView* sourceColorView = nullptr; + RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common; + RenderGraphImportedSurface sourceSurface = {}; + RenderGraphImportedSurface outputSurface = {}; + RenderGraphTextureHandle outputColor = {}; +}; + +RenderPassContext BuildCameraFrameStageGraphPassContext( + const CameraFramePlan& plan, + const CameraFrameStageGraphBuildState& stageState, + const RenderSceneData& sceneData) { + return { + plan.request.context, + stageState.surfaceTemplate, + sceneData, + stageState.hasSourceSurface + ? &stageState.sourceSurfaceTemplate + : nullptr, + stageState.sourceColorView, + stageState.sourceColorState + }; +} + +CameraFrameStageGraphBuildState BuildCameraFrameStageGraphBuildState( + CameraFrameStage stage, + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& sceneData, + RenderGraphBuilder& graphBuilder, + RenderGraphImportedTextureRegistry& importedTextures) { + CameraFrameStageGraphBuildState stageState = {}; + stageState.stage = stage; + stageState.stageName = Containers::String(GetCameraFrameStageName(stage)); + stageState.stageSequence = plan.GetPassSequence(stage); + + const RenderPassContext stagePassContext = + BuildFrameStagePassContext(stage, plan, shadowState, sceneData); + stageState.surfaceTemplate = stagePassContext.surface; + stageState.hasSourceSurface = stagePassContext.sourceSurface != nullptr; + if (stageState.hasSourceSurface) { + stageState.sourceSurfaceTemplate = *stagePassContext.sourceSurface; + } + stageState.sourceColorView = stagePassContext.sourceColorView; + stageState.sourceColorState = stagePassContext.sourceColorState; + stageState.sourceSurface = + ImportRenderGraphSurface( + graphBuilder, + importedTextures, + stageState.stageName + ".Source", + stagePassContext.sourceSurface, + RenderGraphSurfaceImportUsage::Source, + IsCameraFrameFullscreenSequenceStage(stage)); + stageState.outputSurface = + ImportRenderGraphSurface( + graphBuilder, + importedTextures, + stageState.stageName + ".Output", + &stagePassContext.surface, + RenderGraphSurfaceImportUsage::Output, + DoesCameraFrameStageGraphOwnColorTransitions(stage), + DoesCameraFrameStageGraphOwnDepthTransitions(stage)); + stageState.outputColor = + ResolveStageOutputColorHandle( + stage, + plan, + stageState.stageName, + stagePassContext, + stageState.outputSurface, + graphBuilder); + return stageState; +} + +void PublishCameraFrameStageGraphBuildState( + const CameraFrameStageGraphBuildState& stageState, + const DirectionalShadowExecutionState& shadowState, + CameraFrameRenderGraphResources& frameResources) { + if (stageState.stage == CameraFrameStage::ShadowCaster && + shadowState.HasShadowSampling() && + stageState.outputSurface.depthTexture.IsValid()) { + frameResources.mainDirectionalShadow = stageState.outputSurface.depthTexture; + } + + WriteCameraFrameRenderGraphStageSurfaceResources( + frameResources, + stageState.stage, + stageState.outputColor, + stageState.outputSurface.depthTexture); +} + +bool TryRecordCameraFrameStageSequence( + const CameraFrameStageGraphBuildState& stageState, + const CameraFramePlan& plan, + const RenderSceneData& sceneData, + CameraFrameExecutionState& executionState, + RenderGraphBuilder& graphBuilder, + RenderGraphBlackboard& blackboard, + bool& stageExecutionSucceeded, + bool& handled) { + if (stageState.stageSequence == nullptr) { + handled = false; + return true; + } + + handled = true; + const RenderPassContext stagePassContext = + BuildCameraFrameStageGraphPassContext(plan, stageState, sceneData); + const bool recordResult = + IsCameraFrameFullscreenSequenceStage(stageState.stage) + ? RecordFullscreenPassSequenceStage( + stageState.stage, + stageState.stageName, + stagePassContext, + ResolveCameraFrameFullscreenStageGraphSourceBinding( + plan, + stageState.stage, + stageState.surfaceTemplate, + stagePassContext.sourceSurface, + stagePassContext.sourceColorView, + stagePassContext.sourceColorState, + GetPrimaryColorTexture(stageState.sourceSurface), + &blackboard), + stageState.outputColor, + sceneData, + stageState.stageSequence, + executionState, + graphBuilder, + blackboard, + stageExecutionSucceeded) + : RecordRegularPassSequenceStage( + stageState.stage, + stageState.stageName, + stagePassContext, + stageState.outputSurface, + sceneData, + stageState.stageSequence, + executionState, + graphBuilder, + blackboard, + stageExecutionSucceeded); + if (!recordResult) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + Containers::String("CameraRenderer::Render failed: pass-sequence graph recording returned false for ") + + stageState.stageName); + return false; + } + + return true; +} + +bool TryRecordCameraFrameStageStandaloneRenderGraphPass( + const CameraFrameStageGraphBuildState& stageState, + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& sceneData, + CameraFrameExecutionState& executionState, + RenderGraphBuilder& graphBuilder, + RenderGraphBlackboard& blackboard, + bool& stageExecutionSucceeded, + bool& handled) { + RenderPass* const standaloneStagePass = + ResolveStandaloneStagePass(stageState.stage, executionState); + if (standaloneStagePass == nullptr || + !standaloneStagePass->SupportsRenderGraph()) { + handled = false; + return true; + } + + handled = true; + const RenderSceneData stageSceneData = + BuildStandaloneStageSceneData( + stageState.stage, + plan, + shadowState, + sceneData, + stageState.surfaceTemplate); + const RenderPassGraphBeginCallback beginStandalonePass = + [&, standaloneStagePass](const RenderPassContext&) -> bool { + if (!InitializeStandalonePass( + standaloneStagePass, + plan.request.context)) { + stageExecutionSucceeded = false; + return false; + } + + return true; + }; + const RenderPassRenderGraphContext standalonePassContext = { + graphBuilder, + stageState.stageName, + plan.request.context, + stageSceneData, + stageState.surfaceTemplate, + stageState.hasSourceSurface + ? &stageState.sourceSurfaceTemplate + : nullptr, + stageState.sourceColorView, + stageState.sourceColorState, + GetPrimaryColorTexture(stageState.sourceSurface), + std::vector{ stageState.outputColor }, + stageState.outputSurface.depthTexture, + &stageExecutionSucceeded, + beginStandalonePass, + {}, + &blackboard + }; + if (!standaloneStagePass->RecordRenderGraph(standalonePassContext)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + Containers::String("CameraRenderer::Render failed: RenderPass::RecordRenderGraph returned false for ") + + stageState.stageName); + return false; + } + + return true; +} + +bool TryRecordCameraFrameMainSceneGraphPass( + const CameraFrameStageGraphBuildState& stageState, + const CameraFramePlan& plan, + const RenderSceneData& sceneData, + CameraFrameExecutionState& executionState, + RenderGraphBuilder& graphBuilder, + RenderGraphBlackboard& blackboard, + bool& stageExecutionSucceeded, + bool& handled) { + if (stageState.stage != CameraFrameStage::MainScene || + executionState.pipeline == nullptr || + !executionState.pipeline->SupportsMainSceneRenderGraph()) { + handled = false; + return true; + } + + handled = true; + const RenderPipelineMainSceneRenderGraphContext mainSceneContext = { + graphBuilder, + stageState.stageName, + plan.request.context, + sceneData, + stageState.surfaceTemplate, + stageState.hasSourceSurface + ? &stageState.sourceSurfaceTemplate + : nullptr, + stageState.sourceColorView, + stageState.sourceColorState, + std::vector{ stageState.outputColor }, + stageState.outputSurface.depthTexture, + &stageExecutionSucceeded, + &blackboard + }; + if (!executionState.pipeline->RecordMainSceneRenderGraph(mainSceneContext)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + "CameraRenderer::Render failed: RenderPipeline::RecordMainSceneRenderGraph returned false"); + return false; + } + + return true; +} + +void AddCameraFrameStageFallbackRasterPass( + const CameraFrameStageGraphBuildState& stageState, + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& sceneData, + CameraFrameExecutionState& executionState, + RenderGraphBuilder& graphBuilder, + bool& stageExecutionSucceeded) { + const CameraFrameStageGraphBuildState capturedStageState = stageState; + graphBuilder.AddRasterPass( + capturedStageState.stageName, + [&, capturedStageState](RenderGraphPassBuilder& passBuilder) { + if (IsCameraFrameFullscreenSequenceStage(capturedStageState.stage)) { + ReadRenderGraphColorSurface(passBuilder, capturedStageState.sourceSurface); + WriteRenderGraphColorSurface(passBuilder, capturedStageState.outputSurface); + } else { + ReadRenderGraphSurface(passBuilder, capturedStageState.sourceSurface); + WriteRenderGraphSurface(passBuilder, capturedStageState.outputSurface); + } + passBuilder.SetExecuteCallback( + [&, capturedStageState]( + const RenderGraphExecutionContext& executionContext) { + if (!stageExecutionSucceeded) { + return; + } + + const RenderSurface* resolvedSourceSurface = + capturedStageState.hasSourceSurface + ? &capturedStageState.sourceSurfaceTemplate + : nullptr; + RHI::RHIResourceView* resolvedSourceColorView = + capturedStageState.sourceColorView; + RHI::ResourceStates resolvedSourceColorState = + capturedStageState.sourceColorState; + RenderSurface graphManagedSourceSurface = {}; + if (IsCameraFrameFullscreenSequenceStage(capturedStageState.stage) && + capturedStageState.hasSourceSurface && + CanUseGraphManagedImportedSurface( + capturedStageState.sourceSurface, + executionContext)) { + graphManagedSourceSurface = + BuildGraphManagedImportedSurface( + capturedStageState.sourceSurfaceTemplate, + RHI::ResourceStates::PixelShaderResource, + RHI::ResourceStates::PixelShaderResource); + resolvedSourceSurface = &graphManagedSourceSurface; + resolvedSourceColorState = RHI::ResourceStates::PixelShaderResource; + } + + const RenderSurface* resolvedOutputSurface = + &capturedStageState.surfaceTemplate; + RenderSurface graphManagedOutputSurface = {}; + if (CanUseGraphManagedImportedSurface( + capturedStageState.outputSurface, + executionContext)) { + graphManagedOutputSurface = + BuildGraphManagedPassSurface( + capturedStageState.surfaceTemplate); + resolvedOutputSurface = &graphManagedOutputSurface; + } + + const RenderPassContext passContextOverride = { + plan.request.context, + *resolvedOutputSurface, + sceneData, + resolvedSourceSurface, + resolvedSourceColorView, + resolvedSourceColorState + }; + stageExecutionSucceeded = ExecuteRecordedFrameStage( + capturedStageState.stage, + plan, + shadowState, + sceneData, + executionState, + passContextOverride); + }); + }); +} + +bool ExecuteRenderGraphPlan( + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& sceneData, + CameraFrameExecutionState& executionState) { + RenderGraph graph = {}; + RenderGraphBuilder graphBuilder(graph); + RenderGraphBlackboard blackboard = {}; + RenderGraphImportedTextureRegistry importedTextures = {}; + CameraFrameRenderGraphResources& frameResources = + blackboard.Emplace(); + + bool stageExecutionSucceeded = true; + for (const CameraFrameStageInfo& stageInfo : kOrderedCameraFrameStages) { + if (!plan.HasFrameStage(stageInfo.stage) && + stageInfo.stage != CameraFrameStage::MainScene) { + continue; + } + + const CameraFrameStageGraphBuildState stageState = + BuildCameraFrameStageGraphBuildState( + stageInfo.stage, + plan, + shadowState, + sceneData, + graphBuilder, + importedTextures); + PublishCameraFrameStageGraphBuildState( + stageState, + shadowState, + frameResources); + + bool stageHandled = false; + if (!TryRecordCameraFrameStageSequence( + stageState, + plan, + sceneData, + executionState, + graphBuilder, + blackboard, + stageExecutionSucceeded, + stageHandled)) { + return false; + } + if (stageHandled) { + continue; + } + + if (!TryRecordCameraFrameStageStandaloneRenderGraphPass( + stageState, + plan, + shadowState, + sceneData, + executionState, + graphBuilder, + blackboard, + stageExecutionSucceeded, + stageHandled)) { + return false; + } + if (stageHandled) { + continue; + } + + if (!TryRecordCameraFrameMainSceneGraphPass( + stageState, + plan, + sceneData, + executionState, + graphBuilder, + blackboard, + stageExecutionSucceeded, + stageHandled)) { + return false; + } + if (stageHandled) { + continue; + } + + AddCameraFrameStageFallbackRasterPass( + stageState, + plan, + shadowState, + sceneData, + executionState, + graphBuilder, + stageExecutionSucceeded); + } + + CompiledRenderGraph compiledGraph = {}; + Containers::String errorMessage; + if (!RenderGraphCompiler::Compile(graph, compiledGraph, &errorMessage)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + Containers::String("CameraRenderer::Render failed: RenderGraph compile failed: ") + + errorMessage); + return false; + } + + if (!RenderGraphExecutor::Execute(compiledGraph, plan.request.context, &errorMessage)) { + Debug::Logger::Get().Error( + Debug::LogCategory::Rendering, + Containers::String("CameraRenderer::Render failed: RenderGraph execute failed: ") + + errorMessage); + return false; + } + + return stageExecutionSucceeded; +} + +} // namespace + +bool ExecuteCameraFrameRenderGraphPlan( + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& sceneData, + RenderPipeline* pipeline, + RenderPass* objectIdPass, + RenderPass* depthOnlyPass, + RenderPass* shadowCasterPass) { + CameraFrameExecutionState executionState = {}; + executionState.pipeline = pipeline; + executionState.objectIdPass = objectIdPass; + executionState.depthOnlyPass = depthOnlyPass; + executionState.shadowCasterPass = shadowCasterPass; + return ExecuteRenderGraphPlan(plan, shadowState, sceneData, executionState); +} + +} // namespace Rendering +} // namespace XCEngine diff --git a/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphExecution.h b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphExecution.h new file mode 100644 index 00000000..8b4ecad8 --- /dev/null +++ b/engine/src/Rendering/Execution/Internal/CameraFrameRenderGraphExecution.h @@ -0,0 +1,22 @@ +#pragma once + +#include +#include +#include + +namespace XCEngine { +namespace Rendering { + +struct DirectionalShadowExecutionState; + +bool ExecuteCameraFrameRenderGraphPlan( + const CameraFramePlan& plan, + const DirectionalShadowExecutionState& shadowState, + const RenderSceneData& sceneData, + RenderPipeline* pipeline, + RenderPass* objectIdPass, + RenderPass* depthOnlyPass, + RenderPass* shadowCasterPass); + +} // namespace Rendering +} // namespace XCEngine