diff mbox

[Branch,~glmark2-dev/glmark2/trunk] Rev 147: Android: Use a custom EGLConfigChooser that gracefully handles eglChooseConfig failures.

Message ID 20110929081315.7661.76023.launchpad@ackee.canonical.com
State Accepted
Headers show

Commit Message

alexandros.frantzis@linaro.org Sept. 29, 2011, 8:13 a.m. UTC
------------------------------------------------------------
revno: 147
fixes bug: https://launchpad.net/bugs/851334
committer: Alexandros Frantzis <alexandros.frantzis@linaro.org>
branch nick: lp-851334
timestamp: Wed 2011-09-28 18:48:47 +0300
message:
  Android: Use a custom EGLConfigChooser that gracefully handles eglChooseConfig failures.
  
  When proper GLES2.0 drivers are missing from an Android device,
  eglChooseConfig() will fail to find a GLES2.0 capable config, as expected.
  Unfortunately, the default EGLConfigChooser implementation doesn't give us a
  chance to handle this error; it throws an exception that we cannot catch
  (because it comes from an internal thread) and crashes the application.
  
  In order to handle the error gracefully, this commit introduces a custom
  EGLConfigChooser implementation that in case of error displays an informative
  alert and then quits the application.
modified:
  android/src/org/linaro/glmark2/Glmark2Activity.java
  android/src/org/linaro/glmark2/Glmark2SurfaceView.java


--
lp:glmark2
https://code.launchpad.net/~glmark2-dev/glmark2/trunk

You are subscribed to branch lp:glmark2.
To unsubscribe from this branch go to https://code.launchpad.net/~glmark2-dev/glmark2/trunk/+edit-subscription
diff mbox

Patch

=== modified file 'android/src/org/linaro/glmark2/Glmark2Activity.java'
--- android/src/org/linaro/glmark2/Glmark2Activity.java	2011-08-12 10:18:18 +0000
+++ android/src/org/linaro/glmark2/Glmark2Activity.java	2011-09-28 15:48:47 +0000
@@ -3,8 +3,13 @@ 
 import android.app.Activity;
 import android.os.Bundle;
 import android.opengl.GLSurfaceView;
+import android.app.Dialog;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
 
 public class Glmark2Activity extends Activity {
+    public static final int DIALOG_EGLCONFIG_FAIL_ID = 0;
+
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
@@ -24,6 +29,38 @@ 
         mGLView.onResume();
     }
 
+    @Override
+    protected Dialog onCreateDialog(int id) {
+        Dialog dialog;
+        switch (id) {
+            case DIALOG_EGLCONFIG_FAIL_ID:
+                AlertDialog.Builder builder = new AlertDialog.Builder(this);
+                builder.setMessage("Glmark2 cannot run because it couldn't find a suitable EGLConfig for GLES2.0. Please check that proper GLES2.0 drivers are installed.");
+                builder.setCancelable(false);
+                builder.setPositiveButton("Quit",
+                    new DialogInterface.OnClickListener() {
+                        public void onClick(DialogInterface dialog, int id) {
+                            Glmark2Activity.this.finish();
+                            /* 
+                             * Force process shutdown. There is no safer way to
+                             * do this, as we have open threads we can't close
+                             * when we fail to get an EGLConfig
+                             */
+                            android.os.Process.killProcess(android.os.Process.myPid());
+                        }
+                    });
+
+                dialog = builder.create();
+                break;
+            default:
+                dialog = null;
+                break;
+        }
+
+        return dialog;
+    }
+
+
     private GLSurfaceView mGLView;
 
     static {

=== modified file 'android/src/org/linaro/glmark2/Glmark2SurfaceView.java'
--- android/src/org/linaro/glmark2/Glmark2SurfaceView.java	2011-08-12 10:15:46 +0000
+++ android/src/org/linaro/glmark2/Glmark2SurfaceView.java	2011-09-28 15:48:47 +0000
@@ -6,6 +6,8 @@ 
 import android.content.res.AssetManager;
 import android.app.Activity;
 
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLDisplay;
 import javax.microedition.khronos.egl.EGLConfig;
 import javax.microedition.khronos.opengles.GL10;
 
@@ -19,11 +21,125 @@ 
         
         // Uncomment the commands below to get an RGBA8888 surface and config.
         //this.getHolder().setFormat(PixelFormat.TRANSLUCENT);
-        //setEGLConfigChooser(8, 8, 8, 8, 16, 0);
+        //setEGLConfigChooser(new Glmark2ConfigChooser(8, 8, 8, 8, 16, 0));
+        setEGLConfigChooser(new Glmark2ConfigChooser(5, 6, 5, 0, 16, 0));
 
         setRenderer(new Glmark2Renderer(this));
     }
 
+    /**
+     * EGLConfigChooser that quits with an error dialog when a suitable config
+     * cannot be found.
+     */
+    private class Glmark2ConfigChooser implements EGLConfigChooser {
+        private int[] mAttribList;
+
+        public Glmark2ConfigChooser(int redSize, int greenSize, int blueSize,
+                                    int alphaSize, int depthSize, int stencilSize)
+        {
+            mAttribList = new int[] {
+                    EGL10.EGL_RED_SIZE, redSize,
+                    EGL10.EGL_GREEN_SIZE, greenSize,
+                    EGL10.EGL_BLUE_SIZE, blueSize,
+                    EGL10.EGL_ALPHA_SIZE, alphaSize,
+                    EGL10.EGL_DEPTH_SIZE, depthSize,
+                    EGL10.EGL_STENCIL_SIZE, stencilSize,
+                    EGL10.EGL_RENDERABLE_TYPE, 4, /* 4 = EGL_OPENGL_ES2_BIT */
+                    EGL10.EGL_NONE };
+            mRedSize = redSize;
+            mGreenSize = greenSize;
+            mBlueSize = blueSize;
+            mAlphaSize = alphaSize;
+            mDepthSize = depthSize;
+            mStencilSize = stencilSize;
+       }
+
+        @Override
+        public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
+            try {
+                return chooseConfigInternal(egl, display);
+            }
+            catch (Exception e) {
+                /* Display an informative (and lethal for the app) dialog */
+                mActivity.runOnUiThread(new Runnable() {
+                    public void run() {
+                        mActivity.showDialog(Glmark2Activity.DIALOG_EGLCONFIG_FAIL_ID);
+                    }
+                });
+
+                /* Wait here until the app process gets killed... */
+                synchronized (this) {
+                    try { this.wait(); } catch (Exception ex) { }
+                }
+            }
+            return null;
+        }
+
+        private EGLConfig chooseConfigInternal(EGL10 egl, EGLDisplay display) {
+            /* Get the number of available configs matching the attributes */
+            int[] num_config = new int[1];
+            if (!egl.eglChooseConfig(display, mAttribList, null, 0, num_config)) {
+                throw new IllegalArgumentException("eglChooseConfig failed");
+            }
+
+            int numConfigs = num_config[0];
+
+            if (numConfigs <= 0) {
+                throw new IllegalArgumentException("No matching configs found");
+            }
+
+            /* Get the matching configs */
+            EGLConfig[] configs = new EGLConfig[numConfigs];
+            if (!egl.eglChooseConfig(display, mAttribList, configs, numConfigs,
+                                     num_config))
+            {
+                throw new IllegalArgumentException("eglChooseConfig#2 failed");
+            }
+
+            /* 
+             * Try to find a config that matches exactly the RGBA size
+             * specified by the user and is >= for depth and stencil.
+             */
+            for (EGLConfig config : configs) {
+                int d = findConfigAttrib(egl, display, config,
+                                         EGL10.EGL_DEPTH_SIZE, 0);
+                int s = findConfigAttrib(egl, display, config,
+                                         EGL10.EGL_STENCIL_SIZE, 0);
+                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);
+                if (r == mRedSize && g == mGreenSize &&
+                    b == mBlueSize && a == mAlphaSize &&
+                    d >= mDepthSize && s >= mStencilSize)
+                {
+                    return config;
+                }
+            }
+
+            throw new IllegalArgumentException("No configs match exactly");
+        }
+
+        private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config,
+                                     int attribute, int defaultValue)
+        {
+            int[] value = new int[] { defaultValue };
+            egl.eglGetConfigAttrib(display, config, attribute, value);
+            return value[0];
+        }
+
+        protected int mRedSize;
+        protected int mGreenSize;
+        protected int mBlueSize;
+        protected int mAlphaSize;
+        protected int mDepthSize;
+        protected int mStencilSize;
+    }
+
     public Activity getActivity() {
         return mActivity;
     }