feat(srp): add managed camera frame planning seam

Expose native camera frame planning controls to managed pipeline assets and renderer features.

Allow managed planning to override fullscreen stage heuristics while keeping CameraFramePlan as the native execution contract.

Add scripting coverage, probe assets, and archive the phase plan after build, test, and editor smoke validation.
This commit is contained in:
2026-04-20 01:48:16 +08:00
parent 58dde75d3d
commit 9e6c473186
17 changed files with 926 additions and 9 deletions

View File

@@ -1312,9 +1312,9 @@ TEST_F(
EXPECT_FALSE(hasUniversalContextRecordShaderVectorFullscreenPassExtension);
EXPECT_FALSE(hasUniversalRequestContextHasDirectionalShadowExtension);
EXPECT_FALSE(hasUniversalRequestContextClearDirectionalShadowExtension);
EXPECT_FALSE(hasPublicPipelineAssetConfigureCameraFramePlan);
EXPECT_FALSE(hasPlanningContextType);
EXPECT_FALSE(hasRendererFeatureConfigureCameraFramePlan);
EXPECT_TRUE(hasPublicPipelineAssetConfigureCameraFramePlan);
EXPECT_TRUE(hasPlanningContextType);
EXPECT_TRUE(hasRendererFeatureConfigureCameraFramePlan);
EXPECT_FALSE(hasRendererRecordingContextType);
EXPECT_FALSE(hasRendererCameraRequestContextType);
EXPECT_FALSE(hasRendererBackedRenderPipelineAssetType);
@@ -3334,6 +3334,142 @@ TEST_F(
EXPECT_TRUE(plan.IsFinalOutputStageValid());
}
TEST_F(
MonoScriptRuntimeTest,
ManagedRendererFeatureConfiguresCameraFramePlanThroughPlanningContext) {
Scene* runtimeScene =
CreateScene("ManagedFeatureFramePlanningScene");
GameObject* cameraObject = runtimeScene->CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
ASSERT_NE(camera, nullptr);
camera->SetPrimary(true);
TestRenderDevice device;
TestRenderCommandList commandList;
TestRenderCommandQueue commandQueue;
TestRenderResourceView colorView(
XCEngine::RHI::ResourceViewType::RenderTarget,
XCEngine::RHI::ResourceViewDimension::Texture2D,
XCEngine::RHI::Format::R8G8B8A8_UNorm);
TestRenderResourceView depthView(
XCEngine::RHI::ResourceViewType::DepthStencil,
XCEngine::RHI::ResourceViewDimension::Texture2D,
XCEngine::RHI::Format::D32_Float);
const XCEngine::Rendering::RenderContext context =
CreateRenderContext(
device,
commandList,
commandQueue);
XCEngine::Rendering::RenderSurface surface(64u, 64u);
surface.SetColorAttachment(&colorView);
surface.SetDepthAttachment(&depthView);
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor
descriptor = {
"GameScripts",
"Gameplay",
"ManagedFeaturePlannedPostProcessProbeAsset"
};
auto asset =
std::make_shared<
XCEngine::Rendering::Pipelines::ManagedScriptableRenderPipelineAsset>(
descriptor);
XCEngine::Rendering::CameraRenderRequest request = {};
request.scene = runtimeScene;
request.camera = camera;
request.context = context;
request.surface = surface;
XCEngine::Rendering::RenderPipelineHost host(asset);
const std::vector<XCEngine::Rendering::CameraFramePlan> plans =
host.BuildFramePlans({ request });
ASSERT_EQ(plans.size(), 1u);
const XCEngine::Rendering::CameraFramePlan& plan = plans[0];
EXPECT_TRUE(
plan.IsFullscreenStageRequested(
XCEngine::Rendering::CameraFrameStage::PostProcess));
EXPECT_EQ(
plan.ResolveStageColorSource(
XCEngine::Rendering::CameraFrameStage::PostProcess),
XCEngine::Rendering::CameraFrameColorSource::MainSceneColor);
EXPECT_FALSE(
plan.UsesGraphManagedOutputColor(
XCEngine::Rendering::CameraFrameStage::PostProcess));
EXPECT_TRUE(plan.IsPostProcessStageValid());
}
TEST_F(
MonoScriptRuntimeTest,
ManagedRenderPipelineAssetPlanningContextCanOverridePipelineStageHeuristic) {
Scene* runtimeScene =
CreateScene("ManagedAssetFramePlanningOverrideScene");
GameObject* cameraObject = runtimeScene->CreateGameObject("Camera");
auto* camera = cameraObject->AddComponent<CameraComponent>();
ASSERT_NE(camera, nullptr);
camera->SetPrimary(true);
TestRenderDevice device;
TestRenderCommandList commandList;
TestRenderCommandQueue commandQueue;
TestRenderResourceView colorView(
XCEngine::RHI::ResourceViewType::RenderTarget,
XCEngine::RHI::ResourceViewDimension::Texture2D,
XCEngine::RHI::Format::R8G8B8A8_UNorm);
TestRenderResourceView depthView(
XCEngine::RHI::ResourceViewType::DepthStencil,
XCEngine::RHI::ResourceViewDimension::Texture2D,
XCEngine::RHI::Format::D32_Float);
const XCEngine::Rendering::RenderContext context =
CreateRenderContext(
device,
commandList,
commandQueue);
XCEngine::Rendering::RenderSurface surface(64u, 64u);
surface.SetColorAttachment(&colorView);
surface.SetDepthAttachment(&depthView);
const XCEngine::Rendering::Pipelines::ManagedRenderPipelineAssetDescriptor
descriptor = {
"GameScripts",
"Gameplay",
"ManagedClearedPostProcessRenderPipelineProbeAsset"
};
auto asset =
std::make_shared<
XCEngine::Rendering::Pipelines::ManagedScriptableRenderPipelineAsset>(
descriptor);
XCEngine::Rendering::CameraRenderRequest request = {};
request.scene = runtimeScene;
request.camera = camera;
request.context = context;
request.surface = surface;
XCEngine::Rendering::RenderPipelineHost host(asset);
const std::vector<XCEngine::Rendering::CameraFramePlan> plans =
host.BuildFramePlans({ request });
ASSERT_EQ(plans.size(), 1u);
const XCEngine::Rendering::CameraFramePlan& plan = plans[0];
EXPECT_FALSE(
plan.IsFullscreenStageRequested(
XCEngine::Rendering::CameraFrameStage::PostProcess));
EXPECT_TRUE(
plan.IsFullscreenStageRequested(
XCEngine::Rendering::CameraFrameStage::FinalOutput));
EXPECT_EQ(
plan.ResolveStageColorSource(
XCEngine::Rendering::CameraFrameStage::FinalOutput),
XCEngine::Rendering::CameraFrameColorSource::MainSceneColor);
EXPECT_TRUE(plan.IsFinalOutputStageValid());
}
TEST_F(
MonoScriptRuntimeTest,
ManagedRenderPipelineAssetConfiguresCameraRequestsThroughRequestContext) {