Android 4.3 から OpenGL ES 3.0 が使えるようになりました。
対応 GPU も順調に増えていますが、Android 4.3/4.4 が動く端末自体が
まだあまり多くありません。
GPU によっては OpenGL ES 3.0 の動作で問題が生じるものもあり、
互換性の意味でも OpenGL ES 2.0/3.0 両対応が望ましいでしょう。
iOS の方は比較的簡単で、今のところ 64bit 対応 (ARMv8 arm64) なら
OpenGL ES 3.0 にも対応しています。
Android 端末が OpenGL ES 3.0 に対応してるかどうか調べる方法は
ドキュメントに記載されています。
・OpenGL ES : Checking OpenGL ES Version
ただしこの方法は以前も書いたように必ずしもうまく行きません。
1. 及びサンプルコードは OpenGL ES 3.0 の Context を作成し、
エラーかどうかで判断しています。
実際にいくつかの端末を調べてみると、GPU ドライバは未対応でも
エラーを返さない場合がほとんどです。
version != 2.0 で判定している GPU は OpenGL ES 1.1 の context を返しますし、
version < 2.0 で判定している GPU は OpenGL ES 2.0 の context になります。
2. の方法はうまく行きますが、一旦ダミーの Context を作成するため複雑です。
またこの判定方法は Android 限定です。
以下その具体的な方法
package jp.flatlib.gw; import android.opengl.GLES20; import android.os.Build; import android.graphics.SurfaceTexture; import javax.microedition.khronos.egl.EGL10; import javax.microedition.khronos.egl.EGLConfig; import javax.microedition.khronos.egl.EGLContext; import javax.microedition.khronos.egl.EGLDisplay; import javax.microedition.khronos.egl.EGLSurface; import android.util.Log; public class GPUType { public static int VersionCode= 0; // 200 or 300 public static String VersionString; public static String RendererString; private static int AdrenoID= 0; public static boolean isGLES3() { return VersionCode == 300; } public static boolean isAdreno300s() { return AdrenoID >= 300 && AdrenoID < 400; } private static int decodeAdrenoID( String gpu_name ) { if( gpu_name.equals( "Adreno" ) || gpu_name.indexOf( "AMD Z430" ) >= 0 ){ return 200; }else if( gpu_name.indexOf( "Adreno" ) >= 0 ){ return getAdrenoNumber( gpu_name ); } return 0; } public static void update() { EGL10 egl= (EGL10)EGLContext.getEGL(); int[] iparam= new int[8]; if( Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB ){ VersionCode= 200; return; } // Initialize EGLDisplay display= egl.eglGetDisplay( EGL10.EGL_DEFAULT_DISPLAY ); egl.eglInitialize( display, iparam ); // Config int[] config_attr= { EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE }; final int CONFIG_SIZE= 1; EGLConfig[] config_array= new EGLConfig[CONFIG_SIZE]; egl.eglChooseConfig( display, config_attr, config_array, CONFIG_SIZE, iparam ); EGLConfig config= config_array[0]; // Surface SurfaceTexture surfaceTexture= new SurfaceTexture( 0 ); // API Level 11 EGLSurface surface= egl.eglCreateWindowSurface( display, config, surfaceTexture, null ); // Context int[] context_attr= { EGL_CONTEXT_CLIENT_VERSION, 2, EGL10.EGL_NONE }; EGLContext context= egl.eglCreateContext( display, config, EGL10.EGL_NO_CONTEXT, context_attr ); // Make Current egl.eglMakeCurrent( display, surface, surface, context ); // Query VersionString= GLES20.glGetString( GLES20.GL_VERSION ); RendererString= GLES20.glGetString( GLES20.GL_RENDERER ); VersionCode= getGLVersionString( VersionString ); AdrenoID= decodeAdrenoID( RendererString ); // Special if( isAdreno300s() ){ if( Build.VERSION.SDK_INT <= Build.VERSION_CODES.JELLY_BEAN_MR2 ){ // .. Android 4.3 VersionCode= 200; // GLES 2.0 } } // Release egl.eglMakeCurrent( display, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT ); egl.eglDestroyContext( display, context ); egl.eglDestroySurface( display, surface ); } private static int getGLVersionString( String version_string ) { int length= version_string.length(); int ci= 0; for(; ci < length ; ci++ ){ char ch= version_string.charAt( ci ); if( ch >= '0' && ch <= '9' ){ break; } } int version= 0; int num_shift= 100; for(; num_shift > 0 && ci < length ;){ char ch= version_string.charAt( ci++ ); if( ch >= '0' && ch <= '9' ){ if( num_shift == 100 ){ if( version_string.charAt( ci ) == '.' ){ ci++; } } version+= (ch - '0') * num_shift; num_shift/= 10; }else{ break; } } return version; } private static int getAdrenoNumber( String text ) { int length= text.length(); int num= 0; boolean is_num= false; for( int i= 0 ; i< length ; i++ ){ char ch= text.charAt( i ); if( is_num ){ if( ch >= '0' && ch <= '9' ){ num*= 10; num+= ch - '0'; }else{ break; } }else{ if( ch >= '0' && ch <= '9' ){ is_num= true; num= ch - '0'; } } } return num; } }
GPUType.update() でデータを集めて isGLES3() で結果がわかります。
Android 3.0 API Level 11 以降でないと動きませんが、
Android 4.2 (API Level 17) 以前は OpenGL ES 2.0 と決め打ちできるため
特に問題ないはずです。
同じ理由で、EGL10 の代わりに EGL14 を使うこともできます。
EGL14 は API Level 17 以降の API です。
Android 4.3 + Adreno 320 の OpenGL ES 3.0 には問題があるので、
この組み合わせでは OpenGL ES 2.0 を返すようにしています。
関連エントリ
・Android 4.4 Adreno 320 の OpenGL ES 3.0 と Version 判定
・iPhone 5s の Apple A7 GPU
・Adreno 320 の OpenGL ES 3.0 と Uniform Block
・Nexus 7 (2013) の Adreno 320 と OpenGL ES 3.0 (Android 4.3)