Developing AAA Games with Stage3D @ Adobe AIR / Flash Player

Recently, I’ve been working on a larger game project which should run on the Adobe Flash and Adobe AIR platforms.

TL;DR – If you want to create 3D realtime games, use something different, don’t use Flash.

Because the preferred client technology was Flash anyway, we did some quick tests with some groups of meshes rotating around. The results were okay so after some additional tests, we gave the „OK“ to do it with Flash.

Development has started with Away3D 4.0 beta, at that time, Away3D had a lot of bugs and a lot of features were missing. Some of the bugs have been fixed by myself, others were reported and were fixed by the Away3D team.

Let me say that, although Away3D looked unfinished at that time and even nowadays lacks some features, in general, Away3D is not a bad engine and looks like it has been coded by people who know how to do it right.

But whatever improvement the Away3D team or me implemented, in the end we all had to cope with the poor Stage3D interface.


For standard textures, the size is limited to be power-of-two. If you work for mobile devices, you know for sure that you need to save memory wherever you can. POT-textures force you to insert empty areas into a texture which will eat up additional memory. As plenty of mobile devices accept NPOT-textures, this hard restriction doesn’t make sense.

You can create standard textures without mip maps. But even if you do not need them, Flash allocates the whole space for mipmaps on the GPU, always.

Recently, a new texture type became available, which is called „RectangleTexture“ (who can I blame for this name?) which supports NPOT-textures. Having this advantage now, the downside of RectangleTexture is: There is no mip map support at all.

Flash supports runtime texture compression. Not a bad thing, but this feature is not supported on mobile devices! Mobile devices badly need it while it is not so important for web, so why isn’t it available?

There is also an offline tool available, png2atf, but it takes several minutes for a single texture to be compressed.

Additionally, most of the time we cannot use them because they look so bad. At least when using alpha textures, the visual artifacts are unacceptable.


Rendering single objects with a lot of polygons works as expected, performance is good. No 3D api usually has problems rendering static meshes, so this is no surprise.

Things get worse when using more draw calls or if geometries need shader parameters. I haven’t seen any API that is slower here. Context3D.setProgramConstantsFromXXX are totally useless if you want to do something real, for example skeletal animation. Using those functions together with drawTriangles will eat up most of your precious CPU time. Not a big problem on desktop systems, but on iOS, you’ll notice how awfully slow the Context3D interface is here.

This is probably „by design“: While the GPU / DirectX / OpenGL work usually with 32 bit floating point data, Flash only supports Numbers, which are 64 bit float. So everything needs to be converted everytime you call these functions. And there is no way around it when you do for example skeletal animation.

I tried to use FlasCC to work around this problem, but guess what, there are no native calls to these functions where you can use C float data. You are forced to use ActionScript-Variants even there, so there is no win at all.

Shader Language

The language used by Adobe for shaders is called AGAL – Adobe Graphics Assembly Language.

Assembly? Yes, indeed. I’ve worked with D3D, OpenGL, NVidia Cg for 10+ years, they all offer high level shading languages. But with Adobe, you get ported back into the 1980s to fight for register usage, use mov, add, sub again. You don’t want to do that in 2014 anymore. Needles to say that it’s also quite limited in terms of available registers, number of opcodes etc.

ActionScript Language

If you create a 3D game, you need strong math classes. Unfortunately, ActionScript 3 is not the best language for this and the classes that are provided by the runtime lack a lot of features.

In ActionScript, Vector3D is not a value type but a full fledged class with all its advantages but also disadvantages.

There are only three static variables inside, one for each axis. A zero is missing. Due to the fact that all Vector3Ds are references, you can create ugly things if you don’t be careful. For example, take a look at the following code:

What actually happens here is that you invert the value Vector3D.X_AXIS because foo is only a reference. Looking to prank your coworkers? Just fool around with everyones coordinate system.

Missing operator overloading is also something that doesn’t really help to achieve code clarity.

It would be a lot easier to read:

When creating realtime applications, it is eligible to prevent any allocation at all. Unfortunately, because Vector3D is not a value type, flash doesn’t help here. Prevent use of

Because this allocates a new vector. Instead, use

This can be solved, but what if you would like to transform e.g. 10000 Vector3D objects by a Matrix3D? You’re lost. All transformation functions of the Matrix3D class return new Vector3D objects, there is no function to work on a Vector3D inplace. More Matrix3D functions act this way, for example decompose and even the position and rawData properties.

All this leads to a weak math performance of Flash in general.

More language issues are problematic, for example the lack of real inlining. The ASC2 compiler introduced an inlining feature that is so limited that it can be used only on very simple functions. It is not automatic, but must be inserted manually. If you overuse it, you’ll often end up with cryptic compilation errors like „stack underflow“. If you also use C++ sometimes, with „inlining support“ you for sure expect more than what Adobe has to offer here.

Ever tried to deploy a larger AIR app to iOS? Waiting more than 30 minutes caused us to use separate build machines to build iOS versions. They must be optimizing really hard, you may think. Would be nice if the performance would justify this, unfortunately, it doesn’t.

UI Support

With regards to Stage3D, there isn’t any that I’m aware of. There is Starling, but as long as you cannot use your UI that you designed in Flash Pro, it’s more or less useless. We had the idea to write a converter, but animated MovieClips are problematic because you won’t win any performance when rendering a MovieClip to a texture every frame. Or you’ll lose a lot of memory for sprite sheets that may become very large.

So UI with Stage2D is the current solution if you want to have a graphics artist to be able to design it.

Be warned, the 2D scanline renderer of Flash is awfully slow on mobile devices, if your artist really does a good job visually, you’ll probably end up spending days to optimize his number of display objects to something acceptable to reach at least 15 frames/sec.

Adobe decided to always render Stage2D above Stage3D. This may be useful in most cases, but imagine a 2D UI control that should display details of a 3D unit. You’ll start cuting holes into the 2D interface using masking which makes the 2D UI even slower.


An incomplete list of some of the things that happen more or less on a daily base.

  • In Flash Pro, you better split a bigger UI into multiple SWCs and embed them so the artist can work without interrupting the coders. Randomly while compiling the main project, you’ll end up with „cannot convert foo to MovieClip“ while the Flash runtime constructs the display object hierarchy. Just re-publish in Flash Pro and pray to get it running.
  • iOS frame rate drops down heavily on every touch event because the AIR runtime searches for SimpleButton instances inside the whole display list. Adobe is aware of the issue but doesn’t fix it.
  • AIR deployment on iOS fails most of the time. Sometimes with an error message, sometimes not. Just try it again, sometimes it works. I switched to iFunBox (App/file manager for iOS devices) to prevent getting annoyed too often.
  • TextField.textWidth and TextField.textHeight may return wrong numbers if text fields use embedded fonts. Highly depends on the content.
  • Adobe Scout (realtime profiler from Adobe, part of the Adobe Gaming SDK or Creative Cloud) tracks less than 20% of the really used memory in a lot of cases. Additionally, „Other memory“ and „Other bitmap data“ do not really help identifying memory issues at all.
  • Some areas of the 2D UI are sometimes not redrawn. Doesn’t happen in all browsers and varies between different Flash player versions and also debug/release builds.
  • If you fail to set up your native extension properly, iOS version will hang in its splash screen without any useful info to debug what the problem is.

Tips & Tricks

  • Vector3D.length is slower than calculating it manually, both on Web & iOS, tested with AIR 4.0 / FP 12.
  • Vector3D.copyFrom() doesn’t copy the w component, remember this if you use Vector3D e.g. for colors
  • A static Vector3D to be used as temporary vector for calculations can be a huge speed improvement.
  • Throw away your BitmapData with dispose as soon as you uploaded your bitmap to a Texture to prevent doubled memory usage
  • To get rid of 2D/3D sorting problems, on desktop, Context3D.renderToBitmapData is fast enough to even reach 60 fps, but do not try this on mobile devices.
  • TheMiner is a good profiling tool that runs inside your Flash application.
  • Rendering a DisplayObject to a texture is costly, but reduces work on the 2D renderer and is usually a good caching solution.
  • null-out everything when you don’t need it anymore to reduce garbage collection cycles. Even remove weak event listeners.
  • Profiling Hint: Adobe Scout displays memory used by Vector.<int> and Vector.<Number> as „Other“, Vector.<Boolean> as „ActionScript objects“, Vector.<String> as both „Other“ (about 1/3) and „ActionScript Objects“ (about 2/3)

10 Gedanken zu „Developing AAA Games with Stage3D @ Adobe AIR / Flash Player“

  1. Hi,

    Can I ask you a question. Being a really experienced programmer, why did you choose Flash to make a AAA 3D game on iOS? Why not Unity or Project Anarchy or UDK or some native 3D frameworks? Isn’t it a sadistic experiment over your nerves?

    1. I didn’t choose Flash at all 🙂 It was a political decision because no one needs to install any plugin for the desktop/web version.

  2. Sorry to hear your experience wasn’t a good one 🙁

    Couple of tips I have used to help reduce some of the issues you faced:
    1. Don’t have anything on the display list if at all possible!! It will save rendering time and reduce performance issues with touch/mouse events.
    2. So make sure your ui is running on stage3d, if you want movieclips then write a few lines of code to run through it and cache it all in a sprite sheet upfront. No bitmapdata.draw or texture uploading during runtime! If you need 3d content in your ui, render to a small texture on the gpu and use that.
    3. DON’T use the native Vector3D class.
    Write your own, it doesn’t take long at all and you can make use of temporary instances as well as in-lining if you use asc2. Things will run faster! In a game environment you want to avoid any instances of the old „new“ keyword… avoid at all costs… if it means writing your own matrix and vector functions, still worth it!
    4. with regards to the 64 bit vs 32 bit, the new intrinsic function should allow you to write to bytearrays just as fast as vectors but save the unnecessary conversions so may make a big difference, sadly I haven’t tried this yet so cannot confirm – but should work.

    Lastly thanks for sharing your experiences with everyone, more people should do this – it will no doubt prove very useful for folks out there!

  3. on performance, there is also uploadConstantsFromByteArray, which let you store 32bit float values instead of Flash 64bit Number.

    About shaders, we’ve developed our own high level compiler for Stage3D, it works mainly with Flare3D, but I know people who have used the output AGAL to create Away3D materials as well.

    ATF does a great job if you can live with some compression artifacts…use it when possible…it will save a huge amount of GPU memory.

  4. Hi. Well, almost all you wrote is true. But everything not so bad. You just didn’t write positive things, which is much more than negative. Also I’ll try to fix something.
    1. Use your own math, as bwhiting said above. Btw, you can transform vectors without creating new instanses with Matrix3D (see transformVectors).
    2. Again, as bwhiting said – sending constants (and all data) as ByteArray is much (MUCH!!!) faster. And you can use fast ByteArray for fast writing into it.

  5. Regarding the assembly criticism, there are several AS libraries and utilities out there to avoid it. Just saw this one today:

    About the others… I’m sorry, I haven’t bookmarked them… but I’ve seen several in the past, so I’m quite confident they do exist.

    I haven’t had the opportunity to work with Stage3D so far, but I’d love to.

  6. Found this a bit late. We ported a native C++ application to flash with crossbridge as a proof of concept for a small side project. Stage3d was the most cumbersome 3D API I’ve ever dealt with. Let me add these two things to the rant:

    1. Compressed Textures:
    Uploading pre-compressed textures is only possible with the ATF container. All other APIs I know of allow uploading raw compressed data. So If you want to use your own container for pre-compressed textures you have to construct the ATF container around it. To make things even more weird you still have to store the dimension of the texture somewhere else (or get it from the ATF file) because it must be known before creating the texture object.

    2. Sampler Parameters in Shaders:
    I’d really like to know why Adobe decided to make sampler parameters part of the texture fetching opcode in AGAL. Prior to Flashplayer 11.6 all sampler states like filtering and wrap modes had to be kind of hard coded into the shader. Then they added Context3D.setSamplerStateAt so fix this. But if you want to use compressed textures you still have to make different shaders by adding a sampler parameter depending on the type of texture:
    for uncompressed textures
    for compressed textures
    for compressed textures with alpha
    This means that for every texture fetch opcode in a shader you have 3 variations depending on the type of texture being used. We had a material that used 8 different textures and already had some parameters that could create shader variations. This creates an insane amount of different shaders or forces you to compile shaders on demand. Again I have not seen any shading language that didn’t made the type of texture being fetched transparent for the programer.

Kommentare sind geschlossen.