GPU|如何用 GPU硬件层加速优化Android系统的游戏流畅度

GPU|如何用 GPU硬件层加速优化Android系统的游戏流畅度

文章图片

GPU|如何用 GPU硬件层加速优化Android系统的游戏流畅度

文章图片

GPU|如何用 GPU硬件层加速优化Android系统的游戏流畅度

文章图片

GPU|如何用 GPU硬件层加速优化Android系统的游戏流畅度

作为一款VR实时操作游戏App , 我们需要根据重力感应系统 , 实时监控手机的角度 , 并渲染出相应位置的VR图像 , 因此在不同 Android 设备之间 , 由于使用的芯片组和不同架构的GPU , 游戏性能会因此受到影响 。 举例来说:游戏在 Galaxy S20+ 上可能以 60fps 的速度渲染 , 但它在HUAWEI P50 Pro上的表现可能与前者大相径庭 。由于新版本的手机具有良好的配置 , 而游戏需要考虑基于底层硬件的运行情况 。
如果玩家遇到帧速率下降或加载时间变慢 , 他们很快就会对游戏失去兴趣 。 如果游戏耗尽电池电量或设备过热 , 我们也会流失处于长途旅行中的游戏玩家 。 如果提前预渲染不必要的游戏素材 , 会大大增加游戏的启动时间 , 导致玩家失去耐心 。 如果帧率和手机不能适配 , 在运行时会由于手机自我保护机制造成闪退 , 带来极差的游戏体验 。
基于此 , 我们需要对代码进行优化以适配市场上不同手机的不同帧率运行 。
所遇到的挑战 首先我们使用Streamline 获取在 Android 设备上运行的游戏的配置文件 , 在运行测试场景时将 CPU 和 GPU性能计数器活动可视化 , 以准确了解设备处理 CPU 和 GPU 工作负载 , 从而去定位帧速率下降的主要问题 。
以下的帧率分析图表显示了应用程序如何随时间运行 。

在下面的图中 , 我们可以看到执行引擎周期与 FPS 下降之间的相关性 。 显然GPU 正忙于算术运算 , 并且着色器可能过于复杂 。

为了测试在不同设备中的帧率情况 , 使用友盟+U-APM测试不同机型上的卡顿状况 , 发现在onSurfaceCreated函数中进行渲染时出现卡顿 ,应证了前文的分析 , 可以确定GPU是在算数运算过程中发生了卡顿:

因为不同设备有不同的性能预期 , 所以需要为每个设备设置自己的性能预算 。 例如 , 已知设备中 GPU 的最高频率 , 并且提供目标帧速率 , 则可以计算每帧 GPU 成本的绝对限制 。
数学公式: $ 每帧 GPU 成本 = GPU 最高频率 / 目标帧率 $
CPU到 GPU 的调度存在一定的约束 , 由于调度上存在限制所以我们无法达到目标帧率 。 另外 , 由于 CPU-GPU 接口上的工作负载序列化 , 渲染过程是异步进行的 。 CPU 将新的渲染工作放入队列 , 稍后由 GPU 处理 。
数据资源问题 CPU控制渲染过程并且实时提供最新的数据 , 例如每一帧的变换和灯光位置 。 然而 , GPU 处理是异步的 。 这意味着数据资源会被排队的命令引用 , 并在命令流中停留一段时间 。 而程序中的OpenGL ES 需要渲染以反映进行绘制调用时资源的状态 , 因此在引用它们的 GPU 工作负载完成之前无法修改资源 。

调试过程 我们曾做出尝试 , 对引用资源进行代码上的编辑优化 , 然而当我们尝试修改这部分内容时 , 会触发该部分的新副本的创建 。 这将能够一定程度上实现我们的目标 , 但是会产生大量的 CPU 开销 。
于是我们使用Streamline查明高 CPU 负载的实例 。 在图形驱动程序内部libGLES_Mali.so路径函数 视图中看到极高的占用时间 。

由于我们希望在不同手机上适配不同帧率运行 , 所以需要查明libGLES_Mali.so是否在不同机型的设备上都产生了极高的占用时间 , 此处采用了友盟+U-APM来检测用户在不同机型上的函数占用比例 。