973 lines
34 KiB
C++
973 lines
34 KiB
C++
|
|
#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
|