Experimenting wtih Pixel Bender for Blitting in Flash


I’d been meaning to have a play around with Pixel Bender for a long while and finally got some time up my sleeve so decided that today was the day. What I was interested in wasn’t necessarily the image filtering razzle dazzle, but more trying to find out if there was a way to harness the much hyped speed increases presented by using Pixel Bender filters to do some of the processing that I currently use AS3 to do. As a Flash game developer, finding quicker and more efficient ways to render graphics and thus increase both the frame rate and number of intereactive objects on screen is like an obsession, and I thought it would be a good way to see if Pixel Bender could offer any benefits.

The short answer, unfortunately, is no. Clarifying a little bit, for my purposes, with the sort of games I create (2D blitted games) I found out that Pixel Bender performed slower than using copypixels, much slower – by a factor of 10!

Going in to a bit more depth, blitting is so far the most CPU efficient way of animating 2D graphics in Flash, that I know of at least. This means that I render all of my animations as spritesheets and then using copyPixels, I paste each frame of each sprite to the appropriate position on the game screen. I also animate the scrolling backgrounds in the same manner.

Having read a number of other blogs about Pixel Bender it was made apparent that creating instances of ShaderJobs is quite time consuming, and as each job is a once-only use object, you need to create one each frame cycle, for each blit operation. This starts to become extra worrying when you realise that if there are 10 characters on screen, that’s 10 blits, plus all of the other various animated items and the paralax background scrolls. So from the outset I was a bit warey, but decided to put it to the test by just blitting a background image. This of all the potential uses for Pixel Bender blitting I thought would provide the most advantage because of the fact that it is a single large bitmap, so perhaps the inherent speed of the Pixel Bender operation would outweight the cost of creating a FilterJob. Unfortunately, it didn’t.

For a loop of 10000 iterations the copyPixels operation took 1000 ticks whilst the Pixel Bender filter took 13825 – that’s over 10 times longer!

I think Pixel bender has a very specific and really obscure place. Great for doing complex, multi-stage processing on large media or datasets, but apart from that, the overhead of instantiation unfortunately dwarfs the speed benefit.

Here’s the Pixel Bender Filter Code:



kernel CopyPixel
<   namespace : "com.codeandvisual";
    vendor : "Code and Visual";
    version : 1;
    description : "Used to compare copy pixels to pixel bender";
>
{
    input image4 src;
    parameter float x_shift;
    parameter float y_shift;
    output pixel4 dst;

    void
    evaluatePixel()
    {
        float2 out_new = float2(outCoord().x+x_shift,outCoord().y+y_shift);
        dst = sampleNearest(src,out_new );
    }
}

And then the AS3 Project that was run to compare the two processes:

package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Shader;
	import flash.display.ShaderJob;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLLoader;
	import flash.net.URLLoaderDataFormat;
	import flash.net.URLRequest;
	import flash.text.TextField;
	import flash.utils.getTimer;
	
	/**
	 * ...
	 * @author james@codeandvisual.com
	 */
	public class Main extends Sprite 
	{
		[Embed(source="../filter/CopyPixel.pbj", mimeType="application/octet-stream")]
		protected var CopyPixel:Class;
		//
		[Embed(source="../images/image_1.png")]
		private var Image1:Class;
		//

		protected var loader:URLLoader
		protected var shader:Shader; 
		protected const TEST_LENGTH:int  = 10000
		protected var _source_data:BitmapData =  Bitmap(new Image1() as Bitmap).bitmapData
		protected var _output_data:BitmapData = new BitmapData(400,400,false,0)
		protected var _output_data_2:BitmapData = _output_data.clone()

		public function Main():void 
		{
			if (stage) init();
			else addEventListener(Event.ADDED_TO_STAGE, init);
		}
		
		private function init(e:Event = null):void 
		{
			removeEventListener(Event.ADDED_TO_STAGE, init);
			initShader()
		}
		protected function initShader():void {
			var myTime:Number
			//
			shader = new Shader()
			shader.byteCode = new CopyPixel();
			//
			shader.data.src.width = _output_data.width;
			shader.data.src.height = _output_data.height;
			shader.data.src.input = _source_data;
			var myShiftX:Number
			var myShiftY:Number
			var t:int = 0
			//
			myTime = getTimer()
			for (t = 0; t < TEST_LENGTH; t++) {
				myShiftX = Math.random()*100
				myShiftY = Math.random()*100
				shader.data.x_shift.value=[myShiftX]
				shader.data.y_shift.value=[myShiftY]
				var shader_job:ShaderJob = new ShaderJob(shader, _output_data, _output_data.width, _output_data.height);
				shader_job.start(true);
			}
			addChild(new Bitmap(_output_data))
			trace("MY LENGTH FILTER = " + (getTimer() - myTime))
			//
			myTime = getTimer()
			for (t = 0; t < TEST_LENGTH; t++) {
				myShiftX = Math.random()*100
				myShiftY = Math.random()*100
				_output_data_2.copyPixels(_source_data,new Rectangle(myShiftX,myShiftY,_output_data_2.width, _output_data_2.height),new Point())
			}
			var myBitmap2:Bitmap = new Bitmap(_output_data_2)
			myBitmap2.x = _output_data.width
			addChild(myBitmap2)
			trace("MY LENGTH AS3 = " + (getTimer() - myTime))

		}
		
	}
	
}

You can download the source from here:
pixel_bender_blitting.zip

Further reading:
http://www.actionscript.org/resources/articles/876/1/Introduction-to-Pixel-Bender-and-Shader-for-Flash-Player-10/Page1.html

Leave a Reply

Your email address will not be published. Required fields are marked *


Creative Digital Agency

Code and Visual works with clients around Australia to create and build outstanding and accessible digital services. If you want to discus a project contact us now for an initial consultation.


Categories

Recent Posts