3
\$\begingroup\$

Up to 3 days ago I used a Canvas in a SurfaceView to do all the graphics operations but now I switched to OpenGL because my game went from 60FPS to 30/45 with the increase of the sprites in some levels. However, I find myself disappointed because OpenGL now reaches around 40/50 FPS at all levels. Surely (I hope) I'm doing something wrong. How can I increase the performance at stable 60FPS? My game is pretty simple and I can not believe that it is impossible to reach them.

I use 2D sprite texture applied to a square for all the objects. I use a transparent GLSurfaceView, the real background is applied in a ImageView behind the GLSurfaceView.

Some code

    public MyGLSurfaceView(Context context, AttributeSet attrs) {
        super(context);
        setZOrderOnTop(true);
        setEGLConfigChooser(8, 8, 8, 8, 0, 0);
        getHolder().setFormat(PixelFormat.RGBA_8888);
        mRenderer = new ClearRenderer(getContext());
        setRenderer(mRenderer);
        setLongClickable(true);
        setFocusable(true);
    }

    public void onSurfaceCreated(final GL10 gl, EGLConfig config) {
        gl.glEnable(GL10.GL_TEXTURE_2D);
        gl.glShadeModel(GL10.GL_SMOOTH);

        gl.glDisable(GL10.GL_DEPTH_TEST);

        gl.glDepthMask(false);

        gl.glEnable(GL10.GL_ALPHA_TEST);
        gl.glAlphaFunc(GL10.GL_GREATER, 0);

        gl.glEnable(GL10.GL_BLEND);
        gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);

        gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_NICEST);
    }

    public void onSurfaceChanged(GL10 gl, int width, int height) {
        gl.glViewport(0, 0, width, height);
        gl.glMatrixMode(GL10.GL_PROJECTION); 
        gl.glLoadIdentity(); 

        gl.glOrthof(0, width, height, 0, -1f, 1f);

        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();
    }

    public void onDrawFrame(GL10 gl) {
        gl.glClear(GL10.GL_COLOR_BUFFER_BIT);

        gl.glMatrixMode(GL10.GL_MODELVIEW);
        gl.glLoadIdentity();

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

        // Draw all the graphic object.
        for (byte i = 0; i < mGame.numberOfObjects(); i++){
            mGame.getObject(i).draw(gl);
        }

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

mGame.getObject(i).draw(gl) is for all the objects like this:

    /* HERE there is always a translatef and scalef transformation and sometimes rotatef */

    gl.glBindTexture(GL10.GL_TEXTURE_2D, mTexPointer[0]);

    // Point to our vertex buffer
    gl.glVertexPointer(3, GL10.GL_FLOAT, 0, mVertexBuffer);
    gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, mTextureBuffer);

    // Draw the vertices as triangle strip
    gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0, mVertices.length / 3);

EDIT:

After some test it seems to be due to the transparent GLSurfaceView. If I delete this line of code:

    setEGLConfigChooser(8, 8, 8, 8, 0, 0);

the background becomes all black but I reach 60 fps. What can I do?

\$\endgroup\$
  • \$\begingroup\$ Having a transparent GLSurfaceView does sound like it might be a problem in a browser. As for your edit, surely you require a depth buffer bitcount to be set via the 5th parameter of setEGLConfigChooser? 16 being an acceptable value, for instance. \$\endgroup\$ – Engineer Oct 19 '13 at 10:30
  • \$\begingroup\$ I already tried to change it to 16 or 24 but nothing changes. \$\endgroup\$ – VanDir Oct 19 '13 at 10:34
  • 1
    \$\begingroup\$ While it's unlikely the problem you're hitting just now, note that drawing each individual sprite is inefficient. Canvas may be doing some batching optimizations behind the scenes, which you will need to do yourself with OpenGL. For many simpler sprite-based games, you need only a single texture atlas (and one bind) and a single draw call for all sprites. \$\endgroup\$ – Sean Middleditch Oct 19 '13 at 18:38
  • \$\begingroup\$ I'm very interested to this comment, can you link me a site that explores the question? Anyways thank you for the tip. \$\endgroup\$ – VanDir Oct 19 '13 at 23:15
  • 1
    \$\begingroup\$ @VanDir have a look at this answer (and it's question) for a very quick description of how to do a texture atlas. \$\endgroup\$ – free3dom Oct 20 '13 at 20:09
6
\$\begingroup\$

Instead of using an ImageView and transparent GLSurfaceView you should instead render your background using a fullscreen quad (just like you do with your sprites, but sized to fit the entire screen).

Render this fullscreen background first (very important) and then also remove the gl.glClear(GL10.GL_COLOR_BUFFER_BIT); call in from onDrawFrame. You no longer need to clear the color buffer because your "full screen" background image will overwrite the entire surface (essentially doing the exact same thing as clearing) - this will also provide some performance increase.

Also, make sure that you disable ALPHA BLENDING before rendering your background image; you can enable it after the background image is rendered.

\$\endgroup\$
  • \$\begingroup\$ Thanks, you were precise and it worked perfectly. Now I have to re-create many images, but I'm glad to have solved the problem. \$\endgroup\$ – VanDir Oct 19 '13 at 23:08
  • \$\begingroup\$ Glad to help, and good luck :) \$\endgroup\$ – free3dom Oct 20 '13 at 7:21

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.