Obtener el número de fragmentos que pasaron la prueba de profundidad

8

En entornos "modernos", la extensión "NV Occlusion Query" proporciona un método para obtener el número de fragmentos que pasaron la prueba de profundidad. Sin embargo, en el iPad / iPhone que usa OpenGL ES, la extensión no está disponible.

¿Cuál es el enfoque más eficaz para implementar un comportamiento similar en el sombreador de fragmentos?

Algunas de mis ideas

  • Renderice el objeto completamente en blanco, luego cuente todos los colores juntos usando un sombreador de dos pasadas donde primero se representa una línea vertical y para cada fragmento el sombreador calcula la suma en toda la fila. Luego, se representa un único vértice cuyo fragmento suma todas las sumas parciales de la primera pasada. No parece ser muy eficiente.

  • Renderice el objeto completamente en blanco sobre un fondo negro. Reduzca la muestra de forma recursiva, abusando de la interpolación lineal de hardware entre texturas hasta obtener una resolución razonablemente pequeña. Esto conduce a fragmentos que tienen un nivel de escala de grises dependiendo del número de píxeles blancos en su región correspondiente. ¿Es esto lo suficientemente preciso?

  • Use mipmaps y simplemente lea el píxel en el nivel 1x1. Nuevamente, la cuestión de la precisión y si es posible usar texturas que no sean potencia de dos.

El problema con estos enfoques es que la tubería se estanca, lo que resulta en importantes problemas de rendimiento. Por lo tanto, estoy buscando una forma más eficaz de lograr mi objetivo.

Usando la extensión EXT_OCCLUSION_QUERY_BOOLEAN

Apple presentó EXT_OCCLUSION_QUERY_BOOLEAN en iOS 5.0 para iPad 2.

"4.1.6  Occlusion Queries

Occlusion queries use query objects to track the number of fragments or 
samples that pass the depth test. An occlusion query can be started and 
finished by calling BeginQueryEXT and EndQueryEXT, respectively, with a 
target of ANY_SAMPLES_PASSED_EXT or ANY_SAMPLES_PASSED_CONSERVATIVE_EXT.

When an occlusion query is started with the target 
ANY_SAMPLES_PASSED_EXT, the samples-boolean state maintained by the GL is
set to FALSE. While that occlusion query is active, the samples-boolean 
state is set to TRUE if any fragment or sample passes the depth test. When 
the occlusion query finishes, the samples-boolean state of FALSE or TRUE is
written to the corresponding query object as the query result value, and 
the query result for that object is marked as available. If the target of 
the query is ANY_SAMPLES_PASSED_CONSERVATIVE_EXT, an implementation may 
choose to use a less precise version of the test which can additionally set
the samples-boolean state to TRUE in some other implementation dependent 
cases."

La primera oración insinúa un comportamiento que es exactamente lo que estoy buscando: obtener el número de píxeles que pasaron la prueba de profundidad de manera asincrónica sin mucha pérdida de rendimiento. Sin embargo, el resto del documento describe solo cómo obtener resultados booleanos.

¿Es posible explotar esta extensión para obtener el recuento de píxeles? ¿El hardware lo admite para que pueda haber una API oculta para obtener acceso al recuento de píxeles?

Otras extensiones que podrían ser explotables serían las funciones de depuración, como la cantidad de veces que se invocó el sombreador de fragmentos (PSInvocations en DirectX, no estoy seguro de si hay algo similar disponible en OpenGL ES). Sin embargo, esto también daría como resultado un bloqueo de la tubería.

Etan
fuente
¿Cuál es el efecto final que estás tratando de lograr?
Tetrad
Necesito el recuento de píxeles no para un efecto de representación, sino para el cálculo. Quiero usarlo para calcular pesos de partículas en un filtro de partículas.
Etan
¿Apple admite AMD_performance_monitor? En caso afirmativo, puede encontrar el contador que muestra los píxeles pasados. Tenga en cuenta que esto es muy, muy específico del dispositivo, incluso si lo hace funcionar.
Jari Komppa
El problema con AMD_performance_monitor sería que no es asíncrono, por lo que la pérdida de rendimiento también estaría allí, ya que tengo que esperar entre cuadros para saber que las invocaciones del siguiente cuadro ya no tendrán efecto en los contadores de rendimiento.
Etan
Además, AMD_performance_monitor no está disponible.
Etan

Respuestas:

1

¿Es posible explotar esta extensión para obtener el recuento de píxeles? ¿El hardware lo admite para que pueda haber API oculta para obtener acceso al recuento de píxeles?

No y no. Bueno, supongo que si dibujas una serie de triángulos de un píxel en el espacio de la ventana, podrías contar cuántos valores booleanos obtienes. Pero eso requeriría una consulta por separado para cada píxel. Probablemente no sea la cosa más rápida del mundo.

Si hay una "API oculta", no tendrá acceso a ella (ya que está oculta), por lo que no importa. Además, la naturaleza de la extensión ya sugiere que no existe. Después de todo, si el hardware tenía el conteo de fragmentos real, ¿por qué no simplemente exponerlo directamente, como lo hace OpenGL de escritorio? Si el hardware lo admitiera , podrían haber tomado ARB_occlusion_query y usarlo.

Pero no lo hicieron. Lo que sugiere fuertemente que no pudieron.

Nicol Bolas
fuente
¡Gracias por la respuesta! El enfoque con triángulos de un píxel puede mejorarse simplemente representando puntos o líneas pequeñas, e incluso podría mejorarse mediante una escala logarítmica donde una línea que devuelve "verdadero" simplemente se divide en el medio y luego se vuelven a verificar ambas partes. Todavía no estoy seguro del rendimiento, ya que los modelos no tendrán más de 100-200 vértices. El razonamiento de la inexistencia de la "API oculta" también es válido. ¿Hay algún otro medio para que los datos de la GPU vuelvan a la CPU de forma asíncrona sin un bloqueo de canalización (también formas extrañas, por favor)?
Etan
0

Lamentablemente, los resultados se devuelven en un GLuint (también puede ser GLint para una llamada diferente), el resultado siempre es un 0 o un 1, tal vez lo cambiarán para registrar frags en el futuro.

También parece que ni una sola persona en Internet ha publicado sobre estas nuevas extensiones ... así que aquí están configuradas correctamente ... lo que no está documentado en ninguna parte, por lo que puedo decir ... puedes imaginar cómo iría en su código de este pequeño código de sudo aquí:

import UIKit/UIKit.h

import GLKit/GLKit.h

import "GLProgram.h"

GLuint testBox,hasBeenTested,theParams;

//...

glGenQueriesEXT(1, &testBox);

glBeginQueryEXT(GL_ANY_SAMPLES_PASSED_EXT, testBox);


//... draw an object .......

glEndQueryEXT(GL_ANY_SAMPLES_PASSED_EXT);

glGetQueryObjectuivEXT(testBox, GL_QUERY_RESULT_AVAILABLE_EXT, &hasBeenTested);

if (hasBeenTested) glGetQueryObjectuivEXT(testBox, GL_QUERY_RESULT_EXT, &theParams);

glDeleteQueriesEXT(1, &testBox);

if (!theParams)  object is hidden;  don't draw next time;
honjj
fuente
El hecho de que el tipo dice GLintno significa que sea un recuento entero del número de fragmentos que pasan. La especificación es bastante clara de que el QUERY_RESULT_EXTestado es un valor booleano; solo debes consultarlo como un número entero. Es GL_FALSEsi falló y no GL_FALSEsi pasó.
Nicol Bolas
Acababa de implementar el código y descubrí que era solo verdadero o falso y cambié mi respuesta antes de ver su comentario ... dado que es un gluint, tal vez agregarán estados en el futuro con suerte.
honjj
por cierto, parece haber un error en GKKit, donde si usa self.effect2 = [[GLKBaseEffect alloc] init]; tipo de código GLKit para representar un objeto, en lugar de una tubería GLES2.0 normal, las consultas no le darán la respuesta correcta ... (nunca oculto) aunque probé un objeto de tubería que oculta un objeto GLKBaseEffect, por lo que podría haber un error simplemente mezclando los dos, aún no he probado más ...
honjj
Las extensiones se explican con ejemplos en los videos de WWDC que se pueden encontrar en el sitio de Apple con una cuenta de desarrollador activa.
Etan