In the last couple of months I’ve programmed a lot of AS3 code. And when there was performance critical code to write it often got frustrating. The problem is not that AS3 compiles into bytecode which is running on a virtual machine. It’s not the lack of hardware acceleration or threading. The problem is a lack of transparency – it’s often impossible to find the best approach without trying and comparing all the different possible options!
Let me give you an example: I have a source Bitmap object and want to draw it with a PixelBender shader in my target buffer.
var target:BitmapData; var source:Bitmap; ... source.blendShader = myShader; target.draw(source, matrix, colorTransform, BlendMode.SHADER, clipRectangle);
Welcome to the first pitfall: The clipRectangle does work as promised but it doesn’t affect the performance. You can set it to a one pixel square and it still evaluates every pixel in the target buffer. Good to know? Yeah, but it’s not in the docs. Not sure that the people at Adobe even know about it.
So, if the area I need to update is small enough it’s more efficient to copy the relevant pixels into an intermediate buffer apply the shader on it and copy it back. copyPixels comes to mind, right? Yes, that will work. And we all know how fast that is. But besides copyPixels there’s also a getPixels and a getVector method that allows me to extract a rectangular portion of the source. How fast are these? Turns out that copyPixels is the winner, getVector is about 50% slower and getPixels which basically does the same thing is 500% slower then copyPixels. Dooh!
But why do I even mention alternatives to the copyPixels way when it’s fast and everyone that reads blogs knows that it’s fast? Because getVector is a valid alternative. Turns out there’s quite some overhead to setting up and executing a pixelbender Shader. And after some more testing it turn’s out that for my specific simple shader the fastest option to update small rectangles in the target buffer is to just extract that portion using getVector, then iterate over the contents of a target and a source vector, do the calculations in plain Actionscript and copy the result back using setVector.
It’s a matter of luck and stubbornness that the tech demo I’ve been working on was successfully pitched and not canned as “not doable in flash”. Writing bytecode directly can’t be any harder then that.