How To Improve Opengl Es Performance?


Jan-Nik

Active Member
Joined
Jan 5, 2009
Messages
539
Location
Germany
I just compilied my first game with OpenGL ES for the Wiz, a simple tetris clone:

http://www.youtube.com/watch?v=pBCi_-KUVT0

But I have a problem with performance. When there are more then 30 blocks visible, performance drops below 15 FPS which makes the game nearly unplayable. Which tricks could I use to improve the performance on the Wiz?

Does someone know which graphics card the Wiz' 3d chip can be compared to performance-wise? A Voodoo 2?
 
I think the Wiz can handle something like 1M polys/sec (I thought it was 100,000 but that might be a worst case, or textured?). Memory bandwidth might be an issue too.

I don't know what the Voodoo2 could do, maybe someone could post a comparison.
 
just some random thoughts ...

... reduce the number of opengl state changes (shader switching, texture switching)
... i think u are using the nanoGL with glVertex emulation layer? - use VBOs instead, i.e. create a VBO for each tile beforehand and then just use a simple draw call ...
 
Hello

I have very limited experiences yet, but it seems that the 3d hw of wiz is not slower than the PowerVR MBX Lite of the iPhone (not the 3gs with the SGX and Cortex-A8). It should be far enough performace for a tetris.

My game is a little bit faster on the wiz, but it can be a simple lucky case (using things those are slow on iphone but fast on wiz).

Maybe the first hint to decrease the number of batches (number of drawing calls to draw a frame). Also there can be things that is performed slow by the Wiz - point sprites?). How does your code draw a frame exactly?

frozen
 
craigix said:
I think the Wiz can handle something like 1M polys/sec (I thought it was 100,000 but that might be a worst case, or textured?). Memory bandwidth might be an issue too.
Hm .. that should be enough. I also tried to draw untextured, but that didn't improved the performance.

I don't know what the Voodoo2 could do, maybe someone could post a comparison.
AFAIK the Voodoo2 can do about 5M polys/sec.

crow_riot said:
just some random thoughts ...

... reduce the number of opengl state changes (shader switching, texture switching)
What is shader switching?

... i think u are using the nanoGL with glVertex emulation layer? - use VBOs instead, i.e. create a VBO for each tile beforehand and then just use a simple draw call ...
No, already using VBOs, see below :)


frozen said:
Maybe the first hint to decrease the number of batches (number of drawing calls to draw a frame). Also there can be things that is performed slow by the Wiz - point sprites?). How does your code draw a frame exactly?

The code to draw a texture looks like this:

Code:
			glEnable(GL_TEXTURE_2D);
			glEnableClientState(GL_TEXTURE_COORD_ARRAY);

			glBindTexture(GL_TEXTURE_2D, texture_);
			glVertexPointer(2, GL_FLOAT, 0, &vertexes_[0]);
			glTexCoordPointer(2, GL_FLOAT, 0, &texCoords_[0]);
			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);

			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
			glDisable(GL_TEXTURE_2D);
Even when I only call glDrawArrays it doesn't seem to help to improve the performance.

Maybe I shouldn't use floats?
 
Last edited by a moderator:
(1) This is the code of drawing only one tetris block?

In this case you should batch your draw calls, e.g. collecting all the static blocks into one buffer and render it once.

(2) Or do you render the whole game screen into a texture and draw it onto 2 triangles?

Texture creation is a slow operation and should not be called in every frame.

(3) I don't understand your code. :)

frozen
 
Jan-Nik said:
Code:
			glEnable(GL_TEXTURE_2D);
 			glEnableClientState(GL_TEXTURE_COORD_ARRAY);
 
 			glBindTexture(GL_TEXTURE_2D, texture_);
 			glVertexPointer(2, GL_FLOAT, 0, &vertexes_[0]);
 			glTexCoordPointer(2, GL_FLOAT, 0, &texCoords_[0]);
 			glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
 
 			glDisableClientState(GL_TEXTURE_COORD_ARRAY);
 			glDisable(GL_TEXTURE_2D);
Even when I only call glDrawArrays it doesn't seem to help to improve the performance.

Maybe I shouldn't use floats?

I expect floats to be OK if you don't do any math on them in your code because the Wiz's 3D hardware supports them. It depends on the OpenGL ES implementation, of course.

Have you tried not doing the glEnable/glEnableClientState/glDisableClientState/glDisable for every primitive? I see no reason why you should have to keep doing this.

For your particular type of graphics you can probably get away with using a single texture and color modulation to draw the blocks in one batch call. You can also have a large texture that includes many tiles and simply change the texture coordinates. These things would prevent you from having to do glBindTexture constantly, although I don't know what the actual impact of using it is. You could also try using quads instead of triangle strips, but I have no idea which one performs better.

But if the glDrawArrays call itself is so slow then you must have some more critical problem. Especially with the small number of actual elements you're drawing. What you're describing sounds like it's struggling to push more than 4000 or so small textured triangles per second, which is pretty sad.
 
Last edited by a moderator:
just some random thoughts ...

... reduce the number of opengl state changes (shader switching, texture switching)
What is shader switching?

... material/texture/lighting combined.


Maybe I shouldn't use floats?

true, use fixed point - everywhere. someone already posted some useful fixed point code somewhere here in the forum.

i need to agree with frozen, the wiz should be able to handle that handful of triangles. did you ever measure the overall performance without those draw calls? are they really your bottleneck? try to do some timings on different sub-parts of your code and see what part takes that long. i can't really imagine that it's the draw code all alone.
 
Exophase said:
I expect floats to be OK if you don't do any math on them in your code because the Wiz's 3D hardware supports them.

oh, that's a nice thing to know :)
 
Last edited by a moderator:
Floats are ok, and you can easily do 5000 polys on screen at 50-60fps... so my best guess is what others have said, limit your state changes, and draw all of your polygons in one batch (or as few as possible). This second part means you need texture atlases (one big texture with all of the "pieces" you have inside it), then you adjust your uv coordinates as necessary to align with the atlas not the whole texture. If you are drawing one by one it will certainly be too slow, speaking from experience.
 
The same here. Performance with floats vs fixeds is the same when rendering geometry only.
 
Sorry, a little fix: '..when rendering 2d geometry...'. What is the performance difference when rendering 3d geometry? It could be the same if the 3d hardware has hardware TnL i think. Or if the cpu has the same tnl performance with fixeds and floats. :)
 
I expect your floating point performance will differ depending on if you are using the archived toolchain (which does hardware floating point, "FPA"), or a toolchain designed to compile and link cleanly to the libs alaready on the Wiz (which uses VFP, and so has an ABI incompatible to VFA or soft-VFA (this is three-way incompatible ABI's)). I don't know which way it would differ or by exactly how much, but I wouldn't expect it to be the same...it could be an interesting experiment to find out.
 
Yeah, in my case I used nanoGL and static linked libstdc++. Could not figure out at the time how to directly link to the system libs and get it to still work.
 
trentg said:
Yeah, in my case I used nanoGL and static linked libstdc++. Could not figure out at the time how to directly link to the system libs and get it to still work.

There was lib that was hand modified to allow linking. I may have included it in my opengl package
 
Last edited by a moderator:
That drawing code looks sorta... ahm... "straightforward". Enable texturing once, draw everything. Same goes for binding. Put everything into one texture. Bind this once... use it for everything.

Also, there is a difference between the pieces on the floor and the one which is still in midair. Those on the floor are - for the time being - static geometry (easier to use ints there). All of that can be drawn in one go.

Drawing the whole scene...

1 draw tex for the background + labels (no prior clearing - this overdraws everything)
<=5 times draw tex for score
<=2 times draw tex for level
<=3 times draw tex for lines
<=4 times draw tex for time
1 draw tex for preview
1 VBO for the blocks on the floor
1 whatever for the midair piece (w/o smooth rotation you could also use draw tex there)

~16 times drawtex and ~2 VBOs. Only one texture which is bound outside the loop. Should easily run at 60fps, I guess.
 
The first thing i would do is disable the textures in your code and try rendering all your elements with vertex colors or just flat shaded. I cant seem to find anything detailing the 3d hardware in the wiz so its hard to say what it should be capable of but certainly more than a tetris game!
It looks like theres a bottleneck somewhere and i would put money on it being something to do with your textures (assuming you have more than one texture for your tetris blocks. Another thing worth checking (i cant remember if this applies to opengl it certainly does for SDL) is that colour depth of your textures match your screens colour depth (The one you initialised openGL with). Its possible your texture is being converted everytime its drawn onto the final buffer.
Its been a while since ive touched openGL so hopefully i remember it correctly ;)
 
It looks like to me that your using a VBO for the texture information, but not for the vertices. I'd expect your drawing code to do something more similar to:

Code:
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_FIXED, 4 * sizeof(GLfixed), 0);
glTexCoordPointer(2, GL_FIXED, 4 * sizeof(GLfixed), (GLvoid *)(2 * sizeof(GLfixed)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

Note that this example used fixed point, not floating point, but you get the idea.

It appears to me that you're re-uploading the vertex data for every triangle, which will definitely impact performance on the Wiz.

All that said, I can't get much more than 100 textured/alpha blended polies on the screen before I drop to about 30 frames per second. I haven't taken the time to figure out where the time is going, I could still be doing something drastically wrong myself.
 
I render around 1200 triangles (4 tile layers - 2d stuff) in my game, 3 of the 4 texture atlases have perpixel alphamap. It is 20 batches with sprites and effects. Currently (without any optimization) it runs at 25 fps if i use floats, and 28-29 fps if i use fixed math.

frozen
 
Wow, thanks to everyone for his response! You guys are awesome, never thought I would get so much help here :)

frozen said:
(1) This is the code of drawing only one tetris block?

In this case you should batch your draw calls, e.g. collecting all the static blocks into one buffer and render it once.

(2) Or do you render the whole game screen into a texture and draw it onto 2 triangles?

Texture creation is a slow operation and should not be called in every frame.

(3) I don't understand your code. :)

frozen
(1)
What do you mean with one "buffer"? One vertex buffer object?

Exophase said:
Have you tried not doing the glEnable/glEnableClientState/glDisableClientState/glDisable for every primitive? I see no reason why you should have to keep doing this.
Yes, but that didn't help.

For your particular type of graphics you can probably get away with using a single texture and color modulation to draw the blocks in one batch call.
I'm already using only one texture for a block, coloring it with glColor3ub.

You could also try using quads instead of triangle strips, but I have no idea which one performs better.
GL_QUADS is not defined in my GL ES headers that's why I'm using GL_TRIANGLE_FAN.
crow_riot said:
true, use fixed point - everywhere.
Although that would improve the performance a bit, I am too lazy to change all my code. Furthermore I would need to set up some kind of custom type, so that I can still compile my game for normal OpenGL.

are they really your bottleneck? try to do some timings on different sub-parts of your code and see what part takes that long. i can't really imagine that it's the draw code all alone.
I also tried to comment out (can you say so in English?) some code about the game logic like checking for full lines. Even changing the Wiz clock speed doesn't change the FPS that much, so I really think the drawing is the bottleneck.

aho said:
Drawing the whole scene...

1 draw tex for the background + labels (no prior clearing - this overdraws everything)
<=5 times draw tex for score
<=2 times draw tex for level
<=3 times draw tex for lines
<=4 times draw tex for time
1 draw tex for preview
1 VBO for the blocks on the floor
1 whatever for the midair piece (w/o smooth rotation you could also use draw tex there)

~16 times drawtex and ~2 VBOs. Only one texture which is bound outside the loop. Should easily run at 60fps, I guess.
Unfortunately it's to complicated to change my code so that this works. For example I'm not directly using OpenGL but a custom library written by myself. I could change it's API to allow more optimization but I don't want to do that.

Lonewolf9383 said:
The first thing i would do is disable the textures in your code and try rendering all your elements with vertex colors or just flat shaded.
I tried that, but it didn't help.

Another thing worth checking (i cant remember if this applies to opengl it certainly does for SDL) is that colour depth of your textures match your screens colour depth (The one you initialised openGL with).
It's true - I have initialised OpenGL ES with 16 bit, while I am using 24 bit colors. But setting EGL_BUFFER_SIZE to anything else than 16 results in weird graphical glitches. Has anyone managed yet to set up 24 bit OpenGL ES display on the Wiz?

satacoy said:
It looks like to me that your using a VBO for the texture information, but not for the vertices. I'd expect your drawing code to do something more similar to:

Code:
glBindTexture(GL_TEXTURE_2D, texture);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexPointer(2, GL_FIXED, 4 * sizeof(GLfixed), 0);
glTexCoordPointer(2, GL_FIXED, 4 * sizeof(GLfixed), (GLvoid *)(2 * sizeof(GLfixed)));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

Note that this example used fixed point, not floating point, but you get the idea.
Yeah, you're right thanks! I was using vertex arrays, but not VBOs. I thought since the Wiz has no dedicated video memory the speed would be the same. How I was wrong: Now it's about 40 % faster!

As some of you already suggested: I also changed, that glBindBuffer, glVertexPointer and glTexturePointer are only called before drawing ALL blocks and not before drawing every block.

It's still not fast enough though, but definitely playable (assuming you don't suck at Tetris). You can download it here: http://watteimdocht.de/jan-nik/jntetri_wiz_beta1.zip

One thing that also isn't right: After quiting my application you can still see 2/3 of the last frame (hard to describe in English, sry). And my game cannot be started a second time. I heard this is a bug of libopengles_lite.so, is it?
 
Last edited by a moderator:
Back
Top