游戏开发者指南- Qualcomm® Adreno ™ GPU(3)

  • 2.3 质地
  • 2.3.1 压缩策略
  • 2.4 平铺架构
  • 2.4.1 避免 GMEM 负载
  • 2.4.2 删除未使用的渲染目标
  • 2.4.3 缩小渲染目标
  • 2.4.4 Vulkan 子通道
  • 2.5 顶点处理
  • 2.5.1 一般的
  • 2.5.2 OpenGL ES 特定



2.3 质地

2.3.1 压缩策略

压缩纹理可以显着提高图形应用程序的性能和加载时间,因为它减少了纹理内存和总线带宽的使用。与桌面 OpenGL 不同,Vulkan 不提供应用程序在运行时压缩纹理所需的基础设施,因此纹理数据需要离线创作。

Adreno GPU 支持的重要纹理压缩格式有:

  • ATC – 专有的 Adreno 纹理压缩格式,支持 RGB 和 RGBA 组件布局
  • ETC – 标准 OpenGL ES 2.0 纹理压缩格式,仅支持 RGB 分量布局
  • ETC2 – 标准 OpenGL ES 3.0 纹理压缩格式,支持 R、RG、RGB 和 RGBA 组件布局以及 sRGB 纹理数据
  • ASTC – OpenGL ES(3.0 及更高版本)和 Vulkan 支持的纹理压缩格式,允许使用可变块大小进行压缩,在达到压缩比的情况下,图像质量下降程度非常低
笔记
      建议采用以下策略来选择纹理压缩格式:
      1. 如果可用,请使用 ASTC 压缩。
      2. 否则,请使用 ETC2 压缩(如果可用)。
      3. 否则,选择压缩格式如下:
                  a. ATC(如果使用 alpha)
                  b. 如果不使用 alpha 则等

ASTC 是一种较新的格式,可能并非在所有内容创建管道上都受支持或优化。此外,与 RGBA 格式相比,ASTC 的 sRGB 格式在 Adreno 硬件上的处理效率更高。

以下是将纹理转换为 Adreno 硬件的常用方法:

  • 设备上转化
  • 预包装
  • 正在下载

设备上转换涉及到游戏启动时发生的耗时的纹理资源一次性转换。预打包正确的纹理会产生最优化的解决方案,但需要为每个 GPU 提供替代版本的 APK。下载需要 GPU 检测和互联网连接,但允许对每个 GPU 的确切纹理格式进行更多控制。无论哪种情况,第一步都是创建压缩纹理。

可以使用 Adreno 纹理压缩和可视化工具或 Adreno 纹理转换器工具(均包含在适用于 OpenGL 的 Adreno SDK 中)将纹理数据压缩为任何纹理压缩格式。SDK中有一个压缩纹理教程,介绍了如何在OpenGL ES应用程序中使用压缩纹理。

这些压缩格式的有效性如下所述,由一种漫反射纹理和一种对象空间法线 RGB 纹理组成,使用 Adreno 纹理工具进行压缩。这些图显示了原始纹理和使用每种压缩格式的压缩版本。对于每个示例,都有一个差异图像,显示原始版本和压缩版本之间的绝对差异。

漫反射纹理测试

本次测试使用的漫反射纹理如下所示:

Adreno GPU 驱动_Qualcomm

ATC压缩

Adreno GPU 驱动_纹理压缩_02


Adreno GPU 驱动_Adreno GPU 驱动_03


ETC1 压缩

Adreno GPU 驱动_前端_04


Adreno GPU 驱动_Adreno GPU 驱动_05

ETC2 压缩

Adreno GPU 驱动_纹理压缩_06


Adreno GPU 驱动_Adreno GPU 驱动_07

普通质感测试

可以使用适用于 Vulkan 的 Adreno SDK 中包含的 Adreno 纹理工具 (Qcompress.exe) 将纹理数据压缩为任何这些纹理压缩格式。SDK中有一个纹理教程,演示了如何在Vulkan应用程序中使用压缩纹理。用于此测试的正常纹理如下所示。

Adreno GPU 驱动_游戏_08


ATC压缩

Adreno GPU 驱动_前端_09


Adreno GPU 驱动_游戏_10

ETC1 压缩

Adreno GPU 驱动_Qualcomm_11


Adreno GPU 驱动_前端_12

ETC2 压缩

Adreno GPU 驱动_前端_13


Adreno GPU 驱动_Adreno GPU 驱动_14

2.4 平铺架构

2.4.1 避免 GMEM 负载

清除或使所有帧缓冲区附件失效,以提示 GPU 不要将图块数据从系统内存加载到 GMEM 中。
OpenGL :有关 GMEM 负载以及如何识别和解决它们的更详细说明,请参阅了解和解决图形内存负载指南。

ES伏尔甘:确保正确使用loadOp进行渲染通道,不需要使用LOAD_OP_CLEAR或LOAD_OP_DONT_CARE将内容加载到 GMEM 中。

有关 GMEM 负载以及如何识别和解决它们的更详细说明,请参阅了解和解决图形内存负载指南。

2.4.2 删除未使用的渲染目标

当 GMEM 中的图块渲染完成后,它将被解析(GMEM 存储)到系统内存中。这有效地将帧缓冲区“缝合”在一起。

此操作已优化但不是免费的。生成的图块越多,需要的 GMEM Store 操作就越多。建议检查渲染的表面并验证它们是否都需要。删除不必要的渲染表面可以减少帧缓冲区对象的总大小,减少所需的图块数量,并提高整体性能。

Adreno GPU 驱动_Qualcomm_15

2.4.3 缩小渲染目标

与删除未使用的渲染目标最佳实践类似,出于同样的原因,建议在可能的情况下缩小渲染目标。这可以是宽度/高度尺寸或降低渲染目标精度的形式。

笔记
  
  跟踪捕获中的Snapdragon Profiler “渲染阶段”指标可以显示每个表面的信息,其中包括 GPU 为给定表面生成的图块数量。

2.4.4 Vulkan 子通道

Vulkan 引入了渲染“子通道”,它允许开发人员设置渲染管道,明确说明其用途、渲染目标交互、依赖关系、转换等。这使得 GPU 能够就如何有效处理这些帧缓冲区转换做出明智的决策。为了有效地使用 GMEM,在基于 Tile 的渲染架构(例如 Adreno GPU)中正确使用子通道至关重要。

正确构造的渲染通道允许 Vulkan 指示 GPU 在每个图块的基础上执行所有子通道。也就是说,可以对每个图块执行完整的子通道链,从而避免在每次通道之后将子通道解析到系统存储器的需要。Vulkan 驱动程序需要正确设置这些子通道才能将子通道“合并”为一个。这可能会导致超过 10% 的帧时间增益,具体取决于子通道链的复杂性和配置。成功的 Vulkan 子通道会考虑以下因素:

  • 子通道数 > 1
  • Renderpass 有输入目标
  • 解决附件无法在以下子通道中重复使用的问题
  • srcAccessMask不能为VK_ACCESS_SHADER_WRITE_BIT,并且dstAccessMask不能为VK_ACCESS_SHADER_READ_BIT
  • 从使用input_attachments字段的第二个子通道开始, dstAccessMask必须设置为VK_ACCESS_INPUT_ATTACHMENT_READ_BIT
笔记
      
      子通道合并仅适用于以分箱模式渲染给定表面的情况。跟踪捕获中的Snapdragon Profiler “渲染阶段”指标是识别这些表面渲染模式以及是否已完成正确合并的好方法。此外,使用Vulkan Adreno 层还可以通过记录VKDBGUTILWARN003标志来帮助识别子通道是否无法正确合并。

2.5 顶点处理

2.5.1 一般的

本节介绍有助于优化 Vulkan 应用程序组织顶点数据的方式的提示和技巧,以便渲染过程可以在 Adreno 架构上高效运行。

使用交错的压缩顶点

对于顶点获取性能,交错顶点属性(“xyz uv | xyz uv | …”,而不是“xyz | xyz | … | uv | uv | …”)的工作效率最高。交错顶点的吞吐量更好,压缩顶点可以进一步提高吞吐量。延迟渲染为这些优化提供了优势。

对于分箱过程优化,请考虑:

一个包含顶点属性和计算位置所需的其他属性的数组,以及
另一个具有其他属性的交错数组。

目前,Vulkan 着色器不支持半浮点。

笔记
  
  在 OpenGL ES 2.0 下,Adreno OpenGL ES 实现支持 GL_OES_vertex_half_float 扩展,该扩展允许程序员使用半浮点坐标填充顶点缓冲区。此功能成为 OpenGL ES 3.0 的核心功能。半浮点坐标可用于纹理或法线坐标,其中较低的精度不会损害最终图像,并提高渲染性能。

考虑几何实例

几何体实例化可同时渲染场景中同一网格或几何体的多个副本。该技术主要用于树木、草或建筑物等可以表示为重复几何图形而不会显得过度重复的对象。然而,几何实例也可用于角色。

尽管顶点数据在所有实例化网格中重复,但每个实例都可以更改其他区分参数以减少重复的出现,即颜色、变换或光照。

如下图所示,场景中的所有桶都可以使用一组多次实例化的顶点数据,而不是为每个桶使用唯一的几何体。

Adreno GPU 驱动_Adreno GPU 驱动_16


Vulkan

vkCmdDraw、vkCmdDrawIndexed、vkDrawIndirectCommand 和 vkDrawIndexedIndirectCommand 支持实例化渲染。

OpenGL ES

glDrawArraysInstanced 和 glDrawElementsInstanced 支持实例化渲染。

2.5.2 OpenGL ES 特定

使用仅 Z 渲染

GPU 有一种特殊模式,可以以正常速率的两倍写入仅 Z 像素,例如,当应用程序渲染到阴影贴图时。驱动程序必须告知硬件进入这种特殊的渲染模式,并且在没有特定 OpenGL 状态的情况下,驱动程序需要来自应用程序的提示。使用空片段着色器并禁用帧缓冲区写入掩码是很好的提示。

一些开发人员通过在渲染主场景之前放置 Z 预通道来利用双倍速、仅 Z 渲染。仍必须运行性能测试以确定这对 Adreno 是否有益。

选择最佳顶点格式

Adreno GPU 为以下顶点格式提供硬件支持:

  • GL_BYTE 和 GL_UNSIGNED_BYTE
  • GL_SHORT 和 GL_UNSIGNED_SHORT
  • GL_FIXED
  • GL_FLOAT
  • GL_HALF_FLOAT
  • GL_INT_2_10_10_10_REV 和 GL_UNSIGNED_INT_2_10_10_10_REV

在准备顶点数据集以获得最佳性能时,请始终使用能够提供令人满意的精度且占用最少空间的顶点格式。

使用间接索引绘制调用

OpenGL ES 3.1 中引入的间接绘制调用将绘制调用开销从 CPU 转移到 GPU。与 Adreno 架构下的常规绘制调用相比,这可以提供显着的性能优势。

如果应用程序面向最新的 OpenGL ES 版本,请考虑使用此新功能来提高渲染效率。例如,如果渲染器基于场景图的概念,则可以在加载时间期间将渲染网格节点所需的绘制调用参数缓存在缓冲对象存储中。然后可以在渲染期间使用该存储作为 glDrawArraysIndirect 或 glDrawElementsIndirect 函数的输入。