Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

createWindowSurface failed: EGL_BAD_MATCH?

Tags:

android

crash

egl

the version android is 2.2.1 the device is a samsung galaxy II the full crash log is:

java.lang.RuntimeException: createWindowSurface failed: EGL_BAD_MATCH
at android.opengl.GLSurfaceView$EglHelper.throwEglException(GLSurfaceView.java:1077)
at android.opengl.GLSurfaceView$EglHelper.createSurface(GLSurfaceView.java:981)
at android.opengl.GLSurfaceView$GLThread.guardedRun(GLSurfaceView.java:1304)
at android.opengl.GLSurfaceView$GLThread.run(GLSurfaceView.java:1116)

this is the relevant code to the crash:

@Override 
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_NO_TITLE);
    getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                         WindowManager.LayoutParams.FLAG_FULLSCREEN);
    glView = new GLSurfaceView(this);
    glView.setEGLConfigChooser(8 , 8, 8, 8, 16, 0);
    glView.setRenderer(this);
    setContentView(glView);
    \\etc..............}

i used setEGLConfigChooser() because the app would crash on API-17 if it wasnt in there so for this specific device that it is crashing on i been looking around and it has something to do with the PixelFormat for the device.

What im wondering is how can i use some code so this will not crash on the samsung galaxy II android version 2.2.1, i cant test this in an emulator and i dont have the device to test it in, i just need for sure code and im not sure how to change it up?

like image 933
JRowan Avatar asked Mar 22 '13 02:03

JRowan


1 Answers

Update: I found a way to work around this issue and actually it is fairly straightforward.

First of all: Android's default EGLConfigChooser implementation makes bad decisions on some devices. Especially the older Android devices seem to suffer this EGL_BAD_MATCH issue. During my debugging sessions I also discovered that those older troublemaker devices had quite a limited set of available OpenGL ES configurations.

The cause of this "bad match" problem is more than just a mismatch between the GLSurfaceView's pixel format and the color bit depth settings of OpenGL ES. Overall we have to deal with the following issues:

  • A mismatch of the OpenGL ES API version
  • A mismatch of the requested target surface type
  • The requested color bit depth cannot be rendered on the surface view

The Android developer documentation is severely lacking when it comes to explaining the OpenGL ES API. It is therefore important to read the original documentation over at Khronos.org. Especially the doc page about eglChooseConfig is helpful here.

In order to remedy above listed problems you have to make sure to specify the following minimum configuration:

  • EGL_RENDERABLE_TYPE must match the OpenGL ES API version you are using. In the likely case of OpenGL ES 2.x you must set that attribute to 4(see egl.h)
  • EGL_SURFACE_TYPE should have the EGL_WINDOW_BIT set

And of course you also want to set up an OpenGL ES context that provides you with the correct color, depth and stencil buffer settings.

Unfortunately it is not possible to cherry-pick these configuration options in a straightforward way. We have to choose from whatever is available on any given device. That's why it is necessary to implement a custom EGLConfigChooser, that goes through the list of available configuration sets and picks the most suitable one that matches best the given criteria.

Anyway, I whipped up a sample implementation for such a config chooser:

public class MyConfigChooser implements EGLConfigChooser {
    final private static String TAG = "MyConfigChooser";

    // This constant is not defined in the Android API, so we need to do that here:
    final private static int EGL_OPENGL_ES2_BIT = 4;

    // Our minimum requirements for the graphics context
    private static int[] mMinimumSpec = {
            // We want OpenGL ES 2 (or set it to any other version you wish)
            EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,

            // We want to render to a window
            EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,

            // We do not want a translucent window, otherwise the
            // home screen or activity in the background may shine through
            EGL10.EGL_TRANSPARENT_TYPE, EGL10.EGL_NONE, 

            // indicate that this list ends:
            EGL10.EGL_NONE
    };

    private int[] mValue = new int[1];
    protected int mAlphaSize;
    protected int mBlueSize;
    protected int mDepthSize;
    protected int mGreenSize;
    protected int mRedSize;
    protected int mStencilSize;

    /**
    * The constructor lets you specify your minimum pixel format,
    * depth and stencil buffer requirements.
    */
    public MyConfigChooser(int r, int g, int b, int a, int depth, int 
                        stencil) {
        mRedSize = r;
        mGreenSize = g;
        mBlueSize = b;
        mAlphaSize = a;
        mDepthSize = depth;
        mStencilSize = stencil;
    }

    @Override
    public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
        int[] arg = new int[1];
        egl.eglChooseConfig(display, mMinimumSpec, null, 0, arg);
        int numConfigs = arg[0];
        Log.i(TAG, "%d configurations available", numConfigs);

        if(numConfigs <= 0) {
            // Ooops... even the minimum spec is not available here
            return null;
        }

        EGLConfig[] configs = new EGLConfig[numConfigs];
        egl.eglChooseConfig(display, mMinimumSpec, configs,    
            numConfigs, arg);

        // Let's do the hard work now (see next method below)
        EGLConfig chosen = chooseConfig(egl, display, configs);

        if(chosen == null) {
            throw new RuntimeException(
                    "Could not find a matching configuration out of "
                            + configs.length + " available.", 
                configs);
        }

        // Success
        return chosen;
    }

   /**
    * This method iterates through the list of configurations that 
    * fulfill our minimum requirements and tries to pick one that matches best
    * our requested color, depth and stencil buffer requirements that were set using 
    * the constructor of this class.
    */
    public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display,
            EGLConfig[] configs) {
        EGLConfig bestMatch = null;
        int bestR = Integer.MAX_VALUE, bestG = Integer.MAX_VALUE, 
            bestB = Integer.MAX_VALUE, bestA = Integer.MAX_VALUE, 
            bestD = Integer.MAX_VALUE, bestS = Integer.MAX_VALUE;

        for(EGLConfig config : configs) {
            int r = findConfigAttrib(egl, display, config, 
                        EGL10.EGL_RED_SIZE, 0);
            int g = findConfigAttrib(egl, display, config,
                        EGL10.EGL_GREEN_SIZE, 0);
            int b = findConfigAttrib(egl, display, config,         
                        EGL10.EGL_BLUE_SIZE, 0);
            int a = findConfigAttrib(egl, display, config,
                    EGL10.EGL_ALPHA_SIZE, 0);
            int d = findConfigAttrib(egl, display, config,
                    EGL10.EGL_DEPTH_SIZE, 0);
            int s = findConfigAttrib(egl, display, config,
                    EGL10.EGL_STENCIL_SIZE, 0);

            if(r <= bestR && g <= bestG && b <= bestB && a <= bestA
                    && d <= bestD && s <= bestS && r >= mRedSize
                    && g >= mGreenSize && b >= mBlueSize 
                    && a >= mAlphaSize && d >= mDepthSize 
                    && s >= mStencilSize) {
                bestR = r;
                bestG = g;
                bestB = b;
                bestA = a;
                bestD = d;
                bestS = s;
                bestMatch = config;
            }
        }

        return bestMatch;
    }

    private int findConfigAttrib(EGL10 egl, EGLDisplay display,
            EGLConfig config, int attribute, int defaultValue) {

        if(egl.eglGetConfigAttrib(display, config, attribute, 
            mValue)) {
            return mValue[0];
        }

        return defaultValue;
    }
}
like image 85
tiguchi Avatar answered Oct 06 '22 19:10

tiguchi