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)