SRP Batcher - Speed up your rendering
2018 年,我们推出了一种高度可定制的渲染技术,我们称之为Scriptable Render Pipeline (SRP)。其中一部分是一个名为 SRP Batcher 的新低级引擎渲染循环,它可以在渲染过程中将 CPU 加速 1.2 到 4 倍,具体取决于场景。让我们看看如何最好地使用此功能!
该视频展示了 Unity 最坏的情况:每个对象都是动态的,并使用不同的材质(颜色、纹理)。这个场景显示了许多相似的网格,但它会运行相同的每个对象一个不同的网格(因此不能使用 GPU 实例化)。PlayStation 4 上的加速约为 4 倍(此视频为 PC,Dx11)。
注意:当我们谈论 x4 加速时,我们谈论的是 CPU 渲染代码(“RenderLoop.Draw”和“ShadowLoop.Draw”分析器标记)。我们不是在谈论全局帧率 (FPS))。
统一和材料
Unity 编辑器有一个非常灵活的渲染引擎。您可以在帧期间的任何时间修改任何材质属性。此外,Unity 历来是为非常量缓冲区而设计的,支持 DirectX9 等图形 API。然而,如此好的功能也有一些缺点。例如,当 DrawCall 使用新材质时,有很多工作要做。所以基本上,场景中的材质越多,设置 GPU 数据所需的 CPU 就越多。
标准 Unity 渲染工作流程
在内部渲染循环期间,当检测到新材质时,CPU 会收集所有属性并在 GPU 内存中设置不同的常量缓冲区。GPU 缓冲区的数量取决于着色器如何声明其 CBUFFER。
SRP 批处理器的工作原理
我们在做 SRP 技术的时候,不得不重写一些低级的引擎部件。我们看到了原生集成一些新范式的绝佳机会,例如 GPU 数据持久性。我们旨在加快场景使用大量不同材质但很少有着色器变体的一般情况。
现在,低级渲染循环可以使材质数据持久保存在 GPU 内存中。如果 Material 内容没有变化,则无需设置缓冲区并将其上传到 GPU。此外,我们使用专用代码路径在大型 GPU 缓冲区中快速更新内置引擎属性。现在新的流程图如下所示:
SRP Batcher 渲染工作流程
在这里,CPU 仅处理内置引擎属性,标记为对象矩阵变换。所有材质都有位于 GPU 内存中的持久 CBUFFER,可以随时使用。总而言之,加速来自两个不同的事情:
- 每个材质内容现在都在 GPU 内存中持久化
- 专用代码正在管理一个大的“每个对象”GPU CBUFFER
如何启用 SRP 批处理器
您的项目必须使用轻量级渲染管线 (LWRP)、高清渲染管线 (HDRP) 或您自己的自定义 SRP。要在 HDRP 或 LWRP 中激活 SRP Batcher,只需使用 SRP Asset Inspector 中的复选框。
如果您想在运行时启用/禁用 SRP Batcher,以对性能优势进行基准测试,您还可以使用 C# 代码切换此全局变量:
1 |
|
SRP 批处理器兼容性
对于通过 SRP Batcher 代码路径渲染的对象,有两个要求:
- 对象必须在网格中。它不能是粒子或蒙皮网格。
- 您必须使用与 SRP Batcher 兼容的着色器。HDRP 和 LWRP 中的所有点亮和未点亮着色器都符合此要求。
要使着色器与 SRP 兼容:
- 所有内置引擎属性都必须在名为“UnityPerDraw”的单个 CBUFFER 中声明。例如,unity_ObjectToWorld 或 unity_SHAr。
- 所有材质属性都必须在名为“UnityPerMaterial”的单个 CBUFFER 中声明。
您可以在检查器面板中查看着色器的兼容性状态。此兼容性部分仅在您的项目基于 SRP 时显示。
在任何给定场景中,有些对象与 SRP Batcher 兼容,有些则不兼容。但场景仍然正确渲染。兼容对象将使用 SRP Batcher 代码路径,其他对象仍使用标准 SRP 代码路径。
剖析艺术
SRPBatcherProfiler.cs
如果要在特定场景中使用 SRP Batcher 测量速度增加,则可以使用 SRPBatcherProfiler.cs C# 脚本。只需在您的场景中添加脚本。当此脚本运行时,您可以使用 F8 键切换覆盖显示。您还可以在播放过程中使用 F9 键打开和关闭 SRP Batcher。如果您在 PLAY 模式 (F8) 中启用覆盖,您应该会看到很多有用的信息:
在这里,所有时间都以毫秒 (ms) 为单位。这些时间测量显示了在 Unity SRP 渲染循环中花费的 CPU。
注意:计时是指在一帧期间调用的所有“RenderLoop.Draw”和“Shadows .Draw ”标记的累计时间,无论线程所有者是谁。当您看到“1.31ms SRP Batcher code path”时,可能 0.31ms 花费在主线程上,1ms分布在所有图形作业上。
叠加信息
在此表中,您可以从上到下看到 PLAY 模式下可见的 Overlay 中每个设置的说明:
注意:我们对在叠加层底部添加 FPS 犹豫不决,因为您在优化时应该非常小心 FPS 指标。首先,FPS 不是线性的,所以看到 FPS 增加 20% 并不能立即告诉你你优化了多少场景。其次,FPS 是全局的。FPS(或全局帧计时)取决于渲染之外的许多其他因素,例如 C# 游戏玩法、物理、剔除等。
您可以从GitHub 上的SRP Batcher 项目模板获取 SRPBatcherProfiler.cs 。
各种场景基准
以下是一些 Unity 场景镜头,其中 SRP Batcher 处于关闭和开启状态,以查看在各种情况下的加速情况。
死亡之书、HDRP、PlayStation 4. x1.47 加速。请注意 FPS 不会改变,因为此场景受 GPU 限制。你还有 12 毫秒的时间在 CPU 端做其他事情。PC上的加速几乎相同。
FPS 采样、HDRP、PC DirectX 11。X1.23 加速。请注意,由于 SRP Batcher 不兼容,标准代码路径仍有 1.67 毫秒。在这种情况下,蒙皮网格和一些粒子使用材质属性块渲染。
船攻击,LWRP,PlayStation 4。加速 x2.13。
支持的平台
SRP Batcher 几乎适用于所有平台。下表显示了所需的平台和最低 Unity 版本。Unity 2019.2 目前处于开放 alpha 阶段。
关于VR的一些话
VR 中支持 SRP Batcher 快速代码路径,仅适用于“SinglePassInstanced”模式。启用 VR 不会增加任何 CPU 时间(感谢 SinglePassInstanced 模式)
常见问题
我怎么知道我正在以最佳方式使用 SRP Batcher?
使用 SRPBatcherProfiler.cs,首先检查 SRP Batcher 是否开启。然后,查看“标准代码路径”时序。这应该接近于 0,并且所有的时间都应该花在“SRP Batcher 代码路径”中。有时,如果您的场景使用一些蒙皮网格或粒子,在标准代码路径上花费一些时间是正常的。在 GitHub 上查看我们的SRP Batcher Benchmark 项目。
无论 SRP Batcher 是 ON 还是 OFF,SRPBatcherProfiler 都会显示类似的时序。为什么?
首先,您应该检查几乎所有渲染时间都经过新的代码路径(见上文)。如果确实如此,并且数字仍然相似,则查看“冲洗”数字。当 SRP Batcher 开启时,这个“冲洗”数量应该会减少很多。根据经验,除以 10 真的很好,除以 2 几乎是好的。如果刷新计数没有减少很多,则意味着您仍然有很多 Shader 变体。尝试减少着色器变体的数量。如果你做了很多不同的着色器,试着制作一个带有更多参数的“超级”着色器。拥有大量不同的材料参数是免费的。
当我启用 SRP Batcher 时,全局 FPS 没有改变。为什么?
检查上面的两个问题。如果 SRPBatcherProfiler 显示“CPU 渲染时间”快两倍,并且 FPS 没有变化,那么 CPU 渲染部分不是你的瓶颈。这并不意味着您不受 CPU 限制 - 相反,您可能使用了过多的 C# 游戏玩法或过多的物理元素。无论如何,如果“CPU 渲染时间”快两倍,它仍然是积极的。您可能在顶级视频中注意到,即使使用 3.5 倍加速,场景仍为 60FPS。那是因为我们打开了 VSYNC。SRP Batcher 在 CPU 端确实节省了 6.8ms。这些毫秒可用于另一项任务。它还可以在移动设备上节省一些电池寿命。
如何检查 SRP Batcher 效率
了解什么是 SRP Batcher 上下文中的“批处理”很重要。传统上,人们倾向于减少 DrawCall 的数量来优化 CPU 渲染成本。真正的原因是引擎在发布抽奖之前必须设置很多东西。真正的 CPU 成本来自该设置,而不是来自 GPU DrawCall 本身(这只是要推入 GPU 命令缓冲区的一些字节)。SRP Batcher 不会减少 DrawCalls 的数量。它只是降低了 DrawCalls 之间的 GPU 设置成本。
您可以在以下工作流程中看到这一点:
左边是标准的 SRP 渲染循环。右侧是 SRP Batcher 循环。在 SRP Batcher 上下文中,“批处理”只是一系列“绑定”、“绘制”、“绑定”、“绘制”… GPU 命令。
在标准 SRP 中,每个新材质都会调用慢速 SetShaderPass。在 SRP Batcher 上下文中,每个新的着色器变体都会调用 SetShaderPass。
为了获得最佳性能,您需要尽可能地保持这些批次。因此,您需要避免任何着色器变体更改,但如果它们使用相同的着色器,您可以使用任意数量的不同材质。
您可以使用 Unity Frame Debugger 查看 SRP Batcher“批次”长度。每个批次都是称为“SRP Batch”的帧调试器中的一个事件,您可以在此处看到:
请参阅左侧的 SRP Batch 事件。另请参阅批次的大小,即 Draw Calls 的数量(此处为 109)。这是一个非常有效的批次。您还可以看到前一批被破坏的原因(“节点使用不同的着色器关键字”)。这意味着用于该批次的着色器关键字与前一批次中的关键字不同。这意味着着色器变体已更改,我们必须中断批处理。
在某些场景中,某些批次大小可能非常低,例如:
批处理大小仅为 2。这可能意味着您有太多不同的着色器变体。如果您要创建自己的 SRP,请尝试使用最少的关键字编写通用的“超级”着色器。您不必担心在“属性”部分中放置了多少材料参数。
注意:Frame Debugger 中的 SRP Batcher 信息需要 Unity 2018.3 或更高版本。
使用兼容的着色器编写您自己的 SRP
注意:本节是为高级用户编写的,他们编写自己的可编写脚本的渲染循环和着色器库。LWRP 或 HDRP 用户可以跳过此部分,因为我们提供的所有着色器都已与 SRP Batcher 兼容。
如果您正在编写自己的渲染循环,您的着色器必须遵循一些规则才能通过 SRP Batcher 代码路径。
“每材料”变量
首先,所有“每材质”数据都应在名为“UnityPerMaterial”的单个 CBUFFER 中声明。什么是“每材料”数据?通常,您在“着色器属性”部分中声明的所有变量。这是您的艺术家可以使用材质 GUI 检查器调整的所有变量。例如,让我们看一个简单的着色器,如:
属性
1 |
|
如果编译此着色器,着色器检查器面板将显示:
要解决这个问题,只需像这样声明所有“每材料”数据:
1 |
|
“每个对象”变量
SRP Batcher 还需要一个非常特殊的 CBUFFER,名为“UnityPerDraw”。此 CBUFFER 应包含所有 Unity 内置引擎变量。
“UnityPerDraw”CBUFFER 中的变量声明顺序也很重要。所有变量都应该遵循我们称之为“块特征”的一些布局。例如,“空间位置块功能”应包含所有这些变量,按以下顺序:
1 |
|
如果您不需要这些块功能,则不必声明其中的某些功能。“UnityPerDraw”中的所有内置引擎变量都应该是 float4 或 float4x4。在移动设备上,人们可能希望使用 real4(16 位编码浮点值)来节省一些 GPU 带宽。并非所有 UnityPerDraw 变量都可以使用“real4”。请参阅“可能是真的4”一栏。
下表描述了您可以在“UnityPerDraw”CBUFFER 中使用的所有可能的块功能:
注意:如果一个特征块的变量之一被声明为 real4 ( half ),那么该特征块的所有其他潜在变量也应声明为 real4。
提示 1:始终在检查器中检查新着色器的兼容性状态。我们检查了几个潜在的错误(UnityPerDraw 布局声明等)并显示了它不兼容的原因。
提示 2:在编写自己的 SRP 着色器时,您可以参考 LWRP 或 HDRP 包来查看它们的 UnityPerDraw CBUFFER 声明以获取灵感。
未来
我们仍然通过增加一些渲染通道(尤其是阴影和深度通道)中的批大小来继续改进 SRP Batcher。
我们还致力于通过 SRP Batcher 添加自动 GPU 实例化使用。我们从MegaCity 演示中使用的新DOTS渲染器开始。Unity 编辑器中的加速非常令人印象深刻,从 10 到 50 FPS。
https://blog-api.unity.com/sites/default/files/2019/02/SRP_Batcher_Megacity_Editor_FPS_720p.mp4
带有 SRP Batcher 和 DOTS 渲染器的 MegaCity 编辑器。性能差异如此之大,以至于即使是全局帧速率也提高了 5 倍。
注意:准确地说,启用 SRP Batcher 时的这种大幅加速仅适用于编辑器,因为编辑器当前不使用图形作业。独立播放器模式下的加速类似于 x2。
https://blog-api.unity.com/sites/default/files/2019/02/SRP_Batcher_Megacity_Editor_Smooth_720p.mp4
编辑器中的 MegaCity。如果您能以 60hz 播放视频,您会在启用 SRP Batcher 时感受到加速。
注意:带有 DOTS 渲染器的 SRP Batcher 仍处于试验阶段并处于积极开发阶段。
本文来自:https://blog.unity.com/technology/srp-batcher-speed-up-your-rendering