Version: 2021.1
在可编程渲染管线中调度和执行渲染命令
创建自定义渲染管线

可编程渲染管线 SRP Batcher

SRP Batcher 是一个渲染循环,可通过许多使用同一着色器变体的材质来加快场景中的 CPU 渲染速度。

可编程渲染管线 SRP Batcher 通过许多使用同一着色器变体的材质来加快场景中的 CPU 渲染速度。
可编程渲染管线 SRP Batcher 通过许多使用同一着色器变体的材质来加快场景中的 CPU 渲染速度。

使用 SRP Batcher

要使用 SRP Batcher,项目必须使用可编程渲染管线。可编程渲染管线可以是:

要在 URP 中激活 SRP Batcher,请执行以下操作:

  1. 在 Project 窗口中选择 URP 资源
  2. 在该资源的 Inspector 中,找到 Advanced 部分,然后选中 SRP Batcher 复选框。
可以分别在资源中为 URP 或 HDRP 停用 SRP Batcher。默认情况下已启用 SRP Batcher。
可以分别在资源中为 URP 或 HDRP 停用 SRP Batcher。默认情况下已启用 SRP Batcher。

在 HDRP 中,SRP Batcher 默认为启用状态,不应将其禁用。不过,如果需要暂时禁用 SRP Batcher 以进行调试:

  1. 在 Project 窗口中选择 HDRP 资源
  2. 在 Asset Inspector 中,输入 Debug Mode。这会更改 HDRP 资源显示其属性的方式并使 SRP Batcher 属性出现。
  3. 禁用 SRP Batcher 复选框。

也可以在运行时启用或禁用 SRP Batcher。为此,请在 C# 代码中切换以下全局变量:

GraphicsSettings.useScriptableRenderPipelineBatching = true;

支持的平台

SRP Batcher 适用于几乎所有平台。下表显示了支持的平台以及所需的最低 Unity 版本。

Platform Minimum Unity version required
Windows DirectX 11 2018.2
PlayStation 4 2018.2
Vulkan 2018.3
OSX Metal 2018.3
iOS Metal 2018.3
Nintendo Switch 2018.3
Xbox One DirectX 11 2019.2
OpenGL 4.2 and higher 2019.1
OpenGL ES 3.1 and higher 2019.1
Xbox One DirectX 12 2019.1
Windows DirectX 12 2019.1

注意:对于 XR,只能以 SinglePassInstanced 模式来使用 SRP Batcher。

SRP Batcher 的工作原理

Unity 中,可以在一帧内的任何时间修改任何材质的属性。但是,这种做法有一些缺点。例如,DrawCall 使用新材质时,要执行许多作业。因此,场景中的材质越多,Unity 必须用于设置 GPU 数据的 CPU 也越多。解决此问题的传统方法是减少 DrawCall 的数量以优化 CPU 渲染成本,因为 Unity 在发出 DrawCall 之前必须进行很多设置。实际的 CPU 成本便来自该设置,而不是来自 GPU DrawCall 本身(DrawCall 只是 Unity 需要推送到 GPU 命令缓冲区的少量字节)。

SRP Batcher 通过批处理一系列 BindDraw GPU 命令来减少 DrawCall 之间的 GPU 设置。

Bind 和 Draw 命令的批处理可以减少绘制调用之间的 GPU 设置。
Bind 和 Draw 命令的批处理可以减少绘制调用之间的 GPU 设置。

为了获得最大渲染性能,这些批次必须尽可能大。为了实现这一点,可以使用尽可能多具有相同着色器的不同材质,但是必须使用尽可能少的着色器变体。

在内渲染循环中,当 Unity 检测到新材质时,CPU 会收集所有属性并在 GPU 内存中设置不同的常量缓冲区。GPU 缓冲区的数量取决于着色器如何声明其 CBUFFER。

为了在场景使用很多不同材质但很少使用着色器变体的一般情况下加快速度,SRP 在原生集成了范例(例如 GPU 数据持久性)。

SRP Batcher 是一个低级渲染循环,使材质数据持久保留在 GPU 内存中。如果材质内容不变,SRP Batcher 不需要设置缓冲区并将缓冲区上传到 GPU。实际上,SRP Batcher 会使用专用的代码路径来快速更新大型 GPU 缓冲区中的 Unity 引擎属性,如下所示:

这是 SRP Batcher 渲染工作流程。SRP Batcher 使用专用的代码路径来快速更新大型 GPU 缓冲区中的 Unity 引擎属性。
这是 SRP Batcher 渲染工作流程。SRP Batcher 使用专用的代码路径来快速更新大型 GPU 缓冲区中的 Unity 引擎属性。

在此处,CPU 仅处理上图中标记为 Per Object large buffer 的 Unity 引擎属性。所有材质在 GPU 内存中都有持久的 CBUFFER,可供随时使用。这样会加快渲染速度,原因是: 现在,所有材质内容都持久保留在 GPU 内存中。 专用代码针对所有每对象属性,管理着一个大型的每对象 GPU CBUFFER。

SRP Batcher 兼容性

在任何给定场景中,有些对象与 SRP Batcher 兼容,而有些对象则不兼容。即使在使用不兼容的对象时,Unity 也会正确渲染场景。这是因为兼容对象使用 SRP Batcher 代码路径,而其他对象则使用标准 SRP 代码路径。

为了使 SRP Batcher 代码路径能够渲染对象:

  • 渲染的对象必须是网格或蒙皮网格。该对象不能是粒子。
  • 着色器必须与 SRP Batcher 兼容。HDRP 和 URP 中的所有光照和无光照着色器均符合此要求(这些着色器的“粒子”版本除外)。
  • 渲染对象不得使用 MaterialPropertyBlocks。

为了使着色器与 SRP Batcher 兼容:

  • 必须在一个名为“UnityPerDraw”的 CBUFFER 中声明所有内置引擎属性。例如:unity_ObjectToWorldunity_SHAr
  • 必须在一个名为 UnityPerMaterial 的 CBUFFER 中声明所有材质属性。

可以在 Inspector 面板中查看着色器的兼容性状态。

可以在 Inspector 面板中检查特定着色器的兼容性。
可以在 Inspector 面板中检查特定着色器的兼容性。

使用 SRP Batcher 时的性能分析

为了测量使用 SRP Batcher 时场景中的增速,请将 SRPBatcherProfiler.cs C# 脚本从 SRP Batcher 模板添加到您的场景。当此脚本正在运行时: 使用 F8 键来切换覆盖显示。 也可以在运行过程中使用 F9 键来打开和关闭 SRP Batcher。

此覆盖如下所示:

在 SRP Batcher 覆盖中,可以找到有关 SRP Batcher 中发生的情况的详细信息。
在 SRP Batcher 覆盖中,可以找到有关 SRP Batcher 中发生的情况的详细信息。

时间测量值以毫秒 (ms) 为单位,并显示 CPU 在 Unity SRP 渲染循环中花费的时间。

注意:此处的时间等于在一帧内调用的所有 RenderLoop.DrawShadows.Draw 标记的累积时间(与线程所有者无关)。例如,如果看到 1.31ms SRP Batcher 代码路径,表示绘制调用可能在主线程上花费了 0.31ms,并且 1ms 分散在所有图形作业中。

覆盖信息

下表描述了在运行模式下可见的 SRP Batcher 覆盖中的每个设置:

覆盖中的名称 描述
(SRP batcher ON)/(SRP batcher OFF) 指示是否已启用当前的 SRP Batcher。要打开或关闭 SRP Batcher,请按 F9。
CPU Rendering time 指示 SRP 循环在 CPU 中花费的总累积时间,无论使用的是哪种多线程模式(例如单个客户端/工作线程或图形作业)。在这里可以最大限度看到 SRP Batcher 的效果。要查看 SRP Batcher 的优化,请尝试将其打开和关闭来查看 CPU 使用率的差异。在上述示例中,总时间为 2.11 毫秒。
(incl RT idle):__指示 SRP 在渲染线程中花费的空闲时间。这可能意味着应用程序处于没有任何图形作业的客户端/工作模式;在渲染线程必须等待主线程上的图形命令时会发生此情况。在以上示例中,渲染线程空闲了 0.36 毫秒。| ||SRP Batcher code path (flushes)|指示您的游戏或应用程序花费在 SRP Batcher 代码路径中的时间。此时间包括游戏渲染 All objects__(阴影通道除外)(1.18ms) 和 Shadows (1.13ms) 这两个方面。如果 Shadows 数量较大,请尝试减少场景中阴影投射光源的数量,或在渲染管线资源中选择较少数量的级联。在以上示例中,该时间为 1.31ms。
(flush) 数字表示 Unity 由于遇到新着色器变体而刷新场景的次数(在此示例中为 89)。较少的刷新次数总是更好一些,因为这意味着帧中的着色器变体数量较少。
Standard code path (flushes) 指示 Unity 在渲染与 SRP Batcher 不兼容的对象(如粒子)方面花费的时间。
在以上示例中,SRP Batcher 在 0.80 毫秒内刷新了 81 个对象:阴影通道为 0.09 毫秒,所有其他通道为 0.71 毫秒。
Global Main Loop: (FPS) 指示全局主循环时间(以毫秒为单位)以及等效的每秒帧数 (FPS)。注意:FPS 并非线性,因此,如果发现 FPS 增加 20,不一定意味着已经优化场景。若要查看 SRP Batcher 是否优化了场景渲染,请开启和关闭该功能,然后比较 CPU Rendering time 下的数字。

Unity 帧调试器中的 SRP Batcher 数据

可以在 Frame Debugger 窗口中检查 SRP Batcher“批次”的状态。

要检查 SRP Batcher 批次的状态,请执行以下操作:

  1. 在 Editor 中,选择 Window > Analysis > Frame Debugger > Render Camera > Render Opaques__,然后展开 RenderLoopNewBatcher.Draw__ 列表。
  2. 单击要检查的 SRP Batch

SRP Batch 详细信息可以显示使用了多少个绘制调用、着色器附加了哪些关键字以及该特定绘制调用未与前一个调用一起接受批处理的原因。在以下示例中,所述原因是:_Node use different shader keywords_。这意味着该批次的着色器关键字不同于前一个批次中的关键字。由于 SRP Batcher 使用了另一个不同的着色器变体,因此这一批次已破坏。如果一个 SRP 批次的绘制调用数量较少,您很可能使用了太多的着色器变体。

在 Frame Debugger 窗口中,可以找到有关各个批次的详细信息,包括 SRP Batcher 创建新批次而不是继续使用现有批次的原因。
在 Frame Debugger 窗口中,可以找到有关各个批次的详细信息,包括 SRP Batcher 创建新批次而不是继续使用现有批次的原因。

如果您要编写自己的 SRP 而不是使用 URP 或 HDRP,请尝试使用最少的关键字来编写通用的“超级”着色器(但可以在每个材质中使用尽可能多的材质参数和材质属性)。

在可编程渲染管线中调度和执行渲染命令
创建自定义渲染管线