48.性能优化-CPU-图形-SRP Batcher
48.1 知识点
SRP Batcher 是什么
SRP Batcher(Scriptable Render Pipeline Batcher) 是 Unity 在可编程渲染管线(URP、HDRP)中提供的一项 CPU 优化技术,主要用于降低材质切换带来的开销。
主要解决的问题:
- 每次 Draw Call 不仅要告诉 GPU 画哪个网格,还要上传材质常量(Shader 参数)。
- 不同物体即使使用同一个 Shader,只要材质不同,CPU 就要重新设置常量缓冲区(Constant Buffer)。
- 这一步称为 SetPass,开销很大,复杂场景里 CPU 花在切换材质的时间常常比真正发 Draw Call 还多。
- SRP Batcher 用于缓解这部分开销。
流程图对比:

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

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

SRP Batcher 的使用限制
Shader 兼容性:
- 对象使用的 Shader 必须与 SRP Batcher 兼容。
在 HDRP 和 URP 中,所有 Lit Shader 和 Unlit Shader 都符合这一要求(粒子版本除外)。 - 自定义 Shader 需满足:
- Shader 必须将所有引擎内置属性声明在名为
UnityPerDraw的常量缓冲区中。 - Shader 必须将所有材质属性声明在名为
UnityPerMaterial的常量缓冲区中。
- Shader 必须将所有引擎内置属性声明在名为
其它限制:
- 不能使用
MaterialPropertyBlock。
它用于在不复制材质的情况下给某个物体单独设置材质参数,会破坏 SRP Batcher 的批次一致性。 - 对象不能是粒子。
需要是MeshRenderer或SkinnedMeshRenderer(注意:蒙皮网格在新版本支持,2019 之前不支持)。
适合使用 SRP Batcher 的情况
适合的场景:
- 物体种类多(材质多),但 Shader 相同的场景。
这也是 SRP 管线适合移动平台的原因之一。 - 移动平台开发中,游戏对象往往 Shader 相同但材质不同。
SRP Batcher 虽不减少 Draw Call,但降低了 CPU 在 SetPass 时的开销。
举例:
- 大量使用同一 Shader 的物体:
场景里有上百种建筑、石头、家具,材质不同(颜色/贴图不同),但 Shader 相同。 - 大量动态物体但材质切换频繁:
大量移动的敌人、NPC、动态场景物体(破碎瓦片、掉落武器),每个都有自己材质但 Shader 相同。 - 使用 URP/HDRP 项目的大中型游戏:
特别是移动端,CPU 渲染线程常成为瓶颈时,SRP Batcher 能显著降低 CPU 耗时。
不适合的场景:
- 非 SRP 管线项目。
- Shader 不兼容的项目。
48.2 知识点代码
Lesson48_性能优化_CPU_图形_SRPBatcher.cs
public class Lesson48_性能优化_CPU_图形_SRPBatcher
{
#region 知识点一 SRP Batcher是什么?
// SRP Batcher(Scriptable Render Pipeline Batcher)
// 是 Unity 在可编程渲染管线,比如 URP、HDRP 中
// 提供的一项 CPU 优化技术
// 主要目的是用于降低材质切换带来的开销
// 主要解决的问题:
// 每次 Draw Call 不仅要告诉 GPU 画哪个网格,还要上传材质常量(Shader 参数)
// 不同物体哪怕使用同一个 Shader,但只要材质不同
// CPU 就要重新设置常量缓冲区(Constant Buffer),这一步就叫做 SetPass
// SetPass 开销很大,在复杂场景里,CPU 花在切换材质的时间常常比真正发 Draw Call 还多
// 而 SRP Batcher 就是用来解决这一问题的
// 主要原理:
// Unity 在 GPU 显存中为 Shader 的常量缓冲区分配了两个区域
// 1.材质缓冲区:
// 存储材质相关的参数(颜色、贴图索引等数据)
// 存放在 GPU 可缓存的大缓冲池里
// 不用每次切换材质都重新上传
// 2.物体缓冲区:
// 存储物体相关的参数(变换矩阵、光照探针等数据)
// 只更新每个物体独有的少量数据
// 在 CPU 这边:
// 只有内容变化时才更新数据
// 避免每帧为每个物体和材质重复准备和上传参数
// 达到的效果:
// Draw Call 数量不变
// 但 CPU 不再频繁计算和上传数据
// 大幅降低 CPU 到 GPU 的通信开销
// 说人话:
// SRP Batcher 是 SRP 下的一种 CPU 优化机制
// 通过把物体和材质数据缓存到 GPU,减少计算和上传开销
// 从而让同一 Shader 的不同材质也能高效批量绘制
// 严格意义上来说 SRP Batcher 并不是合批处理
// 因为 Draw Call 并不会减少
// 而是替代动态批处理的 CPU 优化方案
// 是一种用显存换性能的方案
// 注意:
// 1.SRP Batcher 并不会直接减少 Draw Call 数量
// 它并没有合并 Draw Call,每个物体依然会产生 Draw Call
// 本质上是让同一 Shader 的不同材质对象
// 共用已缓存的 GPU 常量缓冲
// 避免 CPU 反复上传数据
// 所以 Draw Call 数量不变
// 但 CPU 渲染线程时间(Render Thread)会显著下降
// 2.SRP Batcher 只能在 SRP 渲染管线,即 URP 和 HDRP 中使用
// 3.优先级问题
// 内置渲染管线中:静态批处理 > GPU Instancing > 动态批处理 > 单独绘制
// SRP 管线中:静态批处理 > SRP Batcher > GPU Instancing > 单独绘制
// 4.虽然 SRP Batcher 并不会实际减少 Draw Call
// 但在 Frame Debugger 里只会显示 SRP Batch 条目
// 而不是每个物体的单独 Draw Call
// 但是实际上 GPU 仍然在分别绘制这些物体,只是 CPU 端提交被优化、合并了
#endregion
#region 知识点二 如何开启SRP Batcher
// 在 Unity 2021 后,在 SRP 管线(URP、HDRP)中该功能默认开启,不允许关闭了
// 之前的版本中可以在 URP Asset 的 Inspector 窗口勾选开启
// 观察 SRP Batcher 是否工作,只需要用 Frame Debugger 查看渲染事件是否为 SRP Batch 即可
#endregion
#region 知识点三 SRP Batcher的使用限制
// 1.对象使用的 Shader 必须与 SRP Batcher 兼容
// 在 HDRP 和 URP 中,所有 Lit Shader 和 Unlit Shader 都符合这一要求(除了它们的粒子版本)
// 若要让一个自定义 Shader 与 SRP Batcher 兼容,它必须满足以下要求
// 1-1.Shader 必须将所有引擎内置属性声明在一个名为 UnityPerDraw 的常量缓冲区(Constant Buffer)里
// 1-2.Shader 必须将所有材质属性声明在一个名为 UnityPerMaterial 的常量缓冲区里
// 2.对象不能使用 MaterialPropertyBlocks
// MaterialPropertyBlock 是一个特殊的容器
// 用来在不复制材质的情况下,给某个物体单独设置材质参数
// 之后在讲解 GPU Instancing 相关 API 时会专门讲解
// 3.对象不能是粒子
// 对象需要是 MeshRenderer 或 SkinnedMeshRenderer
// 注意:蒙皮网格渲染器在新版本支持,2019 之前不支持
#endregion
#region 知识点四 适合使用SRP Batcher的情况
// 适合的场景:
// 它特别适合物体种类多(材质多),但是 Shader 相同的场景
// 这也是为什么 SRP 管线非常适合移动平台开发的原因之一
// 因为在移动平台开发时,游戏中的对象往往都是 Shader 相同,但是材质不同
// 它虽然不减少 Draw Call 数量,但是减少了 CPU 在 SetPass 时的开销
// 比如:
// 1.大量使用同一 Shader 的物体
// 场景里有上百种建筑、石头、家具,它们的材质不同(颜色/贴图不同),但是都用相同的 Shader
// 2.大量动态物体,但材质切换频繁
// 大量移动的敌人、NPC、动态场景物体(比如破碎的瓦片、掉落的武器),每个都有自己材质,但 Shader 相同
// 3.使用 URP/HDRP 项目的大中型游戏
// 特别是移动端,CPU 渲染线程经常成为瓶颈时,SRP Batcher 能显著降低 CPU 耗时
// 不适合的场景:
// 1.非 SRP 管线项目
// 2.Shader 不兼容
// 等等
#endregion
}
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com