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

本文围绕Adreno GPU展开,介绍其可见性处理、着色器支持、通用带宽压缩、纹理特征等技术,如早期Z拒绝、统一着色器架构等。还给出最佳实践,包括使用可变速率着色、合理进行遮挡查询、优化带宽和深度范围等,以提升性能和节省功耗。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


Adreno GPU 集成在 Qualcomm ® Snapdragon™ 处理器的一体化设计中,提供复杂的渲染功能,支持当今移动设备中的最新游戏、用户界面和网络技术。它们是专门针对移动 API 和设备限制而设计的,重点是性能和高效的功耗。

本指南概述了 Adreno GPU 提供的支持图形开发人员的各种技术和子系统。最佳实践将在最佳实践部分讨论。

本文档力求涵盖与各种 Adreno GPU 相关的广泛主题。随着架构的发展,GPU 中添加了新的功能。本指南的某些部分仅与支持给定功能的 Adreno GPU 相关。

相关时,会描述具有某个功能的 Adreno GPU 系列。如果未指定,则可以假设大多数或所有 Adreno GPU 上都存在此类功能。

1 概述

1.1 可见性处理

1.1.1 早期 Z 拒绝

早期 Z 拒绝提供了一种快速遮挡方法,可以拒绝从视图位置不可见(隐藏)的对象的不需要的渲染通道。Adreno GPU 可以以高达 4 倍绘制像素填充率的速度拒绝遮挡像素。

下图显示了表示为网格的颜色缓冲区,每个块表示为一个像素。该网格上的渲染像素区域为黑色。这些渲染的黑色像素的 Z 缓冲区值为 1。

如果您尝试将新基元渲染到 Z 缓冲区值为 2 的现有颜色缓冲区的相同像素(带有绿色块的第二个网格),则该新基元中的冲突像素将被拒绝(代表最终颜色缓冲区)。

请添加图片描述
为了充分利用此功能,我们建议使用从前到后排序的图元来绘制场景;即从近到远。这确保了远基元的 Z 拒绝率较高,这对于具有高深度复杂性的应用程序非常有用。

1.1.2 FlexRender™ 技术(混合延迟和直接渲染模式)

FlexRender 是 Adreno GPU 的一项功能。Adreno 3X (A3X) 指的是它们在间接渲染(即合并或平铺渲染)和直接渲染到帧缓冲区之间切换的能力。

直接渲染模式和延迟渲染模式都有优点。Adreno GPU 旨在通过动态方式在两种模式之间切换来最大限度地提高性能。驱动程序和 GPU 分析给定渲染目标的渲染参数并自动选择模式。

1.1.3 基于图块的渲染

为了优化低功耗和内存带宽有限设备的渲染,Adreno GPU 使用基于平铺的渲染架构。这种渲染机制将场景帧缓冲区分成小的矩形区域以进行渲染。区域大小是自动确定的,以便使用 GPU 上的本地低延迟内存(称为 GMEM)进行最佳渲染,而不是使用系统内存的带宽受限总线。

Adreno GPU的延迟模式渲染机制也采用基于图块的渲染架构。它实现了一种分箱方法来创建在每个图块中处理的图元箱。

Adreno GPU 将一帧划分为多个容器并一次渲染一个容器。在渲染过程中,它使用片上高性能图形内存(GMEM)来避免使用系统内存的成本。

在下图中,您可以看到对图形基元执行的两个过程(合并和渲染)。在此示例中,将在帧缓冲区中渲染三个三角形。分箱通道标记了三角形在(可见流)中可见的分箱。该流存储到系统内存中。
请添加图片描述
在渲染通道中,通过读取可见性流仅处理要渲染的每个图块的可见图元。通过使用 GMEM 作为局部颜色和 Z 缓冲区,可以渲染图元。一旦图块的渲染完成,GMEM 颜色内容就会被发送回(解析)到系统内存。对所有箱重复此过程。

Vulkan 的 Renderpass 功能对于 Adreno 等平铺架构非常有利,因为可以在 GMEM 中完成多个渲染通道。这最终最大限度地减少了昂贵的解析操作。

请添加图片描述

1.1.4 低分辨率Z通道

添加了 Adreno 5X (A5X) 低分辨率 Z (LRZ) 通道。该通道也称为与绘制顺序无关的深度拒绝。在合并过程中,会构建一个低分辨率 Z 缓冲区,并且可以拒绝 LRZ 切片宽贡献以提高合并性能。然后,在针对全分辨率 Z 缓冲区进行测试之前,在渲染过程中使用该 LRZ 来有效地拒绝像素。

警告

某些条件会向驱动程序发送禁用 LRZ 的提示,其中包括:

  • 在片段着色器中写入深度
  • 使用辅助命令缓冲区 (Vulkan)
  • 任何需要直接渲染的情况

此功能的优点是减少内存访问、减少渲染图元、不需要应用程序从前到后绘制,并允许提高帧速率。

1.2 着色器支持

1.2.1 统一着色器架构

所有 Adreno GPU 都支持统一着色器模型,该模型允许在所有着色器类型(顶点和片段着色器)中使用一致的指令集。在硬件方面,Adreno GPU 具有支持片段着色器和顶点着色器的计算单元(例如,算法逻辑单元(ALU))。

Adreno GPU 使用共享资源架构,允许顶点着色器、像素或片段着色器以及通用处理共享相同的 ALU 和获取资源。

着色器处理是在统一着色器架构内完成的,如下图所示。该图像显示顶点和像素作为向量或线程以四个为一组进行处理。当线程停止时,可以重新分配着色器 ALU。

请添加图片描述
在统一着色器架构中,顶点着色器和片段着色器没有单独的硬件,如下图所示。这使得像素和顶点负载平衡具有更大的灵活性。
请添加图片描述
Adreno 着色器架构也是多线程的。如果片段着色器执行由于纹理获取而停止,则执行将交给另一个着色器。只要硬件中有空间,就会累积多个着色器。

使用统一着色器架构不需要特殊步骤。Adreno GPU 根据场景组合智能地最有效地利用着色器资源。

1.2.1 标量架构

Adreno GPU 具有标量组件架构。它们本身可以支持的最小组件是标量组件。这导致更有效地使用硬件资源来处理标量分量,并且不会浪费完整的矢量分量来处理标量。

与高精度 32 位 (highp) 浮点相比,标量架构在处理使用中等精度 16 位浮点 (mediump) 处理的片段着色器时,能效提高了一倍,性能提高了一倍。

1.3 通用带宽压缩

所有 A5x GPU 均支持通用带宽压缩 (UBWC)。UBWC 是一种独特的预测带宽压缩方案,可提高系统内存的有效吞吐量。通过最小化数据带宽,可以显着节省功耗。

UBWC 适用于 Snapdragon 处理器中的许多组件,包括 GPU、显示器、视频和相机。压缩支持YUV和RGB格式,并减少内存瓶颈。

1.4 纹理特征

1.4.1 多种纹理

多重纹理或多纹理是指在多边形上一次使用多个纹理。Adreno GPU 在单个渲染通道中最多支持 32 个纹理,即片段着色器中最多支持 16 个纹理,顶点着色器一次最多支持 16 个纹理。

有效使用多个纹理可显着减少过度绘制,节省片段着色器的 ALU 成本,并避免不必要的顶点变换。

要在应用程序中使用多个纹理,请参阅Adreno SDK for OpenGL ES中的多纹理示例。

1.4.2 视频纹理

Adreno GPU 支持视频纹理,其中包含从视频文件实时流式传输的移动图像。视频纹理是 Android(Honeycomb 或更高版本)中的标准 API 功能。有关表面纹理的更多详细信息,请参阅 Android 文档:http://developer.android.com/reference/android/graphics/Sur ​​faceTexture.html 。

除了建议使用标准 Android API 之外,还可以使用标准 OpenGL ES 扩展,例如,如果应用程序需要视频纹理。有关更多信息,请参阅http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image.txt。

请添加图片描述

1.4.3 纹理压缩

纹理压缩可以显着提高图形应用程序的性能和加载时间,因为它减少了纹理内存和总线带宽的使用。压缩纹理可以使用 Adreno 纹理压缩和可视化工具创建,随后由 OpenGL ES 应用程序使用。

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

  • ATC – 专有的 Adreno 纹理压缩格式(适用于 RGB 和 RGBA)。

  • ETC – 标准 OpenGL ES 2.0 纹理压缩格式(仅适用于 RGB)。

  • ETC2 – 标准 OpenGL ES 3.0 和 Vulkan 纹理压缩格式,支持 R、RG、RGB 和 RGBA 组件布局以及 sRGB 纹理数据。

  • ASTC - OpenGL ES(3.0 及更高版本)和 Vulkan 支持的纹理压缩格式,允许压缩使用可变块大小。

Adreno GPU 支持 ASTC 的 HDR 和 LDR 配置文件。

要了解有关纹理压缩使用的更多信息,请参阅Adreno SDK for OpenGL ES中的压缩纹理教程。

1.4.4 浮点纹理

Adreno GPU 支持浮点纹理功能,包括以下功能:

  • 通过 GL_OES_texture_half_float 和 GL_OES_texture_half_float_linear 扩展对 FP16 纹理进行纹理化和线性过滤。

  • 通过 GL_OES_texture_float 从 FP32 纹理进行纹理化。

有关支持的纹理和表面格式的完整列表,请参阅纹理格式功能表。

1.4.5 具有无缝边缘的立方体映射

立方体贴图是一种创建高级图形效果(例如环境贴图)的快速且廉价的方法。立方体贴图采用三维纹理坐标并从给定的立方体贴图返回纹理元素(类似于天空盒)。

Adreno GPU 支持立方体贴图纹理采样的无缝边缘支持。
请添加图片描述

1.4.6 纹理尺寸大

Adreno 4X (A4X) 和 A5X GPU 支持高达 16384x16384x16384 的纹理大小(取决于内存可用性)。A3X 支持最大 8192x8192x8192 的纹理尺寸。

1.4.7 sRGB 纹理和渲染目标

sRGB 是由惠普和微软于 1996 年合作创建的标准 RGB 色彩空间,用于显示器、打印机和互联网。如今的智能手机和平板电脑显示器也采用 sRGB(非线性)色彩空间。sRGB 通过正确的颜色提供最佳的观看体验,并确保渲染目标和纹理的色彩空间与显示器的色彩空间相匹配。

不幸的是,OpenGL ES 默认采用线性或 RGB 颜色空间。由于 Adreno GPU 支持渲染目标和纹理的 sRGB 色彩空间,因此可以确保正确的色彩观看体验。请注意,Vulkan 完全处理纹理和交换链可呈现图像中的 sRGB。

1.5 其他支持的功能

1.5.1 深度纹理的百分比更近过滤

Adreno GPU 为 OpenGL ES 3.0 和百分比接近过滤 (PCF) 的 Vulkan 功能提供硬件支持。硬件双线性样本被提取到阴影贴图纹理中,这减轻了实时应用程序中阴影贴图可能出现的锯齿问题。

1.5.2 指数类型

几何网格可以由两个单独的数组表示。一个数组保存顶点,另一个数组保存该数组的三个索引集。它们一起定义了一个三角形。Adreno GPU 原生支持 8 位、16 位和 32 位索引类型。大多数移动应用程序使用 16 位索引。

1.5.3 多重采样抗锯齿

抗锯齿是提高生成图像质量的一项重要技术。它减少了渲染为离散像素的视觉伪影。在减少锯齿效应的各种技术中,Adreno GPU 有效支持多重采样抗锯齿 (MSAA)。

如下图所示,多重采样将每个像素划分为一组样本,每个样本在光栅化过程中都被视为“迷你像素”。每个样本都有自己的颜色、深度和模板值。这些值将被保留,直到图像准备好显示为止。当需要合成最终图像时,样本将被解析为最终的像素颜色。
请添加图片描述

1.5.4 顶点纹理访问或顶点纹理获取

Adreno GPU 具有共享资源的优势,可以通过直接访问纹理缓存来处理顶点和片段着色器。这使得用户能够在 Adreno GPU 上轻松实现函数定义、位移图或照明细节级别 (LoD) 系统的顶点纹理算法。

顶点纹理置换是一种先进的技术,可以在桌面和游戏机的游戏中渲染逼真的水。现在可以在 Adreno GPU 上运行的应用程序中实现同样的效果。

以下是如何在顶点着色器中创建纹理获取的示例:

//vertex shader

attribute vec4 position;

attribute vec2 texCoord;

uniform sampler2D tex;

void main() {

    float offset = texture2D(tex, texCoord).x;..

    gl_Position = vec4(.);

}

1.6 Adreno API

Adreno GPU 支持行业标准 API,包括:

  • OpenGL ES 1.x(固定功能管道)

  • OpenGL ES 2.0(可编程着色器管道)

  • OpenGL ES 3.0

  • OpenGL ES 3.1 + AEP

  • OpenGL ES 3.2

  • 乙二醇

  • 伏尔甘1.0

  • 伏尔甘1.1

  • OpenCL 1.1e

  • OpenCL 2.0 完整简介

  • DirectX 11 FL 9.3

  • DirectX 12 FL 12

2 最佳实践

2.1 一般的

2.1.1 使用可变速率着色

可变速率着色 (VRS) 允许片段着色器一次为一个或多个像素着色,以便片段可以代表一个像素或一组像素。将 VRS 视为解决抗锯齿技术解决问题的逆过程。抗锯齿技术会更频繁地对每个像素进行采样,通过平滑变化较大的内容来避免锯齿和锯齿状边缘。然而,如果要渲染的表面没有高颜色变化或者在后续通道中会变得模糊(例如,运动模糊),则在 1:1 的基础上执行着色操作(每个像素一次着色操作)可能效率低下。

VRS 允许开发人员指定着色率,其中仅对片段执行一次着色器计算,并将结果操作应用于指定的像素组配置。如果使用得当,这应该不会导致视觉质量下降,同时显着减轻 GPU 渲染帧的工作,从而节省电量并提高性能。随着多种高显示速率移动设备的商用,例如由我们的 Qualcomm® Snapdragon™ 移动平台及其嵌入式 Qualcomm® Adreno™ GPU 提供支持的设备,减少了对所有渲染表面的每个像素进行着色的需要。

下面来自我们的可变速率着色演示的屏幕截图显示了如何在高度详细的区域上使用较高速率(每像素)着色,而在较低细节区域上可以使用较低速率(包含像素组的着色片段)。

请添加图片描述

可变速率着色如何工作?
当 GPU 将对象渲染并光栅化到表面时,它以每个像素一个样本的速率进行操作(假设未使用多重采样,尽管这一概念也可以应用于多重采样)。通过图形API扩展,开发人员可以将给定表面的着色率修改为比像素更粗糙,如下图所示:
请添加图片描述
OpenGLES 中的 VRS 通过 QCOM_shading_rate 扩展和 Vulkan 的 VK_KHR_fragment_shading_rate 扩展公开。OpenGL ES扩展包括许多用于控制不同片段大小的枚举(例如,GL_SHADING_RATE_1X1_PIXELS_QCOM、GL_SHADING_RATE_1X2_PIXELS_QCOM等)。您可以在 GitHub 中的新 Adreno GPU OpenGLES 代码示例框架上查看该扩展的使用演示。

Vulkan VK_KHR_fragment_shading_rate 采用 VkExtent2D 结构,开发人员在其中指定所需片段大小的宽度和高度。

  笔记:   Snapdragon 移动平台上对 VK_KHR_fragment_shading_rate 的支持即将推出。

修改着色率的有效方法这些扩展可以提高大量片段绑定绘制调用的性能,例如:

  • 颜色差异较低的表面。

  • 不需要每像素着色精度的表面区域,例如将通过运动模糊缩小尺寸的颜色目标以及速度场发生显着变化的区域。如果使用景深,焦点之外的区域将会变得模糊。

  • 诸如运动体积渲染之类的效果,其中场景的一部分以全着色率处理,一部分可以以降低的着色率处理。

    笔记: 如果使用不当,降低着色率可能会影响渲染对象的视觉质量。在性能和功耗紧密结合的移动设备上,
    使用更均匀的着色率还可以提高功耗并降低游戏的热量分布,最终增加用户的游戏时间。
    

2.1.2 遮挡查询用法

活动的数量不应超过 512 个,结果通常有 3 帧延迟。查询的性能与 bin 数量相关,bin 数量(来自分辨率、MSAA 等)越高,查询的成本就越高。

Adreno GPU 中遮挡查询的建议用法是尽可能以直接模式运行它们。确保发生这种情况的一种方法是在刷新后一批中发出对帧的所有查询,例如渲染不透明 -> 渲染半透明 -> 刷新 -> 渲染查询 -> 切换 FBO。驱动程序具有启发式功能,可以理解仅向地面发出了查询并切换为直接查询。

  笔记:查询的开销将在Snapdragon Profiler中显示为较高的“% CP Busy”指标。

在某些测试用例中,当向分箱表面发出大量查询时,CP 开销可能会跃升至 20-40%,并直接下降至 4-6%。

2.1.3 带宽优化

OpenGL ES 应用程序可能会遇到内存带宽限制的瓶颈。这是 GPU 在给定时间范围内可以访问多少数据的物理限制的体现。该比率不是恒定的,而是根据许多因素而变化,包括但不限于:

  1. 数据的位置 – 是存储在 RAM、VRAM 还是 GPU 缓存之一中?

  2. 访问类型 – 是读操作还是写操作?它是原子的吗?一定要连贯吗?

  3. 缓存数据的可行性——硬件能否缓存数据以供 GPU 将执行的后续操作使用,这样做是否有意义?

缓存未命中可能导致应用程序带宽受限,从而导致性能显着下降。当应用程序绘制或生成许多图元时,或者当着色器需要访问纹理中的许多位置时,通常会导致这些缓存未命中。

可以采取两种措施来最大程度地减少缓存未命中问题:

  1. 提高传输速率——确保客户端顶点数据缓冲区用于尽可能少的绘制调用;理想情况下,应用程序永远不应该使用它们。

  2. 减少 GPU 执行满足此约束的调度或绘制调用所需访问的数据量。

OpenGL ES 提供了多种方法,开发人员可以使用这些方法来减少传输特定类型数据所需的带宽。

第一种方法是压缩纹理内部格式,它牺牲纹理质量以减少 mipmap 大小。OpenGL ES支持的许多压缩纹理格式将输入图像划分为4x4的块,并对每个块单独执行压缩过程,而不是对整个图像进行操作。虽然从数据压缩理论的角度来看它似乎效率低下,但它确实具有每个块在 4 像素边界上对齐的优点。这允许 GPU 使用单个提取指令检索更多数据,因为每个压缩纹理块保存 16 个像素,而不是像未压缩纹理那样保存单个像素。此外,如果着色器不需要对相距太远的纹素进行采样,则可以减少纹理获取的数量。

第二种方法是使用打包顶点数据格式。这些格式基于这样的前提:许多顶点数据集不会因其组件精度的降低而受到很大影响。强烈建议尽可能使用打包顶点数据格式。

对于预先已知范围跨度的某些资源,尝试将数据映射到受支持的打包顶点数据格式之一。以普通数据为例,通过将 10 位无符号整数数据范围 <0, 1024> 标准化到浮点范围 <-1, 1>,可以将 XYZ 分量映射到 GL_UNSIGNED_INT_2_10_10_10_REV 格式。

第三种方法是始终使用索引绘制调用。始终使用尽可能小的索引类型,同时仍然能够寻址正在绘制的网格的所有顶点。这减少了 GPU 为每个绘制调用需要访问的索引数据量,但代价是应用程序逻辑稍微复杂一些。

2.1.4 深度范围优化

游戏中常见的现象是深度冲突,其中两个或多个图元在深度缓冲区中具有相似的值。当相机视图发生轻微变化并且来自不同图元的片段争夺赢得深度测试并变得可见时,伪像就会变得明显。有几种方法可以消除深度冲突:

  • 修改场景几何体以在近平面之间提供更大的距离(首选)。

  • 选择具有较大深度缓冲区的 EGL 配置(例如 24 位与 16 位),但使用较大缓冲区可能会影响性能。

  • 收紧相机深度范围(近剪裁平面和远剪裁平面),以提高 z 方向的精度,但这对共面基元没有帮助;考虑使用多个范围渲染场景,一个用于近处物体,一个用于远处物体。

2.1.5 其他优化

3D 渲染过程是一项计算密集型活动。屏幕分辨率越来越大,有些即将达到超高清分辨率。这意味着 GPU 需要在同一固定时间段内光栅化更多片段。假设目标帧率为 30 fps,游戏单帧时间不得超过 33 毫秒。如果是这样,那么每秒的屏幕更新次数将会下降,用户将更加难以完全沉浸在游戏中。

此外,硬件越繁忙,产生的热量就越多。如果在很长一段时间内,GPU 在帧之间没有任何空闲时间,设备可能会变得很热并且握起来不舒服。如果温度超过一定的安全阈值,设备甚至可能会自动降低GPU时钟频率以防止过热。这将进一步降低用户体验。

为了减少渲染硬件上的负载,应用程序可以减小所使用的渲染目标的大小,例如,如果本机屏幕分辨率是 1080p (1920x1080),则可以将其渲染为 720p (1280x720) 渲染目标。由于两种分辨率的长宽比相同,因此图像的比例不会受到影响。缩小尺寸的渲染目标不会完全填满屏幕,但 OpenGL ES 提供了针对此问题的修复。

OpenGL ES 3.0 引入了对帧缓冲区 blit 操作的支持。绘制缓冲区的内容可以从一个帧缓冲区传输到另一个帧缓冲区。作为 blit 操作的一部分,该 API 还支持放大,可用于将较小分辨率的纹理的内容复制到另一个较大分辨率的纹理。使用放大来放大缩小尺寸的渲染目标,以匹配完整的本机显示尺寸。最佳策略取决于 GPU 必须为应用程序执行的计算强度。放大可以在渲染过程结束时完成,也可以在渲染管道中的某个时刻完成;例如,一种方法可能是以 1:1 分辨率渲染几何体,但使用分辨率稍低的渲染目标应用后处理效果。

  笔记:使用帧缓冲区位块传输进行升级比直接将全屏四边形渲染到后台缓冲区的替代方法更快,将缩小尺寸的渲染目标作为纹理输入。

或者,通过 Android API 控制缩放:

对于用 Java 编写的应用程序,配置 GLSurfaceView 实例的固定大小属性(自 API 级别 1 起可用)。使用 setFixedSize 函数设置属性,该函数采用两个定义最终渲染目标分辨率的参数。

对于用本机代码编写的应用程序,使用函数 NativeWindow_setBuffersGeometry 定义最终渲染目标的分辨率,该函数是 NativeActivity 类的一部分,在 Android 2.3(API 级别 9)中引入。

在每次交换操作中,操作系统都会获取最终渲染目标的内容并将其放大,以使其与显示器的本机分辨率相匹配。

该技术已成功应用于主机游戏,其中许多游戏对 GPU 提出了很高的要求,如果以全高清分辨率进行渲染,则可能会受到所讨论的硬件限制的影响。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值