This article, the continuation of a two-part series, discusses the barriers that exist to porting OpenGL games to the Google Android platform. You should recognize these barriers before undertaking a game porting project, including differences in OpenGL extensions, floating-point support, texture compression formats, and the OpenGL Utility Library (GLU). Setting up your Android development system for Intel® Atom™ processors and getting the best possible performance from the Android virtual device emulation tools with OpenGL ES are also covered.
Part 1 of this series showed how to use OpenGL ES on the Android platform through either the software development kit (SDK) or the Android Native Development Kit (NDK) and how to decide which approach to use. The various OpenGL ES sample apps in the SDK and NDK were described as well as the Java* Native Interface, which allows you to combine Java and C/C++ components. Deciding whether you should target OpenGL ES version 1.1 or 2.0 was also discussed.
The OpenGL ES 1.1 application programming interface (API) is a subset of the OpenGL 1.x APIs that have been used on desktop Linux* and Windows* systems for decades. Likewise, the OpenGL ES 2.0 API is a subset of the OpenGL 2.0 API from desktop systems. Therefore, any game porting project should start with an assessment of the OpenGL feature set that the game’s code uses to determine the age of the code and identify the parts that you must rewrite because of differences between the OpenGL version used and the OpenGL ES version targeted on Android.
The major differences between OpenGL 2.0 and OpenGL ES 2.0 fall into three main categories: geometry specification, geometry transformation, and changes in the OpenGL Shading Language (GLSL). OpenGL 2.0 offers four ways to specify geometry: immediate mode, display lists, vertex arrays, and vertex buffer objects. OpenGL ES 2.0 does not support immediate mode (
glEnd blocks) or display lists, so you must specify geometry with either vertex arrays or vertex buffer objects.
OpenGL 2.0 has functions for loading the model view, projection, and texture matrices plus some convenience functions for combining these matrices, such as
glScale. OpenGL ES 2.0 has neither these functions nor any of the lighting-related functions because the fixed-function pipeline has been replaced with the shader programming model. For OpenGL ES 2.0, matrix and lighting calculations should be made in the vertex shader.
The shader language for OpenGL ES 2.0 (GLSL ES) is also a subset of the shader language for desktop OpenGL 2.0 (GLSL). One major difference is that GLSL has built-in variables to access states in the fixed-function pipeline in the vertex shader (such as
gl_ModelViewMatrix). Because OpenGL ES 2.0 does not support the fixed-function pipeline, these variables are not supported in GLSL ES.
The following OpenGL 2.0 features are lacking in OpenGL ES 2.0:
Note: For more information on the differences between OpenGL 2.0 and OpenGL ES 2.0, see http://software.intel.com/en-us/articles/targeting-3d-applications-for-mobile-devices-powered-by-opengl-and-opengl-es.
Porting OpenGL ES games from other embedded systems to Android is generally easier than porting from desktop systems with OpenGL because most embedded systems use the same OpenGL ES 1.1 or 2.0 specifications as Android. When porting OpenGL ES code from another embedded system, the most significant differences are typically in the OpenGL ES extensions supported, particularly with regard to compressed texture formats. Another area of concern is possible differences in floating-point support between the embedded systems.
Early implementations of OpenGL ES 1.0 and 1.1 were provided in two versions named Common and Common-Lite. The Common version is for processors that have floating-point hardware; the Common-Lite version is for processors that do not and so must use fixed-point calculations instead. Because Android requires processors with floating-point support, such as Intel Atom processors, there is no need ever to use fixed points, so the system images Google provides for Android include only Common (floating-point) drivers for OpenGL ES 1.1. The Khronos standard for OpenGL ES 2.0 mandates floating-point only. This is important if you are porting an OpenGL ES 1.0 or 1.1 game from another embedded system that uses a Common-Lite implementation of OpenGL ES because you must convert all of the fixed-point calculations in the code to floating-point (as only the Common version of OpenGL ES is available on Android). Common and Common-Lite drivers on embedded Linux systems are typically named something like
If you are porting OpenGL code from a desktop application, it is probably floating-point code already. However, beware of the use of any double-precision floating-point in the code. Android supports double-precision floating-point, but OpenGL ES only supports single-precision float. Therefore, any double-precision values will have to be converted to single precision prior to being passed to OpenGL ES 1.1 or 2.0.
One of the most significant barriers to porting OpenGL code across platforms comes from the use of extensions to OpenGL and the Embedded Systems Graphics Library (EGL) by the application code. It is critical to assess which extensions are being used in the legacy code and compare those against the extensions actually available on the targeted Android devices early in the porting process. Extensions are how GPU developers expose special features of their GPU that go beyond the standard OpenGL specifications. Every extension used in legacy code that is not available on the target platform will require new code to either eliminate the need for the extension or use a different extension.
Supported extensions vary greatly across differing versions of OpenGL, but even across various Android platforms, the extensions supported vary because of differences in GPU architectures. Intel Atom processors feature PowerVR* GPUs, which is the most widely used GPU architecture on mobile devices today. Android applications should never assume that any particular extension to OpenGL ES is available on any particular device. Instead, well-behaved apps query OpenGL ES for a list of available extensions at runtime. You can obtain these extension lists from the OpenGL ES and EGL drivers with the following calls:
All of the function and enumeration names required to call extensions are defined in the
eglext.h header files, so that after your app has verified that a particular extension is available at runtime, it can be called directly.
A useful app on the Google Play website is the OpenGL Extensions Viewer (GLview) that performs this query and displays the returned information for any Android device on which you run it. It’s a good idea to test a range of Android devices yourself for the presence of the extensions you need with a tool like GLview. In addition, Khronos maintains the OpenGL ES API Registry for all known OpenGL ES extensions—an essential reference.
The most important extensions to OpenGL ES provide support for compressed textures. This is an important technique that most 3D games use to reduce their memory requirements and improve performance, but the various formats in use with OpenGL ES are defined only by extensions and therefore vary for each platform. Unfortunately, Ericsson Texture Compression (ETC1) is the only format supported on all Android devices (except for first-generation devices, which did not support OpenGL ES 2.0). ETC1 only supports 8 bits-per-pixel precision and has no support for alpha. Because most games use compressed textures with alpha, this is typically a serious obstacle to porting. Several proprietary formats are supported on various Android platforms that do support alpha, but using them limits your game to the Android devices of that particular GPU architecture. Table 1 summarizes the various GPU architectures and texture compression formats they provide for Android.
Table 1. Proprietary Compressed Texture Formats with Alpha Support
|GPU Architecture||Texture Formats|
|NVIDIA Tegra* 2/3||DXT/S3TC|
The PowerVR GPU on Intel Atom processors supports the PVRTC formats in addition to ETC1. PVRTC supports alpha and either 2 or 4 bits-per-pixel precision, which can significantly reduce the size of textures over the ETC1 format. PVRTC is the most widely supported format after ETC1, and it’s also used in all generations of the Apple iPhone*, iPod touch*, and iPad* devices, so it provides some compatibility with Android on Intel Atom processors beyond the basic OpenGL ES standard, which is important when porting games to both the Android and Apple iOS* platforms. But handling Android devices that have different GPU architectures is still an issue. If your game uses any of the proprietary texture formats, it must query the OpenGL ES extensions at runtime to determine which formats are actually available and use only textures that have been compressed in that format. This presents a tough design decision. Your options are:
After you decide which proprietary formats your game will require, be sure to declare them in its manifest, as discussed later. For more information, see Texture compression support.
Desktop versions of OpenGL typically provide a library of convenience functions called the OpenGL Utility Library. The GLU consists of functions that are not strictly part of OpenGL or essential for using OpenGL but are helpful when coding 3D applications for OpenGL. A typical GLU library includes functions for constructing model-view and projection matrices, performing general matrix calculations, computing quadric surfaces, tessellating polygons, generating mipmaps, and reporting error messages. Most games on desktop OpenGL use some GLU functions, which can be a problem because Android provides only a minimal implementation of GLU that is available only from the SDK. These classes are listed in Table 2.
Table 2. Summary of Android Classes That Provide GLU Functionality
|android.opengl.GLU||Creating projection matrices for OpenGL ES|
|android.graphics.Matrix||Creating model–view and general matrices|
OpenGL ES 1.1 and 2.0 provide support for generating mipmaps, so the missing functionality is computing quadric surfaces and support for tessellating polygons. If you need these functions, other open source implementations of GLU exist that are more complete and suitable for use with the Android NDK—for example, GLU ES.
Apps that require OpenGL ES should declare this fact in their manifest file. This will prevent your app from being installed on devices that do not support the required version of OpenGL ES. The following examples show the proper syntax of required manifest parameters for the AndroidManifest.xml file.
OpenGL ES 1.1:
<uses-feature android:glEsVersion="0x00010001" android:required="true" />
OpenGL ES 2.0:
<uses-feature android:glEsVersion="0x00020000" android:required="true" />
Android 4.0 (API level 14) introduced a major change where OpenGL ES hardware acceleration is enabled by default for all apps that declare a
minSdkVersion parameter of 14 or greater. Apps at lower API levels can enable acceleration by adding
android:hardwareAccelerated=“true” to the
<application> tag. If your app uses new features in Android 4.0 that require hardware acceleration of OpenGL ES, such as the
TextureView class, you must enable it in the manifest or these features will not function.
If your app uses the
NativeActivity class, its manifest must declare that and specify the shared object library name that contains the native Activity. Also, the
minSdkVersion parameter must be 9 or greater. See the
native-activity sample app in the NDK for an example.
If your app uses compressed textures, be sure to declare them as shown below. This will not prevent your app from being installed on devices without these features, so it’s still important to query the device at runtime for the extensions of any proprietary formats required. These manifest parameters are used by external services such as Google Play to filter apps that cannot run on devices that don’t support the required texture formats.
Required manifest parameters for compressed texture formats:
<supports-gl-texture android:name="GL_OES_compressed_ETC1_RGB8_texture" />
<supports-gl-texture android:name="GL_OES_compressed_paletted_texture" />
<supports-gl-texture android:name="GL_IMG_texture_compression_pvrtc" />
When you set up your Android development system, be sure to select an Android version that has support for Intel Atom processors built in. This will allow you to target Intel Atom devices and use Intel Atom System Image Android Virtual Devices (AVDs). Table 3 summarizes all of the major releases of Android to date and which releases have system images for Intel Atom processors built in.
Table 3. Summary of Android Versions with OpenGL ES and Intel® Atom™ Processor Support
|Release||Name||API||Supports||Intel Atom Support|
|Android 1.5||Cupcake||3||OpenGL ES 1.0||No|
|Android 1.6||Donut||4||OpenGL ES 1.0, 1.1||No|
|Android 2.0||Éclair||5||OpenGL ES 1.0, 1.1||No|
|Android 2.1||Éclair||7||OpenGL ES 1.0, 1.1||No|
|Android 2.2||Froyo||8||OpenGL ES 1.0, 1.1, 2.0||No|
|Android 2.3.3||Gingerbread||10||OpenGL ES 1.0, 1.1, 2.0||Yes|
|Android 3.0||Honeycomb||11||OpenGL ES 1.0, 1.1, 2.0||No|
|Android 3.1||Honeycomb||12||OpenGL ES 1.0, 1.1, 2.0||No|
|Android 3.2||Honeycomb||13||OpenGL ES 1.0, 1.1, 2.0||No|
|Android 4.0||Ice Cream Sandwich||14||OpenGL ES 1.0, 1.1, 2.0||No|
|Android 4.0.3||Ice Cream Sandwich||15||OpenGL ES 1.0, 1.1, 2.0||Yes|
|Android 4.1||Jelly Bean||16||OpenGL ES 1.0, 1.1, 2.0||Yes|
Android versions 2.3.3 (Gingerbread), 4.0.3 (Ice Cream Sandwich), and 4.1 (Jelly Bean) have full support for Intel Atom processors, including the drivers for OpenGL ES 1.0, 1.1, and 2.0. Simply select one of these versions from the Android SDK Manager and verify that it lists Intel x86 Atom System Image as being included. Also, be sure to download and install the Intel® Hardware Accelerated Execution Manager (HAXM), which is listed in the SDK Manager under Extras. If you don’t already have the Android SDK Manager installed, you can download it from http://developer.android.com/sdk/index.html.
The SDK Manager downloads the HAXM installer and places it in the Extras folder, but to complete the installation, you must run the HAXM installer manually. You also must enable the Virtualization Technology feature in the ROM BIOS setup menu of your development machine. The HAXM installer resides at
…\android-sdk\extras\intel\Hardware_Accelerated_Execution_Manager. When an x86 AVD is launched with HAXM installed properly, this message is displayed: “HAX is working and emulator runs in fast virt mode.”
Every embedded developer knows how a virtual device emulator can speed up development of new applications. But using an AVD for an ARM system image is painfully slow because the AVD must emulate every ARM instruction on a Windows or Linux development system. It can take 5 minutes or longer just to boot Android on a typical ARM AVD. Intel has solved this problem with its HAXM, which executes Android x86 system images directly using the Virtualization Technology feature built into new Intel desktop processors. When this tool is installed and used with an Intel Atom x86 system image AVD, your application development will be greatly accelerated, and you don’t even need Intel Atom hardware to get started.
Google added support for OpenGL ES 2.0 in the AVD emulation beginning with release 17 of the SDK Tools (Android 4.0.3 r2) in April 2012. It works by translating OpenGL ES 2.0 calls to the OpenGL 2.0 API available on the host operating system, which makes the execution of 3D graphics much faster. However, this feature must be specifically enabled when you create the AVD; otherwise, calls to OpenGL ES 2.0 fail. And of course, your Windows or Linux host system must have drivers installed for OpenGL 2.0 (or better), which usually requires an add-on graphics card, as well. OpenGL ES 2.0 emulation works on both ARM and x86 system images, but to get the best performance, use it with an x86 system image with HAXM enabled. The difference in performance is huge.
To enable OpenGL ES 2.0 emulation, select an AVD in the AVD Manager, and click Edit. Then, in the Hardware Properties window, click New; scroll through the list of properties to find GPU emulation, and then click OK. Finally, change the no for this property to yes, and click Edit AVD, then OK to save the change. A message should appear that states
Prior to release 17 of the SDK Tools, AVD Emulation supported only OpenGL ES 1.0 and 1.1. Enabling GPU emulation is not strictly required for version 1.1 because it can be emulated without help from the host system, albeit much more slowly. However, the SDK Tools cannot emulate version 2.0 without help from the host, so if it’s not available, the AVD simply closes your app as soon as it tries to initialize OpenGL ES 2.0.
HelloEffects sample app as an initial test that OpenGL ES 2.0 emulation is functioning. The
GLES20TriangleRenderer sample actually reverts to version 1.1 when run on an AVD, so it’s not a good test. All of the OpenGL ES 2.0 samples provided in the Android SDK and NDK are relatively primitive examples and should not be considered thorough tests of OpenGL 2.0 emulation.
Another important tool suite available to OpenGL ES app developers targeting Android on Intel Atom processors is the Intel® Graphics Performance Analyzers (Intel® GPA). This suite of tools provides a real-time view of dozens of critical system metrics covering the CPU, GPU, and OpenGL ES. Intel GPA run on either a Windows or Ubuntu Linux development system and communicate with driver components running on the Android target device through the Android debug interface. By running a few experiments, you can quickly spot bottlenecks in the graphics pipeline visually and identify the best opportunities for code optimization.
For more information and to download the latest version of Intel GPA (2012 R4) for Android development, go to http://software.intel.com/en-us/vcsource/tools/intel-gpa?cid=sem121p7972.
Android’s evolving support for OpenGL ES and C/C++ has lowered the barriers to porting games and other apps that make extensive use of 3D graphics to Android platform devices, including Intel Atom processors. Nonetheless, some barriers remain, and it’s essential to assess them before undertaking a game porting project. The most significant barriers are differences in the OpenGL extensions and texture compression formats that are supported on Android. The good news is that Google and Intel have made tremendous strides with improved tools for OpenGL ES 2.0 development in recent years, and there are so many games, game engines, and other legacy software available based on OpenGL standards today that this represents a great opportunity for software developers who are ready to exploit it.
Clay D. Montgomery is a leading developer of drivers and apps for OpenGL on embedded systems. His experience includes the design of graphics accelerator hardware, graphics drivers, APIs, and OpenGL applications across many platforms at STB Systems, VLSI Technology, Philips Semiconductors, Nokia, Texas Instruments, AMX, and as an independent consultant. He was instrumental in the development of some of the first OpenGL ES, OpenVG*, and SVG drivers and applications for the Freescale i.MX and TI OMAP* platforms and the Vivante, AMD, and PowerVR graphics cores. He has developed and taught workshops on OpenGL ES development on embedded Linux and represented several companies in the Khronos Group.
Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for optimizations that are not unique to Intel microprocessors. These optimizations include SSE2, SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the availability, functionality, or effectiveness of any optimization on microprocessors not manufactured by Intel. Microprocessor-dependent optimizations in this product are intended for use with Intel microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for Intel microprocessors. Please refer to the applicable product User and Reference Guides for more information regarding the specific instruction sets covered by this notice.
Notice revision #20110804