# SRP Runtime v2 计划 2026-04-18 ## 1. 结论 当前阶段的下一步,不是继续做 editor 对接,也不是直接开做 deferred,更不是马上把阴影、体积、高斯这些效果全部搬到 C#。 下一阶段的正确主线是: `Native RenderGraph / Native Scene Renderer` `-> Managed SRP Runtime v2` `-> Managed Renderer / Feature / Pass 组织层` `-> 之后再开正式的 URP-like package` 换句话说,`SRP runtime v1` 已经把“managed pipeline 能创建、能被 native 持有、能参与 stage record”这条链路打通了; `SRP runtime v2` 要解决的是另一件更关键的事: **让 managed 侧不再只是“在 ScriptableRenderPipeline 里手写 stage”,而是正式进入 Unity/URP 风格的 `Renderer / Feature / Pass` 组织模型。** --- ## 2. 当前状态判断 从现有代码看,下面这些能力已经成立: 1. `RenderGraph`、`CameraFramePlan`、stage dispatch、compile、execute 已经是工作状态。 2. `ScriptableRenderPipelineHost` 已经能作为 native 宿主,组合 `stage recorder + fallback renderer`。 3. `ManagedScriptableRenderPipelineAsset` 已经不只是 descriptor 空壳,能够通过 bridge 创建 managed asset runtime。 4. `MonoScriptRuntime` 已经提供真实的 `ManagedRenderPipelineBridge`,不再只是测试 seam。 5. `ScriptableRenderContext` 已经有最小可用能力,能: - `RecordScene()` - `RecordScenePhase(...)` - `RecordSceneInjectionPoint(...)` - `RecordFullscreenPass(...)` 6. managed pipeline 已经能通过 `ScriptableRenderContext` 驱动 native `NativeSceneRecorder` 和 fullscreen pass sequence。 7. `ScriptableRenderPipelineAsset` 已经可以参与: - `ConfigureCameraRenderRequest(...)` - `ConfigureCameraFramePlan(...)` - `GetDefaultFinalColorSettings()` 也就是说,**SRP runtime 的“宿主打通”问题已经不是主矛盾了。** 当前真正的主矛盾变成了: 1. managed 侧还没有 `ScriptableRenderer` 2. managed 侧还没有 `ScriptableRendererFeature` 3. managed 侧还没有 `ScriptableRenderPass` 4. managed 侧还没有 `RenderPassEvent` 5. pipeline 仍然直接在自己内部录制 stage,缺少可组合的 renderer 层 这意味着你现在虽然已经能“用 C# 自定义渲染”,但它还不是 Unity/URP 那种成熟形态。 现在的形态更接近: `Pipeline 直接写 RenderGraph 录制逻辑` 而不是: `Pipeline -> Renderer -> Feature -> Pass` --- ## 3. 为什么下一步必须先做这个 如果这一层不先补起来,后面会出现三个结构性问题: ### 3.1 自定义能力会卡死在 `ScriptableRenderPipeline` 当前用户要改渲染逻辑,主要方式还是: 1. 继承 `ScriptableRenderPipeline` 2. 覆盖 `SupportsStageRenderGraph(...)` 3. 覆盖 `RecordStageRenderGraph(...)` 4. 直接手写 `RecordScenePhase / RecordSceneInjectionPoint / RecordFullscreenPass` 这条路能做 demo,但不能支撑成熟工程。 因为它缺少: 1. renderer 内部 pass 队列 2. feature 注入点 3. renderer data / pipeline data 4. 面向 camera/frame 的稳定数据载体 继续沿这条路堆功能,最后只会变成“能工作的脚本版 builtin forward”,而不是 Unity 意义上的 SRP/URP。 ### 3.2 未来的阴影、后处理、体积、高斯没地方上移 你之前关心的那些东西,长期来看确实应该逐步从 C++ builtin 组织层往更高层移动,但它们要上移的不是裸 `Pipeline`,而是: 1. `Renderer` 2. `RendererFeature` 3. `RenderPass` 4. `RendererData` 如果这层不存在,那后面谈“把 shadow 组织权搬到 URP 层”“把 volumetric/gassian 搬到包层”,都会没有落点。 ### 3.3 未来正式做 URP-like package 会缺承接面 真正的 URP-like package 不是只多几个 C# 类名,而是至少要有: 1. `PipelineAsset` 2. `RendererData` 3. `Renderer` 4. `RendererFeature` 5. `RenderPassEvent` 6. `RenderPass` 这几个层次如果不先在 SRP runtime 里长出来,后面直接开做 URP-like package 只会是壳子工程。 --- ## 4. 本阶段目标 本阶段只做一件事: **把当前“managed pipeline 直接录 stage”的模型,升级成“managed pipeline 驱动 managed renderer,renderer 再组织 feature/pass”的模型。** 收口后应该形成这样的关系: `ScriptableRenderPipelineAsset` `-> ScriptableRenderPipeline` `-> ScriptableRenderer` `-> ScriptableRendererFeature` `-> ScriptableRenderPass` `-> ScriptableRenderContext` `-> Native RenderGraph / NativeSceneRenderer` 这一步完成后,你这个引擎才算真正进入“能继续往 Unity SRP/URP 方向长”的状态。 --- ## 5. 本阶段明确不做的内容 这一阶段不做下面这些事: 1. 不做 deferred pipeline。 2. 不做 lightmap / baking。 3. 不做 editor 侧 inspector、资源面板、renderer asset 可视化编辑。 4. 不把阴影、体积、高斯、后处理全部迁到 C#。 5. 不直接暴露 raw RHI、raw RenderGraph handle 给脚本层。 6. 不为了兼容临时方案而长期保留双轨 API。 注意: 这不是说这些东西以后不做,而是说**现在最值钱的一刀不是它们**。 现在最值钱的是先把 renderer 组织层做对。 --- ## 6. 目标架构 ### 6.1 继续留在 C++ 的部分 1. `RHI` 2. `RenderGraph` 3. frame planning / stage dispatch / graph compile / execute 4. scene extraction / culling / frame data 5. native scene renderer 执行内核 6. shadow / fullscreen / scene phase 的底层执行 primitive ### 6.2 开始在 managed 侧稳定下来的部分 1. `ScriptableRenderPipelineAsset` 2. `ScriptableRenderPipeline` 3. `ScriptableRenderer` 4. `ScriptableRendererFeature` 5. `ScriptableRenderPass` 6. `RenderPassEvent` 7. `RenderingData / CameraData` 这类组织层数据 ### 6.3 这一阶段的核心原则 1. C++ 负责执行内核,不负责未来用户级管线组织。 2. managed 负责 renderer 组织,不直接持有底层 RHI 细节。 3. `BuiltinForwardPipeline` 继续做默认 native backend,但不再是未来自定义渲染的最终承载层。 4. shadow / volumetric / gaussian 这类东西后续上移时,上移的是“组织权”,不是把所有 draw code 都改成 C#。 --- ## 7. 分阶段实施 ### Phase A: 建立 managed renderer 基础抽象 先把 managed 侧最基础的几块搭出来: 1. `ScriptableRenderer` 2. `ScriptableRendererFeature` 3. `ScriptableRenderPass` 4. `RenderPassEvent` 5. `RenderingData v1` 6. `CameraData v1` 第一版不要追求大而全,只解决最小闭环: 1. pass 能声明执行时机 2. renderer 能收集 pass 3. feature 能往 renderer 注入 pass 4. pipeline 能把 camera/frame 数据传给 renderer ### Phase B: 建立 renderer 的执行骨架 这一阶段要解决的是: 1. `ScriptableRenderer.EnqueuePass(...)` 2. pass 按 `RenderPassEvent` 排序 3. renderer 根据 event 把 pass 映射到当前已有的 native 能力: - `RecordScenePhase(...)` - `RecordSceneInjectionPoint(...)` - `RecordFullscreenPass(...)` 4. renderer 能组织默认的主场景录制顺序 这里的关键不是“把所有 pass 都写复杂”,而是先把**组织模型**做出来。 ### Phase C: 做一个最小前向 renderer 在 managed 侧做第一条真正能跑的 renderer 主链: 1. 默认 opaque pass 2. 默认 skybox pass 3. 默认 transparent pass 4. 默认 post-process/fullscreen pass 5. 允许 feature 在标准 injection point 前后插入 pass 注意这里的“前向 renderer”还不是最终版 URP,只是: **一个 SRP runtime v2 上的 first-party renderer 验证样板。** ### Phase D: 把 pipeline asset 和 renderer data 关系收清楚 这一阶段要让 `ScriptableRenderPipelineAsset` 不再只是“创建 pipeline”,还要能稳定持有 renderer 配置关系。 第一版建议先做到: 1. asset 持有一个默认 renderer data 2. pipeline 从 asset 创建 renderer 3. renderer feature 由 renderer data 决定启用顺序 4. camera/frame 规划仍然通过现有 planning context 接入 也就是说,要先有: `PipelineAsset -> RendererData -> Renderer` 这条关系。 ### Phase E: 替换 probe 级实现,形成正式 smoke path 这一阶段不再满足于 probe/demo,而是要形成正式可回归的主链: 1. 用 renderer/pass 模型重做当前 managed forward probe 2. 验证主场景 + fullscreen 仍然能工作 3. 验证 pipeline 切换时生命周期正确 4. 验证 native fallback 路径仍然可用 这一步收口后,才算本阶段真正完成。 --- ## 8. 第一批要改的文件 ### Managed 侧 优先会落在这些位置: 1. `managed/XCEngine.ScriptCore/ScriptableRenderPipelineAsset.cs` 2. `managed/XCEngine.ScriptCore/ScriptableRenderPipeline.cs` 3. `managed/XCEngine.ScriptCore/ScriptableRenderContext.cs` 4. 新增 `managed/XCEngine.ScriptCore/Rendering/*` 或等价目录 5. `managed/GameScripts/RenderPipelineApiProbe.cs` 第一批大概率会新增这些类型: 1. `ScriptableRenderer` 2. `ScriptableRendererFeature` 3. `ScriptableRenderPass` 4. `RenderPassEvent` 5. `RenderingData` 6. `CameraData` ### Native 侧 native 这一阶段不是主战场,但仍可能需要补桥接: 1. `engine/src/Scripting/Mono/MonoScriptRuntime.cpp` 2. `engine/include/XCEngine/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.h` 3. `engine/src/Rendering/Pipelines/ManagedScriptableRenderPipelineAsset.cpp` 只有当 managed renderer 需要额外上下文时,才增加新的 internal call / bridge 数据。 原则是: **能用现有 `ScriptableRenderContext` 表达的,就不继续扩 raw native API。** --- ## 9. 验收标准 这一阶段收口时,至少要同时满足下面这些条件: 1. managed 侧存在正式的 `Renderer / Feature / Pass` 基础抽象。 2. `ScriptableRenderPipeline` 不再是唯一的直接录制组织层。 3. 一个 managed forward renderer 能通过 pass 队列稳定跑通主场景和 fullscreen。 4. feature 可以在标准 injection point 上插入 pass。 5. pipeline asset 能稳定持有 renderer 配置关系。 6. native `RenderGraph`、`NativeSceneRenderer`、fallback renderer 路径不被破坏。 7. editor 编译通过,并完成基础 smoke test。 只要上面任意一条不成立,这一阶段都不能算收口。 --- ## 10. 完成本阶段之后,下一步才是什么 等这一阶段收口之后,下一步才适合正式进入更像 URP 的层级: 1. `UniversalRenderPipelineAsset` 2. `UniversalRendererData` 3. `UniversalRenderer` 4. 官方 first-party `RendererFeature` 5. 更成熟的 `RenderPassEvent` 6. 逐步把 shadow / volumetric / gaussian / post-process 的组织权上移 也就是说: **不是现在不能往 Unity 的 SRP/URP 方向走,而是现在要先把“SRP runtime 的 renderer 层”补齐。** 这一步做对了,后面你再做: 1. URP-like package 2. deferred 3. lightmap 4. renderer asset 资源化 5. editor 可视化配置 都会顺很多。 --- ## 11. 下一刀从哪里下 下一步建议直接从 managed 侧开刀,顺序如下: 1. 先加 `ScriptableRenderer / ScriptableRenderPass / RenderPassEvent` 基础类型。 2. 再把当前 probe 级 `ManagedForwardRenderPipelineProbe` 改造成 renderer 驱动。 3. 确认 renderer/pass 模型能复用现有 `ScriptableRenderContext`。 4. 只有在 managed 侧明确缺上下文时,再补 native internal call。 简单说,下一刀不是继续修 C++ 渲染内核,而是: **开始正式搭 managed renderer 组织层。**