3
votes

I'd like to hear what people think the optimal draw calls are for Open GL ES (on the iphone).

Specifically I've read in many places that it is best to minimise the number of calls to glDrawArrays/glDrawElements - I think Apple say 10 should be the max in their recent WWDC presentation. As I understand it to do this you need to put all the vertices into one array if possible, so you only need to make the drawArrays call once.

But I am confused because this surely means you can't use the translate, rotate, scale functions, because it would apply across the whole geometry. Which is fine except doesn't that mean you need to pre-calculate every vertex position yourself, rather than getting open gl to do it?

Also, doesn't it mean you can't use any of the fan/strip settings unless you just have a continuous shape?

These drawbacks make me think I'm not understanding something correctly, so I guess I'm looking for confirmation that I should:

  • Be trying to make an uber array of all triangles to draw.
  • Resign myself to the fact I'll have to work out all the vertex positions myself.
  • Forget about push'ing and pop'ing each thing to draw into it's desired location

Is that what others do?

Thanks

1

1 Answers

8
votes

Vast question, batching is always a matter of compromise.

The ideal structure for performance would be, as you mention, to one single array containing all triangles to draw.

Starting from here, we can start adding constraints :

  • One additional constraint is that having vertex indices in 16bits saves bandwidth and memory, and probably the fast path for your platform. So you could consider grouping triangles in chunks of 65536 vertices.

  • Then, if you want to switch the shader/material/glState used to draw geometry, you have no choice (*) but to emit one draw call per shader/material/glState. So grouping triangles could consider grouping by shaderID/materialID/glStateID.

  • Next, if you want to animate things, you have no choice (*) but to transmit your transform matrix to GL, and then issue a draw call. So grouping triangles could consider grouping triangles by 'transform groups', for example, all static geometry together, animated geometry that have common transforms can be grouped too.

In these cases, you'd have to transform the vertices yourself (using CPU) before merging the meshes together.

Regarding triangle strips, you can transform any mesh in strips, even if it has discontinuities in its topology, by introducing degenerate triangles. So this is a technique that always apply.

All in all, reducing draw calls is a game of compromises, some techniques might work well for a 3d model, while others may be more suited for other 3d models. IMHO, the key is to be creative and to carefully benchmark your application to see if your changes actually improve performance on your target platform.

HTH, cheers,


(*) actually there are techniques that allow to reduce the number of draw calls in these cases, such as :

  • texture atlases to group different textures in a single one, to prevent switching textures in GL, thus allowing to limit draw calls

  • (pseudo) hardware instancing that allow shaders to fetch transforms from various sources to transform mesh instances in different ways.

  • ...