On devices using the PowerVR G6200 GPU such as the Sony Xperia M5 (E5603) and Xiaomi Redmi Note 3 (hennessy), creating an EGL context for rendering with OpenGL ES 2 fails, while it works on all other devices I have tested:
java.lang.RuntimeException:
at android.opengl.GLSurfaceView$EglHelper.throwEglException (GLSurfaceView.java:1233)
at android.opengl.GLSurfaceView$EglHelper.throwEglException (GLSurfaceView.java:1224)
at android.opengl.GLSurfaceView$EglHelper.start (GLSurfaceView.java:1074)
at android.opengl.GLSurfaceView$GLThread.guardedRun (GLSurfaceView.java:1447)
at android.opengl.GLSurfaceView$GLThread.run (GLSurfaceView.java:1286)
The config chooser is implemented like this:
class CustomEGLConfigChooser implements GLSurfaceView.EGLConfigChooser {
public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display) {
EGLConfig [] configs = new EGLConfig[1];
int [] num_config = new int[1];
int [] attrib_list = new int[] {
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_DEPTH_SIZE, 24,
EGL10.EGL_STENCIL_SIZE, 8,
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
EGL10.EGL_NONE,
};
boolean res = egl.eglChooseConfig(display, attrib_list, configs, configs.length, num_config);
if (res && num_config[0] > 0) {
return configs[0];
}
return null;
}
}
The config chooser is used from a GLSurfaceView
subclass like this:
public class GameView extends GLSurfaceView {
public GameView (Context context, ClientConfig clientConfig) {
super(context);
setEGLContextClientVersion(2);
setEGLConfigChooser(new CustomEGLConfigChooser());
}
}
By comparing the list of EGL configurations on a device where this code works (Nexus 5x EGL configs) with a non-working device (Xiaomi Redmi Note 3 EGL configs), I found that while there are matching configs, they differ in one property, namely EGL_RENDERABLE_TYPE
.
First Nexus 5x EGL config that matches:
EGL_CONFIG_ID: 11
[...]
EGL_ALPHA_SIZE: 8
EGL_BLUE_SIZE: 8
EGL_GREEN_SIZE: 8
EGL_RED_SIZE: 8
EGL_DEPTH_SIZE: 24
EGL_STENCIL_SIZE: 8
[...]
EGL_RENDERABLE_TYPE: OpenGL_ES OpenGL_ES_2 (5)
First Xiaomi Redmi Note 3 EGL config that matches:
EGL_CONFIG_ID: 1
[...]
EGL_ALPHA_SIZE: 8
EGL_BLUE_SIZE: 8
EGL_GREEN_SIZE: 8
EGL_RED_SIZE: 8
EGL_DEPTH_SIZE: 24
EGL_STENCIL_SIZE: 8
[...]
EGL_RENDERABLE_TYPE: OpenGL_ES (1)
Note that the Nexus 5x supports EGL_RENDERABLE_TYPE
with EGL_OPENGL_ES2_BIT
(in addition to also supporting EGL_OPENGL_ES_BIT
with the same configuration), so we were just lucky that all the configs on the existing devices happened to support both renderable types.
There is another config for the Xiaomi Redmi Note 3 that supports the ES2 renderable type, but this didn't happen to be the first config that matched:
EGL_CONFIG_ID: 23
[...]
EGL_ALPHA_SIZE: 8
EGL_BLUE_SIZE: 8
EGL_GREEN_SIZE: 8
EGL_RED_SIZE: 8
EGL_DEPTH_SIZE: 24
EGL_STENCIL_SIZE: 8
[...]
EGL_RENDERABLE_TYPE: OpenGL_ES_2 (4)
Trying to use the first (config ID 1) with an ES2 rendering context obviously doesn't work, because the config doesn't support ES2 renderables. The fix is to explicitly request the renderable type as part of the EGL config chooser like this, modifying the example in the question like this:
int [] attrib_list = new int[] {
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_DEPTH_SIZE, 24,
EGL10.EGL_STENCIL_SIZE, 8,
EGL10.EGL_SURFACE_TYPE, EGL10.EGL_WINDOW_BIT,
EGL10.EGL_RENDERABLE_TYPE, EGL10. EGL_OPENGL_ES2_BIT,
EGL10.EGL_NONE,
};
Note that in the case where only the RGBA + depth/stencil values need to be requested, another option is to use setEGLConfigChooser(int, int, int, int, int, int) instead of a custom implementation, and this will take care of requesting a EGL_RENDERABLE_TYPE
based on the value set in setEGLContextClientVersion()
.