Adobe AIR Mobile: Application performance optimization on Android
When we talk about mobile development, we have to make sure our application is optimized as good as possible to run smooth on a wide variety of devices. Like Kevin Lynch said at MAX 2010, mobile development is like desktop/web development 7 years ago. Let’s take a look on how we can make sure that our mobile applications run smooth. I can already tell you that always a lot of testing (starting early in your development process) on different devices will be necessary to achieve the results you want.
When your application slows down on a device, it means that your code execution per frame or the rendering per frame or both is the bottleneck.
What to display in the DisplayList ?
Always make sure you use the right DisplayOject for the right job. As you know, a MovieClip uses more bytes then a Sprite and Sprite uses more bytes than a Bitmap…etc. When building up your DisplayList always keep in mind that the DisplayList really affects the memory usage of your application. If you have a set of Sprites on your stage for example, you can draw them in a BitmapData object and put that in a bitmap on the DisplayList. That approach will save some memory for sure!
When we talk about Bitmaps, we have to say something about the 2 Flash player render operations also. In the Flash Player every graphical element in your application is rasterized inside a bit/pixel buffer (=rasterizing) and those tiles of pixels are then arranged to make up your scene (=scene compositing) in the main pixel buffer (what you finally see on the device). Every frame, the player calculates a dirty region (=the redraw regions) to see what must be rasterized again and merged again in the main pixel buffer. All those tasks are done by the CPU when doing web/desktop development but with Adobe AIR 2.5 targeting mobile devices, you can choose if the CPU or the GPU needs to do those important tasks.
At this moment on IOS, a ‘special’ GPU mode is only supported, it is called GPU Blend. This means that the task of the the creation of the different pixel buffers is done by the CPU and then the CPU sends it to the GPU. The GPU finally does the scene compositing.
On Android, when you use GPU rendering, this is called GPU Vector, the tasks are done fully by the GPU. So, the creation of individual pixel buffers and the scene compositing, it all happens at the GPU. This can give you a huge performance boost. But can we make sure we are using GPU rendering?
That is where bitmap caching comes in.
Bitmap caching – blitting from an off-screen pixel buffer
Just like with desktop/web Flash development, you can set the cacheAsBitmap property of a display object. This way, an offscreen pixel buffer is created beforehand and when a rerender is necessary (your object is part of the dirty area), the pixels will be blitted together in the main pixel buffer, which is less expensive, so your applications runs smoother. This also happens automatically when you set a filter to be applied on a display object. The operations happening behind the scenes is called bit-blitting and if you want to know more about this technique, check this Wikipedia entry: http://en.wikipedia.org/wiki/Bit_blit .
So does bitmap caching also work on mobile devices? The answer is YES when using CPU mode on devices, it will work the same but just take care of the following pitfall. You maybe are thinking that your application will run smoother if you set bitmap caching to true on the main container of your application or on other display object containers. Well that actually is not true because it results in an off-screen pixel buffer that is as expensive as rasterizing everything. Just remember as a best practice to never set the cacheAsBitmap property to true on a display object container that has siblings that move relative to each other. Instead set it to the lowest leafs in the DisplayList tree.
But there is ever more to optimize when you combine bitmap cashing with GPU render mode, especially on Android powered devices.
GPU render mode + bitmap caching on Android
Inside the Air for Android settings in Flash we can clearly see that 3 render modes are supported at the moment: CPU, GPU and AUTO (which is actually CPU at the moment). Ok now let’s dive into GPU render mode combined with caching.
GPU mode on Android means that the Graphic Processor on your device is taking care of creating the offscreen pixel buffers of the several Display Objects and also takes care of the final scene compositing.
When you want to use GPU mode, and your object are not using the 2.5D space (=not in ‘3D space’), you must explicitly tell the player which objects need to cached on the GPU. You can do this by setting cacheAsBitmap to true AND cacheAsBitmapMatrix to a given Matrix instance:
object.cacheAsBitmap = true; object.cacheAsBitmapMatrix =new Matrix();
When you use objects in 2.5D space (=3D like rotationY,rotationX,..) they will always be cached in the GPU, and it is not necessary to set the caching manually. But as best practice I would advise to always set the properties if you want to have your object cached on the GPU.
The result of all this is that the transformations will be calculated on the GPU. As you know, every displayObject has an underlying Matrix representation in the Flash player even if it has no graphics inside (rotation, translation,…) In a nested display object all the matrices are concatenated to make up the final transformation. So giving it to the GPU will make your application faster!
You can easily set the cacheAsBitmapMatrix property to the identity Matrix by calling the constructor of the Matrix class. This is the most common way, because you not want to cache a given transformation. But you can also cache a transformation eg. A scale transformation. This can be handy when you have big assets and want to reuse them on different screen sizes and in that way you use less memory in your off-screen pixel buffer.
A last thing to know is that caching the bitmap matrix must be used always in combination with setting the cacheAsBitmap property to true, otherwise it will not work. The last cool thing is that a bitmap representation of your DisplayObject will be cached on the GPU, even if the object’s visibility is set to false. This makes it less expensive when reusing your objects.
I did some quick tests by placing 500 instances of an expensive vector object on stage and looked to the average frameRate achieved after running 500 frames. Seems like using GPU mode is with this simple app on this phone (Motorolla Droid 2) 17x faster and we are nearly the targetted frame rate of 24 fps !
If you wonder how I make screenshots of my Droid 2 screen, well I am using the Dalvik Debug Monitor>Device>Screen Capture for that. More information on take screenshots of your cell: click here .
Lee Brimelow also has a nice video tutorial on different rendering modes: watch the video tutorial here
Christian Cantrell also has a demo of showing the different rendering modes: watch the article (+video demo) here
If you LIKE this article, do not hesitate to share it on Facebook, Twitter,… sharing makes me happy !