Removing Unnecessary State Changes

So let's look at the present() method of BobTest and see what we can change. Here's the snippet for reference (I added the FPSCounter in, and we also use glRotatef() and glScalef()):

^Override public void present(float deltaTime) { GL10 gl = glGraphics.getGL();

gl.glViewport(0, 0, glGraphics.getWidth(), glGraphics.getHeight());

gl.glClearColor(1,0,0,1);

gl.glClear(GL10. GL_COLOR_BUFFER_BIT);

gl.glMatrixMode(GL10.GL_PROJECTION);

gl.glLoadIdentity();

gl.glEnable(GL10. GL_TEXTURE_2D); bobTexture.bind();

gl.glMatrixMode(GL10.GL_MODELVIEW); for(int i = 0; i < NUM_BOBS; i++) { gl.glLoadIdentity();

gl.glTranslatef(bobs[i].x, bobs[i].y, 0); gl.glRotatef(45, 0, 0, 1); gl.glScalef(2, 0.5f, 1); bobModel.draw(GL10.GL_TRIANGLES, 0, 6);

fpsCounter.logFrame();

The first thing we could do is to move the calls to glViewport() and glClearColor(), as well as the method calls that set the projection matrix to the BobScreen.resume() method. The clear color will never change, the viewport and the projection matrix won't change either. Why not put the code to setup all persistent OpenGL states like the viewport or projection matrix in the constructor of BobScreen? Well, we need to battle context loss. All OpenGL ES state modifications we perform will get lost, and when our screen's resume() method is called, we know that the context has been recreated and is thus missing all the states we might have set before. We can also put the call the glEnable() and the texture-binding call into the resume() method. After all, we want texturing to be enabled all the time, and we also only want to use that single Bob texture. For good measure we also call texture.reload() in the resume() method so that our texture image data is also reloaded in the case of a context loss. So here are our modified present() and resume() methods:

@0verride public void resume() {

GL10 gl = glGraphics.getGL();

gl.glViewport(0, 0, glGraphics.getWidth(), glGraphics.getHeight());

gl.glMatrixMode(GL10.GL_PROJECTION);

gl.glLoadIdentity();

bobTexture.reload(); gl.glEnable(GL10. GL_TEXTURE_2D); bobTexture.bind();

@0verride public void present(float deltaTime) { GL10 gl = glGraphics.getGL(); gl.glClear(GL10. GL_COLOR_BUFFER_BIT);

gl.glMatrixMode(GL10.GL_MODELVIEW); for(int i = 0; i < NUM_BOBS; i++) { gl.glLoadIdentity();

gl.glTranslatef(bobs[i].x, bobs[i].y, 0); gl.glRotatef(45, 0, 0, 1); gl.glScalef(2, 0.5f, 0); bobModel.draw(GL10.GL_TRIANGLES, 0, 6);

fpsCounter.logFrame();

Running this "improved" version gives the following performance on the three devices:

Hero:

12-10 04:41:56.750: DEBUG/FPSCounter(467): fps: 23

12-10 04:41:57.770: DEBUG/FPSCounter(467): fps: 23

12-10 04:41:58.500: DEBUG/dalvikvm(467): GC freed 21821 objects / 524288 bytes in 133ms

12-10 04:41:58.790: DEBUG/FPSCounter(467): fps: 19

12-10 04:41:59.830: DEBUG/FPSCounter(467): fps: 23

Droid:

12-10 04:45:26.906: DEBUG/FPSCounter(9116): fps: 39

12-10 04:45:27.914: DEBUG/FPSCounter(9116): fps: 41

12-10 04:45:28.922: DEBUG/FPSCounter(9116): fps: 41

12-10 04:45:29.937: DEBUG/FPSCounter(9116): fps: 40

Nexus One:

12-10 04:37:46.097: DEBUG/FPSCounter(2168): fps: 43 12-10 04:37:47.127: DEBUG/FPSCounter(2168): fps: 45 12-10 04:37:48.147: DEBUG/FPSCounter(2168): fps: 44 12-10 04:37:49.157: DEBUG/FPSCounter(2168): fps: 44 12-10 04:37:50.167: DEBUG/FPSCounter(2168): fps: 44

So all the devices have already benefited a tiny bit by our optimizations. Of course, the effect is not exactly huge. This can be attributed to the fact that when we originally called all those methods at the beginning of the frame, there were no triangles in the pipeline yet.

0 0

Post a comment