GLES10.glGetIntegerv devuelve 0 sólo en Lollipop
Este pedazo de código solía trabajar en mi Nexus 7 2012 KitKat:
int[] maxSize = new int[1]; GLES10.glGetIntegerv(GL10.GL_MAX_TEXTURE_SIZE, maxSize, 0);
En KitKat puedo obtener el valor máximo de píxeles correctamente, pero después de la actualización a la imagen de fábrica Lollipop este fragmento de código causa problema, ya que sólo devuelve 0. El logcat mostró esta salida cuando llegó a este método:
- LibGDX FreeType fuente borrosa
- Android OpenGL ES 2.0: El modelo de cubo no sólo está distorsionado (la perspectiva es incorrecta?), Sino también las caras se cargan incorrectamente (los vértices no son correctos?)
- ¿Cuál es el significado de la clase EGL14
- Renderizar la representación de script es mucho más lento que el renderizado de OpenGL en Android
- Recursos para aprender desarrollando juegos con ndk + opengl en C ++?
E/libEGL﹕ call to OpenGL ES API with no current context (logged once per thread)
Ya tengo android:hardwareAccelerated="true"
en mi Manifest.xml. ¿Hay cambios de API que no conozco, que hacen que el código anterior no sea posible? Por favor avise.
- Haskell Android OpenGL
- Esfera 3D OpenGL
- Combinación Android de OpenGL de SurfaceTexture (imagen externa) y textura ordinaria
- IOS OpenGL ES compatible con Android OpenGL ES?
- Determinación del límite de tamaño de textura máximo / mínimo en Android OpenGLES
- Android Vista vs SurfaceView vs GLSurfaceView para la aplicación de dibujo 2D con Zoomable interfaz de usuario
- Uso de OpenGL para reemplazar Canvas - Android
- OpenGL (ES) - ¿Cuál es la diferencia entre frustum y ortho?
El registro de errores señala el problema básico muy claramente:
Llamada a OpenGL ES API sin contexto actual (registrada una vez por hilo)
Necesitas un contexto OpenGL actual en tu subproceso antes de poder realizar llamadas OpenGL, que incluye tu llamada glGetIntegerv()
. Esto siempre fue cierto. Pero parece que en pre-Lollipop, había un contexto OpenGL que se creó en los marcos, y que a veces (siempre?) Actual cuando se llamó el código de la aplicación.
No creo que esto haya sido nunca documentado o comportamiento previsto. Siempre se supone que las aplicaciones creaban explícitamente un contexto y lo hacían actual, si querían hacer llamadas OpenGL. Y parece que esto se aplica más estrictamente en Lollipop.
Existen dos enfoques principales para crear un contexto de OpenGL:
- Cree un
GLSurfaceView
( documentación ). Este es el enfoque más fácil y conveniente, pero sólo tiene sentido si planea realizar el renderizado de OpenGL en la pantalla. - Utilice
EGL14
( documentación ). Esto proporciona una interfaz de nivel inferior que le permite completar la configuración necesaria para llamadas OpenGL sin crear una vista o representación en la pantalla.
El enfoque GLSurfaceView
está ampliamente documentado con ejemplos y tutoriales en todo el lugar. Así que me centraré en el enfoque EGL.
Uso de EGL14 (API nivel 17)
El siguiente código asume que le interesa ES 2.0, algunos valores de atributo tendrían que ser ajustados para otras versiones de ES.
Al inicio del archivo, importe la clase EGL14
y algunas clases relacionadas:
import android.opengl.EGL14; import android.opengl.EGLConfig; import android.opengl.EGLContext; import android.opengl.EGLDisplay; import android.opengl.EGLSurface; import android.opengl.GLES20;
A continuación, obtener una retención de la pantalla predeterminada, e inicializar. Esto podría ser más complejo si tienes que tratar con dispositivos que podrían tener múltiples pantallas, pero será suficiente para un típico teléfono / tablet:
EGLDisplay dpy = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); int[] vers = new int[2]; EGL14.eglInitialize(dpy, vers, 0, vers, 1);
A continuación, tenemos que encontrar una configuración. Dado que no vamos a utilizar este contexto para la prestación, los atributos exactos no son muy críticos:
int[] configAttr = { EGL14.EGL_COLOR_BUFFER_TYPE, EGL14.EGL_RGB_BUFFER, EGL14.EGL_LEVEL, 0, EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT, EGL14.EGL_SURFACE_TYPE, EGL14.EGL_PBUFFER_BIT, EGL14.EGL_NONE }; EGLConfig[] configs = new EGLConfig[1]; int[] numConfig = new int[1]; EGL14.eglChooseConfig(dpy, configAttr, 0, configs, 0, 1, numConfig, 0); if (numConfig[0] == 0) { // TROUBLE! No config found. } EGLConfig config = configs[0];
Para hacer un contexto actual, que necesitaremos más tarde, necesitará una superficie de renderizado, incluso si realmente no planea procesar. Para satisfacer este requisito, cree una pequeña superficie fuera de pantalla (Pbuffer):
int[] surfAttr = { EGL14.EGL_WIDTH, 64, EGL14.EGL_HEIGHT, 64, EGL14.EGL_NONE }; EGLSurface surf = EGL14.eglCreatePbufferSurface(dpy, config, surfAttr, 0);
A continuación, cree el contexto:
int[] ctxAttrib = { EGL14.EGL_CONTEXT_CLIENT_VERSION, 2, EGL14.EGL_NONE }; EGLContext ctx = EGL14.eglCreateContext(dpy, config, EGL14.EGL_NO_CONTEXT, ctxAttrib, 0);
Listo para hacer el contexto actual:
EGL14.eglMakeCurrent(dpy, surf, surf, ctx);
Si todo lo anterior tuvo éxito (se omitió la comprobación de errores), puede realizar ahora sus llamadas OpenGL:
int[] maxSize = new int[1]; GLES20.glGetIntegerv(GLES20.GL_MAX_TEXTURE_SIZE, maxSize, 0);
Una vez que haya terminado, puede derribar todo:
EGL14.eglMakeCurrent(dpy, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_CONTEXT); EGL14.eglDestroySurface(dpy, surf); EGL14.eglDestroyContext(dpy, ctx); EGL14.eglTerminate(dpy);
Uso de EGL10 (API nivel 1)
Si necesita algo que funcione para los niveles anteriores, puede utilizar EGL10
( documentación ) en lugar de EGL14, que está disponible desde el nivel 1 de la API. El código anterior adoptado para 1.0 se parece a esto:
import android.opengl.GLES10; 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; EGL10 egl = (EGL10)EGLContext.getEGL(); EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY); int[] vers = new int[2]; egl.eglInitialize(dpy, vers); int[] configAttr = { EGL10.EGL_COLOR_BUFFER_TYPE, EGL10.EGL_RGB_BUFFER, EGL10.EGL_LEVEL, 0, EGL10.EGL_SURFACE_TYPE, EGL10.EGL_PBUFFER_BIT, EGL10.EGL_NONE }; EGLConfig[] configs = new EGLConfig[1]; int[] numConfig = new int[1]; egl.eglChooseConfig(dpy, configAttr, configs, 1, numConfig); if (numConfig[0] == 0) { // TROUBLE! No config found. } EGLConfig config = configs[0]; int[] surfAttr = { EGL10.EGL_WIDTH, 64, EGL10.EGL_HEIGHT, 64, EGL10.EGL_NONE }; EGLSurface surf = egl.eglCreatePbufferSurface(dpy, config, surfAttr); final int EGL_CONTEXT_CLIENT_VERSION = 0x3098; // missing in EGL10 int[] ctxAttrib = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL10.EGL_NONE }; EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, ctxAttrib); egl.eglMakeCurrent(dpy, surf, surf, ctx); int[] maxSize = new int[1]; GLES10.glGetIntegerv(GLES10.GL_MAX_TEXTURE_SIZE, maxSize, 0); egl.eglMakeCurrent(dpy, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT); egl.eglDestroySurface(dpy, surf); egl.eglDestroyContext(dpy, ctx); egl.eglTerminate(dpy);
Tenga en cuenta que esta versión del código utiliza un contexto ES 1.x. El tamaño de textura máximo reportado puede ser diferente para ES 1.x y ES 2.0.
El mensaje de error indica que está llamando a la función GLES antes de que exista el contexto de OpenGL ES. He encontrado que KitKat es más estricto acerca de la corrección en varias áreas por lo que puede ser la razón del problema que aparece ahora, o puede haber alguna diferencia en el orden en que está iniciando la aplicación que está causando. Si publicó más de su código de inicialización, la razón puede ser más clara.
Normalmente tiene una clase que implementa GLSurfaceView.Renderer
que tiene una función:
public void onSurfaceCreated(GL10 gl, EGLConfig config)
En esta función, deberías poder llamar a gl.glGetIntegerv
forma segura ya que en este momento sabes que se ha creado el contexto de OpenGL ES. Si lo está llamando antes que esto, entonces eso explicaría el error que está viendo.