Re-use your BitmapData objects, speed up your apps
This is a post that I started writing about 5 months ago, and I may not be posting for a while, so here’s some info I gathered when doing per-frame analysis of Onyx‘s bitmap rendering engine …. I tried to optimize per-frame bitmapdata drawing, since there were so many bitmapdata events happening on a per frame basis. The flow for one layer was as follows:
var bitmap = new BitmapData();
bitmap.draw(layer);
filter.apply(bitmap);
filter.apply(bitmap);
filter.apply(bitmap); // repeat for as many filters are added into the layer
preview.draw(bitmap, scaleDownMatrix);
Now on average, even without any filters being applied, drawing one layer was taking 8ms on a really really fast machine. With 5 active layers in their simplist state – that’s 40ms — which is already reducing the application to around 24fps. Not so great. Now there’s not really a ton you can do about it, but hey, if you can speed up your operations by 1ms or 2ms, that will make a big difference if you’re running 5 of those processes. Here’s what little I found about BitmapData operations:
Expensive Operations (from most expensive to least expensive):
BitmapData.draw() – drawing content into a bitmap
new BitmapData() – creation of a new bitmap in memory
BitmapData.clone() – clones a bitmap
BitmapData.fillRect() – fill a bitmap with a color
BitmapData.copyPixels() – Copy pixels from a bitmap to another
10000 operations of “BitmapData.draw()” 4068 ms
10000 operations of “new BitmapData()” : 2324 ms
10000 operations of “BitmapData.clone()” 1012 ms
10000 operations of “BitmapData.copyPixels()” 962 ms
10000 operations of “BitmapData.fillRect()” : 515 ms
Methods to speed up bitmap operations.
1) When doing per-frame bitmap operations, create and store a bitmap outside of the per-frame operation, and do a fillrect per-frame.
Slower:
- creation of a bitmapdata
- bitmapdata.draw on an object every frame
Faster:
- Create and store a bitmapdata
- on every frame fillRect with 0×00000000, then do your bitmapdata.draw
Slower:
- BitmapData.clone() into a newly created bitmapdata
Faster:
- Create and store a bitmap in memory
- BitmapData.copyPixels into another bitmapdata object
Below is the code i used for the tests (i executed the code a second after the plug-in started). If I’m wrong with any of this, I give you permission to shoot me.
/**
* Testing bitmap speed operations
*/
public function test():void {
var start:int, count:int, times:int;
times = 10000;
var bmp1:BitmapData = new BitmapData(320,240,true,0x00000000);
var bmp2:BitmapData = new BitmapData(320,240,true,0x00000000);
start = getTimer();
for (count = 0; count < times; count++) {
bmp2.fillRect(bmp2.rect, 0x00000000);
}
trace(times, 'operations of "BitmapData.fillRect()" :', getTimer() - start, 'ms');
start = getTimer();
for (count = 0; count < times; count++) {
bmp1 = new BitmapData(320,240,true,0x00000000);
}
trace(times, 'operations of "new BitmapData()" :', getTimer() - start, 'ms');
start = getTimer();
for (count = 0; count < times; count++) {
var bmp3:BitmapData = bmp2.clone();
}
trace(times, 'operations of "BitmapData.clone()"', getTimer() - start, 'ms');
start = getTimer();
for (count = 0; count < times; count++) {
bmp1.copyPixels(bmp2, bmp2.rect, new Point(0,0));
}
trace(times, 'operations of "BitmapData.copyPixels()"', getTimer() - start, 'ms');
start = getTimer();
for (count = 0; count < times; count++) {
bmp1.draw(bmp2);
}
trace(times, 'operations of "BitmapData.draw()"', getTimer() - start, 'ms');
}

