GPU guide

From JPCT
Jump to: navigation, search

What you should know about different GPUs

Android runs on a variety of different GPUs (Graphics Processing Units). All of them have some issues that you should know about. This isn't meant to be an all-encompassing list, but it mentions some problems and workarounds that surfaced during the development of jPCT-AE. Keep in mind that not all problems surface on all devices/drivers and in all applications.

On all GPUs are much faster to use "disposable" shaders, than use conditions. Try to avoid using something like if(shadows == true) especially in fragment shader, separated shader supporting shadows will be faster. For dynamic generation required shaders may be used #ifdef blocks, that is perform during the compile time. Or by connecting blocks in Java.

PowerVR

Overall, PowerVR's chips are very common. There are a few problems though:

  • The shader compiler creates shaders that render everything in black: This seems to be a bug in the shader compiler. The only solution that i found was to add some additional variables to the shader that serve no real purpose but somehow fix the problem. This problem is very rare though.
  • Missing polygons: This can happen with large polygons that are in parallel with the x/y-plane. They simply disappear in some situations. A solution is to either rotate them in a way that they aren't parallel to the x/y-plane anymore or split them into smaller ones.
  • Missing polygons on first render pass: This happens on models with high polygon counts. Looks like as if the chip's internal binning can't handle the polygon count in the first pass. Solution: None that i know of. One option might be not to show the first render pass or simply live with it.
  • Anti-aliasing can cause strange artifacts on polygon edges when used on models with a high polygon count: This looks like an additional wire frame layered on top of the actual rendering. Solution: None known.
  • if-else conditions did not help to increase performance: It seems PowerVR SGX 540 GPU does not perform jumps at lines. It means that if is used conditions and condition is not met, its content is performed anyway, but results are not reflected.

Adreno

Adreno chips suck when it comes to shaders (but they have very accurate texture rendering!).

  • Avoid any kind of loops in the shader, may they be static or dynamic. They will compile fine but chances are, that the result will either render complete nonsense or crash your device. Solution: Replace loops with unrolled code and/or a bunch of if/then statements.
  • z-Buffer accuracy is lower than on PowerVR and Mali if you are using a 16bit depth buffer. It should be increased to at least 24 bit to give good results.

Mali

Mali chips are pretty common. Their rendering accuracy is below PowerVR's chips, which is why you might see some rendering artifacts on Mali powered device on applications that look fine on PowerVR. Older Mali chips don't support highp in the fragment shaders while PowerVR does.

  • Some Mali chips can't handle numbers >~65500: In your shaders, don't calculate sin/cos/sqrt or similar on numbers larger than ~65500. The results will be all wrong and your shader won't work. Solution: Don't do it, try to use lower values instead.

Tegra

Tegra chips are immediate mode renderers while PowerVR, Adreno and Mali are tile-based/deferred renderers. That leads to different performance characteristics in some cases, but that's usually nothing you should have to worry about.

  • Insufficient depth buffer accuracy: Tegra uses an external depth buffer that is limited to 16bit only. That makes it pretty inaccurate and you'll see all kind of flickering or rendering errors, if you surpass its accuracy, which is pretty easy. Solution: Use an extension to enable non-linear depth buffering. jPCT-AE offers a class in util that takes care of this.
  • Textures look blocky: Tegra's rendering accuracy is very low, even lower than Mali's. On large polygons, this can cause the textures to look as if no bilinear filtering is being applied. Solution: Use smaller polygons and/or larger texture coordinates.
  • glError 1281 or error message "profile requires index expression to be compile-time constant": on Tegra 3 have to be array index constant value (can not be used uniform).
  • Unexpected result with pow(x, y): result of pow(x, y), where x or y < 0 is zero on Tegra 3. Avoid to use negative values.
  • if-else conditions did not help to increase performance: It seems Tegra 3 GPU does not perform jumps at lines. It means that if is used conditions and condition is not met, its content is performed anyway, but results are not reflected.