Flash vs. HTML5: Bitmap Drawing Speed
Flash vs. HTML5: Bitmap Drawing Speed

				HTML5 is all the rage and a lot of Flash developers are either curious about it or have actually made the switch. But how does its performance stack up against Flash? That is a very complicated question, so we’ll begin today with just a simple test of the speed at which a lot of bitmaps can be drawn to the screen. Who will win? Read on to find out.

Today’s test comes in two parts: an JavaScript/HTML5 app using the canvas tag and an AS3 app using BitmapData. Both of them draw 10,000 16×16 images to a 640×480 screen at random positions.
Launch the HTML5 version
Launch the Flash version
Here is the source code for the Flash version:


package
{
	import flash.geom.Point;
	import flash.events.MouseEvent;
	import flash.text.TextFormat;
	import flash.geom.Rectangle;
	import flash.utils.getTimer;
	import flash.text.TextFieldAutoSize;
	import flash.display.StageScaleMode;
	import flash.display.StageAlign;
	import flash.text.TextField;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Sprite;
 
	public class BitmapTest extends Sprite
	{
		[Embed(source="opaque.jpg")]
		private static const OPAQUE:Class;
 
		[Embed(source="alpha.png")]
		private static const ALPHA:Class;
 
		private var opaqueBMD:BitmapData = (new OPAQUE() as Bitmap).bitmapData;
		private var alphaBMD:BitmapData = (new ALPHA() as Bitmap).bitmapData;
		private var screenBMD:BitmapData;
		private var screenRect:Rectangle;
		private var sourceRect:Rectangle;
		private var destPoint:Point;
		private var time:TextField;
 
		public function BitmapTest()
		{
			stage.align = StageAlign.TOP_LEFT;
			stage.scaleMode = StageScaleMode.NO_SCALE;
 
			screenRect = new Rectangle(0, 0, stage.stageWidth, stage.stageHeight);
			screenBMD = new BitmapData(640, 480);
			addChild(new Bitmap(screenBMD));
 
			sourceRect = new Rectangle(0, 0, opaqueBMD.width, opaqueBMD.height);
			destPoint = new Point(0, 0);
 
			makeButtons("Opaque", "Alpha");
 
			time = new TextField();
			time.text = "Time: 9999";
			time.autoSize = TextFieldAutoSize.LEFT;
			time.x = stage.stageWidth - time.width;
			time.y = stage.stageHeight - time.height;
			addChild(time);
		}
 
		private function makeButtons(...labels): Number
		{
			const PAD:Number = 5;
			var curX:Number = PAD;
			var curY:Number = stage.stageHeight - PAD;
			for each (var label:String in labels)
			{
				if (label == null)
				{
					curX = PAD;
					curY -= button.height + PAD;
					continue;
				}
 
				var tf:TextField = new TextField();
				tf.mouseEnabled = false;
				tf.selectable = false;
				tf.defaultTextFormat = new TextFormat("_sans");
				tf.autoSize = TextFieldAutoSize.LEFT;
				tf.text = label;
				tf.name = "lbl";
 
				var button:Sprite = new Sprite();
				button.buttonMode = true;
				button.graphics.beginFill(0xF5F5F5);
				button.graphics.drawRect(0, 0, tf.width+PAD, tf.height+PAD);
				button.graphics.endFill();
				button.graphics.lineStyle(1);
				button.graphics.drawRect(0, 0, tf.width+PAD, tf.height+PAD);
				button.addChild(tf);
				button.addEventListener(MouseEvent.CLICK, onButton);
				if (curX + button.width > stage.stageWidth - PAD)
				{
					curX = PAD;
					curY -= button.height + PAD;
				}
				button.x = curX;
				button.y = curY - button.height;
				addChild(button);
 
				curX += button.width + PAD;
			}
 
			return curY - button.height;
		}
 
		private function onButton(ev:MouseEvent): void
		{
			var mode:String = ev.target.getChildByName("lbl").text;
			switch (mode)
			{
				case "Opaque":
					test(opaqueBMD);
					break;
				case "Alpha":
					test(alphaBMD);
					break;
			}
		}
 
		private function test(bmd:BitmapData): void
		{
			var REPS:int = 10000;
			var maxX:int = screenRect.width - bmd.width;
			var maxY:int = screenRect.height - bmd.height;
			var beforeTime:int = getTimer();
			screenBMD.fillRect(screenRect, 0xffffffff);
			screenBMD.lock();
			for (var i:int = 0; i < REPS; ++i)
			{
				destPoint.x = Math.random() * maxX;
				destPoint.y = Math.random() * maxY;
				screenBMD.copyPixels(bmd, sourceRect, destPoint);
			}
			screenBMD.unlock();
			var afterTime:int = getTimer();
			time.text = "Time: " + (afterTime-beforeTime); 
		}
	}
}


And here are the images it embeds:


You can get the source code of the HTML5 version by simply opening up the HTML file. Its embedded images are Base64-encoded into the img tags.
Here are the devices tested:


Name
CPU
GPU
OS


MacBook Pro Retina
2.3 GHz Intel Core i7
Intel HD Graphics 4000
OS X 10.8.3


Windows Desktop
2.66 GHz Intel Xeon X5550
Nvidia GeForce GTX 660
Windows 7 SP 1


iPad 2
1 GHz ARM Cortex-A9
PowerVR SGX543MP2
iOS 6.1.3



LG Optimus G
1.5 GHz Qualcomm Krait
Qualcomm Adreno 320
Android 4.1

HTC Evo V 4G
1.2 GHz Qualcomm Snapdragon
Qualcomm Adreno 220
Android 4.0


And here are the results:


Device
Opaque
Alpha


HTC Evo V 4G – Android 4 Browser
278
330


HTC Evo V 4G – Google Chrome 27
1093
1102


Apple iPad 2 – Safari
225
225


LG Optimus G – Android Browser
465
503


LG Optimus G – Google Chrome 27
358
349


Motorola Xoom – Android 4 Browser
231
232


Motorola Xoom – Google Chrome 27
289
276


MacBook Pro Retina – Google Chrome 27
35
36


MacBook Pro Retina – Firefox 21
70
73


MacBook Pro Retina – Safari 6
17
16


MacBook Pro Retina – Flash Player 11.7
33
35


Windows Desktop – Google Chrome 27
51
52


Windows Desktop – Firefox 21
141
139


Windows Desktop – Internet Explorer 10
188
180


Windows Desktop – Flash Player 11.7
11
12





From this data we can draw some interesting conclusions:

Regardless of device, choice of browser will make a huge performance difference with HTML5. On Mac OS X, Safari is about 4x faster than Firefox. On Windows 7, Google Chrome is 4x faster than Internet Explorer. On the HTC Evo V 4G, the Android Browser is 3x faster than Google Chrome.
On Windows and Mac, Google Chrome seems to be about twice as fast as Firefox.
Safari is about twice as fast as Flash on Mac OS X. Google Chrome is a little slower and Firefox is far slower.
Flash beats everything on Windows by a long shot. It’s 5x faster than Google Chrome, 13x faster than Firefox, and 17x faster than Internet Explorer
Mobile processors still have a long way to go to match their desktop/laptop counterparts. A modern phone (HTC Evo V 4G) was beaten by a modern desktop computer (Windows Desktop) by a factor of 100x. How much worse would the performance be on a typical 2-3 year old phone? If you go with HTML5 you’ll need to plan for performance to vary by at least two orders of magnitude.

There’s definitely no clear “HTML5 is faster” or “Flash is faster” conclusion here. As ever with HTML and JavaScript, your results will vary heavily by browser. If you go with HTML5 it’s imperative that you test on many browsers! However, Flash Player outperforms HTML5 on all browsers except Safari on Mac OS X in this test. So it’s safe to say that Flash Player is usually faster and certainly faster for the vast majority of users given that Safari only has about 5% of the desktop marketshare.
As a disclaimer with mobile, there are many devices out there with wildly different performance characteristics. Even iOS has five base models of iPad, six of the iPhone, and five of the iPod Touch. There are hundreds to thousands of Android devices. It’s therefore really hard to get a complete picture of mobile performance since very few people have access to so many devices. I certainly don’t. However, I’m guessing many people reading this article have a couple of minutes to point their mobile browsers at the above tests. Want to contribute your own test results? Post a comment with your device name, opaque and alpha times, and if you have them or can look them up, CPU and GPU specs.
			