Evaluating spritesheet animations on mobile

Recently, after haxeCon in May I got really exited to try some mobile development possibilities with Haxe and NME (many thanks for really inspring session and source code sharing to Tarwin from Touchmypixel!). The performance of displaying animations (based on spritesheets) was very low at first so I decided to take a closer look at it. I’ve implemented a small spritesheet rendering/animation framework  as part of my personal library and decided to compare some results. This is how I got into writing those few tests.

I’ve run all tests on HTC Nexus One with Android 2.3 with AIR 2.7.0.1948 installed. Used haxe (2.07) and latest NME (svn revision 681) to compile and also generate action script 3.0 source that I then compiled with Flash Professional CS 5.5 with AIR 2.7 SDK (See: Overlaying AIR SDK for Flash Professional CS5.5). On each test the desired frame rate is set to 60.

Test 1 – 30×50 animated sprites

Sprite sheet looks like this: spritesheet image. It is a simple 64×64 spritesheet that I made from brand new haXe logo for a proof-of-concept game I recently developed (more on that soon…). Test scenario is as follow: place 30 rows x 50 columns of 16×16 animating sprites made of that spritesheet on stage, play the animation starting from frame 16 modulo spriteNumber. Observe frame rate-and that’s it. Here is a flash version to check how it should look like.

  • Flash/AIR naive approach (using movieclips) – I’ve just create a movieclip with 16 frames (each contain a single 16×16 bitmap) and place them on stage (just few lines of code on timeline..) = very unstable at first, settles at 7-8 FPS CPU (GPU completly unstable…)
  • Corona sprites – same test implemented with Corona sprite API = I expected something more… 3 FPS
  • Flash/AIR with copyPixels on seperate (1500) bitmap instances added to display list = not bad, 12-13 FPS on CPU (starting to look ok, on however GPU it 1 fps and hangs…)
  • NME similar as above (just not copyPixels because it is really slow on NME but beginBitmapFill instead and 1500 Shape instances) - honestly I hoped for some more.. 5 FPS

All above approaches have animated sprite as a separate display object (movieclip and bitmap for AIR, shape for NME and corona sprites). This means that we could hitTest, depth sort and use all those goodies that particular api provides. Now let’s focus on performance and use rendering technique called blitting =in short, everything on a single layer (bitmap for AIR and shape for NME).  Using this technique you need to take care about depth sorting, hitTesting etc yourself but this is pretty common approach (e.g. http://blog.theflashblog.com/?p=2749). I don’t see any option of blit or something similar in Corona so I’ll just stick to Flash/AIR and NME.

  • Flash/AIR  - Blit –  single bitmap on display list + 15000 copyPixels on it = 21-22 FPS on CPU / 16 on GPU – smooth :) With GPU render mode it looks a little better regardless the lower fps

Really impressive result-it works quite smooth. So you might think we have a winner cause Flash/AIR was far better then NME with previous approach ;)

  • NME blit – using the awesome nme.display.Graphics.drawTiles method by Hugh = 57-59 FPS!

It runs so smooth so you can basically say that is runs on maximal FPS. This is quite impressive in my opinion-1500 animated sprites on mobile device running on almost 60 FPS! So let’s see how far we can push it ;)

Test 2 – 60×100 animated sprites (blit) + 35 kill-able critters flying on top of it

Previous test was very simple so I decided to add some interactivity. And reduce the size of background sprite so that 6000 will fit on stage(36×36 spritesheet). To spare you reading long description this should look like this. This time background tiles starts animation on a random frame. Flying monsters are clickable. Credits for the nice spritesheet of flying critter goes to my brother-thanks Kubasa! :)

  • Flash/AIR – blitting  + 35 sprites and bitmap inside of it  = unstable and slow at start, after 1-2 seconds 8 FPS on CPU but still playable (on GPU very unstable 5-15… not really playable)
  • NME – blitting background (drawTiles method) + 35 sprites and shapes inside of it = initialize very fast, 24-26 FPS, really smooth!!

Below are all android application .apk files so you can test it yourself. The sources are available here (hapi library ver 0.2 is required). Because I don’t have any iDevice, nor a Mac I can not currently test it on iOS but if someone would be willing to compile and run those tests on iPhone or something I am VERY curious about the results.

Test Frame rate Memory usage APK
Flash Naive 30×50 MovieClip 7-8 4.5 – 5.3 Mb  

here

Corona 30×50 sprites 3 0.01 Mb here
NME 30×50 shapes 5 1.29 Mb here
Flash/AIR 30×50 bitmaps 12 – 13 3.93 Mb here
Flash/AIR 30×50 blitting 21 – 22 3.7.0 – 4.0 Mb here
NME 30×50 blitting 57 – 59 0.59 Mb here
Flash/AIR 60×100+35 8 4.55 Mb here
NME 60×100+35 24-26 2.2 Mb here

I think the table above is at least a pretty good reason to give haxe+NME a try. The great thing about haxe is that you can have AIR (generate-as3), Flash, Android NDK with NME and event HTML5/Phonegap (with js target) versions at the same time without big effort. Isn’t that awesome? ;)

Here is a video-recording of running those tests on my phone

  1. Andy Li says:

    What version of Flash/AIR are you using? Heard that AIR 2.7 has a major (up to 4x) speed up.

    • Yeah-I’ve heard that too ;) I was using 2.6 then updated to 2.7 and the results where pretty much the same. I guess the performance improvement was mostly on iOS not Android. Anyway this are results from 2.7.0.1948 :)

  2. MgGee says:

    We tried your sample code and without any changes to it we ran it against the latest drop of Corona SDK for 2.2 and ARMv7 and it yields a steady 7FPS and 0.01 MB consumption. I ran it on a Galaxy Tab 2.2 device.

    M.

    • Thanks for the result. Do you think if there is any option of optimizing the Corona implementation of this particular test? I couldn’t found any but I am not that experienced with Corona (although a big fan :) )

      • MgGee says:

        We are looking at our sprite engine see if it something in there and then look to see if we can do something else. We know that the text updating is a FPS bog – so we will see. I will let you know as soon as I have more data. Thanks

        M.

  3. Huge says:

    Hi,
    Nice writeup. NME has not really been optimised for hundreds of objects – it may be worth doing a bit of profiling to see if there is any “low hanging fruit” as far as optimisation goes.
    But then again, if you found the drawTiles API easy to use, the gains may only be academic.

    • Thanks Huge!
      I was a bit worried about the result of first test for NME (5fps for 1500 tiny sprites) so I decided to investigate a little more on that. I am testing another scenario and the results are quite different. Very promising for NME in fact. But the difference between AIR and NME is so significant that I need to make sure that I am doing whatever is possible in Flash/AIR for this particular use case to get the best performance possible before sharing my findings. So far you can check it here:
      http://krozalski.com/lab/spritesheet-anim/test3.html

      And by the way-thanks for the awesome work on NME!!! :)

  1. There are no trackbacks for this post yet.

Leave a Reply