Extract camera frame render-graph stage policy helpers

This commit is contained in:
2026-04-14 22:17:12 +08:00
parent a02ff65651
commit a67f8597ba
4 changed files with 257 additions and 103 deletions

View File

@@ -0,0 +1,100 @@
#pragma once
#include <XCEngine/Rendering/Execution/CameraFrameRenderGraphResources.h>
#include <XCEngine/Rendering/RenderSurface.h>
namespace XCEngine {
namespace Rendering {
struct CameraFrameRenderGraphSourceBinding {
const RenderSurface* sourceSurfaceTemplate = nullptr;
RHI::RHIResourceView* sourceColorView = nullptr;
RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common;
RenderGraphTextureHandle sourceColor = {};
};
inline bool IsCameraFrameFullscreenSequenceStage(
CameraFrameStage stage) {
return stage == CameraFrameStage::PostProcess ||
stage == CameraFrameStage::FinalOutput;
}
inline bool DoesCameraFrameStageGraphOwnColorTransitions(
CameraFrameStage stage) {
return stage == CameraFrameStage::MainScene ||
stage == CameraFrameStage::PostProcess ||
stage == CameraFrameStage::FinalOutput ||
stage == CameraFrameStage::ObjectId;
}
inline bool DoesCameraFrameStageGraphOwnDepthTransitions(
CameraFrameStage stage) {
return stage == CameraFrameStage::ShadowCaster ||
stage == CameraFrameStage::DepthOnly ||
stage == CameraFrameStage::MainScene ||
stage == CameraFrameStage::ObjectId;
}
inline bool UsesCameraFrameStageGraphManagedOutputColor(
const CameraFramePlan& plan,
CameraFrameStage stage) {
switch (stage) {
case CameraFrameStage::MainScene:
return plan.usesGraphManagedMainSceneColor;
case CameraFrameStage::PostProcess:
return plan.usesGraphManagedPostProcessColor;
default:
return false;
}
}
inline CameraFrameColorSource ResolveCameraFrameStageGraphManagedColorSource(
const CameraFramePlan& plan,
CameraFrameStage stage) {
switch (stage) {
case CameraFrameStage::PostProcess:
return plan.postProcessSource;
case CameraFrameStage::FinalOutput:
return plan.finalOutputSource;
default:
return CameraFrameColorSource::ExplicitSurface;
}
}
inline CameraFrameRenderGraphSourceBinding ResolveCameraFrameFullscreenStageGraphSourceBinding(
const CameraFramePlan& plan,
CameraFrameStage stage,
const RenderSurface& stageSurfaceTemplate,
const RenderSurface* explicitSourceSurfaceTemplate,
RHI::RHIResourceView* explicitSourceColorView,
RHI::ResourceStates explicitSourceColorState,
RenderGraphTextureHandle explicitSourceColor,
const RenderGraphBlackboard* blackboard) {
CameraFrameRenderGraphSourceBinding binding = {};
binding.sourceSurfaceTemplate = explicitSourceSurfaceTemplate;
binding.sourceColorView = explicitSourceColorView;
binding.sourceColorState = explicitSourceColorState;
binding.sourceColor = explicitSourceColor;
const CameraFrameColorSource graphManagedSource =
ResolveCameraFrameStageGraphManagedColorSource(plan, stage);
if (graphManagedSource != CameraFrameColorSource::ExplicitSurface) {
binding.sourceSurfaceTemplate = &stageSurfaceTemplate;
binding.sourceColorView = nullptr;
binding.sourceColorState = RHI::ResourceStates::PixelShaderResource;
binding.sourceColor =
ResolveCameraFrameRenderGraphColorSource(
blackboard,
graphManagedSource);
}
if (binding.sourceSurfaceTemplate == nullptr &&
binding.sourceColor.IsValid()) {
binding.sourceSurfaceTemplate = &stageSurfaceTemplate;
}
return binding;
}
} // namespace Rendering
} // namespace XCEngine

View File

@@ -1,6 +1,7 @@
#include "Rendering/Execution/CameraRenderer.h"
#include "Components/CameraComponent.h"
#include "Rendering/Execution/CameraFrameRenderGraphStagePolicy.h"
#include "Rendering/Execution/DirectionalShadowExecutionState.h"
#include "Rendering/Graph/RenderGraph.h"
#include "Rendering/Graph/RenderGraphCompiler.h"
@@ -256,12 +257,6 @@ void WriteRenderGraphColorSurface(
}
}
bool IsFullscreenSequenceStage(
CameraFrameStage stage) {
return stage == CameraFrameStage::PostProcess ||
stage == CameraFrameStage::FinalOutput;
}
Containers::String BuildRenderGraphSequencePassName(
const Containers::String& stageName,
size_t passIndex) {
@@ -530,14 +525,6 @@ RenderSurface BuildGraphManagedPassSurface(
return surface;
}
struct FullscreenStageGraphBinding {
const RenderSurface* sourceSurfaceTemplate = nullptr;
RHI::RHIResourceView* sourceColorView = nullptr;
RHI::ResourceStates sourceColorState = RHI::ResourceStates::Common;
RenderGraphTextureHandle sourceColor = {};
RenderGraphTextureHandle outputColor = {};
};
const RenderSurface* ResolveFrameStageOutputSurface(
CameraFrameStage stage,
const CameraFramePlan& plan,
@@ -560,22 +547,6 @@ const RenderSurface* ResolveFrameStageOutputSurface(
}
}
bool ShouldGraphOwnStageColorTransitions(
CameraFrameStage stage) {
return stage == CameraFrameStage::MainScene ||
stage == CameraFrameStage::PostProcess ||
stage == CameraFrameStage::FinalOutput ||
stage == CameraFrameStage::ObjectId;
}
bool ShouldGraphOwnStageDepthTransitions(
CameraFrameStage stage) {
return stage == CameraFrameStage::ShadowCaster ||
stage == CameraFrameStage::DepthOnly ||
stage == CameraFrameStage::MainScene ||
stage == CameraFrameStage::ObjectId;
}
bool CanUseGraphManagedImportedSurface(
const RenderGraphImportedSurface& surface,
const RenderGraphExecutionContext& graphContext) {
@@ -609,69 +580,24 @@ RenderGraphTextureHandle ResolveStageOutputColorHandle(
const RenderPassContext& stagePassContext,
const RenderGraphImportedSurface& outputSurface,
RenderGraphBuilder& graphBuilder) {
if (stage == CameraFrameStage::MainScene &&
plan.usesGraphManagedMainSceneColor) {
return graphBuilder.CreateTransientTexture(
stageName + ".Color",
BuildImportedTextureDesc(
stagePassContext.surface,
kRenderGraphImportedColorFormat));
}
if (stage == CameraFrameStage::PostProcess &&
plan.usesGraphManagedPostProcessColor) {
return graphBuilder.CreateTransientTexture(
stageName + ".Color",
BuildFullscreenTransientTextureDesc(stagePassContext.surface));
}
return GetPrimaryColorTexture(outputSurface);
}
FullscreenStageGraphBinding ResolveFullscreenStageGraphBinding(
CameraFrameStage stage,
const CameraFramePlan& plan,
const RenderPassContext& stagePassContext,
const RenderGraphImportedSurface& sourceSurface,
RenderGraphTextureHandle outputColor,
const RenderGraphBlackboard* blackboard) {
FullscreenStageGraphBinding binding = {};
binding.sourceSurfaceTemplate = stagePassContext.sourceSurface;
binding.sourceColorView = stagePassContext.sourceColorView;
binding.sourceColorState = stagePassContext.sourceColorState;
binding.sourceColor = GetPrimaryColorTexture(sourceSurface);
binding.outputColor = outputColor;
if (stage == CameraFrameStage::PostProcess &&
plan.postProcessSource == CameraFrameColorSource::MainSceneColor) {
binding.sourceSurfaceTemplate = &stagePassContext.surface;
binding.sourceColorView = nullptr;
binding.sourceColorState = RHI::ResourceStates::PixelShaderResource;
binding.sourceColor =
ResolveCameraFrameRenderGraphColorSource(
blackboard,
plan.postProcessSource);
}
if (stage == CameraFrameStage::FinalOutput) {
if (plan.finalOutputSource == CameraFrameColorSource::MainSceneColor ||
plan.finalOutputSource == CameraFrameColorSource::PostProcessColor) {
binding.sourceSurfaceTemplate = &stagePassContext.surface;
binding.sourceColorView = nullptr;
binding.sourceColorState = RHI::ResourceStates::PixelShaderResource;
binding.sourceColor =
ResolveCameraFrameRenderGraphColorSource(
blackboard,
plan.finalOutputSource);
if (UsesCameraFrameStageGraphManagedOutputColor(plan, stage)) {
switch (stage) {
case CameraFrameStage::MainScene:
return graphBuilder.CreateTransientTexture(
stageName + ".Color",
BuildImportedTextureDesc(
stagePassContext.surface,
kRenderGraphImportedColorFormat));
case CameraFrameStage::PostProcess:
return graphBuilder.CreateTransientTexture(
stageName + ".Color",
BuildFullscreenTransientTextureDesc(stagePassContext.surface));
default:
break;
}
}
if (binding.sourceSurfaceTemplate == nullptr &&
binding.sourceColor.IsValid()) {
binding.sourceSurfaceTemplate = &stagePassContext.surface;
}
return binding;
return GetPrimaryColorTexture(outputSurface);
}
RenderPassContext BuildFrameStagePassContext(
@@ -816,7 +742,8 @@ bool RecordFullscreenPassSequenceStage(
CameraFrameStage stage,
const Containers::String& stageName,
const RenderPassContext& stagePassContext,
const FullscreenStageGraphBinding& binding,
const CameraFrameRenderGraphSourceBinding& binding,
RenderGraphTextureHandle finalOutputColor,
const RenderSceneData& sceneData,
RenderPassSequence* stageSequence,
CameraFrameExecutionState& executionState,
@@ -846,7 +773,6 @@ bool RecordFullscreenPassSequenceStage(
};
RenderGraphTextureHandle currentSourceColor = binding.sourceColor;
const RenderGraphTextureHandle finalOutputColor = binding.outputColor;
const RenderGraphTextureDesc transientDesc =
BuildFullscreenTransientTextureDesc(stagePassContext.surface);
@@ -945,7 +871,7 @@ bool ExecuteRenderGraphPlan(
stageName + ".Source",
stagePassContext.sourceSurface,
RenderGraphSurfaceImportUsage::Source,
IsFullscreenSequenceStage(stage));
IsCameraFrameFullscreenSequenceStage(stage));
const RenderGraphImportedSurface outputSurface =
ImportRenderGraphSurface(
graphBuilder,
@@ -953,8 +879,8 @@ bool ExecuteRenderGraphPlan(
stageName + ".Output",
&stagePassContext.surface,
RenderGraphSurfaceImportUsage::Output,
ShouldGraphOwnStageColorTransitions(stage),
ShouldGraphOwnStageDepthTransitions(stage));
DoesCameraFrameStageGraphOwnColorTransitions(stage),
DoesCameraFrameStageGraphOwnDepthTransitions(stage));
const RenderGraphTextureHandle stageOutputColor =
ResolveStageOutputColorHandle(
stage,
@@ -984,18 +910,21 @@ bool ExecuteRenderGraphPlan(
if (stageSequence != nullptr) {
const bool recordResult =
IsFullscreenSequenceStage(stage)
IsCameraFrameFullscreenSequenceStage(stage)
? RecordFullscreenPassSequenceStage(
stage,
stageName,
stagePassContext,
ResolveFullscreenStageGraphBinding(
stage,
ResolveCameraFrameFullscreenStageGraphSourceBinding(
plan,
stagePassContext,
sourceSurface,
stageOutputColor,
stage,
stagePassContext.surface,
stagePassContext.sourceSurface,
stagePassContext.sourceColorView,
stagePassContext.sourceColorState,
GetPrimaryColorTexture(sourceSurface),
&blackboard),
stageOutputColor,
sceneData,
stageSequence,
executionState,
@@ -1103,7 +1032,7 @@ bool ExecuteRenderGraphPlan(
stageName,
[&, sourceSurface, outputSurface, stage, stageSurfaceTemplate, hasStageSourceSurface, stageSourceSurfaceTemplate, stageSourceColorView, stageSourceColorState](
RenderGraphPassBuilder& passBuilder) {
if (IsFullscreenSequenceStage(stage)) {
if (IsCameraFrameFullscreenSequenceStage(stage)) {
ReadRenderGraphColorSurface(passBuilder, sourceSurface);
WriteRenderGraphColorSurface(passBuilder, outputSurface);
} else {
@@ -1125,7 +1054,7 @@ bool ExecuteRenderGraphPlan(
const_cast<RHI::RHIResourceView*>(stageSourceColorView);
RHI::ResourceStates resolvedSourceColorState = stageSourceColorState;
RenderSurface graphManagedSourceSurface = {};
if (IsFullscreenSequenceStage(stage) &&
if (IsCameraFrameFullscreenSequenceStage(stage) &&
hasStageSourceSurface &&
CanUseGraphManagedImportedSurface(sourceSurface, executionContext)) {
graphManagedSourceSurface =

View File

@@ -7,6 +7,7 @@ set(RENDERING_UNIT_TEST_SOURCES
test_object_id_encoding.cpp
test_builtin_forward_pipeline.cpp
test_builtin_gaussian_splat_pass_resources.cpp
test_camera_frame_render_graph_stage_policy.cpp
test_camera_scene_renderer.cpp
test_scene_render_request_planner.cpp
test_scene_render_request_utils.cpp

View File

@@ -0,0 +1,124 @@
#include <gtest/gtest.h>
#include <XCEngine/Rendering/Execution/CameraFrameRenderGraphStagePolicy.h>
using namespace XCEngine::Rendering;
namespace {
RenderSurface CreateColorSurface(
uint32_t width,
uint32_t height,
XCEngine::RHI::RHIResourceView* colorAttachment) {
RenderSurface surface(width, height);
surface.SetColorAttachment(colorAttachment);
return surface;
}
} // namespace
TEST(CameraFrameRenderGraphStagePolicy_Test, ReportsStageFullscreenAndTransitionPolicies) {
EXPECT_TRUE(IsCameraFrameFullscreenSequenceStage(CameraFrameStage::PostProcess));
EXPECT_TRUE(IsCameraFrameFullscreenSequenceStage(CameraFrameStage::FinalOutput));
EXPECT_FALSE(IsCameraFrameFullscreenSequenceStage(CameraFrameStage::MainScene));
EXPECT_TRUE(DoesCameraFrameStageGraphOwnColorTransitions(CameraFrameStage::MainScene));
EXPECT_TRUE(DoesCameraFrameStageGraphOwnColorTransitions(CameraFrameStage::FinalOutput));
EXPECT_FALSE(DoesCameraFrameStageGraphOwnColorTransitions(CameraFrameStage::ShadowCaster));
EXPECT_TRUE(DoesCameraFrameStageGraphOwnDepthTransitions(CameraFrameStage::MainScene));
EXPECT_TRUE(DoesCameraFrameStageGraphOwnDepthTransitions(CameraFrameStage::ShadowCaster));
EXPECT_FALSE(DoesCameraFrameStageGraphOwnDepthTransitions(CameraFrameStage::FinalOutput));
}
TEST(CameraFrameRenderGraphStagePolicy_Test, ReportsGraphManagedOutputColorStagesFromPlan) {
CameraFramePlan plan = {};
plan.usesGraphManagedMainSceneColor = true;
plan.usesGraphManagedPostProcessColor = true;
EXPECT_TRUE(UsesCameraFrameStageGraphManagedOutputColor(plan, CameraFrameStage::MainScene));
EXPECT_TRUE(UsesCameraFrameStageGraphManagedOutputColor(plan, CameraFrameStage::PostProcess));
EXPECT_FALSE(UsesCameraFrameStageGraphManagedOutputColor(plan, CameraFrameStage::FinalOutput));
}
TEST(CameraFrameRenderGraphStagePolicy_Test, KeepsExplicitFullscreenSourceBindingUntouched) {
CameraFramePlan plan = {};
RenderSurface stageSurface(320, 180);
RenderSurface explicitSourceSurface =
CreateColorSurface(
320,
180,
reinterpret_cast<XCEngine::RHI::RHIResourceView*>(11));
XCEngine::RHI::RHIResourceView* const explicitSourceColorView =
reinterpret_cast<XCEngine::RHI::RHIResourceView*>(12);
const CameraFrameRenderGraphSourceBinding binding =
ResolveCameraFrameFullscreenStageGraphSourceBinding(
plan,
CameraFrameStage::PostProcess,
stageSurface,
&explicitSourceSurface,
explicitSourceColorView,
XCEngine::RHI::ResourceStates::CopySrc,
RenderGraphTextureHandle{ 21u },
nullptr);
EXPECT_EQ(binding.sourceSurfaceTemplate, &explicitSourceSurface);
EXPECT_EQ(binding.sourceColorView, explicitSourceColorView);
EXPECT_EQ(binding.sourceColorState, XCEngine::RHI::ResourceStates::CopySrc);
EXPECT_EQ(binding.sourceColor.index, 21u);
}
TEST(CameraFrameRenderGraphStagePolicy_Test, ResolvesGraphManagedPostProcessSourceFromBlackboard) {
CameraFramePlan plan = {};
plan.postProcessSource = CameraFrameColorSource::MainSceneColor;
RenderGraphBlackboard blackboard = {};
CameraFrameRenderGraphResources& frameResources =
blackboard.Emplace<CameraFrameRenderGraphResources>();
frameResources.mainScene.color = RenderGraphTextureHandle{ 31u };
RenderSurface stageSurface(640, 360);
const CameraFrameRenderGraphSourceBinding binding =
ResolveCameraFrameFullscreenStageGraphSourceBinding(
plan,
CameraFrameStage::PostProcess,
stageSurface,
nullptr,
reinterpret_cast<XCEngine::RHI::RHIResourceView*>(41),
XCEngine::RHI::ResourceStates::Common,
{},
&blackboard);
EXPECT_EQ(binding.sourceSurfaceTemplate, &stageSurface);
EXPECT_EQ(binding.sourceColorView, nullptr);
EXPECT_EQ(binding.sourceColorState, XCEngine::RHI::ResourceStates::PixelShaderResource);
EXPECT_EQ(binding.sourceColor.index, 31u);
}
TEST(CameraFrameRenderGraphStagePolicy_Test, ResolvesGraphManagedFinalOutputSourceFromBlackboard) {
CameraFramePlan plan = {};
plan.finalOutputSource = CameraFrameColorSource::PostProcessColor;
RenderGraphBlackboard blackboard = {};
CameraFrameRenderGraphResources& frameResources =
blackboard.Emplace<CameraFrameRenderGraphResources>();
frameResources.postProcess.color = RenderGraphTextureHandle{ 51u };
RenderSurface stageSurface(800, 600);
const CameraFrameRenderGraphSourceBinding binding =
ResolveCameraFrameFullscreenStageGraphSourceBinding(
plan,
CameraFrameStage::FinalOutput,
stageSurface,
nullptr,
reinterpret_cast<XCEngine::RHI::RHIResourceView*>(61),
XCEngine::RHI::ResourceStates::Common,
{},
&blackboard);
EXPECT_EQ(binding.sourceSurfaceTemplate, &stageSurface);
EXPECT_EQ(binding.sourceColorView, nullptr);
EXPECT_EQ(binding.sourceColorState, XCEngine::RHI::ResourceStates::PixelShaderResource);
EXPECT_EQ(binding.sourceColor.index, 51u);
}