Split camera frame render-graph stage recording helpers

This commit is contained in:
2026-04-14 23:33:35 +08:00
parent 39c7ef5fdf
commit 3e5b7287c7
42 changed files with 820 additions and 703 deletions

View File

@@ -536,8 +536,13 @@ add_library(XCEngine STATIC
${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/CameraFrameRenderGraphStageRuntime.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageRecording.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageRecording.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageState.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphStageState.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h

View File

@@ -0,0 +1,384 @@
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.h"
#include "Debug/Logger.h"
#include "Rendering/Execution/CameraFrameRenderGraphStagePolicy.h"
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageRuntime.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageState.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h"
#include "Rendering/Graph/RenderGraph.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;
}
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;
}
}
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;
}
}
} // namespace
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<RenderGraphTextureHandle>{ 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<RenderGraphTextureHandle>{ 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);
});
});
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,45 @@
#pragma once
namespace XCEngine {
namespace Rendering {
struct CameraFrameExecutionState;
struct CameraFramePlan;
struct CameraFrameStageGraphBuildState;
struct DirectionalShadowExecutionState;
struct RenderSceneData;
class RenderGraphBuilder;
class RenderGraphBlackboard;
bool TryRecordCameraFrameStageStandaloneRenderGraphPass(
const CameraFrameStageGraphBuildState& stageState,
const CameraFramePlan& plan,
const DirectionalShadowExecutionState& shadowState,
const RenderSceneData& sceneData,
CameraFrameExecutionState& executionState,
RenderGraphBuilder& graphBuilder,
RenderGraphBlackboard& blackboard,
bool& stageExecutionSucceeded,
bool& handled);
bool TryRecordCameraFrameMainSceneGraphPass(
const CameraFrameStageGraphBuildState& stageState,
const CameraFramePlan& plan,
const RenderSceneData& sceneData,
CameraFrameExecutionState& executionState,
RenderGraphBuilder& graphBuilder,
RenderGraphBlackboard& blackboard,
bool& stageExecutionSucceeded,
bool& handled);
void AddCameraFrameStageFallbackRasterPass(
const CameraFrameStageGraphBuildState& stageState,
const CameraFramePlan& plan,
const DirectionalShadowExecutionState& shadowState,
const RenderSceneData& sceneData,
CameraFrameExecutionState& executionState,
RenderGraphBuilder& graphBuilder,
bool& stageExecutionSucceeded);
} // namespace Rendering
} // namespace XCEngine

View File

@@ -1,664 +1,19 @@
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageRecording.h"
#include "Debug/Logger.h"
#include "Rendering/Execution/CameraFrameRenderGraphResources.h"
#include "Rendering/Execution/CameraFrameRenderGraphStagePolicy.h"
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStagePassRecording.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageRuntime.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageState.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;
}
bool EnsureInitializedPassSequence(
std::unique_ptr<ScopedInitializedPassSequence>& activeSequence,
RenderPassSequence* sequence,
const RenderContext& context) {
if (activeSequence == nullptr) {
activeSequence = std::make_unique<ScopedInitializedPassSequence>(sequence, context);
}
return activeSequence->IsReady();
}
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<ScopedInitializedPassSequence>* 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);
}
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<ScopedInitializedPassSequence>* 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<ScopedInitializedPassSequence>* 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<RenderGraphTextureHandle>{ passOutputColor },
{},
&stageExecutionSucceeded,
beginSequencePass,
{},
&blackboard
};
if (!RecordSequencePass(
*pass,
passContext,
{
true,
true,
false
})) {
return false;
}
currentSourceColor = passOutputColor;
}
return true;
}
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<RenderGraphTextureHandle>{ 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<RenderGraphTextureHandle>{ 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);
});
});
}
} // namespace
bool ExecuteCameraFrameRenderGraphStages(
const CameraFramePlan& plan,
const DirectionalShadowExecutionState& shadowState,
@@ -681,7 +36,6 @@ bool ExecuteCameraFrameRenderGraphStages(
RenderGraphImportedTextureRegistry importedTextures = {};
bool stageExecutionSucceeded = true;
stageExecutionSucceeded = true;
for (const CameraFrameStageInfo& stageInfo : kOrderedCameraFrameStages) {
if (!plan.HasFrameStage(stageInfo.stage) &&
stageInfo.stage != CameraFrameStage::MainScene) {

View File

@@ -4,63 +4,10 @@
#include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/RenderPipeline.h>
#include <memory>
namespace XCEngine {
namespace Rendering {
struct CameraFrameRenderGraphResources;
struct DirectionalShadowExecutionState;
class RenderGraphBuilder;
class RenderGraphBlackboard;
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;
};
struct CameraFrameExecutionState {
RenderPipeline* pipeline = nullptr;
RenderPass* objectIdPass = nullptr;
RenderPass* depthOnlyPass = nullptr;
RenderPass* shadowCasterPass = nullptr;
std::unique_ptr<ScopedInitializedPassSequence> preScenePasses;
std::unique_ptr<ScopedInitializedPassSequence> postProcessPasses;
std::unique_ptr<ScopedInitializedPassSequence> finalOutputPasses;
std::unique_ptr<ScopedInitializedPassSequence> postScenePasses;
std::unique_ptr<ScopedInitializedPassSequence> overlayPasses;
};
bool ExecuteCameraFrameRenderGraphStages(
const CameraFramePlan& plan,

View File

@@ -0,0 +1,60 @@
#pragma once
#include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/RenderPipeline.h>
#include <memory>
namespace XCEngine {
namespace Rendering {
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;
};
struct CameraFrameExecutionState {
RenderPipeline* pipeline = nullptr;
RenderPass* objectIdPass = nullptr;
RenderPass* depthOnlyPass = nullptr;
RenderPass* shadowCasterPass = nullptr;
std::unique_ptr<ScopedInitializedPassSequence> preScenePasses;
std::unique_ptr<ScopedInitializedPassSequence> postProcessPasses;
std::unique_ptr<ScopedInitializedPassSequence> finalOutputPasses;
std::unique_ptr<ScopedInitializedPassSequence> postScenePasses;
std::unique_ptr<ScopedInitializedPassSequence> overlayPasses;
};
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,298 @@
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageSequenceRecording.h"
#include "Debug/Logger.h"
#include "Rendering/Execution/CameraFrameRenderGraphStagePolicy.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageRuntime.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphStageState.h"
#include "Rendering/Execution/Internal/CameraFrameRenderGraphSurfaceUtils.h"
#include "Rendering/Graph/RenderGraph.h"
#include "Rendering/Internal/RenderPassGraphUtils.h"
namespace XCEngine {
namespace Rendering {
namespace {
bool EnsureInitializedPassSequence(
std::unique_ptr<ScopedInitializedPassSequence>& activeSequence,
RenderPassSequence* sequence,
const RenderContext& context) {
if (activeSequence == nullptr) {
activeSequence =
std::make_unique<ScopedInitializedPassSequence>(sequence, context);
}
return activeSequence->IsReady();
}
std::unique_ptr<ScopedInitializedPassSequence>* 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);
}
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<ScopedInitializedPassSequence>* 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<ScopedInitializedPassSequence>* 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<RenderGraphTextureHandle>{ passOutputColor },
{},
&stageExecutionSucceeded,
beginSequencePass,
{},
&blackboard
};
if (!RecordSequencePass(
*pass,
passContext,
{
true,
true,
false
})) {
return false;
}
currentSourceColor = passOutputColor;
}
return true;
}
} // namespace
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;
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,24 @@
#pragma once
namespace XCEngine {
namespace Rendering {
struct CameraFrameExecutionState;
struct CameraFramePlan;
struct CameraFrameStageGraphBuildState;
struct RenderSceneData;
class RenderGraphBuilder;
class RenderGraphBlackboard;
bool TryRecordCameraFrameStageSequence(
const CameraFrameStageGraphBuildState& stageState,
const CameraFramePlan& plan,
const RenderSceneData& sceneData,
CameraFrameExecutionState& executionState,
RenderGraphBuilder& graphBuilder,
RenderGraphBlackboard& blackboard,
bool& stageExecutionSucceeded,
bool& handled);
} // namespace Rendering
} // namespace XCEngine