From 2d91085567b11be8bdde30ebcb511b783a250a41 Mon Sep 17 00:00:00 2001 From: ssdfasd <2156608475@qq.com> Date: Tue, 28 Apr 2026 00:38:52 +0800 Subject: [PATCH] Close URP stage planning authority --- engine/include/XCEngine/Rendering/AGENTS.md | 9 +++ .../Planning/CameraFramePlanBuilder.cpp | 58 ------------------- .../CameraFrameFullscreenStagePlanner.cpp | 21 +++---- .../unit/test_camera_scene_renderer.cpp | 43 ++++++++++++++ 4 files changed, 59 insertions(+), 72 deletions(-) diff --git a/engine/include/XCEngine/Rendering/AGENTS.md b/engine/include/XCEngine/Rendering/AGENTS.md index 6317bde6..e3c87296 100644 --- a/engine/include/XCEngine/Rendering/AGENTS.md +++ b/engine/include/XCEngine/Rendering/AGENTS.md @@ -97,6 +97,9 @@ Unity 兼容的公开命名、对象所有权和扩展点。 built-in forward pipeline policy,而不是作为 URP-declared work 的 backend executor。 - 目标所有权模型是:URP 决定渲染什么、何时渲染、哪些 renderer lists/passes/features 激活,以及 哪些 stages 存在;native 只执行这些声明,不夹带 built-in pipeline policy。 +- `CameraFramePlanBuilder` 现在只负责从 request 构造 `CameraFramePlan` 并委托所选 + `RenderPipelineAsset::ConfigureCameraFramePlan`。它不再在 asset hook 之后追加通用 legacy + fullscreen stage heuristic;默认 native fullscreen/final-output 行为应留在 native asset policy 内部。 - Hidden fallback 很危险。如果 managed URP stage 声明支持但无法 record,失败必须可见。不要静默用 default built-in path 画同一个 stage,然后称之为 URP。 - Camera-frame graph dispatch 必须询问所选 pipeline 是否允许 legacy stage fallback。Managed @@ -246,6 +249,9 @@ package。 - URP stage planning 以 `ScriptableRenderer` 的 active pass queue 为最终事实源。`ConfigureCameraFramePlan` 仍是兼容和高级策略 hook,但它不能单独声明 shadow、depth、post 或 final-output stage;没有被 pass queue 覆盖到的 side/fullscreen stage 必须在最终 plan 中清掉。 +- Native `CameraFramePlanBuilder` 不得在 renderer/pass-queue-derived manifest 应用之后再补 + fullscreen stage 请求;URP path 中 post/final stage 的存在性必须完全来自 `ScriptableRenderer` + active pass queue。 - `ConfigurePassQueueCameraFramePlanInstance` 必须在 planning 阶段为当前 renderer 和 `framePlanId` 生成一次 per-camera `RendererFramePlan`,冻结 active pass queue 中每个 pass 的当帧状态,并用同一份 plan 派生 stage manifest。`SupportsStageRenderGraph` @@ -400,6 +406,9 @@ Scene data 每个 camera frame 提取一次,然后由 pipeline 调整。 - URP stage planning 已收口到 renderer active pass queue 派生的 per-`framePlanId` `RendererFramePlan` 和 stage manifest。Stage support 和 stage recording 现在消费 planning 阶段保存的同一份冻结 plan, 关闭了 feature planning hook、support probe、recording 和各 stage 分别重建 pass queue 的重复事实源。 +- `CameraFramePlanBuilder` 已移除对 fullscreen stages 的通用尾部自动补齐;selected + `RenderPipelineAsset` 现在是 native plan policy 的唯一入口,managed URP path 不再保留第二个 + fullscreen stage planner。 - `ScriptableRenderPass.CreateFramePlanSnapshot` 已接入 `RendererFramePlan` 生成路径。多 camera planning 会冻结 每个 camera 当时的 pass 状态,后续 camera 对复用 pass 实例的 `Configure` 不应污染已生成的 frame plan。 - URP runtime-state invalidation 已覆盖 asset-level shadow/final-color settings 和 renderer-data-level diff --git a/engine/src/Rendering/Planning/CameraFramePlanBuilder.cpp b/engine/src/Rendering/Planning/CameraFramePlanBuilder.cpp index 6bc35e7c..1feb3033 100644 --- a/engine/src/Rendering/Planning/CameraFramePlanBuilder.cpp +++ b/engine/src/Rendering/Planning/CameraFramePlanBuilder.cpp @@ -5,62 +5,6 @@ namespace XCEngine { namespace Rendering { -namespace { - -bool UsesExplicitFullscreenSource( - const FullscreenPassRenderRequest& request, - CameraFrameColorSource source) { - return source == CameraFrameColorSource::ExplicitSurface && - HasValidColorTarget(request.sourceSurface); -} - -void ConfigureLegacyFullscreenStageRequests( - CameraFramePlan& plan) { - const bool postProcessExplicitlyConfigured = - plan.HasExplicitFullscreenStageConfiguration( - CameraFrameStage::PostProcess); - const bool finalOutputExplicitlyConfigured = - plan.HasExplicitFullscreenStageConfiguration( - CameraFrameStage::FinalOutput); - const bool hasPostProcess = - plan.postProcess.IsRequested(); - const bool hasFinalOutput = - plan.finalOutput.IsRequested(); - - if (!postProcessExplicitlyConfigured && - hasPostProcess && - !UsesExplicitFullscreenSource( - plan.postProcess, - plan.ResolveStageColorSource( - CameraFrameStage::PostProcess))) { - plan.RequestFullscreenStage( - CameraFrameStage::PostProcess, - CameraFrameColorSource::MainSceneColor, - hasFinalOutput); - } - - const bool canChainFromPostProcess = - hasPostProcess && - !UsesExplicitFullscreenSource( - plan.postProcess, - plan.ResolveStageColorSource( - CameraFrameStage::PostProcess)); - if (!finalOutputExplicitlyConfigured && - hasFinalOutput && - !UsesExplicitFullscreenSource( - plan.finalOutput, - plan.ResolveStageColorSource( - CameraFrameStage::FinalOutput))) { - plan.RequestFullscreenStage( - CameraFrameStage::FinalOutput, - canChainFromPostProcess - ? CameraFrameColorSource::PostProcessColor - : CameraFrameColorSource::MainSceneColor); - } -} - -} // namespace - std::vector CameraFramePlanBuilder::BuildPlans( const std::vector& requests, const RenderPipelineAsset* pipelineAsset) { @@ -89,8 +33,6 @@ void CameraFramePlanBuilder::ConfigurePlans( } else { ApplyDefaultRenderPipelineAssetCameraFramePlanPolicy(plan); } - - ConfigureLegacyFullscreenStageRequests(plan); } } diff --git a/engine/src/Rendering/Planning/Internal/CameraFrameFullscreenStagePlanner.cpp b/engine/src/Rendering/Planning/Internal/CameraFrameFullscreenStagePlanner.cpp index 46ac049a..064c94d5 100644 --- a/engine/src/Rendering/Planning/Internal/CameraFrameFullscreenStagePlanner.cpp +++ b/engine/src/Rendering/Planning/Internal/CameraFrameFullscreenStagePlanner.cpp @@ -53,27 +53,20 @@ void PlanCameraFrameFullscreenStages(CameraFramePlan& plan) { if (hasPostProcess) { plan.SetOwnedPostProcessSequence( SharePassSequence(std::move(postProcessSequence))); - plan.colorChain.usesGraphManagedSceneColor = true; - plan.colorChain.postProcess.source = CameraFrameColorSource::MainSceneColor; - plan.colorChain.postProcess.usesGraphManagedOutputColor = hasFinalOutput; - if (!hasFinalOutput) { - plan.postProcess.destinationSurface = plan.request.surface; - } + plan.RequestFullscreenStage( + CameraFrameStage::PostProcess, + CameraFrameColorSource::MainSceneColor, + hasFinalOutput); } if (hasFinalOutput) { plan.SetOwnedFinalOutputSequence( SharePassSequence(std::move(finalOutputSequence))); - plan.colorChain.usesGraphManagedSceneColor = true; - plan.colorChain.finalOutput.source = + plan.RequestFullscreenStage( + CameraFrameStage::FinalOutput, hasPostProcess ? CameraFrameColorSource::PostProcessColor - : CameraFrameColorSource::MainSceneColor; - plan.finalOutput.destinationSurface = plan.request.surface; - } - - if (plan.UsesGraphManagedOutputColor(CameraFrameStage::MainScene)) { - plan.ConfigureGraphManagedSceneSurface(); + : CameraFrameColorSource::MainSceneColor); } } diff --git a/tests/Rendering/unit/test_camera_scene_renderer.cpp b/tests/Rendering/unit/test_camera_scene_renderer.cpp index 5e6d2950..2ef5c21d 100644 --- a/tests/Rendering/unit/test_camera_scene_renderer.cpp +++ b/tests/Rendering/unit/test_camera_scene_renderer.cpp @@ -4444,6 +4444,49 @@ TEST(RenderPipelineHost_Test, PlansFullscreenStagesFromPipelineAssetPolicy) { EXPECT_TRUE(plan.IsFinalOutputStageValid()); } +TEST(RenderPipelineHost_Test, DoesNotPromoteFullscreenPassRequestFieldsAfterAssetPlanning) { + RenderPassSequence postProcessPasses; + + auto assetState = std::make_shared(); + assetState->configureCameraFramePlan = [&postProcessPasses]( + CameraFramePlan& plan) { + plan.postProcess.passes = &postProcessPasses; + }; + + auto allocationState = std::make_shared(); + 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); + + CameraRenderRequest request = {}; + request.context = CreateValidContext(); + request.surface = RenderSurface(320, 180); + request.surface.SetColorAttachment(&colorView); + request.surface.SetDepthAttachment(&depthView); + + RenderPipelineHost host(std::make_shared(assetState)); + const std::vector plans = + host.BuildFramePlans({ request }); + + ASSERT_EQ(plans.size(), 1u); + const CameraFramePlan& plan = plans[0]; + EXPECT_EQ(plan.postProcess.passes, &postProcessPasses); + EXPECT_FALSE( + plan.IsFullscreenStageRequested( + CameraFrameStage::PostProcess)); + EXPECT_FALSE(plan.UsesGraphManagedSceneColor()); + EXPECT_EQ( + plan.ResolveStageColorSource(CameraFrameStage::PostProcess), + CameraFrameColorSource::ExplicitSurface); +} + TEST(RenderPipelineHost_Test, ForwardsPipelineAssetLifetimeAndRenderCallsToCameraRenderer) { Scene scene("RenderPipelineHostScene");