Aggiornamento: Ho trovato un modo per ovviare a questo problema e in realtà è abbastanza semplice.
Prima di tutto: l'implementazione predefinita di Android EGLConfigChooser
prende decisioni sbagliate su alcuni dispositivi . Soprattutto i vecchi dispositivi Android sembrano soffrire questo problema EGL_BAD_MATCH
. Durante le mie sessioni di debug ho anche scoperto che quei vecchi dispositivi troublemaker disponevano di un insieme abbastanza limitato di configurazioni OpenGL ES disponibili.
La causa di questo problema di "corrispondenza errata" è molto più di una mancata corrispondenza tra il formato pixel di GLSurfaceView e le impostazioni di profondità bit di colore di OpenGL ES. Nel complesso abbiamo a che fare con i seguenti problemi:
- Una mancata corrispondenza della versione API OpenGL ES
- Una mancata corrispondenza del target richiesto tipo di superficie
- La profondità di bit colore richiesto non può essere reso sulla superficie vista
La documentazione per gli sviluppatori Android è gravemente carente quando si tratta di spiegare l'API OpenGL ES. È quindi importante leggere la documentazione originale su Khronos.org. Soprattutto la pagina di documentazione su eglChooseConfig è utile qui.
Al fine di porre rimedio ai problemi sopra elencati si deve fare in modo di specificare la seguente configurazione minima:
EGL_RENDERABLE_TYPE
deve corrispondere alla versione API OpenGL ES che si sta utilizzando. Nel caso probabile di OpenGL ES 2.x è necessario impostare l'attributo per 4
(vedi egl.h
)
EGL_SURFACE_TYPE
dovrebbe avere la EGL_WINDOW_BIT
set
E naturalmente anche voi volete impostare un contesto OpenGL ES che fornisce le impostazioni corrette per il colore, la profondità e il buffer dello stampino.
Sfortunatamente non è possibile selezionare queste opzioni di configurazione in modo semplice. Dobbiamo scegliere tra tutto ciò che è disponibile su un determinato dispositivo. Ecco perché è necessario implementare una custom EGLConfigChooser
, che passa attraverso l'elenco dei set di configurazione disponibili e sceglie quello più adatto che corrisponde al meglio ai criteri specificati.
Comunque, ho montata su un esempio di implementazione di un tale selettore di configurazione:
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;
}
}
Supponiamo che io desideri RGB_565. Sceglierà RGB_888 su RGB_965 (se esiste) Supponendo che RGB_888 arrivi prima nella lista 'configs'? – Kiran
@Kiran Questa è una buona domanda. Temo che ciò dipenda dall'ordine della lista dei set di configurazione di OpenGL ES (ovvero l'array 'EGLConfig [] config'), e credo che possa essere completamente specifico per il dispositivo. Se si vuole essere sicuri di poter modificare il selettore di configurazione per prendere in considerazione i limiti superiori per la configurazione del colore. Il mio chooser di esempio non è così restrittivo, considera solo le profondità di bit fornite dall'utente come requisiti minimi e sceglie felicemente tutto ciò che va oltre. – tiguchi
@Kiran BTW, credo che Android sia in grado di convertire automaticamente un contesto EGL 'RGB_888' in' RGB_565' della vista superficie di destinazione del rendering. Nelle mie sessioni di debug ho capito che il flag 'EGL_TRANSPARENT_TYPE' era in effetti il principale creatore di problemi (almeno per il mio caso). Se un selettore non limita il valore a 'EGL_NONE', è possibile che venga selezionata accidentalmente una configurazione che richiede che la vista di superficie stessa supporti i pixel traslucidi per consentire alle viste al di sotto di" risplendere ". Di solito non è l'impostazione predefinita e su alcuni dispositivi meno recenti non è supportata. – tiguchi