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