Draw Algorithm

In the previous section we described how to create the two geometry sets for each sprite. Now we can render the optimized version of our test scene. First, we render all the opaque sprites regions, then we render the background - using front-to-back rendering - with both depth testing and depth writes enabled.

This results in the output shown in the following image:

Mali Shield Scene 4 

The renderer has not calculated or drawn the pixels for each sprite, or the part of the background, that is hidden underneath another opaque sprite. This is because the early depth test was performed before the shading calculations occurred.

With the opaque geometry rendering complete, it is now possible to render the transparent region for each sprite in a back-to-front order. Depth testing must be left on, so that sprites on a lower layer do not overwrite an opaque region from a sprite that has already been rendered in a higher layer. If you want to save a little bit of power, you can disable depth buffer writes.

To show the additional rendering added by the pass, clear the color output of the opaque stage, keep its depth values, and then draw the transparent pass. The result of this can be seen in the following image:

Mali Shield Scene 4 

Areas in which one of the outer rings is obscured indicates where rendering work has been saved. The depth test has removed the missing parts.

If we put the scene all back together, and render both passes to the same image, then we arrive back at the same visual output as the original back-to-front render, which you can see again in the following image:

Mali Shield Scene 

The new render results in around 35% fewer fragment threads started, equaling around a 35% drop in MHz required to render this scene.

The final bit of operational logic that we needed is to ensure that the depth buffer that was added to the scene is not written back to memory. If your application is rendering directly to the EGL window surface, then there is nothing to do here. This is because depth is implicitly discarded for window surfaces automatically.

However, if your engine is rendering to an off-screen Draw , then you must add either of the following OpenGL ES calls before changing the FBO binding away from the off-screen target:

  • OpenGL ES 3.0 or newer: glInvalidateFramebuffer()
  • OpenGL ES 2.0 only: glDiscardFramebufferEXT()
Previous Next