diff --git a/docs/used/SRP_SharedNativeBackendSubstratePlan_2026-04-21_完成归档.md b/docs/used/SRP_SharedNativeBackendSubstratePlan_2026-04-21_完成归档.md new file mode 100644 index 00000000..7d3e477c --- /dev/null +++ b/docs/used/SRP_SharedNativeBackendSubstratePlan_2026-04-21_完成归档.md @@ -0,0 +1,90 @@ +# SRP Shared Native Backend Substrate Plan + +日期:2026-04-21 + +## 背景 + +前两个小阶段已经完成两件事: + +1. native scene draw contract 从 `NativeSceneRenderer` 收口成了 `SceneDrawBackend` +2. native host/runtime bridge 中代表底层执行体的命名,从 `renderer` 收口成了 `backend` + +但当前还有一个更深的结构问题没有彻底收干净: + +- managed `rendererIndex` 已经在按 Unity/URP 思路选择 `ScriptableRendererData` / `ScriptableRenderer` +- native bridge 仍然保留了 `GetPipelineBackendAsset(int rendererIndex)` 这条链路 +- `MonoManagedRenderPipelineStageRecorder::ResolveSceneDrawBackend(...)` 也还在按 `rendererIndex` 去尝试解析 contextual backend asset + +这会留下一个错误暗示: + +- 好像不同 `ScriptableRenderer` 需要切换不同 native backend + +这和当前目标路线不一致。按 Unity 的 SRP + URP 思路,这一阶段应该明确成: + +- managed `ScriptableRenderer` 负责选择 pass / stage 组织 +- native C++ 提供共享的 backend substrate / scene draw substrate +- `rendererIndex` 只影响 managed renderer 选择,不负责切 native backend + +## 本阶段目标 + +把当前桥接模型彻底收口成 “shared native backend substrate”: + +- managed asset runtime 对外只暴露共享 native backend asset +- native stage recorder 不再按 `rendererIndex` 解析 backend asset +- `rendererIndex` 保留给 managed renderer 选择和 planning/recording 上下文 +- host/runtime/managed 代码中的接口语义与实现保持一致,不再留下 future per-renderer backend 的假入口 + +## 为什么现在做 + +如果这层不先收口,后面继续做: + +- 更完整的 `ScriptableRendererFeature` +- renderer data 资源生命周期 +- SRP asset / renderer data 序列化 +- 最终的 C# 可定制渲染管线 + +都会建立在一条含混的桥接语义上。到时候用户会天然误解成: + +- “renderer slot = native backend slot” + +这会直接污染后续 API、文档、调试认知和资源生命周期设计。 + +## 改动范围 + +只做 shared native backend substrate 收口,不新增渲染功能,不碰 deferred,不碰 new editor。 + +主要涉及: + +- `engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h` +- `engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp` +- `engine/src/Scripting/Mono/MonoScriptRuntime.cpp` +- `engine/include/XCEngine/Rendering/Pipelines/ScriptableRenderPipelineHost.h` +- `engine/src/Rendering/Pipelines/ScriptableRenderPipelineHost.cpp` + +如有必要,少量同步到 managed C# 命名或注释,但不改当前 URP 行为。 + +## 预期结果 + +重构后,当前 SRP 主链应当表达成: + +- `RenderPipelineAsset` / managed SRP asset 决定使用哪个共享 native backend substrate +- `ScriptableRendererData` / `ScriptableRenderer` 决定每个 camera request 用哪个 renderer,以及该 renderer 录哪些 pass +- `ScriptableRenderPipelineHost` 绑定一个共享 native backend,并把它提供给 stage recorder +- `MonoManagedRenderPipelineStageRecorder` 只复用这个共享 backend,不再偷偷实现 per-renderer backend 切换 + +## 实施步骤 + +1. 收口 `ManagedRenderPipelineAssetRuntime` 接口,去掉基于 `rendererIndex` 的 backend asset 解析语义 +2. 收口 `MonoManagedRenderPipelineStageRecorder` 的 backend 解析逻辑,只保留共享 backend 绑定/兜底创建 +3. 检查 `ScriptableRenderPipelineHost` 与 `ManagedScriptableRenderPipelineAsset` 调用链,确保语义一致 +4. 编译 `XCEditor` +5. 运行旧版 `editor/bin/Debug/XCEngine.exe` 冒烟至少 10 秒,并确认新的 `SceneReady` +6. 归档计划,提交并推送 + +## 验证标准 + +- `cmake --build . --config Debug --target XCEditor` 成功 +- 运行 `editor/bin/Debug/XCEngine.exe` +- 冒烟至少 10 秒 +- `editor/bin/Debug/editor.log` 出现新的 `SceneReady` +- 本阶段提交只包含 SRP/rendering 主线相关代码与计划文档 diff --git a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h index df6ae627..5227700e 100644 --- a/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h +++ b/engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h @@ -62,7 +62,7 @@ private: std::shared_ptr ResolveManagedAssetRuntime() const; std::shared_ptr - ResolvePipelineBackendAsset() const; + ResolveSharedPipelineBackendAsset() const; ScriptableRenderPipelineHostAsset CreateExecutionHostAsset() const; @@ -101,14 +101,9 @@ public: } virtual std::shared_ptr - GetPipelineBackendAsset() const { + GetSharedPipelineBackendAsset() const { return nullptr; } - virtual std::shared_ptr - GetPipelineBackendAsset(int32_t rendererIndex) const { - (void)rendererIndex; - return GetPipelineBackendAsset(); - } virtual bool UsesNativeCameraFramePlanBaseline() const { return false; } diff --git a/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp b/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp index 5d57c5ba..e0591d97 100644 --- a/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp +++ b/engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp @@ -38,11 +38,11 @@ ManagedScriptableRenderPipelineAsset::ResolveManagedAssetRuntime() const { } std::shared_ptr -ManagedScriptableRenderPipelineAsset::ResolvePipelineBackendAsset() const { +ManagedScriptableRenderPipelineAsset::ResolveSharedPipelineBackendAsset() const { if (const std::shared_ptr runtime = ResolveManagedAssetRuntime(); runtime != nullptr) { - return runtime->GetPipelineBackendAsset(); + return runtime->GetSharedPipelineBackendAsset(); } return nullptr; @@ -53,7 +53,7 @@ ManagedScriptableRenderPipelineAsset::CreateExecutionHostAsset() const { const std::shared_ptr runtime = ResolveManagedAssetRuntime(); if (const std::shared_ptr pipelineBackendAsset = - ResolvePipelineBackendAsset(); + ResolveSharedPipelineBackendAsset(); pipelineBackendAsset != nullptr) { return ScriptableRenderPipelineHostAsset( pipelineBackendAsset, diff --git a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp index 894e6429..8c6b583d 100644 --- a/engine/src/Scripting/Mono/MonoScriptRuntime.cpp +++ b/engine/src/Scripting/Mono/MonoScriptRuntime.cpp @@ -1498,9 +1498,7 @@ public: bool TryGetDefaultFinalColorSettings( Rendering::FinalColorSettings& settings) const override; std::shared_ptr - GetPipelineBackendAsset() const override; - std::shared_ptr - GetPipelineBackendAsset(int32_t rendererIndex) const override; + GetSharedPipelineBackendAsset() const override; bool UsesNativeCameraFramePlanBaseline() const override; bool UsesNativeCameraFramePlanBaseline( int32_t rendererIndex) const override; @@ -1571,9 +1569,9 @@ private: mutable int32_t m_runtimeResourceVersion = 0; mutable uint32_t m_pipelineHandle = 0; mutable bool m_pipelineCreationAttempted = false; - mutable bool m_pipelineBackendAssetResolved = false; + mutable bool m_sharedPipelineBackendAssetResolved = false; mutable std::shared_ptr - m_pipelineBackendAsset = nullptr; + m_sharedPipelineBackendAsset = nullptr; }; class MonoManagedRenderPipelineStageRecorder final @@ -1607,7 +1605,7 @@ public: if (m_ownedSceneDrawBackend != nullptr) { m_ownedSceneDrawBackend->Shutdown(); } - m_ownedPipelineBackendAsset.reset(); + m_ownedSharedPipelineBackendAsset.reset(); m_supportsStageContextualMethod = nullptr; m_supportsStageMethod = nullptr; m_recordStageMethod = nullptr; @@ -1718,7 +1716,7 @@ public: managedContextState.stage = context.stage; managedContextState.graphContext = &context; Rendering::SceneDrawBackend* const sceneDrawBackend = - ResolveSceneDrawBackend(context.rendererIndex); + ResolveSceneDrawBackend(); if (sceneDrawBackend == nullptr) { return false; } @@ -1904,40 +1902,31 @@ private: return true; } - Rendering::SceneDrawBackend* ResolveSceneDrawBackend( - int32_t rendererIndex) { - const std::shared_ptr - contextualPipelineBackendAsset = - m_assetRuntime != nullptr - ? m_assetRuntime->GetPipelineBackendAsset( - rendererIndex) - : nullptr; - const std::shared_ptr - defaultPipelineBackendAsset = - m_assetRuntime != nullptr - ? m_assetRuntime->GetPipelineBackendAsset() - : nullptr; - if (m_boundSceneDrawBackend != nullptr && - contextualPipelineBackendAsset != nullptr && - contextualPipelineBackendAsset == - defaultPipelineBackendAsset) { + Rendering::SceneDrawBackend* ResolveSceneDrawBackend() { + if (m_boundSceneDrawBackend != nullptr) { return m_boundSceneDrawBackend; } - if (contextualPipelineBackendAsset == nullptr) { + const std::shared_ptr + sharedPipelineBackendAsset = + m_assetRuntime != nullptr + ? m_assetRuntime->GetSharedPipelineBackendAsset() + : nullptr; + if (sharedPipelineBackendAsset == nullptr) { return nullptr; } if (m_ownedSceneDrawBackend == nullptr || - contextualPipelineBackendAsset != m_ownedPipelineBackendAsset) { + sharedPipelineBackendAsset != + m_ownedSharedPipelineBackendAsset) { if (m_ownedSceneDrawBackend != nullptr) { m_ownedSceneDrawBackend->Shutdown(); } m_ownedSceneDrawBackend = Rendering::Internal::CreateSceneDrawBackendFromAsset( - contextualPipelineBackendAsset); - m_ownedPipelineBackendAsset = - contextualPipelineBackendAsset; + sharedPipelineBackendAsset); + m_ownedSharedPipelineBackendAsset = + sharedPipelineBackendAsset; } return m_ownedSceneDrawBackend.get(); @@ -1952,7 +1941,7 @@ private: std::vector> m_fullscreenPassPool = {}; Rendering::SceneDrawBackend* m_boundSceneDrawBackend = nullptr; std::shared_ptr - m_ownedPipelineBackendAsset = nullptr; + m_ownedSharedPipelineBackendAsset = nullptr; std::unique_ptr m_ownedSceneDrawBackend = nullptr; }; @@ -2195,29 +2184,23 @@ bool MonoManagedRenderPipelineAssetRuntime::TryGetDefaultFinalColorSettings( } std::shared_ptr -MonoManagedRenderPipelineAssetRuntime::GetPipelineBackendAsset() const { - return GetPipelineBackendAsset(-1); -} - -std::shared_ptr -MonoManagedRenderPipelineAssetRuntime::GetPipelineBackendAsset( - int32_t rendererIndex) const { +MonoManagedRenderPipelineAssetRuntime::GetSharedPipelineBackendAsset() const { if (!SyncManagedAssetRuntimeState()) { return nullptr; } - if (m_pipelineBackendAssetResolved) { - return m_pipelineBackendAsset; + if (m_sharedPipelineBackendAssetResolved) { + return m_sharedPipelineBackendAsset; } if (GetManagedAssetObject() == nullptr) { return nullptr; } - m_pipelineBackendAssetResolved = true; - m_pipelineBackendAsset = + m_sharedPipelineBackendAssetResolved = true; + m_sharedPipelineBackendAsset = Rendering::Internal::CreateDefaultPipelineBackendAsset(); - return m_pipelineBackendAsset; + return m_sharedPipelineBackendAsset; } bool MonoManagedRenderPipelineAssetRuntime::UsesNativeCameraFramePlanBaseline() @@ -2417,8 +2400,8 @@ bool MonoManagedRenderPipelineAssetRuntime::SyncManagedAssetRuntimeState() const } ReleaseManagedPipeline(); - m_pipelineBackendAsset.reset(); - m_pipelineBackendAssetResolved = false; + m_sharedPipelineBackendAsset.reset(); + m_sharedPipelineBackendAssetResolved = false; m_runtimeResourceVersion = runtimeResourceVersion; return true; } @@ -2488,8 +2471,8 @@ void MonoManagedRenderPipelineAssetRuntime::ReleaseManagedAsset() const { m_usesNativeCameraFramePlanBaselineContextualMethod = nullptr; m_configureRenderSceneSetupMethod = nullptr; m_configureDirectionalShadowExecutionStateMethod = nullptr; - m_pipelineBackendAsset.reset(); - m_pipelineBackendAssetResolved = false; + m_sharedPipelineBackendAsset.reset(); + m_sharedPipelineBackendAssetResolved = false; m_runtimeResourceVersionResolved = false; m_runtimeResourceVersion = 0; const bool ownsManagedAssetHandle = m_ownsManagedAssetHandle;