Extract camera frame render-graph execution module

This commit is contained in:
2026-04-14 22:50:16 +08:00
parent 599f622ba4
commit 61ecb7146d
4 changed files with 1006 additions and 948 deletions

View File

@@ -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<ScopedInitializedPassSequence>& activeSequence,
RenderPassSequence* sequence,
const RenderContext& context) {
if (activeSequence == nullptr) {
activeSequence = std::make_unique<ScopedInitializedPassSequence>(sequence, context);
}
return activeSequence->IsReady();
}
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;
};
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);
}
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<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;
}
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<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);
});
});
}
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<CameraFrameRenderGraphResources>();
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

View File

@@ -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<ScopedInitializedPassSequence>& activeSequence,
RenderPassSequence* sequence,
const RenderContext& context) {
if (activeSequence == nullptr) {
activeSequence = std::make_unique<ScopedInitializedPassSequence>(sequence, context);
}
return activeSequence->IsReady();
}
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;
};
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);
}
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<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;
}
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<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);
});
});
}
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<CameraFrameRenderGraphResources>();
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

View File

@@ -0,0 +1,22 @@
#pragma once
#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <XCEngine/Rendering/RenderPass.h>
#include <XCEngine/Rendering/RenderPipeline.h>
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