¿Por qué está bloqueando glClear en OpenGLES?

Estoy tratando de perfil mi procesador, y estoy viendo un comportamiento de perfil extraño que no puedo explicar.

Estoy usando un glSurfaceView, que he fijado para hacer continuamente.

Así es como mi onDrawFrame() está estructurado

 public void onDrawFrame(GL10 unused) { GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); executeAllDrawCommands(); } 

Esto se comportaba lentamente bajo carga ligera, así que creé una clase de temporizador y comencé a perfilar esto. Me sorprendió mucho lo que vi.

Puse algunas sondas en mi método onDrawFrame así:

 public void onDrawFrame(GL10 unused) { swapTimer.end(); clearTimer.start(); GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT); clearTimer.end(); drawTimer.start(); executeAllDrawCommands(); drawTimer.end(); swapTimer.start(); } 

clearTimer mide el tiempo que se tarda en llamar a glClear, drawTimer mide el tiempo que tarda en ejecutar todas mis llamadas de draw y swapTimer mide el tiempo desde que onDrawFrame sale y cuando regresa (el tiempo que se tarda en llamar a eglSwapBuffers).

Cuando corrí una escena muy ligeramente cargada, conseguí algunos números realmente extraños que no puedo explicar:

 swapTimer : 20ms (average) clearTimer : 11ms (average) drawTimer : 2ms (average) 

Esperaba que el tiempo de intercambio para ser un poco largish, ya que creo que el dispositivo tiene forzada vsync habilitar a ~ 30fps, aunque no sé por qué la llamada "claro" actual es el bloqueo de 11 milisegundos? Pensé que se suponía que debía emitir un comando asíncrono y volver?

Cuando dibujo una escena mucho más ocupada, los números cambian bastante:

 swapTimer : 2ms (average) clearTimer : 0ms (average) drawTimer : 44ms (average) 

En esta escena mis llamadas de dibujo están tomando tanto tiempo que parece que esconden mucho del período vsync, y el bloque en la llamada clara desaparece totalmente.

¿Hay alguna explicación de por qué glClear está bloqueando mi escena ligeramente cargada?

Enlace a mi código fuente de la clase 'Timer' en caso de que alguien sospeche de mi técnica de medición: http://pastebin.com/bhXt368W

Pongo un glFinish (y finishTimer.start () / end () a su alrededor), y toma todo el tiempo lejos de glClear. Ahora glFinish toma un cierto número de milisegundos, y glClear se convierte en instantáneo.

Eso lo explica.

Cuando su escena es muy ligera y los dibujos son renderizados muy rápido, el tiempo para borrar y rellenar los píxeles con el nuevo color tomará algún tiempo (siempre tomará tiempo, de lo contrario el renderizador está detrás y es currenty dibujo nuevo material). Los dispositivos Android más nuevos tienen límites de llenado. Por ejemplo, Nexus One tiene un bloqueo de llenado a 30 Hz – la pantalla se sincronizará a esa frecuencia sin importar lo rápido que vayan los dibujos. Si los dibujos terminan por debajo de 30 Hz, el procesador se sincronizará con la pantalla. Esta es la razón por la que se nota este retraso, que debe observar incluso si quita la llamada glClear() . El procesador es anterior y más rápido que las actualizaciones de la pantalla.

Cuando el renderizador tiene muchos objetos que dibujar, la sincronización se detendrá (dados los datos del perfil de la escena ocupada) porque el procesador está ahora después de las actualizaciones de la pantalla.

Cuando utiliza glFinish() , elimina el tiempo que la función glClear() podría causar, lo cual, siguiendo la lógica de fillrate, significa que glFinish() es ahora la función que garantiza la sincronización con la pantalla.

Cálculos :

F = 1 / T

Escena fácil :

F = 1 / T = 1 / ((20 + 11 + 2) * 10 ^ -3) = ~ 30 Hz

El tiempo de retardo de sincronización aparece en su generador de perfiles. Renderer se está sincronizando con la pantalla. Esto significa que si quita la glClear() o glFinish() , la demora aparecería en otro lugar.

Escena pesada :

F = 1 / T = 1 / ((2 + 0 + 44) * 10 ^ -3)) = ~ 22 Hz

El tiempo de retardo de sincronización no aparece en su profiler. Renderer es después de la frecuencia de actualización de la pantalla.

Parece que esto está relacionado con vsync

Eso parece correcto.

  • Android: los hilos no se ejecutan en paralelo
  • ¿Por qué glReadPixels da resultados faltados en algunos dispositivos Android más antiguos?
  • ¿Cuál es el significado de la clase EGL14
  • La mejor práctica para usar Sprites en un juego usando AndEngine GLES2
  • Uso del flujo de vídeo como textura abierta de GL ES 2.0
  • Cómo forzar el modo de paisaje con NDK utilizando códigos C ++ puros
  • Problema de detección de colisiones basado en píxeles con OpenGLES 2.0 bajo Android
  • Cómo implementar gesto multitouch en android
  • Aprenda OpenGL: ¿por dónde empezar o cómo ha aprendido OpenGL?
  • Cómo obtener una pantalla EGL / contexto a un GLSurfaceView específico
  • OpenGL ES 2.0 vs OpenGL 3 - Similitudes y diferencias
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.