Files
XCEngine/docs/plan/SRP_Runtime_v2_2026-04-18.md

349 lines
11 KiB
Markdown
Raw Normal View History

# 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 rendererrenderer 再组织 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 组织层。**