Imagination PowerVR SDK Blog

[bug] iPad 2 flicker using 3d + zbuffer



I apologize if this is not the right place to report a bug.

It seems that the iPad 2 flickers when:

  • a perspective projection is used

  • AND a depth buffer is used (16-bit or 24-bit depth buffer)

  • AND GL_DEPTH_TEST is enabled

  • AND “big” quads are rendered

  • AND the quads uses the same z value. eg:z=0

Using an orthogonal projection prevents the flicker, as well as using a 0-bit depth buffer, or rendering “small” quads. And it can’t be reproduced on an iPad 1.

This flicker happens both in GL ES 1.1 and GL ES 2.0 mode.

I’m not sure if this is an Apple’s bug, a bug in the GL drivers or a bug in the chip, that’s why I’m reporting it here.

These are some videos that shows the bug:



Minimal test project that reproduces the issue:

I’ve already opened this bug in Apple’s bugtracker: Bug ID# 9241017.



What you are seeing is “depth fighting”: intuitively, the transformation of your geometry should result in both quads having the same depth-buffer value, given ideal precision for geometry calculations, but the calculations to produce the depth value are not done at infinite precision so the output is not perfectly precise (neither can the value stored in the depth buffer be perfectly precise). As the vertex positions change in your quads these imprecisions lead to the produced value being inconsistently higher or lower than the ideal value and the result is that sometimes fragments from one quad are recorded as in front, sometimes it’s the other way round.

In this case, the calculations for a perspective projection seem to be different enough for the outcome to be less consistent than an orthogonal projection. It seems like coincidence that the iPad 1 is not showing the same issues - similar imprecisions will be present, but don’t seem to be resulting in the same kind of inconsistent behaviour.

The solution is not to render overlapping geometry at the same or very close depth, if possible. If one quad is supposed to be in front of the other then render it closer or don’t use depth testing at all and rely on submission order. Also, consider using multitexture techniques as these will avoid any depth issues entirely.

In the second video it looks like you are rendering a full-screen blended layer in order to fade/dim the quads behind it. Consider passing a uniform value to your shader instead. Use changing texture coordinates to read from a gradient texture that is combined with the image textures in order to simulate variable dimness. Or use a directional light.


Thanks Gordon.

Also, this behavior is not present on the iPhone (1st, 2nd, 3rd and 4th generation).

Do you think it is possible to reduce the “depth fighting” if I use a different perspective projection. Perhaps by using different values for zNear and zFar ?



Moving the near plane further away and far plane nearer allows for higher precision in the distance between them, but this only helps when objects are rendered at different depths.

One of the fundamental limitations of using depth testing on polys rendered at the same depth is that rounding errors in the perspective (and clipping etc.) calculations can make the result unpredictable.

The solution is not to do it: find another way such as one of those I suggest above - if you need advice on implementation, please ask.


Thanks Gordon.

I’m using this technique in a 2d game engine (cocos2d

And although the engine is for 2d games, I use the 3d projection + depth buffer to allow certain 3d effects.

By default depth testing is disabled, so this problem doesn’t appear.

But sometimes it is needed to perform a certain 3d effects, and the flicker appears.

I have a scene graph, and by default all the objects of the scene graph are rendered in z=0. So with its current design I won’t be able to use multi-texturing.

Using different z values might be a possibility, but it will alter the scaling of the objects.

I think that I will use by default an orthographic projection, and I will change to perspective + depth buffer only when it is needed.

By the way, is there a formula that calculates the next and previous flicker-free z values for a given z and a given projection ?


Lets say that I have the following projection:

P = gluPerspective(60,1, 0.5,1500);

And I want to render an sprite on z=0, but lets say that z=0 is already “used”. So I want to render it in the next flicker-free Z.

Thank you.


Could you describe those 3D effects, e.g. do some objects actually appear in front of, or intersect, the 2D planes? If you only need to make sure that one plane always appears in front of another then that can be easily achieved without affecting the shape of the projected geometry, e.g. by using glDepthRange or by manipulating the third row of the projection matrix.


Gordon, thank’s for your replies. I am having exactly the same issue, our game looks OK on older hardware (iPhone4, iPad, 3GS, 3G and iPod’s), but iPad2 & iPhone4S have depth fighiting issues.

We were assuming, that rendering polygons with the same Z-value and with all matrices set to orthogonal ones should not produce this problem (and it’s true for thatt older hardware as well as on PS’s and NVdia/ATI accelerators).

Is it really possible, that even though the matrices are orthogonal and theroretically matrix transformations & clipping should not have any precision issues, the 3D math on SGX is different somehow and the problem still occurs?


It seems that using smaller polygons reduces/eliminates the problem, but I need some further tests to be sure. Is it clipping issue?

I will restate my question:

If I do it as follows:

- render one polygon with given Z value (a nice round number for Z coords, say -10.0)

- than render one smaller polygon with Z-Equals, exactly the same matrices (no OpenGL ES state change), exactly the same Z values (-10), but not exactly the same XY vertices (the vertices do not have the same positions as first polygon, the second polygon is “inside” the first one looking on XY plane)

- the matrices set up are all orthogonal (no rotations, just translation in modelview matrix and frustum on projection matrix)

Can I make this work without artifacts on SGX 535?

Because othwerwise it means Z-Equals is useless on this hardware (unless I render exactly the same polygons with identical vertices).

I am no expert on 3D hardware, but it seems to me it’s SGX 535 hardware/driver bug and this accelerator does not keep OpenGL ES conformancy standards.