UPL6-5——SRP Batcher
UPL6-5——SRP Batcher
SRP Batcher
SRP Batcher(Scriptable Render Pipeline Batcher)是 Unity 在可编程渲染管线,比如 URP、HDRP 中提供的一项 CPU 优化技术
主要目的是用于降低 材质切换 带来的开销
主要解决的问题:
每次 DrawCall 不仅要告诉 GPU 画哪个网格,还要上传 材质常量(Shader 参数),
不同物体哪怕使用同一个 Shader,但只要材质不同,CPU 就要重新设置常量缓冲区(Constant Buffer),这一步就叫做 SetPass
SetPass 开销很大,在复杂场景里,CPU 花在切换材质的时间常常比真正发 DrawCall 还多,而 SRP Batcher 就是用来解决这一问题的

主要原理:Unity 在 GPU 显存中为 Shader 的常量缓冲区分配了两个区域:
-
材质缓冲区:
存储材质相关的参数(颜色、贴图索引 等数据),存放在 GPU 可缓存的大缓冲池里,不用每次切换材质都重新上传
-
物体缓冲区:
存储物体相关的参数(变换矩阵、光照探针 等数据),只更新每个物体独有的少量数据
在 CPU 这边:只有内容变化时才更新数据,避免每帧为每个物体和材质重复准备和上传参数
达到的效果:DrawCall 数量不变,但 CPU 不再频繁计算和上传数据,大幅降低 CPU 到 GPU 的通信开销

说人话:
SRP Batcher 是 SRP 下的一种 CPU 优化机制,通过把物体和材质数据缓存到 GPU,减少计算和上传开销,从而让同一 Shader 的不同材质也能高效批量绘制
严格意义上来说 SRP Batcher 并不是合批处理,因为 DrawCall 并不会减少,而是替代动态批处理的 CPU 优化方案,是一种用显存换性能的方案
注意:
SRP Batcher 并不会直接减少 DrawCall 数量
它并没有合并 DrawCall,每个物体依然会产生 DrawCall,
本质上是让 同一 Shader 的不同材质对象,共用已缓存的 GPU 常量缓冲,
避免 CPU 反复上传数据,所以 Draw Call 数量不变,但 CPU 渲染线程时间(Render Thread)会显著下降SRP Batcher 只能在 SRP 渲染管线,即 URP 和 HDRP 中使用
优先级问题
- 内置渲染管线中:静态批处理 > GPU Instancing > 动态批处理 > 单独绘制
- SRP 管线中:静态批处理 > SRP Batcher > GPU Instancing > 单独绘制
虽然 SRP Batcher 并不会实际减少 DrawCall,但在 Frame Debugger 里只会显示 SRP Batch 条目,而不是每个物体的单独 DrawCall,但是实际上 GPU 仍然在分别绘制这些物体,只是 CPU 端提交被优化、合并了
如何开启 SRP Batcher
在 Unity 2021 后,在 SRP 管线(URP、HDRP)中该功能默认开启,不允许关闭了
之前的版本中可以在 URP Asset 中的 Inspector 窗口勾选开启
观察 SRP Batcher 是否工作,只需要用 Frame Debugger 查看渲染事件是否为 SRP Batch 即可

SRP Batcher 的使用限制
-
对象使用的 Shader 必须与 SRP Batcher 兼容
在 HDRP 和 URP 中,所有 Lit Shader 和 Unlit Shader 都符合这一要求(除了它们的粒子版本)
若要让一个自定义 Shader 与 SRP Batcher 兼容,它必须满足以下要求- Shader 必须将所有引擎内置属性声明在一个名为
UnityPerDraw的常量缓冲区(Constant Buffer)里 - Shader 必须将所有材质属性声明在一个名为
UnityPerMaterial的常量缓冲区里
- Shader 必须将所有引擎内置属性声明在一个名为
-
对象不能使用
MaterialPropertyBlock
MaterialPropertyBlock 是一个特殊的容器,用来在 不复制材质的情况下,给某个物体单独设置材质参数
之后在讲解 GPU Instancing 会提到 -
对象不能是粒子
对象需要时
MeshRenderer 或SkinnedMeshRenderer注意:蒙皮网格渲染器
SkinnedMeshRenderer在新版本支持,Unity 2019 之前不支持
适合使用 SRP Batcher 的情况
适合的场景:
SRP Batcher 特别适合物体种类多(材质多),但是 Shader 相同的场景
这也是为什么 SRP 管线非常适合移动平台开发的原因之一
因为在移动平台开发时,游戏中的对象往往都是 Shader 相同,但是材质不同
它虽然不减少 DrawCall 数量,但是减少了 CPU 在 SetPass 时的开销
比如:
-
大量使用同一 Shader 的物体
场景里有上百种建筑、石头、家具,它们的材质不同(颜色 / 贴图不同),但是都用相同的 Shader
-
大量动态物体,但材质切换频繁
大量移动的敌人、NPC, 动态场景物体(比如破碎的瓦片、掉落的武器),每个都有自己材质,但 Shader 相同
-
使用 URP / HDRP 项目的大中型游戏
特别是 移动端,CPU 渲染线程经常成为瓶颈时,SRP Batcher 能显著降低 CPU 耗时
不适合的场景:
- 非 SRP 管线项目
- Shader 不兼容
等等
