分析顶点格式

通过帧分析,您可以诊断几个可能的顶点相关性能问题。使用命令面板可以查看游戏在给定帧中执行的所有绘制调用,以及每个绘制调用的图元绘制计数。这可以近似得出单个帧中提交的顶点总数。

Frame profiling view for a glDrawElements call, hovered for detail
            on the draw call parameters
图 1. 单个 glDrawElements 调用的帧分析视图,显示绘制了 2,718 个三角形图元

顶点属性压缩

您的游戏可能面临的一个常见问题是平均顶点大小过大。提交大量具有高平均顶点大小的顶点会导致 GPU 读取时产生大量的顶点内存读取带宽。

要观察给定绘制调用的顶点格式,请完成以下步骤:

  1. 选择感兴趣的绘制调用。

    这可以是场景的典型绘制调用、具有大量顶点的绘制调用、复杂角色模型的绘制调用或其他类型的绘制调用。

  2. 导航到管道面板,然后点击IA进行输入汇编。这定义了进入 GPU 的顶点的顶点格式。

  3. 观察一系列属性及其格式;例如,R32G32B32_SFLOAT 是一个 3 分量 32 位带符号浮点数。

Frame profiling view for a draw call's input assembly, with
            uncompressed vertex attributes
图 2. 绘制调用的输入汇编,未压缩属性导致顶点大小为 56 字节

通常,可以在模型绘制质量最小程度降低的情况下压缩顶点属性。我们特别建议:

  • 将顶点位置压缩为半精度 16 位浮点数
  • 将 UV 纹理坐标压缩为 16 位无符号整数 ushort
  • 通过使用四元数编码法线、切线和副法线向量来压缩切线空间

其他杂项属性也可以根据具体情况考虑使用较低精度类型。

顶点流拆分

您还可以调查顶点属性流是否已正确拆分。在移动 GPU 等分块渲染架构中,顶点位置首先用于分箱过程,以创建在每个图块中处理的图元箱。如果顶点属性交错到一个缓冲区中,所有顶点数据都会被读入缓存进行分箱,即使只使用了顶点位置。

为了减少顶点读取内存带宽并提高缓存效率,从而减少分箱过程花费的时间,顶点数据应拆分为两个独立的流,一个用于顶点位置,一个用于所有其他顶点属性。

要调查顶点属性是否已正确拆分:

  1. 选择感兴趣的绘制调用,并记下绘制调用编号。

    这可以是场景的典型绘制调用、具有大量顶点的绘制调用、复杂角色模型的绘制调用或其他类型的绘制调用。

  2. 导航到管道面板,然后点击IA进行输入汇编。这定义了进入 GPU 的顶点的顶点格式。

  3. 观察顶点属性的绑定;通常这些可能会线性增加(0、1、2、3 等),但并非总是如此。顶点位置通常是列出的第一个顶点属性。

  4. 状态面板中,找到 LastDrawInfos 并展开匹配的绘制调用编号。然后,展开此绘制调用的 BoundVertexBuffers

  5. 观察在给定绘制调用期间绑定的顶点缓冲区,其索引与之前顶点属性绑定匹配。

  6. 展开绘制调用的顶点属性的绑定,然后展开缓冲区。

  7. 观察缓冲区的 VulkanHandle,它代表顶点数据来源的底层内存。如果 VulkanHandle 不同,则意味着属性来自不同的底层缓冲区。如果 VulkanHandle 相同但偏移量很大(例如,大于 100),则属性仍可能来自不同的子缓冲区,但这需要进一步调查。

Frame profiling view for a draw call's input assembly and state showing the bound vertex buffer
图 3. 绘制调用的输入汇编,右侧的状态面板显示绑定 0 和 1 处的属性(顶点位置和法线)共享一个底层缓冲区

有关顶点流拆分以及如何在各种游戏引擎上解决此问题的更多详细信息,请参阅我们关于此主题的博文