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 就是用来解决这一问题的

SROShaderPass

主要原理:Unity 在 GPU 显存中为 Shader 的常量缓冲区分配了两个区域:

  1. 材质缓冲区:

    存储材质相关的参数(颜色、贴图索引 等数据),存放在 GPU 可缓存的大缓冲池里,不用每次切换材质都重新上传

  2. 物体缓冲区:

    存储物体相关的参数(变换矩阵、光照探针 等数据),只更新每个物体独有的少量数据

在 CPU 这边:只有内容变化时才更新数据,避免每帧为每个物体和材质重复准备和上传参数
达到的效果:DrawCall 数量不变,但 CPU 不再频繁计算和上传数据,大幅降低 CPU 到 GPU 的通信开销

image

说人话:
SRP Batcher 是 SRP 下的一种 CPU 优化机制,通过把物体和材质数据缓存到 GPU,减少计算和上传开销,从而让同一 Shader 的不同材质也能高效批量绘制
严格意义上来说 SRP Batcher 并不是合批处理,因为 DrawCall 并不会减少,而是替代动态批处理的 CPU 优化方案,是一种用显存换性能的方案

注意:

  1. SRP Batcher 并不会直接减少 DrawCall 数量

    它并没有合并 DrawCall,每个物体依然会产生 DrawCall,
    本质上是让 同一 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 并不会实际减少 DrawCall,但在 Frame Debugger 里只会显示 SRP Batch 条目,而不是每个物体的单独 DrawCall,但是实际上 GPU 仍然在分别绘制这些物体,只是 CPU 端提交被优化、合并了

如何开启 SRP Batcher

在 Unity 2021 后,在 SRP 管线(URP、HDRP)中该功能默认开启,不允许关闭了
之前的版本中可以在 URP Asset 中的 Inspector 窗口勾选开启
观察 SRP Batcher 是否工作,只需要用 Frame Debugger 查看渲染事件是否为 SRP Batch 即可

image

SRP Batcher 的使用限制

  1. 对象使用的 Shader 必须与 SRP Batcher 兼容

    在 HDRP 和 URP 中,所有 Lit Shader 和 Unlit Shader 都符合这一要求(除了它们的粒子版本)
    若要让一个自定义 Shader 与 SRP Batcher 兼容,它必须满足以下要求

    1. Shader 必须将所有引擎内置属性声明在一个名为 UnityPerDraw 的常量缓冲区(Constant Buffer)里
    2. Shader 必须将所有材质属性声明在一个名为 UnityPerMaterial 的常量缓冲区里
  2. 对象不能使用 MaterialPropertyBlock

    MaterialPropertyBlock​ 是一个特殊的容器,用来在 不复制材质的情况下,给某个物体单独设置材质参数
    之后在讲解 GPU Instancing 会提到

  3. 对象不能是粒子

    对象需要时 MeshRenderer​ 或 SkinnedMeshRenderer

    注意:蒙皮网格渲染器 SkinnedMeshRenderer 在新版本支持,Unity 2019 之前不支持

适合使用 SRP Batcher 的情况

适合的场景:
SRP Batcher 特别适合物体种类多(材质多),但是 Shader 相同的场景
这也是为什么 SRP 管线非常适合移动平台开发的原因之一
因为在移动平台开发时,游戏中的对象往往都是 Shader 相同,但是材质不同
它虽然不减少 DrawCall 数量,但是减少了 CPU 在 SetPass 时的开销

比如:

  1. 大量使用同一 Shader 的物体

    场景里有上百种建筑、石头、家具,它们的材质不同(颜色 / 贴图不同),但是都用相同的 Shader

  2. 大量动态物体,但材质切换频繁

    大量移动的敌人、NPC, 动态场景物体(比如破碎的瓦片、掉落的武器),每个都有自己材质,但 Shader 相同

  3. 使用 URP / HDRP 项目的大中型游戏

    特别是 移动端,CPU 渲染线程经常成为瓶颈时,SRP Batcher 能显著降低 CPU 耗时

不适合的场景:

  1. 非 SRP 管线项目
  2. Shader 不兼容

等等