分析 AGI 纹理数据并提升 GPU 性能

Android GPU Inspector (AGI) 能够帮助我们洞悉 Android 设备上的 GPU 内部运行情况。对 GPU 来说,最具挑战性的任务之一就是在着色器中获取和过滤纹理数据。通过采集带宽缓存行为滤镜渲染三个方面的数据,我们就可以使用 AGI 监视与纹理相关的 GPU 工作负载。

我常常从观察纹理带宽入手,因为它表明了每帧画面中有多少纹理数据输入到了 GPU,进而可以快速定位潜在的性能问题。

就纹理带宽来说,一个很好的经验法则就是确保纹理读取带宽 (Texture Read Bandwidth) 均值不高于 1GB/s,而峰值远低于 5GB/s。

比如这个游戏,它就消耗了大量的纹理带宽,因为平均带宽达到了 4GB/s,而到了帧结尾的部分,峰值已超过 6GB/s。

后续渲染步骤 (Post Processing steps) 对纹理带宽需求较高是可以理解的,也许您可以在渲染的后序阶段把部分带宽使用于一些特殊的效果处理上面,比如实现光晕和色调映射。但是如果您的游戏存在很高的纹理读取带宽峰值,那么就需要注意潜在的性能问题了。

对于这个游戏来说,纹理带宽的消耗非常高,需要进一步分析。

要分析潜在的纹理带宽问题,首先我会检查纹理缓存情况。我的关注点在于纹理的停滞比例,L1 和 L2 缓存未命中的比例。当 L1 缓存未命中所需的纹理数据时,请求会转向 L2 缓存,然后会再转向系统内存。每一步都会增加延迟并且提高功耗。L1 的平均未命中比例不应该超过 10%,未命中的峰值比例不应该超过 50%。

这个游戏在 GPU 系统的数据采集显示 L1 缓存的平均未命中比例超过了 20%,而峰值已经达到 80% 甚至更高。

可见这些数据的确非常高了。

对于纹理停滞比例较高的典型原因是纹理未压缩、复杂的过滤操作 (如非等向性过滤),以及纹理未经 mipmap 处理。

为了分析造成纹理缓存未命中的潜在原因,我会观察非等向性过滤 (anisotropic filtering) 的纹理获取比例 (属于移动终端上的耗时操作) 和非基础级别纹理 (Non Base Level) 的获取比例。

获取非基础级别纹理的比例是对 mipmap 纹理获取效率的初略估计。当该数字为 0 时,它意味着 GPU 常常访问最顶级的 mipmap 纹理数据,也就是纹理的 mipmap 链中最大的一片或者未进行 mipmap 处理的纹理。

虽然在 2D 游戏中基本上可以接受这样的处理,但是在 3D 游戏中,这就算是问题了。

当渲染 GUI 或者 PostProcessing 期间访问未经 mipmap 处理的纹理是可以的。但是在其它场景下,这样的操作会带来很大的性能损失,也是导致较差数据缓存效果的原因。

事实上,获取纹理会消耗大量的系统带宽,同时可能会造成延迟、电池寿命缩短,甚至引起过热问题进而导致进一步的性能下降。分析纹理行为相关的 GPU 计数数据并解决所发现的问题,能够更轻易、更大幅度地提升用户体验。

要发现该类型和纹理相关的 GPU 性能问题,可以使用 Android GPU Inspector 采样您的游戏数据,然后依据这里为大家介绍的内容比较分析 GPU 计数器的数据和变化趋势。