简介
本教程是关于对基于 Android* 的 OpenGL ES* 3.0 应用进行性能分析、瓶颈识别和渲染优化的分布指南。 示例应用 “City Racer” 将通过程式化城市设置模拟公路赛车。 我们通过英特尔® 图形性能分析器(英特尔® GPA)工具套件对应用进行性能分析。
城市与车辆组合而成的几何结构包含大约 23 万个多边形(69 万个顶点),各种材料映射于四周,而照明由单个无阴影平行光投射灯提供。 提供的源材料包括构建应用所需的代码、项目文件和艺术资产,包含本教程介绍的源代码优化。
致谢
本教程是 David Houlton 编写的 Android 和 OpenGL ES 3.0 版面向第三代英特尔酷睿处理器 (Ivy Bridge) 的英特尔图形性能研讨会 (PDF)。 它配有英特尔 GPA。
教程结构
本教程将为您展示四个优化步骤。 每一步都会采用英特尔 GPA 分析应用识别特定的性能瓶颈。 然后在应用中切换至相应的优化以消除瓶颈,并再次进行分析以测量所实现的性能提升。 所采用的优化步骤均遵循面向英特尔® 处理器显卡的开发人员指南 (PDF)。
在本教程中,采用优化后,City Racer 的渲染性能提高了 83%。
前提条件
- 采用 Android API 版本 20和 Android NDK 版本 10构建 City Racer 示例。
- 采用英特尔 GPA 工具套件执行性能分析。
- 英特尔 GPA 可与大多数 Android 设备兼容;不过基于 x86 架构的 Android 设备可提供最详细的分析指标。
City Racer 示例应用
City Racer 逻辑划分成赛车模拟和渲染子组件。 赛车模拟包含对车辆加速、刹车、转向参数,以及针对轨迹跟踪和防撞的 AI 建模。 赛车模拟代码位于 track.cpp 和 vehicle.cpp 文件中,本教程中采用的优化不会对其产生任何影响。
渲染组件包括使用 OpenGL ES 3.0 和内部开发的 CPUT 框架牵引车辆和场景几何图。 第一版渲染代码就表现出了一次通过的努力和决心,可提供多种性能限制设计选择。
网格和纹理资产可从 Media/defaultScene.scene 文件中加载。 独立网格即可标记成预先放置的场景物品,或基于每实例转换数据的实例化场景,也可标记成可接受模拟提供的转换数据的车辆。 场景中设置了多个摄像头: 车辆尾部各设置一个,还设置了另外一个摄像头以支持用户自由开发场景。 所有性能分析和代码优化均面向车尾摄像头模式。
为实现本教程的目的,City Racer 设计成从暂停模式开始,这样有利于大家了解各分析步骤以及相似的数据集。 取消选中 City Racer HUD 的 Pause 复选框,或在 CityRacer.cpp 顶部设置 g_Paused = false,可解除 City Racer 的暂停状态。
优化潜力
将 City Racer 应用视作可以工作但未经优化的原型。 在初始状态下,它可提供所需的视觉效果,但不提供渲染性能。 它包含许多技巧和设计选择,是典型游戏类开发(限制渲染性能)中比较具有代表性的。 开发过程中的优化阶段旨在逐步识别性能瓶颈、通过修改代码消除瓶颈,并测量所获得的性能提升。
请注意,本教程仅介绍一小部分适用于 City Racer 的优化方法。 具体来说,它仅考虑源代码会完全采用的优化,不对模式或纹理资产做出任何更改。 我们此处不介绍其他会更改资产的优化方法,因为通过教程实施这些方法会非常繁琐。但它们可通过英特尔 GPA 工具来识别,而且在真实游戏优化中应该考虑使用。
本文所展示的性能数据均通过运行 Android、基于英特尔® 凌动™ 处理器的系统(代号 “Bay Trail”)获得。 具体数据可能因系统的不同而有所差异,但相对性能关系应该类似,因此从逻辑上来说,性能优化应该相同。
整个教程采用的优化方法均可在 CityRacer.cpp 中找到。 通过 City Racer 的 HUD 或在 CityRacer.cpp 中直接修改可对这些方法进行切换。
CityRacer.cpp
bool g_Paused = 真; bool g_EnableFrustumCulling = 假; bool g_EnableBarrierInstancing =假; bool g_EnableFastClear = 假; bool g_DisableColorBufferClear = 假; bool g_EnableSorting = 假;
随着优化的逐步开展,它们将一个一个启用。 一个变量控制一个或多个代码段的替换,以实现教程中相应步骤的优化目标。
优化教程
第一步是在 Android 设备上构建和部署 City Racer。 如果正确设置了 Android 环境,位于 CityRacer/Game/Code/Android 的 buildandroid.bat 文件将为您执行这些步骤。
接下来启动英特尔 GPA Monitor,右击系统托盘图标,然后选择 System Analyzer。
System Analyzer 将显示待连接的平台列表。 选择您的 Android x86 设备并按下 “Connect”。
System Analyzer 连接 Android 设备后,将显示供分析的应用列表。 选择 City Racer 并等待启动。
在 City Racer 运行的过程中,按下帧采集按钮以采集 GPU 帧的截图以供分析。
检查帧
打开面向 OpenGL* 的帧分析器,并选择刚才采集的 City Racer 帧,以详细地检查 GPU 性能。
顶部的时间线将按照均匀分布的工作 ‘erg’ 展开,一个 erg 通常对应一次 OpenGL 绘制调用。 如欲了解更多有关传统时间线显示的信息,请在 X 轴和 Y 轴上选择 GPU Duration。 这样可以快速显示哪些 erg 的 GPU 耗时最长,以及我们首先应该关注的地方。 如果没有选择 erg,右侧面板将显示整个帧的 GPU 耗时,为 55 毫秒。
优化 1 — Frustum Culling (视锥剔除)
查看所有绘制时,我们发现,许多已绘制的条目并未显示在屏幕中。 通过将 Y 轴改成裁剪后图元数,视图中的空白可指出哪些绘制遭到了浪费,因为整个几何图都将被裁剪。
City Racer 中的建筑物根据空间位置组合在一起。 我们可以剪掉看不见的组,这样可免除相关的 GPU 工作。 切换 Frustum Culling 复选框后,每个绘制都会在提交至 GPU 之前通过视锥剔除例程在 CPU 上运行。
打开 Frustum Culling 复选框,使用 System Analyzer 采集另一个帧。 采集后,在 Frame Analyzer 中将其重新打开。
通过查看我们发现,绘制数量从 740 降至 576,减少了 22%,因此总 GPU 时间缩短了 18%。
优化 2 — Instancing (实例化)
尽管视锥剔除能够减少 erg 数量,但还有大量 erg (以黄色标注),如果累计使用,会占用大部分 GPU 时间。
通过检查几何图中的 erg,我们发现大部分 erg 是车道两旁的混凝土防撞栏。
我们可以将它们整合成单个实例化绘制,从而避免大部分开销。 切换 Barrier Instancing 复选框,防护栏将整合成单个实例化绘制,因此 CPU 无需通过绘制到 GPU 来提交各个绘制。
打开 Barrier Instancing 复选框,使用 System Analyzer 采集另一个帧。 采集后,在 Frame Analyzer 中将其打开。
通过查看我们发现,绘制数量从 576 降至 60,减少了 90%。
混凝土防撞栏实例化前(顶部)后(底部)的绘制调用
此外,GPU 持续时间也缩短至 13 毫秒,缩短了 71%。
优化 3 — Front to Back Sorting(从前到后分类)
术语 “重绘” 指多次写入各像素;这样会影响像素填充率并延长帧渲染时间。 示例写入指标显示,每帧各像素的写入次数约为 1.8 次(分辨率/示例写入)。
在渲染前从前到后对绘制进行分类可以直接减少重绘的数量,因为 GPU 管道会拒绝之前绘制阻挡的像素。
打开 Sort Front to Back 复选框,使用 System Analyzer 采集另一个帧。 采集后,在 Frame Analyzer 中将其打开。
通过查看我们发现,示例写入指标下降了 6%,而且总 GPU 时间也缩短了 8%。
优化 4 — Fast Clear(快速清除)
最后,绘制时间显示,第一个 erg 占用了最长的 GPU 时间。 选择该 erg,表示它不是绘制,而是 glClear 调用。
英特尔 GPU 硬件包含优化路径,可执行 ‘快速清除’,其耗时要远远短于传统清除方法。 快速清除的执行方法是:将 glClearColor 设置成全黑或全白(0, 0, 0, 0 或 1, 1, 1, 1)。
打开 Fast Clear 复选框,使用 System Analyzer 采集另一个帧。 采集后,在 Frame Analyzer 中将其打开。
通过查看我们发现,相比于常规清除方法,快速清除的 GPU 持续时间缩短了 87%,从之前的 1.2 毫秒缩短至 0.2 毫秒。
因此,GPU 的总体帧持续时间缩短至 9.2 毫秒,缩短了 24%。
结论
本教程以比较具有代表性的早期游戏应用为例,使用英特尔 GPA 分析应用行为,并有针对性地做出一些调整以提升性能。 做出的调整和实现的性能提升如下所示:
优化 | 之前 | 之后 | 提升率 |
Frustum Culling(视锥裁剪) | 55.2 毫秒 | 45.0 毫秒 | 18% |
Instancing(实例化) | 45.0 毫秒 | 13.2 毫秒 | 71% |
Sorting(分类) | 13.2 毫秒 | 12.1 毫秒 | 8% |
Fast Clear(快速清除) | 12.1 毫秒 | 9.2 毫秒 | 24% |
GPU 总体优化 | 55.2 毫秒 | 9.2 毫秒 | 83% |
在性能检测过程中涉及的软件及其性能只有在英特尔微处理器的架构下才能得到优化。 诸如 SYSmark* 和 MobileMark* 等测试均系基于特定计算机系统、硬件、软件、操作系统及功能。 上述任何要素的变动都有可能导致测试结果的变化。 请参考其它信息及性能测试(包括结合其它产品使用时的运行性能)以对目标产品进行全面评估。 如欲了解更多信息,请访问 http://www.intel.com/performance。
总体而言,从 City Racer 的最初实施到最佳优化版本,我们证明渲染性能可以提升 300%(从 11 fps 到 44 fps)。 由于这种实施方法一开始无法达到最佳性能,因此使用这些技巧的开发人员可能无法在真实游戏中实现同样绝对的性能提升。
尽管如此,本教程的目的不是优化某个特定示例应用,但如果采纳面向英特尔处理器显卡的开发人员指南,大家可以实现潜在的性能提升,而且还可以使用英特尔 GPA 查看并测量这些性能提升。