Mattias Rost

Researcher and Coder

Texture problems in Android OpenGL

Posted on 2013-11-22

Encountered such a stupid thing that I do not wish anyone else ever to encounter so I feel I have to write a post about it. Tl;dr: BitmapFactory.decodeResource may rescale the image to match the pixel density of the device, which is not good if you are concerned about the pixel size of the image.

I recently had a problem with textures in OpenGL ES 2.0 on Android. Everything worked like a charm on the development device I was using, and everyone was happy. But when I found a less common device in the office, I decided to try it on that device to see the performance. I did not expect it not to work, but was prepared that might be some performance issues. Little did I expect that nothing would show on the screen. Also, no proper error messages were shown anything. Just black screen.

When loading textures in OpenGL on android, people generally use something like

[code]
Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(),R.drawable.cool_texture);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
[/code]

Its doubtful that anything would go wrong with these two lines, so I went to check the most obvious things I could think of. First off I checked if the device required power of two sized textures (256x256, 512x512, etc). I created a texture that was 256x256 and loaded it. Did not work. So I went ahead and tried all kinds of things, stripped down the code to bare minimum to isolate where the problem was.

To cut things short. The problem was with the two lines, and the way BitmapFactory.decodeResources decodes resources... The bitmap I obtained ended up not being the dimensions of the image I created, but something slightly less. The fix:

[code]
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
Bitmap bitmap =
BitmapFactory.decodeResource(context.getResources(),R.drawable.cool_texture, options);
[/code]

Once this was added, I learned the problem indeed was with power of two sized textures, and could take care of it.

Ps. if you want to check the platform supports non-power of two sized textures, you can run this check:

[code]
String extensions = gl.glGetString(GL10.GL_EXTENSIONS);
mSupportsNPOT = extensions.indexOf("GL_OES_texture_npot") != -1;
[/code]

Potentially not the nicest way of doing it, but it works. Ds.