Tips for rendering a lot of objects with different textures


This is a bit of a generic question. I’m writing an application that renders map tiles (like you’d see with Google Maps or OpenStreetMap) that uses OpenGL ES2. My test device has a PowerVR SGX540. If I have a scene with relatively simple geometry, but a lot of different textures, what are some suggestions/tips that I could employ to maintain a good frame rate? Map tiles are kind of tricky because they’re dynamically loaded and tend to be pretty large (so using a texture atlas would be difficult). In the worst case, I might have 15-20+ map tiles that need to be shown, each with their own 512x512 texture.


can the spec called “Navigation Rendering Techniques” located at :

GraphicsSDK/SDK_3.0/Documentation/Whitepapers directory related to the demo navigation 2d can help on that matter ?

Sort by texture and just draw the tiles - you shouldn’t have any problems with 20 batches (or even 50). Even better if you have only one tile per texture (usually the case for maps).

As a rule of thumb, just make it work first, then optimize. Otherwise you may end up with a design which is hard to maintain and extend. If you already did that and you are not satisfied with performance - that’s different, please post your numbers (amount of textures, batches, timings etc).

Texture atlas may sound like a good idea only until they are static (or rarely updated) and lots of small images (small enough that texture switching has impact on performance). Textures as large as 512x512 are best managed as separate textures. Also keep in mind that glTexSubImage2D may do a full texture upload even if you specify only a part of it.

Overall, I’d care more about minimizing fillrate and overdraw rather than context switches. Once again, profile before optimizing!

For maps I’d also argue that doing a smart image decoding and texture upload to a) minimize time between image being requested and image being displayed on screen and b) not blocking UI thread during that process (e.g. user could scroll and it should be still butter-smooth) is a lot more important.

Good luck with your project!

Thanks for the replies.

I went ahead and tried to implement map tile rendering in my scene. I get poor performance inconsistently – it seems like I get major slowdowns when really large tiles fill up all or most of the scene.

  • For testing I set some limits: 16 tiles, with 256x256 RGBA (4444) textures
  • I tried using different textures for each geometry and with a texture atlas (didn’t notice much of a difference)
  • I tried playing with texture modes (mipmapping, nearest/linear, etc) – didn’t really do much

    As for profiling, I’m a little lost on the best way to proceed with that. I use apitrace on my computer to get the number of calls and other general stats. But I can’t get device specific stats like timing since I have a ‘closed’ device (I’m using a BlackBerry Playbook) … so I’d appreciate any advice in that regard.

    Right now, my scene only has one other texture, a 1024x1024 glyph map. I have 9 shaders that are being used altogether. They are all simple, almost trivial shaders. At its most complex I have about 205,000 vertices in the scene. I’d say about 60% of those are position vertices and the rest are other attributes… nearly all of the geometry is specified as indexed triangle lists so, say ~40,000 triangles in the scene. All geometry is batched and put in VBOs. I average 500-600 total calls to OpenGL when the scene has a ton of stuff in it per frame [worst case], with maybe ~60 of those calls being glDrawArrays or glDrawElements.

Did you use texture compression?

given that the tiles are really used with map data, they would probably compress a lot

Wow, there’s a huge difference between “15-20+ map tiles” and “~40,000 triangles”. Are you sure you need to many of them? On a 1024x600 screen, that’s about 15 pixels per triangle. I would definitely start with optimizing your geometry, using LODs for models etc.

500 GL calls per frame is next thing to work on, 10 to 1 setup calls to glDraw call seems to be very high.

Perhaps you could be more specific about your geometry and the way you render it? Is it 2D or 3D? Are you culling your geometry? Is there an overdraw? Are you drawing front to back?

As to performance testing, most of OpenGL functions as asynchronous, the only reasonable counter is raw FPS which you can get by disabling vsync (by setting eglSwapInterval to 0), and measuring time after each frame. Aim at nothing less than 60 FPS or ~16ms between 2 eglSwapBuffers() calls.

Good luck!