diff --git a/engine/include/XCEngine/Rendering/AGENTS.md b/engine/include/XCEngine/Rendering/AGENTS.md index f1a8d383..3aa9da6c 100644 --- a/engine/include/XCEngine/Rendering/AGENTS.md +++ b/engine/include/XCEngine/Rendering/AGENTS.md @@ -33,11 +33,13 @@ SceneRenderer - managed 侧产品骨架仍是: `ScriptableRenderPipelineAsset -> ScriptableRendererData -> ScriptableRenderer -> ScriptableRendererFeature/Pass` - builtin 和 SRP 现在都必须是显式可切换的顶层路径,而不是“SRP 隐式优先,builtin 只是兜底”。 +- `ScriptableRenderPipelineHost` 里的 native backend 是 managed SRP 的绘制后端,不是 SRP stage 录制失败时的顶层兜底。 ## 5. 当前硬边界 - `RenderPipelineFactory` 在无显式 asset、无托管配置、创建失败回退时,都必须先回 builtin,而不是回 `ScriptableRenderPipelineHost`。 - `MonoScriptRuntime::OnRuntimeStart()` 不得隐式写入 render pipeline 选择。 - builtin 私有 native feature 通道只能留在 native 内部使用。 +- managed SRP runtime 或 stage recorder 存在时,stage 组织权归 managed SRP;native backend 不得在 host 层隐式接管 `RecordStageRenderGraph`、`Render(...)` 或 scene-pass standalone stage。 - 下列能力不得再暴露给 managed / URP 公开层: `NativeSceneFeaturePassId` `ScriptableRenderContext.RecordNativeSceneFeaturePass(...)` @@ -66,6 +68,7 @@ SceneRenderer - 不要再把 builtin 私有 native feature 包成 public managed API 方便调用。 - 不要再让 “null 选择” 默认落到 `ScriptableRenderPipelineHost`。 - 不要把非通用产品层策略继续直接塞回 `BuiltinForwardPipeline`。 +- 不要让 `ScriptableRenderPipelineHost` 在 managed SRP 未支持或未录制某个 stage 时自动回退到 native backend;需要绘制时应通过 managed `ScriptableRenderContext` 显式调用 native draw 能力。 ## 8. 关键文件 - `engine/src/Rendering/Internal/RenderPipelineFactory.cpp` diff --git a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp index 44eb7c25..7023acd0 100644 --- a/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp +++ b/engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp @@ -14,6 +14,13 @@ std::shared_ptr CreateDefaultPipelineBackendAsset() { return Rendering::Internal::CreateDefaultPipelineBackendAsset(); } +bool UsesAuthoritativeStageRecorder( + const RenderPipelineStageRecorder* stageRecorder, + const ManagedRenderPipelineAssetRuntime* managedAssetRuntime) { + return stageRecorder != nullptr || + managedAssetRuntime != nullptr; +} + } // namespace ScriptableRenderPipelineHost::ScriptableRenderPipelineHost() @@ -103,6 +110,10 @@ bool ScriptableRenderPipelineHost::SupportsStageRenderGraph( return m_stageRecorder->SupportsStageRenderGraph(context); } + if (m_managedAssetRuntime != nullptr) { + return false; + } + return m_pipelineBackend != nullptr && m_pipelineBackend->SupportsStageRenderGraph(context); } @@ -117,9 +128,12 @@ bool ScriptableRenderPipelineHost::RecordStageRenderGraph( const RenderPipelineStageSupportContext supportContext = { context.stage, context.rendererIndex }; - if (m_stageRecorder->SupportsStageRenderGraph(supportContext)) { - return m_stageRecorder->RecordStageRenderGraph(context); - } + return m_stageRecorder->SupportsStageRenderGraph(supportContext) && + m_stageRecorder->RecordStageRenderGraph(context); + } + + if (m_managedAssetRuntime != nullptr) { + return false; } return m_pipelineBackend != nullptr && @@ -128,6 +142,12 @@ bool ScriptableRenderPipelineHost::RecordStageRenderGraph( bool ScriptableRenderPipelineHost::Render( const FrameExecutionContext& executionContext) { + if (UsesAuthoritativeStageRecorder( + m_stageRecorder.get(), + m_managedAssetRuntime.get())) { + return false; + } + if (!EnsureInitialized(executionContext.renderContext)) { return false; } @@ -140,6 +160,12 @@ bool ScriptableRenderPipelineHost::Render( const RenderContext& context, const RenderSurface& surface, const RenderSceneData& sceneData) { + if (UsesAuthoritativeStageRecorder( + m_stageRecorder.get(), + m_managedAssetRuntime.get())) { + return false; + } + if (!EnsureInitialized(context)) { return false; } @@ -186,12 +212,10 @@ bool ScriptableRenderPipelineHost::ConfigureDirectionalShadowExecutionState( RenderPass* ScriptableRenderPipelineHost::GetCameraFrameStandalonePass( CameraFrameStage stage, int32_t rendererIndex) const { - if (m_managedAssetRuntime != nullptr && - IsCameraFrameScenePassRequestStage(stage) && - SupportsStageRenderGraph( - RenderPipelineStageSupportContext{ - stage, - rendererIndex })) { + if (UsesAuthoritativeStageRecorder( + m_stageRecorder.get(), + m_managedAssetRuntime.get()) && + IsCameraFrameScenePassRequestStage(stage)) { return nullptr; }