Extract frame-plan fullscreen stage builder

This commit is contained in:
2026-04-14 01:01:45 +08:00
parent e83f911aef
commit 5797a75619
5 changed files with 279 additions and 207 deletions

View File

@@ -548,6 +548,8 @@ add_library(XCEngine STATIC
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Extraction/RenderSceneExtractor.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Extraction/RenderSceneUtility.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Caches/RenderResourceCache.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/CameraFramePlanBuilder.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/CameraFramePlanBuilder.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/SceneRenderRequestPlanner.cpp
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/Internal/DirectionalShadowPlanning.h
${CMAKE_CURRENT_SOURCE_DIR}/src/Rendering/Planning/Internal/DirectionalShadowPlanning.cpp

View File

@@ -16,8 +16,8 @@ class Scene;
namespace Rendering {
class CameraFramePlanBuilder;
class RenderPipelineAsset;
class FullscreenPassSurfaceCache;
class SceneRenderer {
public:
@@ -57,18 +57,10 @@ public:
private:
std::vector<CameraFramePlan> CreateFramePlansFromLegacyRequests(
const std::vector<CameraRenderRequest>& requests) const;
void PrepareOwnedFullscreenStageState(size_t requestCount);
void ResolveCameraFinalColorPolicies(
std::vector<CameraFramePlan>& plans) const;
void AttachFullscreenStageRequests(
const RenderContext& context,
std::vector<CameraFramePlan>& plans);
SceneRenderRequestPlanner m_requestPlanner;
CameraRenderer m_cameraRenderer;
std::vector<std::unique_ptr<RenderPassSequence>> m_ownedPostProcessSequences;
std::vector<std::unique_ptr<RenderPassSequence>> m_ownedFinalOutputSequences;
std::vector<std::unique_ptr<FullscreenPassSurfaceCache>> m_ownedFullscreenStageSurfaces;
std::unique_ptr<CameraFramePlanBuilder> m_framePlanBuilder;
};
} // namespace Rendering

View File

@@ -1,12 +1,9 @@
#include "Rendering/Execution/SceneRenderer.h"
#include "Components/CameraComponent.h"
#include "Debug/Logger.h"
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
#include "Rendering/Planning/CameraPostProcessPassFactory.h"
#include "Rendering/Planning/FinalColorPassFactory.h"
#include "Rendering/Planning/CameraFramePlanBuilder.h"
#include "Rendering/Planning/SceneRenderRequestUtils.h"
#include "Rendering/RenderPipelineAsset.h"
namespace XCEngine {
namespace Rendering {
@@ -21,70 +18,20 @@ bool CompareCameraFramePlans(
rhs.request);
}
RenderSurface ConfigureFullscreenStageSurface(
const FullscreenPassSurfaceCache::SurfaceEntry& entry,
const RenderSurface& templateSurface,
bool copyDepthAttachment) {
RenderSurface surface = entry.surface;
if (copyDepthAttachment) {
surface.SetDepthAttachment(templateSurface.GetDepthAttachment());
surface.SetDepthStateBefore(templateSurface.GetDepthStateBefore());
surface.SetDepthStateAfter(templateSurface.GetDepthStateAfter());
if (templateSurface.HasClearColorOverride()) {
surface.SetClearColorOverride(templateSurface.GetClearColorOverride());
}
}
if (templateSurface.HasCustomRenderArea()) {
surface.SetRenderArea(templateSurface.GetRenderArea());
} else {
surface.ResetRenderArea();
}
surface.SetColorStateBefore(entry.currentColorState);
surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource);
return surface;
}
void UpdateTrackedFullscreenSurfaceState(
std::vector<std::unique_ptr<FullscreenPassSurfaceCache>>& surfaceCaches,
const RenderSurface* surface) {
if (surface == nullptr || surface->GetColorAttachments().empty()) {
return;
}
RHI::RHIResourceView* colorAttachment = surface->GetColorAttachments()[0];
if (colorAttachment == nullptr) {
return;
}
for (const std::unique_ptr<FullscreenPassSurfaceCache>& cache : surfaceCaches) {
if (cache == nullptr) {
continue;
}
for (size_t entryIndex = 0; entryIndex < cache->GetSurfaceCount(); ++entryIndex) {
FullscreenPassSurfaceCache::SurfaceEntry* entry = cache->GetSurfaceEntry(entryIndex);
if (entry == nullptr || entry->renderTargetView != colorAttachment) {
continue;
}
entry->currentColorState = surface->GetColorStateAfter();
return;
}
}
}
} // namespace
SceneRenderer::SceneRenderer() = default;
SceneRenderer::SceneRenderer()
: m_framePlanBuilder(std::make_unique<CameraFramePlanBuilder>()) {
}
SceneRenderer::SceneRenderer(std::unique_ptr<RenderPipeline> pipeline)
: m_cameraRenderer(std::move(pipeline)) {
: m_cameraRenderer(std::move(pipeline))
, m_framePlanBuilder(std::make_unique<CameraFramePlanBuilder>()) {
}
SceneRenderer::SceneRenderer(std::shared_ptr<const RenderPipelineAsset> pipelineAsset)
: m_cameraRenderer(std::move(pipelineAsset)) {
: m_cameraRenderer(std::move(pipelineAsset))
, m_framePlanBuilder(std::make_unique<CameraFramePlanBuilder>()) {
}
SceneRenderer::~SceneRenderer() = default;
@@ -119,10 +66,9 @@ std::vector<CameraFramePlan> SceneRenderer::BuildFramePlans(
const RenderSurface& surface) {
const std::vector<CameraRenderRequest> requests =
m_requestPlanner.BuildRequests(scene, overrideCamera, context, surface);
std::vector<CameraFramePlan> plans = CreateFramePlansFromLegacyRequests(requests);
ResolveCameraFinalColorPolicies(plans);
AttachFullscreenStageRequests(context, plans);
return plans;
return m_framePlanBuilder != nullptr
? m_framePlanBuilder->BuildPlans(requests, GetPipelineAsset())
: std::vector<CameraFramePlan>();
}
bool SceneRenderer::Render(const CameraRenderRequest& request) {
@@ -161,13 +107,13 @@ bool SceneRenderer::Render(const std::vector<CameraFramePlan>& plans) {
return false;
}
UpdateTrackedFullscreenSurfaceState(
m_ownedFullscreenStageSurfaces,
&plan.GetMainSceneSurface());
if (m_framePlanBuilder != nullptr) {
m_framePlanBuilder->UpdateTrackedSurfaceState(&plan.GetMainSceneSurface());
}
if (plan.postProcess.IsRequested()) {
UpdateTrackedFullscreenSurfaceState(
m_ownedFullscreenStageSurfaces,
&plan.postProcess.destinationSurface);
if (m_framePlanBuilder != nullptr) {
m_framePlanBuilder->UpdateTrackedSurfaceState(&plan.postProcess.destinationSurface);
}
}
rendered = true;
@@ -195,131 +141,5 @@ std::vector<CameraFramePlan> SceneRenderer::CreateFramePlansFromLegacyRequests(
return plans;
}
void SceneRenderer::PrepareOwnedFullscreenStageState(size_t requestCount) {
m_ownedPostProcessSequences.clear();
m_ownedPostProcessSequences.resize(requestCount);
m_ownedFinalOutputSequences.clear();
m_ownedFinalOutputSequences.resize(requestCount);
if (m_ownedFullscreenStageSurfaces.size() < requestCount) {
m_ownedFullscreenStageSurfaces.resize(requestCount);
}
for (size_t index = 0; index < requestCount; ++index) {
if (m_ownedFullscreenStageSurfaces[index] == nullptr) {
m_ownedFullscreenStageSurfaces[index] = std::make_unique<FullscreenPassSurfaceCache>();
}
}
}
void SceneRenderer::ResolveCameraFinalColorPolicies(
std::vector<CameraFramePlan>& plans) const {
const RenderPipelineAsset* pipelineAsset = GetPipelineAsset();
const FinalColorSettings pipelineDefaults =
pipelineAsset != nullptr ? pipelineAsset->GetDefaultFinalColorSettings() : FinalColorSettings();
for (CameraFramePlan& plan : plans) {
if (plan.request.camera == nullptr) {
continue;
}
plan.finalColorPolicy = ResolveFinalColorPolicy(
pipelineDefaults,
&plan.request.camera->GetFinalColorOverrides());
}
}
void SceneRenderer::AttachFullscreenStageRequests(
const RenderContext& context,
std::vector<CameraFramePlan>& plans) {
PrepareOwnedFullscreenStageState(plans.size());
for (size_t index = 0; index < plans.size(); ++index) {
CameraFramePlan& plan = plans[index];
if (plan.request.camera == nullptr ||
plan.request.context.device == nullptr ||
!HasValidColorTarget(plan.request.surface)) {
continue;
}
std::unique_ptr<RenderPassSequence> postProcessSequence =
BuildCameraPostProcessPassSequence(plan.request.camera->GetPostProcessPasses());
std::unique_ptr<RenderPassSequence> finalOutputSequence =
BuildFinalColorPassSequence(plan.finalColorPolicy);
const bool hasPostProcess =
postProcessSequence != nullptr && postProcessSequence->GetPassCount() > 0u;
const bool hasFinalOutput =
finalOutputSequence != nullptr && finalOutputSequence->GetPassCount() > 0u;
if (!hasPostProcess && !hasFinalOutput) {
continue;
}
if (plan.request.surface.GetSampleCount() > 1u) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"SceneRenderer fullscreen post-process/final-output chain currently requires a single-sample main scene surface");
continue;
}
const std::vector<RHI::RHIResourceView*>& colorAttachments = plan.request.surface.GetColorAttachments();
const RHI::Format colorFormat = colorAttachments[0]->GetFormat();
if (colorFormat == RHI::Format::Unknown) {
continue;
}
const size_t fullscreenSurfaceCount = hasPostProcess && hasFinalOutput ? 2u : 1u;
FullscreenPassSurfaceCache* surfaceCache = m_ownedFullscreenStageSurfaces[index].get();
if (surfaceCache == nullptr ||
!surfaceCache->EnsureSurfaces(
context,
plan.request.surface.GetWidth(),
plan.request.surface.GetHeight(),
colorFormat,
fullscreenSurfaceCount)) {
continue;
}
const FullscreenPassSurfaceCache::SurfaceEntry* sceneColorEntry = surfaceCache->GetSurfaceEntry(0u);
if (sceneColorEntry == nullptr || sceneColorEntry->shaderResourceView == nullptr) {
continue;
}
const FullscreenPassSurfaceCache::SurfaceEntry* postProcessOutputEntry =
hasPostProcess && hasFinalOutput ? surfaceCache->GetSurfaceEntry(1u) : nullptr;
if (hasPostProcess && hasFinalOutput &&
(postProcessOutputEntry == nullptr || postProcessOutputEntry->shaderResourceView == nullptr)) {
continue;
}
if (hasPostProcess) {
plan.postProcess.sourceSurface =
ConfigureFullscreenStageSurface(*sceneColorEntry, plan.request.surface, true);
plan.postProcess.sourceColorView = sceneColorEntry->shaderResourceView;
plan.postProcess.sourceColorState = plan.postProcess.sourceSurface.GetColorStateAfter();
plan.postProcess.destinationSurface =
hasFinalOutput
? ConfigureFullscreenStageSurface(*postProcessOutputEntry, plan.request.surface, false)
: plan.request.surface;
m_ownedPostProcessSequences[index] = std::move(postProcessSequence);
plan.postProcess.passes = m_ownedPostProcessSequences[index].get();
}
if (hasFinalOutput) {
const FullscreenPassSurfaceCache::SurfaceEntry* finalOutputSourceEntry =
hasPostProcess ? postProcessOutputEntry : sceneColorEntry;
plan.finalOutput.sourceSurface =
hasPostProcess
? plan.postProcess.destinationSurface
: ConfigureFullscreenStageSurface(*sceneColorEntry, plan.request.surface, true);
plan.finalOutput.sourceColorView = finalOutputSourceEntry->shaderResourceView;
plan.finalOutput.sourceColorState = plan.finalOutput.sourceSurface.GetColorStateAfter();
plan.finalOutput.destinationSurface = plan.request.surface;
m_ownedFinalOutputSequences[index] = std::move(finalOutputSequence);
plan.finalOutput.passes = m_ownedFinalOutputSequences[index].get();
}
}
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,217 @@
#include "Rendering/Planning/CameraFramePlanBuilder.h"
#include "Components/CameraComponent.h"
#include "Debug/Logger.h"
#include "Rendering/Caches/FullscreenPassSurfaceCache.h"
#include "Rendering/Planning/CameraPostProcessPassFactory.h"
#include "Rendering/Planning/FinalColorPassFactory.h"
#include "Rendering/RenderPipelineAsset.h"
namespace XCEngine {
namespace Rendering {
namespace {
RenderSurface ConfigureFullscreenStageSurface(
const FullscreenPassSurfaceCache::SurfaceEntry& entry,
const RenderSurface& templateSurface,
bool copyDepthAttachment) {
RenderSurface surface = entry.surface;
if (copyDepthAttachment) {
surface.SetDepthAttachment(templateSurface.GetDepthAttachment());
surface.SetDepthStateBefore(templateSurface.GetDepthStateBefore());
surface.SetDepthStateAfter(templateSurface.GetDepthStateAfter());
if (templateSurface.HasClearColorOverride()) {
surface.SetClearColorOverride(templateSurface.GetClearColorOverride());
}
}
if (templateSurface.HasCustomRenderArea()) {
surface.SetRenderArea(templateSurface.GetRenderArea());
} else {
surface.ResetRenderArea();
}
surface.SetColorStateBefore(entry.currentColorState);
surface.SetColorStateAfter(RHI::ResourceStates::PixelShaderResource);
return surface;
}
} // namespace
std::vector<CameraFramePlan> CameraFramePlanBuilder::BuildPlans(
const std::vector<CameraRenderRequest>& requests,
const RenderPipelineAsset* pipelineAsset) {
std::vector<CameraFramePlan> plans = CreatePlansFromCompatibilityRequests(requests);
ResolveCameraFinalColorPolicies(plans, pipelineAsset);
AttachFullscreenStageRequests(plans);
return plans;
}
void CameraFramePlanBuilder::UpdateTrackedSurfaceState(const RenderSurface* surface) {
if (surface == nullptr || surface->GetColorAttachments().empty()) {
return;
}
RHI::RHIResourceView* colorAttachment = surface->GetColorAttachments()[0];
if (colorAttachment == nullptr) {
return;
}
for (const std::unique_ptr<FullscreenPassSurfaceCache>& cache : m_ownedFullscreenStageSurfaces) {
if (cache == nullptr) {
continue;
}
for (size_t entryIndex = 0; entryIndex < cache->GetSurfaceCount(); ++entryIndex) {
FullscreenPassSurfaceCache::SurfaceEntry* entry = cache->GetSurfaceEntry(entryIndex);
if (entry == nullptr || entry->renderTargetView != colorAttachment) {
continue;
}
entry->currentColorState = surface->GetColorStateAfter();
return;
}
}
}
std::vector<CameraFramePlan> CameraFramePlanBuilder::CreatePlansFromCompatibilityRequests(
const std::vector<CameraRenderRequest>& requests) const {
std::vector<CameraFramePlan> plans = {};
plans.reserve(requests.size());
for (const CameraRenderRequest& request : requests) {
plans.push_back(CameraFramePlan::FromRequest(request));
}
return plans;
}
void CameraFramePlanBuilder::PrepareOwnedFullscreenStageState(size_t planCount) {
m_ownedPostProcessSequences.clear();
m_ownedPostProcessSequences.resize(planCount);
m_ownedFinalOutputSequences.clear();
m_ownedFinalOutputSequences.resize(planCount);
if (m_ownedFullscreenStageSurfaces.size() < planCount) {
m_ownedFullscreenStageSurfaces.resize(planCount);
}
for (size_t index = 0; index < planCount; ++index) {
if (m_ownedFullscreenStageSurfaces[index] == nullptr) {
m_ownedFullscreenStageSurfaces[index] = std::make_unique<FullscreenPassSurfaceCache>();
}
}
}
void CameraFramePlanBuilder::ResolveCameraFinalColorPolicies(
std::vector<CameraFramePlan>& plans,
const RenderPipelineAsset* pipelineAsset) const {
const FinalColorSettings pipelineDefaults =
pipelineAsset != nullptr ? pipelineAsset->GetDefaultFinalColorSettings() : FinalColorSettings();
for (CameraFramePlan& plan : plans) {
if (plan.request.camera == nullptr) {
continue;
}
plan.finalColorPolicy = ResolveFinalColorPolicy(
pipelineDefaults,
&plan.request.camera->GetFinalColorOverrides());
}
}
void CameraFramePlanBuilder::AttachFullscreenStageRequests(
std::vector<CameraFramePlan>& plans) {
PrepareOwnedFullscreenStageState(plans.size());
for (size_t index = 0; index < plans.size(); ++index) {
CameraFramePlan& plan = plans[index];
if (plan.request.camera == nullptr ||
plan.request.context.device == nullptr ||
!HasValidColorTarget(plan.request.surface)) {
continue;
}
std::unique_ptr<RenderPassSequence> postProcessSequence =
BuildCameraPostProcessPassSequence(plan.request.camera->GetPostProcessPasses());
std::unique_ptr<RenderPassSequence> finalOutputSequence =
BuildFinalColorPassSequence(plan.finalColorPolicy);
const bool hasPostProcess =
postProcessSequence != nullptr && postProcessSequence->GetPassCount() > 0u;
const bool hasFinalOutput =
finalOutputSequence != nullptr && finalOutputSequence->GetPassCount() > 0u;
if (!hasPostProcess && !hasFinalOutput) {
continue;
}
if (plan.request.surface.GetSampleCount() > 1u) {
Debug::Logger::Get().Error(
Debug::LogCategory::Rendering,
"SceneRenderer fullscreen post-process/final-output chain currently requires a single-sample main scene surface");
continue;
}
const std::vector<RHI::RHIResourceView*>& colorAttachments =
plan.request.surface.GetColorAttachments();
const RHI::Format colorFormat = colorAttachments[0]->GetFormat();
if (colorFormat == RHI::Format::Unknown) {
continue;
}
const size_t fullscreenSurfaceCount = hasPostProcess && hasFinalOutput ? 2u : 1u;
FullscreenPassSurfaceCache* surfaceCache = m_ownedFullscreenStageSurfaces[index].get();
if (surfaceCache == nullptr ||
!surfaceCache->EnsureSurfaces(
plan.request.context,
plan.request.surface.GetWidth(),
plan.request.surface.GetHeight(),
colorFormat,
fullscreenSurfaceCount)) {
continue;
}
const FullscreenPassSurfaceCache::SurfaceEntry* sceneColorEntry =
surfaceCache->GetSurfaceEntry(0u);
if (sceneColorEntry == nullptr || sceneColorEntry->shaderResourceView == nullptr) {
continue;
}
const FullscreenPassSurfaceCache::SurfaceEntry* postProcessOutputEntry =
hasPostProcess && hasFinalOutput ? surfaceCache->GetSurfaceEntry(1u) : nullptr;
if (hasPostProcess && hasFinalOutput &&
(postProcessOutputEntry == nullptr || postProcessOutputEntry->shaderResourceView == nullptr)) {
continue;
}
if (hasPostProcess) {
plan.postProcess.sourceSurface =
ConfigureFullscreenStageSurface(*sceneColorEntry, plan.request.surface, true);
plan.postProcess.sourceColorView = sceneColorEntry->shaderResourceView;
plan.postProcess.sourceColorState = plan.postProcess.sourceSurface.GetColorStateAfter();
plan.postProcess.destinationSurface =
hasFinalOutput
? ConfigureFullscreenStageSurface(*postProcessOutputEntry, plan.request.surface, false)
: plan.request.surface;
m_ownedPostProcessSequences[index] = std::move(postProcessSequence);
plan.postProcess.passes = m_ownedPostProcessSequences[index].get();
}
if (hasFinalOutput) {
const FullscreenPassSurfaceCache::SurfaceEntry* finalOutputSourceEntry =
hasPostProcess ? postProcessOutputEntry : sceneColorEntry;
plan.finalOutput.sourceSurface =
hasPostProcess
? plan.postProcess.destinationSurface
: ConfigureFullscreenStageSurface(*sceneColorEntry, plan.request.surface, true);
plan.finalOutput.sourceColorView = finalOutputSourceEntry->shaderResourceView;
plan.finalOutput.sourceColorState = plan.finalOutput.sourceSurface.GetColorStateAfter();
plan.finalOutput.destinationSurface = plan.request.surface;
m_ownedFinalOutputSequences[index] = std::move(finalOutputSequence);
plan.finalOutput.passes = m_ownedFinalOutputSequences[index].get();
}
}
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -0,0 +1,41 @@
#pragma once
#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <memory>
#include <vector>
namespace XCEngine {
namespace Rendering {
class FullscreenPassSurfaceCache;
class RenderPipelineAsset;
class CameraFramePlanBuilder {
public:
CameraFramePlanBuilder() = default;
CameraFramePlanBuilder(const CameraFramePlanBuilder&) = delete;
CameraFramePlanBuilder& operator=(const CameraFramePlanBuilder&) = delete;
~CameraFramePlanBuilder() = default;
std::vector<CameraFramePlan> BuildPlans(
const std::vector<CameraRenderRequest>& requests,
const RenderPipelineAsset* pipelineAsset);
void UpdateTrackedSurfaceState(const RenderSurface* surface);
private:
std::vector<CameraFramePlan> CreatePlansFromCompatibilityRequests(
const std::vector<CameraRenderRequest>& requests) const;
void PrepareOwnedFullscreenStageState(size_t planCount);
void ResolveCameraFinalColorPolicies(
std::vector<CameraFramePlan>& plans,
const RenderPipelineAsset* pipelineAsset) const;
void AttachFullscreenStageRequests(std::vector<CameraFramePlan>& plans);
std::vector<std::unique_ptr<RenderPassSequence>> m_ownedPostProcessSequences;
std::vector<std::unique_ptr<RenderPassSequence>> m_ownedFinalOutputSequences;
std::vector<std::unique_ptr<FullscreenPassSurfaceCache>> m_ownedFullscreenStageSurfaces;
};
} // namespace Rendering
} // namespace XCEngine