All hail iOS 5
Tuesday, October 18, 2011 8:59:33 PM
iOS 5 is here, there is much rejoicing in the streets! While I followed flowery prose comments on twitter about how blazingly fast everyones HTML5 got with this update I was silently muttering words a family father will have to just mutter instead of saying out loud. My neat little iOS game Emberwind had gone from running perfectly smooth on any prior iOS version to a stuttering sluggish mess on iOS 5.
The first choice for a programmer is of course always to blame the OS or gfx-driver or keyboard or whatever seems remotely plausible before scrutinizing your own code... to be perfectly honest it did seem reasonable to do so this time... I hadn't changed a thing and it went from 30 FPS to 10-ish FPS.
I think I muttered more than once "POS iOS 5.. don't they do any automated regression testing on their releases at Apple!?!".
I don't know the answer to that question... I'd be interested to hear, but I'm guessing not or they would've spotted this and let people know.
I'm not going to ramble too much, let's dive into the solution... precision!
Yes, you heard right... precision, you know the little precision qualifiers everyone who's starting out with some WebGL or GLSL copies from a sample, that little seemingly insignificant
precision highp float;Cause let's face it...everyone always picks highp!
What it does is to determine how much precision the GPU should use for your floats and ints etc. At least 2^-8 for lowp, 2^-10 for mediump and 2^-16 for highp when we're talking floats.
So how did this affect Emberwind? Well, it's a 2d game so you're mostly only moving textured clip space quads so there really is no need to use anything but lowp (EDIT: Re-read my post when it was mentioned on the WebGL mailing list and I actually meant to say mediump here). Or at least that's what I thought I was doing... turns out there was one place, in the vertex shader where I hadn't specified precision. The GLES Shading Language spec clearly says
The vertex language has the following predeclared globally scoped default precision statements:
precision highp float;
precision highp int;
precision lowp sampler2D;
precision lowp samplerCube;
The fragment language has the following predeclared globally scoped default precision statements:
precision mediump int;
precision lowp sampler2D;
precision lowp samplerCube;
Which meant I really were using highp in the vertex shader.
Now the regression in iOS 5 appears to be that using a highp varying in the vertex shader will promote any mismatched varying in the fragment shader to highp thereby causing a major performance hit. You can see a profile run of the game using highp struggling to reach 13-14 FPS. (Note how lovely quiet it is on the CPU except when loading)
Using lowp in the second sample it sits quite comfortably at 33 FPS. It's a quite staggering difference. And if you say "You call 30FPS smooth?" Then my only defence is... well...it's a port...they're always second class citizens! You're so damn tired of the game by the time you get to ports so you're bound to take a few shortcuts. 30 FPS seemed like a reasonable one.
So, summing up... dropping from 33 to 13 fps because of precision! It may not matter much on desktop graphics hardware, but it apparently very much does on mobile... that goes for you WebGL-ers as well... not just native app devs!
Now I just need to send my one line optimization off to Chillingo and get it all fixed on the appstore!
And finally.. I'm speaking at New Game Conference in SF together with heaps of other talented speakers. It'll be awesome... and you should come! Free Chromebooks for everyone if they sell out 97% of the tickets!


Constantine Vesnac69 # Wednesday, October 19, 2011 8:28:29 PM
Erik Mölleremoller # Thursday, December 1, 2011 11:48:34 PM
Erik Mölleremoller # Thursday, December 1, 2011 11:50:43 PM
Originally posted by emoller:
I actually did try lowp as well back when I were experimenting with this, but lowp didn't have enough precision so cracks and seams were visible in the game. mediump rendered just fine.