更新:この問題を回避する方法を見つけましたが、実際にはかなり簡単です。
まず第一に、Android のデフォルトのEGLConfigChooser
実装は、一部のデバイスで不適切な決定を下します。特に古い Android デバイスでは、このEGL_BAD_MATCH
問題が発生しているようです。デバッグ セッション中に、これらの古いトラブルメーカー デバイスで使用できる OpenGL ES 構成のセットが非常に限られていることも発見しました。
この「不適切な一致」の問題の原因は、GLSurfaceView のピクセル形式と OpenGL ES の色ビット深度設定との間の不一致だけではありません。全体として、次の問題に対処する必要があります。
- OpenGL ES API バージョンの不一致
- 要求されたターゲット サーフェス タイプの不一致
- 要求された色のビット深度をサーフェス ビューでレンダリングできません
OpenGL ES API の説明に関しては、Android 開発者向けドキュメントが大幅に不足しています。したがって、Khronos.org で元のドキュメントを読むことが重要です。特に、ここではeglChooseConfigに関するドキュメント ページが役に立ちます。
上記の問題を解決するには、次の最小構成を指定する必要があります。
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;
}
}