NOTE: If you read this post then please also read the comment at the end from sHTiF (creator of Genome2D) who details some poor assumptions/misunderstandings on my part.
When writing my Monster Dash clone, I opted to start by using Flash’s classic display list. Although my intention was to eventually swap over to the Starling Framework, I knew I’d be able to knock together test animations and do all my graphics layout within Flash Professional much faster than I could programmatically in pure ActionScript. Of course, since I was targeting iOS I knew at some point I’d hit a GPU limit using the classic display list that only Starling (and by extension Stage 3D) would be able to overcome.
The first few iterations went pretty much as expected. Using Box2D I built an increasingly sophisticated game world and quickly added visuals to represent it using traditional Movie Clips and Flash’s timeline. With the help of Adobe Scout I was able to measure the performance of each build and could see that rendering times on my iPad 1 were inching up as I applied more visuals. On the other hand, while GPU rendering was taking up a large proportion of each frame’s budget, my ActionScript was consuming a very small percentage of the allocated budget.
You can see this in the screenshot below, which is captured from Adobe Scout. The vertical slices represents the time taken to render each frame. The green bars represent the time taken to render my visuals, whereas the blue bars represents the time taken to execute my ActionScript. To achieve my target frame rate of 60 frames per second, each slice (a blue bar stacked on top of a green bar) needs to stay below the red horizontal line. If a slice pops up above the red line then my game has failed to perform all the work required of it within its allocated frame budget. When this happens your application’s frame rate drops and the user notices a visible stutter. As you can see from the screenshot, my demo was close to bursting point with my rendering times simply taking too long to consistently stay within budget.
At this point I knew it was time to ditch Flash’s classic display list and move over to Starling. After all, with my ActionScript execution times already so low (on average around 3ms per frame), I’d surely be able to get my overall frame execution times drastically down by simply plugging in Starling and reducing the rendering times, right? Well, unfortunately by dropping Flash’s classic display list I actually hit a new problem. Take a look at the screenshot below, which was taken from Scout after I’d implemented all my visuals in Starling.
As you can see, as expected, the green bars are gone! Stage 3D is so blazing fast that the rendering times for each frame are now negligible. However, the execution time for my ActionScript has shot way up (around 14ms per frame compared to 3ms previously)! In fact, my overall frame budget times aren’t much of an improvement over my original classic display list approach at all. But why has this happened? Well, you’ve got to remember that the classic display list APIs are native to the Flash runtime. Therefore there’s almost no cost involved in calling them within your ActionScript. Starling’s API however is actually written entirely in ActionScript 3. Therefore each equivalent call to the Starling API results in layers of ActionScript being executed before the bulk of your graphics work is offloaded to the GPU.
Thanks to Adobe Scout I was eventually able to optimize things so that everything ran within budget on iPad 1 but I only just managed to scrape it. But the harsh truth is that the GPU savings I made by moving to Starling were almost completely blown away by the ActionScript overhead.
Now this doesn’t necessarily mean I should have just stuck with the classic display list. There were some things I didn’t bother implementing using the classic display list, such as the large scrolling backgrounds (you can see a video of an early prototype using the classic display list here). They would have simply crippled my frame rate, whereas Starling was able to effortlessly handled them. I’d also like to point out that the Starling framework itself isn’t to blame either. With Stage 3D being such a low-level abstraction layer, a fair chunk of ActionScript is required when writing higher-level frameworks that sit on top of it. The same is unfortunately true for all other frameworks built on top of Stage 3D such as Away3D, Feathers, Minko etc.
So what can be done about this? Well I guess I could target better hardware. The iPad 1 is obsolete by today’s standards and my iPad 2 is actually able to run my Monster Dash clone without even breaking sweat, but I guess that’s not the point. I think Flash developers should expect to run simple 2D games with some basic physics on even iPad 1 and similar Android hardware at a full 60fps. If I was to add additional complexity to my Monster Dash clone then I’d likely run into performance issues again. I accept that my code was hardly the most optimised I’ve ever written but it certainly isn’t the worst either.
Personally I think the solution is to make some of the more common frameworks such as Starling native by bringing them into the Flash runtime. Considering the increased focus on Starling development and the constraints of mobile hardware, this makes a lot of sense. When using Starling, the traditional workflow of using Flash Professional disappears somewhat, leaving developers with a more code-centric approach. If that’s the case then many will argue what’s the point of using Flash and ActionScript, especially when alternative languages such as Objective-C or C++ can provide significantly better performance. Even Flash’s claim of being a cross-platform solution has been mostly eroded over the last few years.
While Adobe has taken some significant strides with the Flash platform in recent years there are some areas that need some serious consideration. At this moment in time I think ActionScript 3 performance has to be one of the highest priorities.