1

I know very little about OpenGL so please be gentle.

The app needs to load a bitmap (from resources), resize it, and use it in an OpenGL texture. I have an implementation that works, but there was a bad banding issue on the Wildfire S. So I changed the implementation and fixed the banding issue (by switching to ARGB_8888) but that then broke the functionality on the Galaxy Nexus and the Nexus One.

I am seeing three visual presentations:

  1. The bitmap (a smooth 24-bit gradient) shows correctly, with no banding.

  2. The gradient shows, but with obvious banding

  3. The texture shows as flat white, no bitmap (or issues in logcat)

Here are two versions of the method to load the bitmap, and notes on the results seen with each:

    // White on Galaxy Nexus. White on Nexus One. Renders correct image (no banding) on Wildfire S
    private Bitmap getBitmap1() {
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        options.outWidth = getTextureSize();
        options.outHeight = getTextureSize();
        final Bitmap bmp;
        bmp = BitmapFactory.decodeResource(getResources(), bitmapResourceId, options);
        return bmp;
    }

    // Renders correctly (no banding) on Galaxy Nexus. Renders on Nexus One and Wildfire S but with obvious banding.
    private Bitmap getBitmap2() {
        int textureSize = getTextureSize();
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inPreferredConfig = Bitmap.Config.ARGB_8888;
        options.outWidth = getTextureSize();
        options.outHeight = getTextureSize();
        final Bitmap bmp;
        bmp = Bitmap.createScaledBitmap(BitmapFactory.decodeResource(getResources(), bitmapResourceId, options), textureSize, textureSize, true);
        return bmp;
    }

getTextureSize() returns 1024.

How do I build a single method that shows the bitmap without banding on all devices, and without any devices show a big white box?

Ollie C
  • 28,313
  • 34
  • 134
  • 217
  • For the phones where it is white, can you try inserting glGetError calls in your program flow and see if it returns anything? If the return is nonzero it is an error code that indicates some kind of problem. You won't necessarily see any problems in logcat from incorrect opengl api usage, it just fails silently unless you check the error codes. – Tim Apr 25 '12 at 19:06
  • Thanks Tim. The error code is 1281. – Ollie C Apr 25 '12 at 19:51

3 Answers3

1

OpenGL.org has this to say about that error:

GL_INVALID_VALUE​, 0x0501: Given when a value parameter is not a leval value for that function. This is only given for local problems; if the spec allows the value in certain circumstances, and other parameters or state dictate those circumstances, then GL_INVALID_OPERATION is the result instead.

Step one is to find the exact opengl call that is causing the problem. You'll have to do trial and error to see which line is throwing that error. If you set up the program flow like this:

glSomeCallA()
glGetError() //returns 0
glSomeCallB()
glGetError() //returns 0
glSomeCallC()  
glGetError() //returns 0x501

Then you'll know that glSomeCallC was the operation that caused the error. If you look at the man page for that particular call, it will enumerate everything that could cause a specific error to occur.

In your case I'll guess that the error will be after glTexImage call just to save you some time, though I'm not positive.

If you look at the glTexImage man page, at the bottom it will list everything that can cause an invalid value error. My guess will be that your texture is larger than the GL_MAX_TEXTURE_SIZE. You can confirm this by checking glGetIntegerv(GL_MAX_TEXTURE_SIZE);

Tim
  • 35,413
  • 11
  • 95
  • 121
  • the line that's causing the error is "GLUtils.texImage2D(GLES11.GL_TEXTURE_2D, 0, bmp, 0);" which suggests the bitmap isn't suitable in some way – Ollie C Apr 25 '12 at 20:58
1

getBitmap1

outHeight and outWidth are used in conjunction with inJustDecodeBounds. You cannot use them to load a scaled bitmap. So the reason you are seeing a white texture is that the bitmap is not a power of two.

getBitmap2

you should keep a reference to the bitmap returned by decodeResource so that you can recycle it later. also use options.inScaled = false;to load an unscaled version of the bitmap. Also take note that createScaledBitmap may change the depth of the bitmap to RGB_565 if the original bitmap contains no alpha channel (Source);

Questions: is the original Bitmap Resource square? If not your scaling code will change the aspect ratio which could result in artifacts.

EDIT: so how do you scale a bitmap and preserve the bit depths? Easiest solution is to pass a bitmap with alpha channel into createScaledBitmap. You can also scale yourself like so:

                    Bitmap newBitmap = Bitmap.createBitmap(1024, 1024, Bitmap.Config.ARGB_8888);
                    Canvas canvas = new Canvas(newBitmap);
                    final int width = src.getWidth();
                    final int height = src.getHeight();
                    final float sx = 1024  / (float)width;
                    final float sy = 1024 / (float)height;
                    Matrix m = new Matrix();
                    m.setScale(sx, sy);
                    canvas.drawBitmap(src,m,null );
                    src.recycle();

ANOTHER EDIT: take a look at this Question for pointers on how to deal with that.

Community
  • 1
  • 1
Renard
  • 6,909
  • 2
  • 27
  • 23
  • Interesting. So how do I create a scaled version using RGB_8888? By switching to 888, the banding vanishes on the two smaller phones, so the key to getting high-quality rendering seems to be to use 888. I guess I could manually scale the bitmap to 1024x1024 and just load it without scaling. Hmm. – Ollie C Apr 25 '12 at 20:46
  • The original bitap was not square, though I just tried with a scaled version, 1024x1024, and I get the same result (scaling code not present). I think I'm more confused now, unfortunately. – Ollie C Apr 25 '12 at 20:54
  • It seems I have two choices. a) use bitmaps that are 1024x1024 in size and not scale (to preserve as 888), or b) load the bitmap and scale it whilst maintaining the 888 format (no idea how to do this). – Ollie C Apr 25 '12 at 21:08
  • so you used getBitmap1 with a 32bit square bitmap and options.inScaled = false and the texture is still banded or white? What you need to ensure is: 32 bit texture which is pot. Also your EGLSurface needs to be 32 bit. Call setEGLConfigChooser(8, 8, 8, 8, 16, 0) to ensure that. – Renard Apr 25 '12 at 21:11
  • I have resized the bitmap to 1024x1024, and set the ConfigChooser as you suggested. I'm also using isScaled=false. The texture displays on all devices, but has serious banding on both smaller devices (Galaxy Nexus ok, looks great). the texture is being fit to the screen, so is being resized at some point, but the banding doesn't look like resize banding, it looks like color depth banding (not enough colours) – Ollie C Apr 25 '12 at 21:25
  • Its hard to tell and nearly warrants an extra question :-). some devices might simply not support 32 bit openGL surfaces. You can try to use Bitmap.Options.inDither in that case. Or it might be related to your texture filter options. Are you using GL10.GL_NEAREST? – Renard Apr 25 '12 at 21:48
  • The solution that worked for me was to manually resize the input images, provide them in various sizes (hdpi, etc) and then just load the bitmap and apply to a canvas. Removing the auto-resize step sorted it out. Many thanks for your help. – Ollie C Apr 27 '12 at 09:22
1

Color Banding Solved ooooooooooyyyyyyyeaaaaaaaaaa

I solved color banding in two phases

1) * when we use the BitmapFactory to decode resources it decodes the resource in RGB565 which shows color banding, instead of using ARGB_8888, so i used BitmapFactory.Options for setting the decode options to ARGB_8888

second problem was whenever i scaled the bitmap it again got banded

2) This was the tough part and took a lot of searching and finally worked * the method Bitmap.createScaledBitmap for scaling bitmaps also reduced the images to RGB565 format after scaling i got banded images(the old method for solving this was using at least one transparent pixel in a png but no other format like jpg or bmp worked)so here i created a method CreateScaledBitmap to scale the bitmap with the original bitmaps configurations in the resulting scale bitmap(actually i copied the method from a post by logicnet.dk and translated in java)

    BitmapFactory.Options myOptions = new BitmapFactory.Options();
    myOptions.inDither = true;
    myOptions.inScaled = false;
    myOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;//important
    //myOptions.inDither = false;
    myOptions.inPurgeable = true;
    Bitmap tempImage =  
    BitmapFactory.decodeResource(getResources(),R.drawable.defaultart, myOptions);//important

    //this is important part new scale method created by someone else
    tempImage = CreateScaledBitmap(tempImage,300,300,false);

    ImageView v = (ImageView)findViewById(R.id.imageView1);
    v.setImageBitmap(tempImage);

// the function

public static Bitmap CreateScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter)
{
    Matrix m = new Matrix();
    m.setScale(dstWidth  / (float)src.getWidth(), dstHeight / (float)src.getHeight());
    Bitmap result = Bitmap.createBitmap(dstWidth, dstHeight, src.getConfig());
    Canvas canvas = new Canvas(result);
    //using (var canvas = new Canvas(result))
    {
        Paint paint = new Paint();
        paint.setFilterBitmap(filter);
        canvas.drawBitmap(src, m, paint);
    }
    return result;

}

Please correct me if i am wrong. Also comment if it worked for you.

I am so happy i solved it, Hope it works for you.

Diljeet
  • 1,896
  • 20
  • 24