This is why I always run a raster pipeline. The DisplayObject API is a trick played on the gullible and the trusting… — @bengarney
Everyone has their hot buttons. I work on libraries and architecture for a living, meaning that I am personally invested in those kinds of issues, meaning that I get excited about things like platform feature sets in ways that maybe most developers don’t.
Here are my assumptions: most Flash developers want to put art on the screen and move it around at a mostly decent framerate. Most of these developers are building interactive experiences and don’t have heavy coding backgrounds (although this is changing). Their priorities are influenced by this – they want ease of use, fast iterations, and don’t necessarily care about high performance (although this is changing, too).
Meanwhile, I inhabit an alternative universe. The last game I contributed to, Social City, had high thousands of frames of animation and hundreds of animated objects on screen at any given moment. In the whole scene there might be low thousands of visible objects. Because the world was isometric all these objects had to be drawn in the right order and most of them updated every frame.
In our initial technology tests, just having that many objects in the display list would make mouse interactions take up most of the CPU. Rendering was also extremely slow. Between these two issues we were entering the seconds-per-frame zone – and we hadn’t even added the gameplay or complex animation yet!
I am a big believer in finding the fast paths and sticking to them. Computers are fast. Really fast. My current low-end MacBook Pro, on a single core, has something like 1200 instructions per pixel to burn if I am trying to render 640×480 @ 24Hz. In the Social City case, all we wanted to do was copy opaque pixel data – which should be something like 5-10 ops per pixel, probably much less. So really, even taking into account that buildings often overlap, I should be able to push around a hundred frames a second if all I do is render.
All this is primarily to point out how awful a one second frame is. It means I am running a thousand times slower than I should be.
You might think that the most important thing in a game is how fast things can run. After all we always want to push the limit. So maximum speed is vital, right? That’s not necessarily true – we’re only looking at part of the picture. The human eye responds to rate of motion. It is really good at spotting speedups or slowdowns on the order of tens of milliseconds. It’s actually better to run at a lower, consistent framerate than it is to have a higher average framerate with occasional dips, because dips draw attention to performance or lack thereof. That’s why movies run at 24Hz, even though the TV in my living room can update at 120Hz, and why console games often target a fixed 30Hz or 60Hz.
A big part of building a rendering system for a game is identifying how to deliver a consistently good experience for the player, even when they have a fully built out complex level with tons of bad guys, interactive objects, and/or special effects.
How does all this relate to the Flash display list? Well, it is very powerful. But it is also unpredictable. It’s like the dark side of the Force. It’s a quick path to great power. Only later, do you realize that you’re wearing restricting black clothing, hanging out at weird parties with old men, and experiencing hard-to-diagnose performance issues.
Or more technically: the enemy of a system with consistent performance is black box code. Of course, I use the display list for lots of things, just like any Flash developer. It’s a useful, flexible, and powerful tool.
But when I have specific, performance oriented needs, I ditch it in favor of something I can control completely. That’s why I always use a raster pipeline – drawing all my own pixels – for my game rendering. Using BitmapData.copyPixels has a consistent, reliable cost, whereas the cost of drawing a DisplayObject hierarchy, either on stage or via draw(), is highly variable and difficult to predict in terms of both memory and CPU consumption. This is also why I avoid using Flash IDE created assets; it’s too hard to rely on the performance characteristics of art produced from it. If I have to, I always render everything to a BitmapData first and draw it later on my own terms.
(As an aside, Mobile Flash platforms lack CPU, so taking advantage of the GPU is important. In this case, I would still use bitmaps but let the GPU manage compositing when I can, for instance by using flash.display.Bitmap. I would also carefully measure the cost of off-screen Bitmaps to see if I need to manually add/remove stuff as it becomes visible. Some early tests also suggest that you can get pretty far on BitmapData on mobile if you are careful, too.)
I could write more on raster based rendering, but if you are interested in nitty gritty, you might enjoy looking over the Rendering2D library from PBE; it’s the basis of the rendering in Social City and other titles that I have worked on, and demonstrates a framework for efficient hybrid raster/vector rendering.