2012-09-01 28 views
8

Estoy tratando de perfilar mi procesador, y estoy viendo un comportamiento de perfil extraño que no puedo explicar.¿Por qué se bloquea glClear en OpenGLES?

Estoy usando un glSurfaceView, que he configurado para representar 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 con una carga ligera, así que creé una clase temporizador y comenzó a Profile alguna. Estaba bastante sorprendido por lo que vi.

os pongo unas 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 tarda en llamar glClear, drawTimer mide el tiempo que tarda en ejecutar todas mis llamadas dibujar, y swapTimer mide el tiempo desde cuando sale onDrawFrame y cuando vuelve (el tiempo necesario para llamar a eglSwapBuffers).

Cuando me encontré con una escena muy poca carga, que tiene unos números realmente extraño que no puedo explicar:

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

que esperaba el momento de intercambio a ser algo bastante grande, ya que creo que el dispositivo tiene VSYNC forzada habilitar a ~ 30fps, aunque no sé por qué la llamada real "clara" está bloqueando durante 11 milisegundos? Pensé que se suponía que debía emitir un comando asíncrono y regresar?

Cuando dibujo una escena mucho más ocupados, los números cambian un poco:

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

En esta escena mis llamadas de sorteo están tomando tanto tiempo que parece que está ocultando una gran parte del período de VSYNC , y el bloqueo en la llamada clara desaparece por completo.

¿Hay alguna explicación de por qué glClear está bloqueando en mi escena con poca carga?

enlace a mi 'Contador' código fuente de la clase en caso de que alguien es sospechoso de mi técnica de medición: http://pastebin.com/bhXt368W

+0

Podría intentar llamar a GLES20.glFinish() antes de clearTimer.start método() y ver cómo cambia el tiempo, entonces? –

+0

pongo un 'glFinish' (y finishTimer.start()/fin() alrededor de ella), y se lleva todo el tiempo fuera de glClear. En cambio, ahora glFinish tarda algunos milisegundos, y glClear se vuelve instantáneo. Parece que esto es todo lo relacionado con VSYNC, aunque me sorprendió ver el tiempo VSYNC aparecer dentro de glClear. – Tim

Respuesta

10

pongo un glfinish (y finishTimer.start()/fin() alrededor de ella), y toma todo el tiempo lejos de glClear. En cambio, ahora glFinish tarda algunos milisegundos, y glClear se vuelve instantáneo.

Eso lo explica.

Cuando la escena es muy ligera y los dibujos se renderizan muy rápido, el tiempo para limpiar y llenar los píxeles con el nuevo color tomará un tiempo (siempre llevará tiempo; de lo contrario, el procesador está detrás y está dibujando) cosas nuevas). Los dispositivos Android más nuevos tienen límites de fillrate. Por ejemplo, Nexus One tiene un bloqueo de llenado a 30 Hz: la pantalla se sincronizará a esa frecuencia sin importar qué tan rápido vayan tus dibujos reales. Si los dibujos finalizan por debajo de 30 Hz, el renderizador se sincronizará con la pantalla. Es por esto que nota este retraso, que debe notar incluso si elimina la llamada glClear(). El renderizador es anterior y más rápido que las actualizaciones de la pantalla.

Cuando el procesador tiene muchos objetos para dibujar, la sincronización se detenga (teniendo en cuenta los datos del perfil de su ocupada escena) debido a que el procesador es ahora después de las actualizaciones de la pantalla.

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

Cálculos:

F = 1/T

Fácil escena:

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

tiempo de retardo de la sincronización aparece en su perfilador. Renderer se sincroniza con la pantalla. Eso significa que si se quita la glClear() o la llamada glFinish(), el retraso aparecería en otro lugar.

escena pesada:

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

tiempo de retardo de la sincronización no hace aparecer en su generador de perfiles. Renderer busca la frecuencia de actualización de la pantalla.

Parece que esto es todo lo relacionado con vsync

Eso parece ser correcta.

Cuestiones relacionadas