Formalize chained fullscreen post-process execution
This commit is contained in:
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Components/CameraComponent.h"
|
||||
#include "Rendering/Caches/DirectionalShadowSurfaceCache.h"
|
||||
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
|
||||
#include "Rendering/Passes/BuiltinDepthOnlyPass.h"
|
||||
#include "Rendering/Passes/BuiltinObjectIdPass.h"
|
||||
#include "Rendering/Passes/BuiltinShadowCasterPass.h"
|
||||
@@ -11,6 +12,8 @@
|
||||
#include "RHI/RHIResourceView.h"
|
||||
#include "Scene/Scene.h"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
namespace XCEngine {
|
||||
namespace Rendering {
|
||||
|
||||
@@ -135,9 +138,10 @@ public:
|
||||
ScopedInitializedPassSequence& operator=(const ScopedInitializedPassSequence&) = delete;
|
||||
|
||||
~ScopedInitializedPassSequence() {
|
||||
if (m_sequence != nullptr && m_initialized) {
|
||||
m_sequence->Shutdown();
|
||||
}
|
||||
// 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 {
|
||||
@@ -159,6 +163,8 @@ struct CameraFrameExecutionState {
|
||||
RenderPass* objectIdPass = nullptr;
|
||||
RenderPass* depthOnlyPass = nullptr;
|
||||
RenderPass* shadowCasterPass = nullptr;
|
||||
FullscreenPassSurfaceCache* postProcessSurfaceCache = nullptr;
|
||||
FullscreenPassSurfaceCache* finalOutputSurfaceCache = nullptr;
|
||||
std::unique_ptr<ScopedInitializedPassSequence> preScenePasses;
|
||||
std::unique_ptr<ScopedInitializedPassSequence> postProcessPasses;
|
||||
std::unique_ptr<ScopedInitializedPassSequence> finalOutputPasses;
|
||||
@@ -175,6 +181,94 @@ bool ExecutePassSequenceStage(
|
||||
return activeSequence->IsReady() && activeSequence->Execute(passContext);
|
||||
}
|
||||
|
||||
void CopyIntermediateSurfaceLayout(
|
||||
const RenderSurface& templateSurface,
|
||||
RenderSurface& destinationSurface) {
|
||||
destinationSurface.SetSize(templateSurface.GetWidth(), templateSurface.GetHeight());
|
||||
if (templateSurface.HasCustomRenderArea()) {
|
||||
destinationSurface.SetRenderArea(templateSurface.GetRenderArea());
|
||||
} else {
|
||||
destinationSurface.ResetRenderArea();
|
||||
}
|
||||
|
||||
destinationSurface.ClearClearColorOverride();
|
||||
destinationSurface.SetAutoTransitionEnabled(true);
|
||||
}
|
||||
|
||||
bool ExecuteFullscreenPassSequenceStage(
|
||||
std::unique_ptr<ScopedInitializedPassSequence>& activeSequence,
|
||||
RenderPassSequence* sequence,
|
||||
const RenderContext& context,
|
||||
const RenderPassContext& passContext,
|
||||
FullscreenPassSurfaceCache* surfaceCache) {
|
||||
activeSequence = std::make_unique<ScopedInitializedPassSequence>(sequence, context);
|
||||
if (!activeSequence->IsReady()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sequence == nullptr || sequence->GetPassCount() <= 1u) {
|
||||
return activeSequence->Execute(passContext);
|
||||
}
|
||||
|
||||
if (surfaceCache == nullptr ||
|
||||
passContext.sourceSurface == nullptr ||
|
||||
passContext.sourceColorView == nullptr ||
|
||||
!HasValidColorTarget(passContext.surface)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const std::vector<RHI::RHIResourceView*>& colorAttachments = passContext.surface.GetColorAttachments();
|
||||
const RHI::Format outputFormat = colorAttachments[0]->GetFormat();
|
||||
const size_t intermediateSurfaceCount = std::min<size_t>(2u, sequence->GetPassCount() - 1u);
|
||||
if (!surfaceCache->EnsureSurfaces(
|
||||
context,
|
||||
passContext.surface.GetWidth(),
|
||||
passContext.surface.GetHeight(),
|
||||
outputFormat,
|
||||
intermediateSurfaceCount)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const RenderSurface* currentSourceSurface = passContext.sourceSurface;
|
||||
RHI::RHIResourceView* currentSourceColorView = passContext.sourceColorView;
|
||||
|
||||
for (size_t passIndex = 0; passIndex < sequence->GetPassCount(); ++passIndex) {
|
||||
const bool isLastPass = (passIndex + 1u) == sequence->GetPassCount();
|
||||
const RenderSurface* outputSurface = &passContext.surface;
|
||||
FullscreenPassSurfaceCache::SurfaceEntry* intermediateEntry = nullptr;
|
||||
if (!isLastPass) {
|
||||
intermediateEntry = surfaceCache->GetSurfaceEntry(passIndex % intermediateSurfaceCount);
|
||||
if (intermediateEntry == nullptr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
CopyIntermediateSurfaceLayout(passContext.surface, intermediateEntry->surface);
|
||||
intermediateEntry->surface.SetColorStateBefore(intermediateEntry->currentColorState);
|
||||
intermediateEntry->surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource);
|
||||
outputSurface = &intermediateEntry->surface;
|
||||
}
|
||||
|
||||
const RenderPassContext chainedContext = {
|
||||
context,
|
||||
*outputSurface,
|
||||
passContext.sceneData,
|
||||
currentSourceSurface,
|
||||
currentSourceColorView
|
||||
};
|
||||
if (!sequence->ExecutePass(passIndex, chainedContext)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (intermediateEntry != nullptr) {
|
||||
intermediateEntry->currentColorState = RHI::ResourceStates::PixelShaderResource;
|
||||
currentSourceSurface = &intermediateEntry->surface;
|
||||
currentSourceColorView = intermediateEntry->shaderResourceView;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RenderPassContext BuildFrameStagePassContext(
|
||||
CameraFrameStage stage,
|
||||
const CameraRenderRequest& request,
|
||||
@@ -184,7 +278,8 @@ RenderPassContext BuildFrameStagePassContext(
|
||||
request.context,
|
||||
outputSurface != nullptr ? *outputSurface : request.surface,
|
||||
sceneData,
|
||||
request.GetSourceSurface(stage)
|
||||
request.GetSourceSurface(stage),
|
||||
request.GetSourceColorView(stage)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -219,17 +314,19 @@ bool ExecuteFrameStage(
|
||||
return executionState.pipeline != nullptr &&
|
||||
executionState.pipeline->Render(request.context, passContext.surface, sceneData);
|
||||
case CameraFrameStage::PostProcess:
|
||||
return ExecutePassSequenceStage(
|
||||
return ExecuteFullscreenPassSequenceStage(
|
||||
executionState.postProcessPasses,
|
||||
request.GetPassSequence(stage),
|
||||
request.context,
|
||||
passContext);
|
||||
passContext,
|
||||
executionState.postProcessSurfaceCache);
|
||||
case CameraFrameStage::FinalOutput:
|
||||
return ExecutePassSequenceStage(
|
||||
return ExecuteFullscreenPassSequenceStage(
|
||||
executionState.finalOutputPasses,
|
||||
request.GetPassSequence(stage),
|
||||
request.context,
|
||||
passContext);
|
||||
passContext,
|
||||
executionState.finalOutputSurfaceCache);
|
||||
case CameraFrameStage::ObjectId:
|
||||
return !request.objectId.IsRequested() ||
|
||||
ExecuteStandalonePass(
|
||||
@@ -319,7 +416,9 @@ CameraRenderer::CameraRenderer(
|
||||
: m_pipelineAsset(nullptr)
|
||||
, m_objectIdPass(std::move(objectIdPass))
|
||||
, m_depthOnlyPass(std::move(depthOnlyPass))
|
||||
, m_shadowCasterPass(std::move(shadowCasterPass)) {
|
||||
, m_shadowCasterPass(std::move(shadowCasterPass))
|
||||
, m_postProcessSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>())
|
||||
, m_finalOutputSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>()) {
|
||||
if (m_objectIdPass == nullptr) {
|
||||
m_objectIdPass = std::make_unique<Passes::BuiltinObjectIdPass>();
|
||||
}
|
||||
@@ -336,7 +435,9 @@ CameraRenderer::CameraRenderer(std::shared_ptr<const RenderPipelineAsset> pipeli
|
||||
: m_pipelineAsset(std::move(pipelineAsset))
|
||||
, m_objectIdPass(std::make_unique<Passes::BuiltinObjectIdPass>())
|
||||
, m_depthOnlyPass(CreateDefaultDepthOnlyPass())
|
||||
, m_shadowCasterPass(CreateDefaultShadowCasterPass()) {
|
||||
, m_shadowCasterPass(CreateDefaultShadowCasterPass())
|
||||
, m_postProcessSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>())
|
||||
, m_finalOutputSurfaceCache(std::make_unique<FullscreenPassSurfaceCache>()) {
|
||||
SetPipelineAsset(m_pipelineAsset);
|
||||
}
|
||||
|
||||
@@ -481,6 +582,8 @@ bool CameraRenderer::ExecuteRenderPlan(
|
||||
executionState.objectIdPass = m_objectIdPass.get();
|
||||
executionState.depthOnlyPass = m_depthOnlyPass.get();
|
||||
executionState.shadowCasterPass = m_shadowCasterPass.get();
|
||||
executionState.postProcessSurfaceCache = m_postProcessSurfaceCache.get();
|
||||
executionState.finalOutputSurfaceCache = m_finalOutputSurfaceCache.get();
|
||||
|
||||
for (const CameraFrameStageInfo& stageInfo : kOrderedCameraFrameStages) {
|
||||
if (!request.HasFrameStage(stageInfo.stage) &&
|
||||
|
||||
Reference in New Issue
Block a user