在英特尔® 架构平台上开发和优化基于 NDK 的 Android 游戏应用
作者:杜伟
Android 原生开发套件 (NDK) 是 Android SDK 的附带工具。借助该工具,您可以使用诸如 C 和 C++ 等本地代码语言实现部分应用。
您可以从以下网址下载该 NDK 工具包:http://developer.android.com/tools/sdk/ndk/index.html
适合 X86 指令集架构的 NDK
Android 是一个由 Google 开发的开源操作系统。 当前,Android 可以在三种指令集架构上运行: ARM、x86 和 MIPS。 X86 表示一组基于英特尔 8086 CPU(自 1978 年开始使用)的指令集架构。我们现在从应用程序的角度介绍 X86 (也称为英特尔® 架构,或 IA) 和其他 Android 可以运行的芯片组之间的差异。
Android 应用可被分成两类:
- 包含 Java* 代码和仅使用 Android 官方 SDK API 和必要资源文件(诸如 .xml 和 .png)的 Dalvik 应用,可编译成一个 APK 文件。
- 包含 Java 代码、资源文件、C/C++ 源代码(有时也包含汇编码)的 Android NDK 应用。 所有本地代码被编译成一个动态链接库 (.so 文件),然后在主程序中通过使用 JNI 机制的 Java 进行调用。
Android 游戏引擎
游戏引擎是游戏应用的一个重要模块。 有几个引擎可以在 Android 上运行,其中包括一些开源的商用 2D 和 3D 引擎。 因此,我们很难将 Android 游戏迁移到 IA 平台上,也难以在这种平台上开发 Android 游戏。 Cocos2d-x 和 Unity 3D 是 Android 平台最受欢迎的游戏引擎。
Cocos2d-x 基于 Cocos2d-iPhone 构建而成,包含各种扩展支持平台,同时还有多种可以共享同一种 API 结构的编程语言。 自 2010 年 7 月开始使用以来,cocos2d-x 下载的次数已经超过了 5 亿次。 包括 Zynga、Glu、GREE、DeNA、Konami、TinyCo、Gamevil、HandyGames、Renren Games、4399、HappyElements、SDO 和 Kingsoft 在内的著名手机游戏公司正在使用 cocos2d-x。
Unity 3D 是一个跨平台的游戏引擎,内建有 Unity Technologies 公司开发的 IDE。 我们可以使用它开发适合 web 插件、台式机平台、控制台和移动设备的视频游戏。迄今为止,已经有超过一百万的开发人员使用过该引擎。 2005 年时,它只是一个 OS X 支持的游戏开发工具,现在,它已经成长为一个多平台游戏引擎。 最新的更新 Unity 4.1 于 2013 年三月发布。它现在可以支持 iOS、Android、Windows、Blackberry 10、OS X、Linux、web 浏览器、Flash*、PlayStation 3、Xbox 360、Windows Phone 和 Wii 的应用开发。
在 IA 平台上开发基于 NDK 的游戏
在我们讨论游戏开发之前,我们应当先讨论 Android 平台。 如您所知,游戏有着多种不同的风格。 不同风格的游戏需要不同的设计原理。 在您的项目开始前,您应当先为您的游戏确定风格。 如果您不能想出全新的和前所未见的思路,那么很可能您的游戏思路就会因为效仿当前流行风格而变得普通。 大多数的风格已经成为了机械的游戏标准(例如控制方案、具体目标等)。 而偏离这些标准则可能让您的游戏变得与众不同,因为游戏玩家总会期待出现新的事物。 一些常见的风格包括:
- 街机与动作
- 益智解密
- 纸牌与赌场
- 休闲
- 动态壁纸
- 竞赛
- 体育游戏
- 小游戏
- 等等
开发普通 Android 游戏的过程和任何其他的 Android 应用相类似。 首先,从 Google 的网站下载 Android SDK 和 NDK,然后进行正确安装。
我假设您已经完成了所有的安装和准备工作。 我们以 Cocos2d-x 游戏引擎为例,说明如何为英特尔人架构创建一款游戏。
下载 Cocos2D-x
从以下网站下载稳定、最新的 Cocos2D-x 版本:http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Download
执行批处理
执行来自 Windows Explorer 的批处理任务。 当它询问你项目位置时,请把它设置成像 com.yourproject.something 一样的格式,并选择项目名称和目标 ID。这将在 cocos2dx 安装文件夹中创建一个以项目名称的名称的文件夹。 您应当参考无错式脚本的执行情况,具体如下:
设置 NDK_ROOT 的环境变量
将以下环境变量添加到 home\<yourname>\.bash_profile 文件的结尾处(在本案例中:c:\cygwin\home\user\.bash_profile):
1 |
NDK_ROOT=/cygdrive/<yourname>/ |
2 |
3 |
export
NDK_ROOT |
重启 cygwin,输入 cd $NDK_ROOT,您会看到该屏幕:
执行 build_native.sh 文件
默认的配置是 ARM;我们需要改变配置,使其符合 x86 的编译要求。 打开 \helloworld\proj.android \build_native.sh 文件,找到 ndk-build 命令,将 APP_ABI=x86 参数添加到该命令的结尾处。 在 Cygwin 中运行它,您会看到:
把项目导入到 Eclipse
现在转至 Eclipse,创建一个新的项目 -> 从现有项目导入。
构建并运行
到该步骤时,Eclipse 将会出现一些问题:
导入问题 org.cocos2dx.lib 不能被解析为 HelloWorld.java
/HelloWorld/src/com/young40/test 第 26 行 Java 问题 Cocos2dxActivity 不能被解析为 HelloWorld.java 类型
/HelloWorld/src/com/young40/test 第 30 行 Java 问题 Cocos2dxActivity 不能被解析为 HelloWorld.java 类型
/HelloWorld/src/com/young40/test 第 33 行 Java 问题
你必须将下列库导入到 Eclipse 中:
cocos2d-2.1beta3-x-2.1.1/cocos2dx/platform/android/java
转至 Project -> Build,然后运行 As -> Android Application:
然后将针对 cocos2dx 游戏引擎构建一个游戏框架。 您可以将游戏逻辑、音频、图片等资源添加到该项目中,使其成为一款完整的游戏。
在 IA 平台上优化基于 Android NDK 的游戏
英特尔® System Studio 是一套可对Android 平台上的应用进行配置和优化的工具。 当然,我们也可以使用它对游戏进行优化。英特尔 System Studio包括:
- 英特尔®C++ 编译器
- 英特尔®图形性能分析器
- 英特尔®VTune™放大器
- (英特尔®JTAG 调试器)
本文中我们无法针对每个工具进行详细解释。 我们只能通过一个示例为您演示英特尔工具的工作原理。
首先,我们以一个名为“弹跳小球”的应用为例,该应用将在一个因特尔® 凌动™ Z2460 (代号 Medfield) 处理器上运行。 该游戏共有 800 多个小球,这些小球移动时的速度是随机的,彼此之间的碰撞也毫无规律性。 我们通过测量 FPS 发现其性能很差,在不进行任何优化的情况下仅为 6。
我们可以使用英特尔® 图形性能分析器 (Intel® GPA) 找出是哪个模块造成这种瓶颈,查明 CPU 或 GPU 是否是这种问题的根源。
以下为英特尔 GPA 屏幕截图,该图表通过 Android 平台上的 GPA 说明了该应用的细节情况。 您会看到此时 CPU 消耗了 52.5% 的资源。 这对一款应用来说已经是相当高的比例。 同时,运行在 GPU 内的 ISP 负载、TA 负载、TSP 负载和 USSE 总负载都低于 10%,这意味着 GPU 负载是正常的。 因此我们可以推断出 CPU 模块是造成瓶颈的根源。 为了进一步分析 CPU 瓶颈问题,我们需要使用 VTune™ 分析器配置代码。
此处我们不会说明如何使用 VTune 分析器,我们只对我们在运行它时获得的结果进行解释。 关键就在于 libm.so 之内的正弦和余弦函数。因此问题就是: 该应用在运行这两个函数时为何会花费如此多的时间和 CPU 循环?
通过检查应用源代码,我们发现每个小球在被 OpenGL ES* 渲染时都会调用这两个关键函数。 所有小球的几何结构都是相同的,只是尺寸有所不同。 我们可以使用 OpenGL 的 glScale 函数复制小球,这样关键函数的工作量就会大幅降低。
代码优化之后,性能提升了 80%;FPS 是 14。而且,我们可以通过英特尔 C/C++ 编译器编译应用,进而在英特尔架构平台上实现更出色的性能。 英特尔 C/C++ 编译器在 IA 平台上有许多性能优化标识。 此处我们只介绍其中一些标识。
- SSSE3_ATOM
补充流 SIMD 扩展 3 (SSSE3 或 SSE3S) 是一种由英特尔创建的 SIMD 指令集,属于第四代 SSE 技术。 - IPO
过程间优化标识会降低函数调用开销、消除死码同时对常数传播和流程进行重新整理。 - PGO
配置文件导引优化标识通过分析将许多问题留给优化程序处理,例如:- x > y 的频率
- 计数的大小是多少
- 接触的代码有哪些,以及频率
此外,因特尔 C/C++ 编译器也可按如下方式提升应用性能:
- 更准确的分支预测
- 基本块移动提升指令高速缓存行为
- 更好的内联函数决策(有助于 IPO)
- 更好的函数排序优化
- 开关语句优化
- 更好的向量化决策
通过使用不同的编译器和不同的编译参数,一款应用可以实现不同的性能。 此处对比了两种编译器 GCC 和 ICC 的性能。 我们让同一款“弹跳小球”应用运行在搭载英特尔 Medfield 的 android 手机上。 蓝色部分代表 GCC 的性能,红色部分代表 ICC 性能。 而对比的基准就是不使用任何参数进行编译。 图表的第二部分表示通过 arch=atom 进行编辑。 第三部分表示通过所有上述参数进行重新编译。 最后,您能看到通过 ICC 编译的应用与 GCC 相比在性能上提升了 60%。
总结
我们为您快速介绍了在 IA 平台上进行 Android 游戏开发和优化。 游戏引擎是所有游戏开发的核心部分。 如果它们在 IA 平台上运行得很流畅,那么游戏也会运行的很流畅。 我们以流行的游戏引擎 cocos2dx 为例演示如何在 IA 平台上进行开发。 英特尔也为开发人员提供了许多工具,帮助他们在 Android 平台上优化自己的游戏应用。 通过使用英特尔 System Studio,我们展示了如何对一个示例应用进行优化。
关于作者
Tao Peng 是英特尔软件和服务事业部的一名应用工程师,专注于移动应用支持领域,主要负责为 x86 设备进行 Android 应用开发和优化以及 Web HTML5 应用开发。