# Rendering multiple squares fast?

so I'm doing my first steps with openGL development on android and I'm kinda stuck at some serious performance issues...

What I'm trying to do is render a whole grid of single colored squares on to the screen and I'm getting framerates of ~7FPS. The squares are 9px in size right now with one pixel border in between, so I get a few thousand of them. I have a class "Square" and the Renderer iterates over all Squares every frame and calls the draw() method of each (just the iteration is fast enough, with no openGL code the whole thing runs smootlhy at 60FPS). Right now the draw() method looks like this:

// Prepare the square coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX,
GLES20.GL_FLOAT, false,
vertexStride, vertexBuffer);

// Set color for drawing the square
GLES20.glUniform4fv(mColorHandle, 1, color, 0);

// Draw the square
GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length,
GLES20.GL_UNSIGNED_SHORT, drawListBuffer);


So its actually only 3 openGL calls. Everything else (loading shaders, filling buffers, getting appropriate handles, etc.) is done in the Constructor and things like the Program and the handles are also static attributes. What am I missing here, why is it rendering so slow? I've also tried loading the buffer data into VBOs, but this is actually slower... Maybe I did something wrong though.

Any help greatly appreciated! :)

Several thousand draw calls is enough to slow down a desktop, let alone a mobile.

Refer to geometry batching. That is, instead of creating 1000 tiny meshes, just create 1 gigantic mesh. Just try to make sure the number of vertices doesn't exceed 65536 (since the vertex index register is only 16-bit wide, 2 to the 16th power = 65k).

Further, to get the same sort of output you're getting right now, you'd use vertex coloring. I would just search on "OpenGL ES 2 vertex color". This answer gives you a good idea -- it's just another array like the position or index arrays that you already supply for upload to the graphics card.

NB: Because you want hard colour edges between your tiles (as opposed to interpolated vertex colours), you will need to create duplicate vertices at all of the corners which you might ordinarily think a vertex would be shared by two or more tiles. This is just a limitation you'll have to live with. (There is another way to do this without duplicating verts, but it involves using a non-bilerp texture laid onto one very large 4-vertex quad -- definitely efficient but I don't know how if you need your tiles destructible / replaceable so ignore this for now, you can comment here later if you want me to elaborate.) So in a grid like this, which accomodates 4 quads:

1-2-3
| | |
4-5-6
| | |
7-8-9


You would need 1 vertex each at 1, 3, 7, 9, 2 vertices at 2, 4, 6, 8, and 4 vertices at 5, reflecting how many quads each labeled position is shared by.

So just as if you were setting up one of your current draw calls, you run a big nested loop to create all your vertex positions, vertex colours and vertex indices in order, and upload them like so. You will need an extra glVertexAttribPointer for your colour array, among other things. But I leave the nasty codey bits to you, as this is more a conceptual answer. I would suggest that you work from the simplest test case, i.e. change your code to spit out just one simple quad, as you have it at present, make it white for instance, enlarge its dimensions, then start pushing additional geometry into that same batch and get it working that way until you have all your mini tiles overlaid over your larger white tile.

• Ok thanks, thought about something like that, too. So if I understand correctly once I do this I only have to make on draw call to render all the squares? But how can I then draw them in a different color? – Sam Oct 28 '12 at 13:12
• @Sam I'm updating your answer, as there's not enough space here... – Engineer Oct 28 '12 at 13:15
• @Sam And yes, just a single draw call. This is how massive terrains are rendered in games. Because the geometry is static, you can batch it. When geometry is non-static (eg. characters) then you cannot batch it, as GL must apply a separate spatial transform to each individual character model. Whereas with terrain, it all exists in the same, shared space and vertices do not move with respect to one another. – Engineer Oct 28 '12 at 13:35
• Great! Thank you :) I will try this as soon as I can. – Sam Oct 28 '12 at 13:51
• @Sam Cool, NP. Feel free to accept if (when) this has helped you get on your feet. – Engineer Oct 28 '12 at 13:52