Opengl ES performance problems

Tutorials concerning the OpenGL® ES cross-platform API for full-function 2D and 3D graphics on the Google-Android platform.

Opengl ES performance problems

Postby Hachaso » Sat Mar 20, 2010 10:28 am

Hi!

I'm creating a 3D cube, with different textures on each plane. I'm doing this with OpenGL.
The Cube is scaled to fit the whole screen but can be zoomed out when I touch it.
I have managed to measure the FPS and get around 15 fps when the cube takes the whole screen. As I zoom out I noticed that the fps increases to around 20 - 25.

My question is.
How can I boost performance on this?
Do I have to make sure that my PNG images are in the correct format so the GPU doesn't have to change them to a format suitet for it?
I have heard that some graphics cards like the images to be in certain format otherwise it has to convert them to that format, creating a decrease in performance?

What about the texture sizes?

Any suggestion would be appreciated.

Thanks
Hachaso
Developer
Developer
 
Posts: 43
Joined: Mon Jan 26, 2009 11:44 am

Top

Postby Skywhy » Sat Mar 20, 2010 2:58 pm

Sure ways to boost performance:
- Draw as many triangles as possible with one draw call using either GL_TRIANGLE_STRIPS or GL_TRIANGLES.
- Have all textures on one atlas and map the coordinates from there. OpenGL ES dies when you change textures (states).
- Minimise OpenGL ES state changes. Everytime you change OpenGL ES state, OpenGL goes dead slow because of this.
- Textures always need to be power of two (map all into one big power of two atlas).


It's next to impossible to help you if you don't provide anything to bounce off from, ie. show us some code. Really hard to tell how you could boost performance if we don't know how you are doing things.

I threw together some general bits of info that is quaranteed to give you a boost in performance. Other than that, hard to help without seeing how you do things in your code.
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Postby Hachaso » Sat Mar 20, 2010 5:42 pm

Hi!

Thanks for the suggestions.

I will provide my drawing code here.
Please let me know if you need more information or code to help me
Hope this helps.

Code: Select all
public void onDrawFrame(GL10 gl)
{
.....

      timeNow = System.currentTimeMillis();
        if(timePreviousUpdate == 0)
             timePreviousUpdate = timeNow;
        dt = (int) (timeNow - timePreviousUpdate);
        timePreviousUpdate = timeNow;
        if (dt > 500)
            dt = 1;
      
      
      if(bZoomIn)
      {
            currentZ += dt*0.0015f;
          Log.d("OPENGL", "Z Position: " + currentZ);
      }
       if(bZoomOut)
       {
          
           currentZ -= dt*0.0015f;
           if(currentZ < -10f)
           {
              currentZ = -10f;
              bZoomOut = false;
           }
          Log.d("OPENGL", "Z Position: " + currentZ);
       }

      
       gl.glTranslatef(0.0f, 0.0f, currentZ);
      
      
      gl.glScalef(2.2f, 1.8f, 0.9f);          //Scale the Cube to 80 percent, otherwise it would be too large for the screen
      
      
      gl.glRotatef(yrot, 0.0f, 1.0f, 0.0f);   //Y
      
      gl.glEnable(GL10.GL_TEXTURE_2D);
      
      cube.draw(gl, filter);



Code: Select all
// Cube class

public class Cube {

   private int[] textures = new int[4];
   
   //  bottom plane
   private float plane1_tri1[] = {-1.0f, -1.0f, -1.0f,
          1.0f, -1.0f, -1.0f,          
          -1.0f, -1.0f, 1.0f,
          1.0f, -1.0f, 1.0f };
   
    // top plane
   private float plane2_tri1[] = {-1.0f, 1.0f, 1.0f,
          1.0f, 1.0f, 1.0f,          
          -1.0f, 1.0f, -1.0f,
          1.0f, 1.0f, -1.0f };
   
   // front plane

   private float plane3_tri1[] = {-1.0f, -1.0f, 1.0f, //Vertex 0
          1.0f, -1.0f, 1.0f,  //v1
          -1.0f, 1.0f, 1.0f,  //v2
          1.0f, 1.0f, 1.0f};
   
   // left plane
   private float plane4_tri1[] = {-1.0f, -1.0f, -1.0f,
          -1.0f, -1.0f, 1.0f,          
          -1.0f, 1.0f, -1.0f,
          -1.0f, 1.0f, 1.0f};
   
   // back plane
   private float plane5_tri1[] = {1.0f, -1.0f, -1.0f,
          -1.0f, -1.0f, -1.0f,          
          1.0f, 1.0f, -1.0f,
          -1.0f, 1.0f, -1.0f};
   
   // right plane
   private float plane6_tri1[] = {1.0f, -1.0f, 1.0f,   //...
          1.0f, -1.0f, -1.0f,          
          1.0f, 1.0f, 1.0f,
          1.0f, 1.0f, -1.0f,};
   

   
   private short indexes2[]= {0, 1, 3, 0, 3, 2};
   
   
   public Cube()
   {
      
      
      ///////////////////////////////////////////////
      vertexBuffer1 = FloatBuffer.wrap(plane1_tri1);
      
      vertexBuffer2 = FloatBuffer.wrap(plane2_tri1);
      
      vertexBuffer3 = FloatBuffer.wrap(plane3_tri1);
      
      vertexBuffer4 = FloatBuffer.wrap(plane4_tri1);
      
      vertexBuffer5 = FloatBuffer.wrap(plane5_tri1);
      
      vertexBuffer6 = FloatBuffer.wrap(plane6_tri1);
      
      textureBuffer1 = FloatBuffer.wrap(new_textures);
      
      indexShortBuffer = ShortBuffer.wrap(indexes2);
      ///////////////////////////////////////////////
      
      
   }
   
   public void draw(GL10 gl, int filter)
   {
      //Enable the vertex, texture and normal state
      gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
      

      //Set the face rotation
      gl.glFrontFace(GL10.GL_CCW);
      
      
      //////////////////////////////////////////////////////////////
      
      gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[1]);               
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer1);
        gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,textureBuffer1);       
        gl.glDrawElements(GL10.GL_TRIANGLES, indexes2.length, GL10.GL_UNSIGNED_SHORT, indexShortBuffer);
      
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[2]);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer2);
        gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,textureBuffer1);       
        gl.glDrawElements(GL10.GL_TRIANGLES, indexes2.length, GL10.GL_UNSIGNED_SHORT, indexShortBuffer);
      
      //gl.glColor4f(0.5f, 0.5f, 1.0f, 1.0f);
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[1]);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer3);
        gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,textureBuffer1);       
        gl.glDrawElements(GL10.GL_TRIANGLES, indexes2.length, GL10.GL_UNSIGNED_SHORT, indexShortBuffer);
       
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer4);
        gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,textureBuffer1);       
        gl.glDrawElements(GL10.GL_TRIANGLES, indexes2.length, GL10.GL_UNSIGNED_SHORT, indexShortBuffer);
       
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[2]);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer5);
        gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,textureBuffer1);       
        gl.glDrawElements(GL10.GL_TRIANGLES, indexes2.length, GL10.GL_UNSIGNED_SHORT, indexShortBuffer);
       
        gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[3]);
        gl.glVertexPointer(3, GL10.GL_FLOAT, 0, vertexBuffer6);
        gl.glTexCoordPointer(2,GL10.GL_FLOAT,0,textureBuffer1);       
        gl.glDrawElements(GL10.GL_TRIANGLES, indexes2.length, GL10.GL_UNSIGNED_SHORT, indexShortBuffer);
       
      //////////////////////////////////////////////////////////////
      
      
      //Disable the client state before leaving
      gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
      
   }
   
Hachaso
Developer
Developer
 
Posts: 43
Joined: Mon Jan 26, 2009 11:44 am

Postby Skywhy » Sat Mar 20, 2010 5:48 pm

Currently a bit busy but if my 10second overview of it is correct, you are changing states A LOT _every_ draw loop and thus killing your performance already. I'm not sure is it the root of the problem but a really good place to start looking.

First of all, minimise state changes. Meaning don't call these every loop:
Code: Select all
      //Enable the vertex, texture and normal state
      gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);

     
      //Disable the client state before leaving
      gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
      gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);


Instead, call enable client state once in the initialisation when you get open gl handle and that's it. Do not keep flickering back and forth without any reason. You are drawing from vertex and texture arrays all the time so I see no reason to disable them. Enable once in init. And same goes for gl.glEnable(GL10.GL_TEXTURE_2D); If you don't disable the state, you don't need to tell OpenGL every loop to enable it. It's enabled already.

OpenGL's states stay on unless turned off. So.. Try those out.
You need to remember that unless you turn off opengl's state, it will stay on and this is a fundamental thing to crasp and understand compeltely when developing with OpenGL. Same goes for the textures. You should store all the textures in ONE BIG texture, instead of telling OpenGL to swap texture every side of the cube... This way you tell OpenGL once that alright, use this texture, and using texture coordinates you pinpoint the correct texture from the big texture.



You are swapping texture six times, BAD thing to do.
Code: Select all
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[1]); 

Another BIG performance hit. Instead, like I said, create one big texture, recalculate texture coordinates and call the bindTexture ONCE and render from there. Remember, minimise state changes. Currently you are not doing it and it hits your performance.
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Postby Hachaso » Sat Mar 20, 2010 11:01 pm

Thanks.

I will have a look at the:

gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);


The

gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[1]);
in my draw method.
If I need all the planes to have different textures, how can I do that without calling

glBindTexture as I have done in my code?

Please give me an example of how to do it better?
Hachaso
Developer
Developer
 
Posts: 43
Joined: Mon Jan 26, 2009 11:44 am

Postby Skywhy » Sun Mar 21, 2010 2:33 pm

You use the bind command once to assing the texture what OpenGL is using (and this texture will have to have ALL SIX textures in ONE (texture atlas info), so it's one big texture and you will have to calculate new texture coordinates) and you just use different texture coordinates six times to get the right part of the big image to map on the right side of the cube.

To be fair, I'm not going to start writing an example on this. It's a fundamental thing on how OpenGL works and the internet is full of these examples (how to use texture atlases). Google it up. It should come up :)
Skywhy
Developer
Developer
 
Posts: 35
Joined: Tue Oct 20, 2009 7:55 pm

Top

Return to Android 2D/3D Graphics - OpenGL Tutorials

Who is online

Users browsing this forum: No registered users and 2 guests