Scriptable Render Pipeline (SRP) Batcher

非SRP Batcher的Unity渲染管线怎么做

不多说,先看图:

SRP Batcher OFF

图中有个Unity Engine propeties,其实就是指一些不需要我们显式地写在shaderlab代码的Propeties块中的uniform shader变量。比如物体的变换矩阵等等。

上图中的Unity Engine properties,以及各个材质球数据,存放在System Memory中。每当准备渲染物体时。CPU要将这些数据从System Memory中搜集起来,设置到shader的常量缓冲区中去(即CBUFFER,即从CPU传给GPU的数据,这些数据包含了shaderlab代码的Propeties块中的定义的变量)。在内部的渲染循环中,当渲染某个物体,发现需要用到一个新的材质数据时,CPU就将shader properties搜集起来。放到不同的常量缓冲区中去。这些常量缓冲区的个数,就取决着色器代码中声明了多少个。

SRP Batcher 的工作原理:

在 Unity 中,您可以在一帧中的任何时间修改任何材质的属性。然而这种做法有一些缺点。例如,当在一次DrawCall调用种使用新材质时,有很多工作要做。因此,场景中的材质越多,Unity设置 GPU用到的数据所需要的 CPU时间就越多。传统的处理方式是减少DrawCalls的数量来优化CPU端的渲染成本,因为Unity在发出DrawCall之前要设置很多东西。真正的 CPU耗时是耗在这些设置操作,而不是来自 GPU的绘制本身。这些设置操作也只是Unity 需要推送到 GPU 命令缓冲区的一些字节数据而已。

当场景中有大量的材质球,但是shader的变体比较少时,SRP Batcher就能进行优化。它的方法简而言之是:对Unity Engine properties,尽可能将其留存在GPU memory中。如果材质的内容没有发生变化的话,那么就不需要把这些数据上传到GPU memory上,从而省去了传统方式中的这部分CPU的工作。SRP Batcher专门定制了一些代码(dedicated code),可以快速地将Unity Engine properties更新到一个大的GPU 缓冲区(large GPU buffer) 中。如下图所示:

SRP Bathcer loop

在上图中,CPU仅仅需要处理built-in engine properties,也就是诸如物体的变换矩阵等等。这是因为物体可能会移动,所以它的世界变换矩阵等等会经常发生变化。而其他的材质数据就被持久化地存储在CBUFFER中,这是因为大部分可渲染物体,它进行渲染时,传给shader的一些uniform变量一般都是保持,不随着时间的变化而变化的。这也就是说,SRP Batcher通过两种手段加速渲染:

  • 每个可渲染物体的材质数据持久化存在显存中。
  • 专门定制的代码管理一个大的逐物体GPU Buffer,即图中的Per Object large buffer块。

SRP Batcher compatibility

在任何给定的场景中,有些可渲染物体与 SRP Batcher 兼容,有些则不兼容。即使使用不兼容的对象,Unity 也能正确渲染场景。这是因为兼容对象使用SRP Batcher代码路径,而其他对象使用标准的SRP 代码路径。能使用SRP Batcher 代码路径渲染的可渲染对象必须是以下的类型:

  1. 渲染对象必须是一个meshskinned mesh。它不能是粒子。
  2. 着色器必须与 SRP Batcher 兼容。HDRP 和 URP 中的所有光照和非光照着色器都符合此要求(这些着色器的粒子版本除外)。
  3. 可渲染对象不得使用 MaterialPropertyBlocks。

要使着色器与 SRP Batcher兼容,必须遵循以下几点:

  1. 您必须在名为“UnityPerDraw”的单个CBUFFER块中声明所有内置引擎属性。例如,unity_ObjectToWorld、 或unity_SHAr等等。
  2. 您必须在名为“UnityPerMaterail” 的单个 CBUFFER块中声明所有材质属性(shaderlab中的Properties属性)。
  3. 您可以在检查器面板中查看着色器的兼容性状态。

参考网页

SRP Batcher: Speed up your rendering! https://blog.unity.com/cn/technology/srp-batcher-speed-up-your-rendering 原文地址