Tag Archives: opengl es

Retina Display, Open GL, and You!

Over the long weekend, I took some time to code support for the iPad and iPhone 4’s Retina Display into Red Nova. It was a fairly painless process, after Paul Pridham pointed me in the right direction.

If you are using OpenGL for your app on the iPhone and are using an Orthographic projection for your 2D bits, you shouldn’t have to change much of your code to get it “Retina Ready”.

Setting the View Scale Factor

First, your Open GL View class if you add the following in your init code it will tell the OS that you want to display your graphics at 960×640:

if([[UIScreen mainScreen] respondsToSelector: NSSelectorFromString(@"scale")])
{
	if([self respondsToSelector: NSSelectorFromString(@"contentScaleFactor")])
	{
		self.contentScaleFactor = [[UIScreen mainScreen] scale];
	}
}

If you run your app at this point you should see the content running in the corner of the screen because your GL viewport is still running at 480×320. So that brings us to…

Setting up the Open GL Viewport

Note: If you haven’t already you may want to make a wrapper function that returns the current device scale factor. I did and it’s very useful in code that needs to properly deal with displaying your graphics at the right size.

Anyway, this is the next and pretty much final step.

Find your call to glViewport, and modify it thusly:

glViewport(0,0,usefulGetScreenWidthHelper()*usefulGetScreenScaleHelper(),
	usefulGetScreenHeightHelper()*usefulGetScreenScaleHelper());

Obviously change the width and the height to correspond to your app’s layout.

If the rest of your code sets up your projections (2D and 3D) based on 480×320, when you compile and run your app you should get glorious retina display goodness! You will of course have to adjust your 2D bitmapped assets (fonts and images) to reflect the higher resolution of the display, but the end result is that your app thinks in 480×320 (this is how Apple manages it with Cocoa Touch, as far as I can tell, amusingly enough) but displays at 960×640!

Optimizing for OpenGL ES

If you’re trying to get your OpenGL ES code to run really fast on the iPhone you have to take one very important piece of information into account: writing to memory on the iPhone is expensive. To that effect, I just got another >10fps in my 3D engine by precomputing vertex, normal and texture coordinate buffers for all my 3d models instead of writing to a generic buffer in my drawing loop as I had been doing. So basically when I call gl*Pointer calls, I point to the buffer in my model object.

It means I’m using up a tiny bit more memory per model (not per object, as they reference the models) but the performance increase is amazing and totally worth it.

Whee!

Well, I got my iPod Touch on Wednesday, so I spent about an hour to get a provisioning profile from Apple and to set up Xcode to work with that. I started an Open GL ES project and copied my 3D engine code into it and just kept beating it with a sledgehammer until it compiled. It was actually a fairly easy process overall.

I had already replaced all my immediate mode OpenGL calls with vertex arrays, but I discovered much to my horror that I was still using some unsupported calls. I cleaned that up and I figured out how to install GLU for the iPhone in the simulator and iPhone OS SDKs as well.

Then I realized that the iPhone’s GPU only supports power of two textures… oh great shades of 1998! I consulted the intertubes and found out how to use some GraphicsServices calls to scale my textures to a more appropriate size. This is in no way optimal mind you! Once everything is working properly as is, I’ll get a start on optimizing my textures and stuff like that, but this is a great start.

The next night I decided to start using a thread to run my game code instead of using the timer method as it creates a lot of overhead. If you end up having trouble with this, I have discovered for some reason you should initialize your GL buffers in the main thread instead of the game thread. I’m thinking it’s some sort of resource synchronization issue with the main thread and the forked thread.

So right now I sit with a working 3D engine and my next step is to capture touch input from the main thread and start pushing it into an event queue for my game thread to nom on. I suspect I will need a blocking mechanism while the game thread is doing it’s thing.