Hello! I am working on a 2D scrolling game for iPhone. I have a large image background, say 480×6000 pixels, of only a part is visible (exactly one screen’s worth, 480×320 pixels). What is the best way to get such a background on the screen?

Currently I have the background split into several textures (to get around the maximum texture size limit) and draw the whole background in each frame as a textured triangle strip. The scrolling is done by translating the modelview matrix. The scissor box is set to the window size, 480×320 pixels. This is not meant to be fast, I just wanted a working code before I get to optimizing.

I thought that maybe the OpenGL implementation would be smart enough to discard the invisible portion of the background, but according to some measuring code I wrote it looks like background takes 7 ms to draw on average and 84 ms at maximum. (This is measured in the simulator.) This is about a half of the whole render loop, ie. quite slow for me.

Drawing the background should be as easy as copying some 480×320 pixels from one part of the VRAM to another, or, in other words, blazing fast. What is the best way to get closer to such performance?

+3  A: 

That's the fast way of doing it. Things you can do to improve performance:

  • Try different texture-formats. Presumably the SDK docs have details on the preferred format, and presumably smaller is better.
  • Cull out entirely offscreen tiles yourself
  • Split the image into smaller textures

I'm assuming you're drawing at a 1:1 zoom-level; is that the case?

Edit: Oops. Having read your question more carefully, I have to offer another piece of advice: Timings made on the simulator are worthless.

Thank You, more or less I thought it would be that way. Today I’ll finally get an iPod for testing, I’ll run the code on the actual HW and see what happens.
After trying the code on the device: Yes, Timings made on the simulator are worthless.
+2  A: 

The quick solution:

  • Create a geometry matrix of tiles (quads preferably) so that there is at least one row/column of off-screen tiles on all sides of the viewable area.

  • Map textures to all those tiles.

  • As soon as one tile is outside the viewable area you can release this texture and bind a new one.

  • Move the tiles using a modulo of the tile width and tile height as position (so that the tile will reposition itself at its starting pos when it have moved exactly one tile in length). Also remember to remap the textures during that operation. This allows you to have a very small grid/very little texture memory loaded at any given time. Which I guess is especially important in GL ES.

If you have memory to spare and are still plagued with slow load speed (although you shouldn't for that amount of textures). You could build a texture streaming engine that preloads textures into faster memory (whatever that may be on your target device) when you reach a new area. Mapping as textures will in that case go from that faster memory when needed. Just be sure that you are able to preload it without using up all memory and remember to release it dynamically when not needed.

Here is a link to a GL (not ES) tile engine. I haven't used it myself so I cannot vouch for its functionality but it might be able to help you:

I really don't think that tile rendering library is what the original poster is after. That library is for rendering scenes into huge pixel resolutions, more than OpenGL would support in a single pass.
Yes, the library does something different than what I need, but splitting the background into smaller tiles might be a good idea. (Thanks.)