OpenGL gradient banding on Samsung Galaxy S2 Android phone

I’ve got a live wallpaper out on the market which uses OpenGL to render some basic shapes and a flat plane. The simple lighting creates a gradient effect across the plane, which looks fine on most devices. The Samsung Galaxy S2 series seems to have some trouble rendering the gradient, though, as you can see in this screen shot:

banding on GS2

The color banding looks awful, especially compared to this screen shot from an Incredible:

no banding on DInc

I’m using a 565 EGL config in both cases, so I believe this is just a display issue with the GS2 devices. Can anyone confirm this suspicion?

Is there any solution to the banding?


You’re getting the banding because of a bad setting for colour bit depth on your surface. Romain Guy and Chet Haase (both Google employees who work on graphics in Android gave a presentation that covers these issues at the San Francisco Android User Group in 2010. The video is available on YouTube here and I’ve actually made some notes on the stuff they cover (shameless plug) here. Specifically the section that you want starts at about 25 minutes in and lasts for 10 minutes.

Relevant section from my notes:

Supported Bitmap formats are ALPHA_8 (for alpha masks), ARGB_4444 (this isn’t recommended, uses 4 bits for each component and therefore doesn’t look very good), ARGB_8888 (recommended, 32 bit images, allows for transparency), and RGB_565 (doesn’t contain alpha channel, limited precision for colours, faster to draw, uses dithering). JPEG images do not contain transparency and pre-Gingerbread were loaded automatically with RGB_565. This meant that jpg images automatically lost some quality pre-gingerbread. Post Gingerbread all images are loaded by default as ARGB_8888 (and application memory usage limits are increased to compensate). When loading a Bitmap, make sure to specify the format that you want, otherwise it will be loaded as its default and every time the Bitmap is drawn it will need to be converted. For instance, pre-Gingerbread the default bit depth for a Surface is 16 bits, so a 32 bit image will need to be converted before rendering which can be slow. You can control quality of this rendering by enabling/disabling dithering on the Paint object and the Drawable object that the Bitmap’s being used by. Blending should be avoided with the alpha channel. If Android detects an image is completely opaque it can perform a faster rendering pass.

(emphasis mine)

There’s both performance and precision loss when loading an image with the wrong bit depths and he gives an example at about 30:00 showing how artefacts and banding can occur and the different options you have to cope with it, as well as the differences in rendering speed for each option.

This is relevant even in OpenGL if you’re loading an image with BitmapFactory before putting it into a buffer, you can specify the config you want with BitmapFactory.decodeStream().

Source : Link , Question Author : Josh , Answer Author : Martin Foot

Leave a Comment