Posts Tagged blitting

Flash on iPhone – Better Than Blitting (Real World Performance Results)

I’ve been working with Flash on the iPhone for a few months now, and although I’ve successfully released a game on the App Store (check out The Hypnotist), I’ve spent most of my time experimenting and trying to discover ways of optimising code and working out just how to get the best performance out of the device with the Flash platform.

General Tips

There are a lot of great tutorials out there specifying how to get the best performance out of Flash on mobile devices (and in general). Many of them talk about the subtlties of structuring your code, and some of these do have tremendous impact, however I’ve always found that the graphics are the true bottleneck for me (and collision detection – but that’s for another day).

The key generally comes down to blitting. For those who don’t know, blitting can be very simply described as the act of copy and pasting flat pixels, rather than relying on multilayerd movieclips with vectors and tweening etc. for your animation. The thing that I’ve discovered is that it’s faster to use a hybrid blit technique on the iphone than to go the traditional way.

To explain, traditional blitting would copy the pixels for every object and sprite directly onto a single bitmap canvas, however the best performance I’ve found comes from blitting to individual Bitmap objects on the screen. In one sense that’s quite handy as it means we can still work in the mind set of having separate display objects that we can position independently, on the other hand it worries me a bit because it feels like there’s something not quite right going on for that to be faster than using the one single bitmap canvas.

The Technique

So the following results are based on this hybrid blit/display object technique. But there is one other little difference that I’ve seen increase performance considerably… and again it’s a departure from the standard blitting operation that can only be done with this hybrid technique. And that’s not to blit at all!

Let me explain – Blitting usually utilises a single sprite sheet to contain all of the frames of your animation, you then copy the pixels from that sheet for the particular frame as it’s being rendered, pasting them to the display, and so on as the animation cycle continues.

My approach is different, it splits the sprite sheet up into individual bitmapData objects, one for each frame, at the beginning of the program and stores them in an array. Then to render the animation, you don’t use copyPixels to blit, instead you set the bitmapData property of your sprite’s Bitmap to the appropriate bitmapData frame. Hence copyPixels never gets used – instead you’re swapping bitmapData objects. So I guess at the end of the day, this is a non-blit bitmap technique.

The real world results

Based on the above bitmapData Swap technique, the following results were recorded (compiling with Flex 4.5.1.21328 and Air Beta 3.0 with an app resolution of 480×320)

Sprite size: 40×40 pixels
Sprite frame count:100 frames
Results:

  • 25 Sprites: 60fps
  • 50 Sprites: 52 fps
  • 70 Sprites: 40 fps
  • 100 Sprites: 30fps

Notes about the iPhone’s memory

For these results I was actually using an iPod touch (4th gen) which is listed as having 256MB Ram and runs at 800khz. One very useful guideline I formulated whilst doing this experimentation is a rough approximation of the amount of image data that the device can hold in memory at an one time, and that is 25 mega pixels, or 25,000,000 pixels worth of data.

For instance, if you are working at a screen res of 480×320 that would equate to 153,600 pixels worth of data – so in that case you could hold around 150 frames of animation at that full screen resolution. To put it another way, the iPhone memory could cope with @ 2,500 frames of animation at 100×100 pixels.

Bare in mind that this doesn’t reflect any intimate knowledge of the device or it’s physical specs, but is just a real world observation, and should be a handy benchmark for you to use when determining how much room you have to work with. The key indicator that you’re using too much memory seems to be a black screen of death on the device that will shut down your app and return you to the springboard.

Can you do any better?

The main reason for posting this info is that I’ve been searching online to see the best performance people have been able to achieve and am really just keen to find out what’s yielding best results for everyone out there. So in the interests of pushing the limits and spreading the knowledge please post alternative approaches that might be producing faster results. At the end of the day we shouldn’t be struggling against the technology just to get suitable performance, I’d much rather be focusing on building the content and bringing ideas to life.

Corona?

I’ve looked around the web for information on measurable performance specs for Corona, if there’s anyone out there that can post a comparison it would be very interensting to see. This might be the topic for a future post.

Tags: ,

4 Comments

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:

<languageVersion : 1.0;>
 
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

Tags: , ,

2 Comments