# SRP Mainline 2026-04-16 ## 1. 结论 现在可以正式切到 `SRP` 主线。 但这里的“切到 SRP 主线”不是直接开做 `URP` 包层,也不是马上把所有渲染效果搬到 C#。 当前最正确的主线是: `Native RenderGraph / Planning / Execution` `-> Managed SRP Runtime` `-> Managed Forward Pipeline v1` `-> URP-like 官方包层` 也就是说,下一阶段的真正目标不是“做一个叫 SRP 的壳”,而是先把: 1. `managed pipeline asset` 真正实例化出来 2. `managed pipeline` 真正被 native 持有并回调 3. `C#` 真正能组织主场景 render graph 录制 这三件事做成闭环。 在这之前,`URP-like package` 还不能开工。 ## 2. 当前状态判断 ### 2.1 已经具备的东西 当前 native 底座已经够你正式进入 SRP 主线: 1. `RenderGraph` 已经不是空壳,builder / compiler / executor 都在工作。 2. `ScriptableRenderPipelineHost` 已经能把 “stage recorder + fallback renderer” 组合起来。 3. `BuiltinForwardPipeline` 已经支持按 `MainScene` stage 录制 render graph。 4. 默认 pipeline 工厂已经能从 “managed or default asset” 入口走。 这说明 native 侧已经有了 SRP runtime 可以依附的承接点。 ### 2.2 还没具备的东西 当前 managed 侧还远远没有形成真正的 SRP runtime: 1. `GraphicsSettings` 现在只是在 native 里记录了一个 pipeline asset 类型描述,不是 asset 实例。 2. `ManagedScriptableRenderPipelineAsset` 现在只是 “fallback host + optional stage recorder bridge”。 3. 真正的 `ManagedRenderPipelineBridge` 实现根本还没接进运行时,当前只有测试里在 mock。 4. `ScriptableRenderPipelineAsset` 只有 `CreatePipeline()` 占位,没有 frame/request planning 能力。 5. `ScriptableRenderPipeline` 只有 `SupportsStageRenderGraph/RecordStageRenderGraph` 两个最小占位方法,而且没有上下文对象。 6. C# 层没有 `ScriptableRenderContext`、没有 `CommandBuffer`、没有 `RendererFeature`、没有 `Renderer` 抽象。 所以当前状态不是 “SRP 已经差不多了”,而是: `native SRP host seam 已经有了` 但 `managed SRP runtime 还没开始真正落地` ## 3. 当前最核心的架构根因 ### 3.1 现在的 managed 入口只是“选择器”,不是“运行时” 当前 `GraphicsSettings.renderPipelineAssetType` 的语义本质上是: `把一个 C# 类型名写回 native` 它没有解决下面这些真正关键的问题: 1. asset 谁实例化 2. pipeline 谁实例化 3. 生命周期谁管理 4. native 如何回调到具体 pipeline 对象 5. pipeline 如何持有自己的配置 这意味着现在的 API 形态本身还不是未来可长期保留的最终形态。 ### 3.2 当前 bridge 只允许“补一个 stage recorder”,这还不是 SRP 现在 `ManagedScriptableRenderPipelineAsset` 的工作方式是: 1. 先创建 native fallback host 2. 再给 host 塞一个可选 `stage recorder` 这条路只能得到: `C# 向 builtin forward 注入一个 graph 录制钩子` 而不是: `C# 自己拥有一条 render pipeline` 如果这条边界不改,后面做出来的只会是“脚本包装版 builtin forward”,不是 Unity 意义上的 `SRP`。 ### 3.3 当前 pipeline API 颗粒度太粗,无法支撑未来 SRP/URP 现在 managed pipeline 只有: 1. `SupportsStageRenderGraph(CameraFrameStage)` 2. `RecordStageRenderGraph(CameraFrameStage)` 问题是它没有: 1. frame context 2. camera context 3. render graph builder/context wrapper 4. scene draw / fullscreen / blit / renderer feature 注入接口 5. request/frame planning hook 这意味着即使把 bridge 打通,C# 也拿不到足够的组织能力。 ### 3.4 当前 `BuiltinForwardPipeline` 仍然太像“完整管线”,还不像“可被 SRP 调度的 renderer” 现在 builtin forward 内部已经有: 1. `SceneRenderFeatureHost` 2. scene phase 3. stage graph builder 但这些能力大部分仍然锁在 `BuiltinForwardPipeline` 这个整管线对象内部。 对未来 SRP 来说,更正确的方向应该是: 1. `BuiltinForward` 退化为 native 默认 renderer 实现 2. 把可复用的 scene rendering contract 抽成稳定 native renderer API 3. 让 managed pipeline 调用这个 renderer API 组织主场景,而不是直接操纵 `BuiltinForwardPipeline` 私有实现 ### 3.5 当前 asset API 太弱,无法承担 Unity 风格 pipeline asset 角色 Unity 里的 pipeline asset 至少要承担: 1. 创建 pipeline 实例 2. 保存 renderer 配置 3. 保存阴影/后处理/renderer data 等默认策略 4. 驱动 camera/frame 规划策略 而现在的 managed asset 还没有这些入口。 这会直接阻塞未来: 1. `URP Asset` 2. `RendererData` 3. `RendererFeature` 4. shadow/post-process 默认策略迁移 ## 4. 正确目标架构 正确的长期结构应该是: `RHI` `-> Native Render Kernel` `-> Native RenderGraph` `-> Native Renderer Contract` `-> Managed SRP Runtime` `-> Managed Universal Pipeline Package` `-> 用户自定义 Pipeline / Feature / Pass` 其中边界必须明确: ### 4.1 留在 C++ 的东西 1. `RHI` 2. `RenderGraph` 3. planning / execution 主框架 4. scene extraction / culling / resource lifetime 5. native draw/fullscreen/feature primitive 6. builtin renderer 的底层实现 ### 4.2 去到 managed 的东西 1. `ScriptableRenderPipelineAsset` 2. `ScriptableRenderPipeline` 3. `ScriptableRenderContext` 4. `UniversalRenderPipelineAsset` 5. `UniversalRenderer / RendererFeature / RenderPass` 6. 用户自定义管线逻辑 ### 4.3 不应该长期停留在 C++ builtin pipeline 里的东西 这些能力最终应该逐步上移到 `URP-like package` 的组织层: 1. 阴影默认策略 2. post-process 组合策略 3. gaussian / volumetric / custom effect 的注入时机 4. renderer feature 的启用/排序/注入逻辑 但注意: “上移”指的是组织和调度上移,不是把底层 draw code 全部改成 C#。 ## 5. 执行顺序 ### Step 1: 先做通用 managed object runtime 这是第一刀,必须先做。 目标: 1. 在 `MonoScriptRuntime` 里补通用 managed object 创建/持有/释放能力 2. 不再只支持 `ScriptComponent` 实例和 `GameObject/Component` wrapper 3. 能按类描述创建任意 managed 对象 4. 能持有 GC handle 5. 能反射调用实例方法 6. 能稳定记录异常并向 native 返回失败 这一步是后面所有 SRP runtime 的硬前提。 没有这个,asset/pipeline 实例生命周期根本没法成立。 ### Step 2: 把 managed pipeline asset 从“类型描述”提升成“真实 runtime 对象” 目标: 1. native 不再只拿到 `assembly/namespace/class` 描述 2. native 能真正创建一个 managed asset 实例 3. managed asset 能产出 managed pipeline 实例 4. runtime 能持有 asset/pipeline 的生命周期 这一阶段里,`GraphicsSettings.renderPipelineAssetType` 可以临时继续作为 bootstrap 入口, 但 native 内部不能再停留在 descriptor-only 语义。 后面如果你要彻底对齐 Unity,再把 public API 从 `Type` 收敛到 asset instance。 ### Step 3: 实现真正的 managed render pipeline bridge 目标: 1. 由 `MonoScriptRuntime` 提供真实的 `ManagedRenderPipelineBridge` 2. `ManagedScriptableRenderPipelineAsset` 不再只接测试 mock 3. bridge 负责创建绑定到具体 managed pipeline 实例的 recorder/runtime object 4. native `ScriptableRenderPipelineHost` 能稳定回调到对应 managed pipeline 注意: 这一步不能继续维持“只有一个全局空 bridge”的临时状态。 ### Step 4: 扩展 managed asset / pipeline API 当前 API 太弱,必须补接口。 至少要补到: 1. asset 侧有 request/frame planning 钩子 2. pipeline 侧有真正的 record context 3. pipeline 侧能拿到 camera/stage/frame 语义 4. pipeline 侧不再只有裸 `CameraFrameStage` 推荐的第一版方向: 1. `ScriptableRenderPipelineAsset` - `CreatePipeline()` - `ConfigureCameraRenderRequest(...)` - `ConfigureCameraFramePlan(...)` - `GetDefaultFinalColorSettings()` 或等价设置入口 2. `ScriptableRenderPipeline` - `SupportsStageRenderGraph(...)` - `RecordStageRenderGraph(...)` - 参数升级为真正 context,而不是只有 stage enum ### Step 5: 建立 `ScriptableRenderContext v1` 这是第二个根问题。 如果没有 `ScriptableRenderContext`,C# 根本无法真正组织管线。 第一版不要直接暴露 RHI,要暴露“受控的 native renderer contract”: 1. record graph pass 2. 调用 builtin scene renderer 绘制 opaque / skybox / transparent 3. 执行 fullscreen / blit 4. 访问必要的 frame blackboard / source/target 5. 注入 renderer feature/pass 原则: 1. 不把 native 内部 planning 细节直接暴露给 C# 2. 不把 `RenderGraphTextureHandle`、`RenderSurface` 全量裸暴露成最终 API 3. 先做受控 wrapper,再决定哪些能力继续上放 ### Step 6: 把 builtin forward 拆成可复用的 native renderer contract 这一刀非常关键。 目标: 1. 不让 managed pipeline 直接依赖 `BuiltinForwardPipeline` 私有实现 2. 把主场景绘制能力抽成稳定 native renderer API 3. 让 builtin forward 退化为默认实现,而不是未来所有 SRP 的硬编码中心 正确方向类似: `BuiltinForwardSceneRenderer` 或等价的 `UniversalRendererNativeBackend` 它至少要能被 managed 调度: 1. 主场景 phase 绘制 2. feature injection point 3. shadow sampling 相关约束 4. scene setup / pass begin/end ### Step 7: 做一条最小可用 managed forward pipeline 到这一步,才算真正开始“跑 SRP 主线”。 验收标准不是有类名,而是: 1. C# managed pipeline 可以被创建 2. managed pipeline 可以稳定回调 3. managed pipeline 可以录 `MainScene` graph 4. 这条 managed pipeline 可以替代当前 builtin forward 跑出主场景 这个阶段不要急着搬阴影/体积/高斯的全部组织权。 先把主链跑通。 ### Step 8: 再开 URP-like package 只有当 Step 7 完成,才适合正式开: `UniversalRenderPipelineAsset` `UniversalRendererData` `UniversalRenderer` `RendererFeature` `RenderPassEvent` 到这时才开始逐步把: 1. 阴影策略 2. post-process 组合 3. 体积/高斯等特性注入 从当前 native builtin 组织层往 managed package 迁。 ## 6. 本阶段明确不做的事 现在不应该做: 1. 直接开 `URP` 包 2. 直接做 deferred pipeline 3. 直接把所有阴影/体积/高斯逻辑搬上 C# 4. 直接暴露一堆 raw native internal type 给脚本 这些都会把架构做歪。 ## 7. 第一阶段收口标准 下面这些条件成立,才算 `SRP runtime v1` 收口: 1. 运行时存在真实的 managed bridge,而不是测试 mock 2. native 能创建并持有 managed asset 与 managed pipeline 实例 3. managed pipeline 能稳定参与 camera frame graph 录制 4. managed forward pipeline 能替代 builtin forward 跑通主场景 5. builtin forward 仍保留 native fallback 路径 6. editor / runtime 渲染不会因为切到 managed pipeline 而失稳 ## 8. 下一步从哪里下刀 下一步不要先碰 `URP`,也不要先改渲染效果组织。 第一刀就应该是: `MonoScriptRuntime -> 通用 managed object runtime -> 真实 ManagedRenderPipelineBridge` 原因很简单: 当前最根的缺口不是某个 pass,不是某个 renderer feature,也不是 shader。 而是: `managed pipeline 在运行时根本还不存在` 这个根因不先解决,后面所有“SRP API”“URP 包”“阴影搬迁”都会变成空中楼阁。