createWindowSurface失败:EGL_BAD_MATCH?

JRo*_*wan 11 crash android egl

android的版本是2.2.1,该设备是三星galaxy II的完整崩溃日志是:

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)
Run Code Online (Sandbox Code Playgroud)

这是崩溃的相关代码:

@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..............}
Run Code Online (Sandbox Code Playgroud)

我使用了setEGLConfigChooser()因为应用程序会在API-17上崩溃,如果它不在那里那么对于这个特定的设备,它正在崩溃我一直在环顾四周,它与设备的PixelFormat有关.

我想知道的是我怎么能使用一些代码所以这不会在三星galaxy II安卓版2.2.1上崩溃,我不能在模拟器中测试这个并且我没有设备来测试它,我只需要确保代码我不知道如何改变它?

tig*_*chi 9

更新:我找到了解决此问题的方法,实际上它非常简单.

首先:Android的默认EGLConfigChooser实现会在某些设备上做出错误的决定.特别是较旧的Android设备似乎遇到了这个EGL_BAD_MATCH问题.在我的调试会话期间,我还发现那些较旧的故障排除设备具有相当有限的可用OpenGL ES配置集.

这种"不匹配"问题的原因不仅仅是GLSurfaceView的像素格式与OpenGL ES的颜色位深度设置不匹配.总的来说,我们必须处理以下问题:

  • OpenGL ES API版本不匹配
  • 请求的目标表面类型不匹配
  • 请求的颜色位深度无法在曲面视图上呈现

在解释OpenGL ES API时,Android开发人员文档非常缺乏.因此,阅读Khronos.org上的原始文档非常重要.特别是关于eglChooseConfig的doc页面在这里很有帮助.

为了解决上面列出的问题,您必须确保指定以下最低配置:

  • EGL_RENDERABLE_TYPE必须与您正在使用的OpenGL ES API版本匹配.在OpenGL ES 2.x的可能情况下,您必须将该属性设置为4(请参阅egl.h)
  • EGL_SURFACE_TYPE应该有这个EGL_WINDOW_BIT集合

当然,您还需要设置一个OpenGL ES上下文,为您提供正确的颜色,深度和模板缓冲区设置.

不幸的是,不可能以直截了当的方式挑选这些配置选项.我们必须选择任何给定设备上的可用内容.这就是为什么有必要实现一个自定义EGLConfigChooser,它通过可用配置集列表并选择最符合给定条件的最合适的配置集.

无论如何,我为这样的配置选择器掀起了一个示例实现:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)