Unify camera frame graph resource binding helpers

This commit is contained in:
2026-04-14 22:00:03 +08:00
parent 86eb455ab9
commit a3efcda550
3 changed files with 211 additions and 41 deletions

View File

@@ -1,6 +1,7 @@
#pragma once
#include <XCEngine/Core/Containers/String.h>
#include <XCEngine/Rendering/Execution/CameraFramePlan.h>
#include <XCEngine/Rendering/Execution/FrameExecutionContext.h>
#include <XCEngine/Rendering/FrameData/RenderSceneData.h>
#include <XCEngine/Rendering/Graph/RenderGraphBlackboard.h>
@@ -27,6 +28,50 @@ struct CameraFrameRenderGraphResources {
RenderGraphTextureHandle mainDirectionalShadow = {};
};
inline CameraFrameRenderGraphSurfaceResources* ResolveCameraFrameRenderGraphStageSurfaceResources(
CameraFrameRenderGraphResources& frameResources,
CameraFrameStage stage) {
switch (stage) {
case CameraFrameStage::MainScene:
return &frameResources.mainScene;
case CameraFrameStage::PostProcess:
return &frameResources.postProcess;
case CameraFrameStage::ObjectId:
return &frameResources.objectId;
default:
return nullptr;
}
}
inline const CameraFrameRenderGraphSurfaceResources* ResolveCameraFrameRenderGraphStageSurfaceResources(
const CameraFrameRenderGraphResources& frameResources,
CameraFrameStage stage) {
switch (stage) {
case CameraFrameStage::MainScene:
return &frameResources.mainScene;
case CameraFrameStage::PostProcess:
return &frameResources.postProcess;
case CameraFrameStage::ObjectId:
return &frameResources.objectId;
default:
return nullptr;
}
}
inline const CameraFrameRenderGraphSurfaceResources* ResolveCameraFrameRenderGraphColorSourceResources(
const CameraFrameRenderGraphResources& frameResources,
CameraFrameColorSource source) {
switch (source) {
case CameraFrameColorSource::MainSceneColor:
return &frameResources.mainScene;
case CameraFrameColorSource::PostProcessColor:
return &frameResources.postProcess;
case CameraFrameColorSource::ExplicitSurface:
default:
return nullptr;
}
}
inline CameraFrameRenderGraphResources* TryGetCameraFrameRenderGraphResources(
RenderGraphBlackboard* blackboard) {
return blackboard != nullptr
@@ -41,6 +86,41 @@ inline const CameraFrameRenderGraphResources* TryGetCameraFrameRenderGraphResour
: nullptr;
}
inline RenderGraphTextureHandle ResolveCameraFrameRenderGraphColorSource(
const CameraFrameRenderGraphResources& frameResources,
CameraFrameColorSource source) {
const CameraFrameRenderGraphSurfaceResources* const surfaceResources =
ResolveCameraFrameRenderGraphColorSourceResources(frameResources, source);
return surfaceResources != nullptr
? surfaceResources->color
: RenderGraphTextureHandle{};
}
inline RenderGraphTextureHandle ResolveCameraFrameRenderGraphColorSource(
const RenderGraphBlackboard* blackboard,
CameraFrameColorSource source) {
const CameraFrameRenderGraphResources* const frameResources =
TryGetCameraFrameRenderGraphResources(blackboard);
return frameResources != nullptr
? ResolveCameraFrameRenderGraphColorSource(*frameResources, source)
: RenderGraphTextureHandle{};
}
inline void WriteCameraFrameRenderGraphStageSurfaceResources(
CameraFrameRenderGraphResources& frameResources,
CameraFrameStage stage,
RenderGraphTextureHandle color,
RenderGraphTextureHandle depth) {
CameraFrameRenderGraphSurfaceResources* const surfaceResources =
ResolveCameraFrameRenderGraphStageSurfaceResources(frameResources, stage);
if (surfaceResources == nullptr) {
return;
}
surfaceResources->color = color;
surfaceResources->depth = depth;
}
struct RenderPipelineMainSceneRenderGraphContext {
RenderGraphBuilder& graphBuilder;
Containers::String passName = {};

View File

@@ -608,8 +608,7 @@ RenderGraphTextureHandle ResolveStageOutputColorHandle(
const Containers::String& stageName,
const RenderPassContext& stagePassContext,
const RenderGraphImportedSurface& outputSurface,
RenderGraphBuilder& graphBuilder,
CameraFrameRenderGraphResources& frameResources) {
RenderGraphBuilder& graphBuilder) {
if (stage == CameraFrameStage::MainScene &&
plan.usesGraphManagedMainSceneColor) {
return graphBuilder.CreateTransientTexture(
@@ -621,37 +620,21 @@ RenderGraphTextureHandle ResolveStageOutputColorHandle(
if (stage == CameraFrameStage::PostProcess &&
plan.usesGraphManagedPostProcessColor) {
frameResources.postProcess.color =
graphBuilder.CreateTransientTexture(
stageName + ".Color",
BuildFullscreenTransientTextureDesc(stagePassContext.surface));
return frameResources.postProcess.color;
return graphBuilder.CreateTransientTexture(
stageName + ".Color",
BuildFullscreenTransientTextureDesc(stagePassContext.surface));
}
return GetPrimaryColorTexture(outputSurface);
}
RenderGraphTextureHandle ResolveFrameResourceColorSource(
const CameraFrameRenderGraphResources& frameResources,
CameraFrameColorSource source) {
switch (source) {
case CameraFrameColorSource::MainSceneColor:
return frameResources.mainScene.color;
case CameraFrameColorSource::PostProcessColor:
return frameResources.postProcess.color;
case CameraFrameColorSource::ExplicitSurface:
default:
return {};
}
}
FullscreenStageGraphBinding ResolveFullscreenStageGraphBinding(
CameraFrameStage stage,
const CameraFramePlan& plan,
const RenderPassContext& stagePassContext,
const RenderGraphImportedSurface& sourceSurface,
RenderGraphTextureHandle outputColor,
CameraFrameRenderGraphResources& frameResources) {
const RenderGraphBlackboard* blackboard) {
FullscreenStageGraphBinding binding = {};
binding.sourceSurfaceTemplate = stagePassContext.sourceSurface;
binding.sourceColorView = stagePassContext.sourceColorView;
@@ -665,8 +648,8 @@ FullscreenStageGraphBinding ResolveFullscreenStageGraphBinding(
binding.sourceColorView = nullptr;
binding.sourceColorState = RHI::ResourceStates::PixelShaderResource;
binding.sourceColor =
ResolveFrameResourceColorSource(
frameResources,
ResolveCameraFrameRenderGraphColorSource(
blackboard,
plan.postProcessSource);
}
@@ -677,8 +660,8 @@ FullscreenStageGraphBinding ResolveFullscreenStageGraphBinding(
binding.sourceColorView = nullptr;
binding.sourceColorState = RHI::ResourceStates::PixelShaderResource;
binding.sourceColor =
ResolveFrameResourceColorSource(
frameResources,
ResolveCameraFrameRenderGraphColorSource(
blackboard,
plan.finalOutputSource);
}
}
@@ -979,25 +962,17 @@ bool ExecuteRenderGraphPlan(
stageName,
stagePassContext,
outputSurface,
graphBuilder,
frameResources);
graphBuilder);
if (stage == CameraFrameStage::ShadowCaster &&
shadowState.HasShadowSampling() &&
outputSurface.depthTexture.IsValid()) {
frameResources.mainDirectionalShadow = outputSurface.depthTexture;
}
if (stage == CameraFrameStage::MainScene) {
frameResources.mainScene.color = stageOutputColor;
frameResources.mainScene.depth = outputSurface.depthTexture;
}
if (stage == CameraFrameStage::PostProcess) {
frameResources.postProcess.color = stageOutputColor;
frameResources.postProcess.depth = outputSurface.depthTexture;
}
if (stage == CameraFrameStage::ObjectId) {
frameResources.objectId.color = stageOutputColor;
frameResources.objectId.depth = outputSurface.depthTexture;
}
WriteCameraFrameRenderGraphStageSurfaceResources(
frameResources,
stage,
stageOutputColor,
outputSurface.depthTexture);
const RenderSurface stageSurfaceTemplate = stagePassContext.surface;
const bool hasStageSourceSurface = stagePassContext.sourceSurface != nullptr;
const RenderSurface stageSourceSurfaceTemplate =
@@ -1020,7 +995,7 @@ bool ExecuteRenderGraphPlan(
stagePassContext,
sourceSurface,
stageOutputColor,
frameResources),
&blackboard),
sceneData,
stageSequence,
executionState,

View File

@@ -759,6 +759,18 @@ public:
bool RecordRenderGraph(const RenderPassRenderGraphContext& context) override {
m_state->eventLog.push_back(std::string("record:") + m_label);
lastRecordedSourceColorTextureValid = context.sourceColorTexture.IsValid();
lastRecordedRenderGraphBlackboard = context.blackboard != nullptr;
if (const CameraFrameRenderGraphResources* frameResources =
TryGetCameraFrameRenderGraphResources(context.blackboard)) {
lastRecordedBlackboardMainSceneColorValid =
frameResources->mainScene.color.IsValid();
lastRecordedBlackboardPostProcessColorValid =
frameResources->postProcess.color.IsValid();
} else {
lastRecordedBlackboardMainSceneColorValid = false;
lastRecordedBlackboardPostProcessColorValid = false;
}
const bool writesColor =
context.sourceSurface != nullptr ||
!context.colorTargets.empty();
@@ -815,6 +827,10 @@ public:
bool lastSourceSurfaceAutoTransitionEnabled = true;
XCEngine::RHI::RHIResourceView* lastSourceColorView = nullptr;
XCEngine::RHI::ResourceStates lastSourceColorState = XCEngine::RHI::ResourceStates::Common;
bool lastRecordedSourceColorTextureValid = false;
bool lastRecordedRenderGraphBlackboard = false;
bool lastRecordedBlackboardMainSceneColorValid = false;
bool lastRecordedBlackboardPostProcessColorValid = false;
};
RenderContext CreateValidContext() {
@@ -1791,6 +1807,105 @@ TEST(CameraRenderer_Test, RecordsGraphCapableSinglePassSequenceStagesInDocumente
EXPECT_FALSE(overlayPassRaw->lastSurfaceAutoTransitionEnabled);
}
TEST(CameraRenderer_Test, ResolvesGraphManagedFullscreenSequenceSourcesFromFrameResources) {
Scene scene("CameraRendererGraphManagedFullscreenSources");
GameObject* cameraObject = scene.CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
camera->SetPrimary(true);
camera->SetDepth(3.0f);
auto state = std::make_shared<MockPipelineState>();
state->supportsMainSceneRenderGraph = true;
CameraRenderer renderer(std::make_unique<MockPipeline>(state));
auto allocationState = std::make_shared<MockShadowAllocationState>();
MockShadowDevice device(allocationState);
MockShadowView colorView(
allocationState,
XCEngine::RHI::ResourceViewType::RenderTarget,
XCEngine::RHI::Format::R8G8B8A8_UNorm,
XCEngine::RHI::ResourceViewDimension::Texture2D);
MockShadowView depthView(
allocationState,
XCEngine::RHI::ResourceViewType::DepthStencil,
XCEngine::RHI::Format::D24_UNorm_S8_UInt,
XCEngine::RHI::ResourceViewDimension::Texture2D);
auto postProcessPass = std::make_unique<TrackingPass>(state, "postProcess", true, true, true);
TrackingPass* postProcessPassRaw = postProcessPass.get();
RenderPassSequence postProcessPasses;
postProcessPasses.AddPass(std::move(postProcessPass));
auto finalOutputPass = std::make_unique<TrackingPass>(state, "finalOutput", true, true, true);
TrackingPass* finalOutputPassRaw = finalOutputPass.get();
RenderPassSequence finalOutputPasses;
finalOutputPasses.AddPass(std::move(finalOutputPass));
CameraRenderRequest request;
request.scene = &scene;
request.camera = camera;
request.context = CreateValidContext();
request.context.device = &device;
request.surface = RenderSurface(320, 180);
request.surface.SetColorAttachment(&colorView);
request.surface.SetDepthAttachment(&depthView);
request.cameraDepth = camera->GetDepth();
request.postProcess.passes = &postProcessPasses;
request.finalOutput.passes = &finalOutputPasses;
request.finalOutput.destinationSurface = request.surface;
CameraFramePlan plan = CameraFramePlan::FromRequest(request);
plan.usesGraphManagedMainSceneColor = true;
plan.ConfigureGraphManagedMainSceneSurface();
plan.usesGraphManagedPostProcessColor = true;
plan.postProcessSource = CameraFrameColorSource::MainSceneColor;
plan.finalOutputSource = CameraFrameColorSource::PostProcessColor;
ASSERT_TRUE(plan.IsPostProcessStageValid());
ASSERT_TRUE(plan.IsFinalOutputStageValid());
const bool renderResult = renderer.Render(plan);
EXPECT_TRUE(renderResult);
EXPECT_EQ(state->recordMainSceneCalls, 1);
EXPECT_EQ(state->executeRecordedMainSceneCalls, 1);
EXPECT_EQ(
state->eventLog,
(std::vector<std::string>{
"record:postProcess",
"record:finalOutput",
"pipelineGraph",
"init:postProcess",
"postProcess",
"init:finalOutput",
"finalOutput" }));
ASSERT_NE(postProcessPassRaw, nullptr);
EXPECT_TRUE(postProcessPassRaw->lastRecordedRenderGraphBlackboard);
EXPECT_TRUE(postProcessPassRaw->lastRecordedSourceColorTextureValid);
EXPECT_TRUE(postProcessPassRaw->lastRecordedBlackboardMainSceneColorValid);
EXPECT_NE(postProcessPassRaw->lastSourceColorView, nullptr);
EXPECT_TRUE(postProcessPassRaw->lastHasSourceSurface);
EXPECT_EQ(postProcessPassRaw->lastSourceSurfaceWidth, 320u);
EXPECT_EQ(postProcessPassRaw->lastSourceSurfaceHeight, 180u);
EXPECT_FALSE(postProcessPassRaw->lastSourceSurfaceAutoTransitionEnabled);
EXPECT_EQ(
postProcessPassRaw->lastSourceColorState,
XCEngine::RHI::ResourceStates::PixelShaderResource);
ASSERT_NE(finalOutputPassRaw, nullptr);
EXPECT_TRUE(finalOutputPassRaw->lastRecordedRenderGraphBlackboard);
EXPECT_TRUE(finalOutputPassRaw->lastRecordedSourceColorTextureValid);
EXPECT_TRUE(finalOutputPassRaw->lastRecordedBlackboardPostProcessColorValid);
EXPECT_NE(finalOutputPassRaw->lastSourceColorView, nullptr);
EXPECT_TRUE(finalOutputPassRaw->lastHasSourceSurface);
EXPECT_EQ(finalOutputPassRaw->lastSourceSurfaceWidth, 320u);
EXPECT_EQ(finalOutputPassRaw->lastSourceSurfaceHeight, 180u);
EXPECT_FALSE(finalOutputPassRaw->lastSourceSurfaceAutoTransitionEnabled);
EXPECT_EQ(
finalOutputPassRaw->lastSourceColorState,
XCEngine::RHI::ResourceStates::PixelShaderResource);
}
TEST(CameraRenderer_Test, ExecutesShadowCasterAndDepthOnlyRequestsBeforeMainPipeline) {
Scene scene("CameraRendererDepthAndShadowScene");