Érase una vez, cuando> fue más rápido que <... Espera, ¿qué?

280

Estoy leyendo un increíble tutorial de OpenGL . Es realmente genial, confía en mí. El tema en el que estoy actualmente es Z-buffer. Además de explicar de qué se trata, el autor menciona que podemos realizar pruebas de profundidad personalizadas, como GL_LESS, GL_ALWAYS, etc. También explica que el significado real de los valores de profundidad (que es superior y que no lo es) también puede ser Personalizado. Lo entiendo hasta ahora. Y luego el autor dice algo increíble:

El rango zNear puede ser mayor que el rango zFar; si es así, entonces los valores del espacio de la ventana se invertirán, en términos de lo que constituye lo más cercano o lo más alejado del espectador.

Anteriormente, se decía que el valor Z del espacio de ventana de 0 es el más cercano y 1 es el más alejado. Sin embargo, si se negaran nuestros valores Z del espacio de clip, la profundidad de 1 sería la más cercana a la vista y la profundidad de 0 sería la más lejana. Sin embargo, si cambiamos la dirección de la prueba de profundidad (GL_LESS a GL_GREATER, etc.), obtenemos exactamente el mismo resultado. Entonces, en realidad es solo una convención. De hecho, voltear el signo de Z y la prueba de profundidad fue una optimización de rendimiento vital para muchos juegos.

Si entiendo correctamente, en cuanto al rendimiento, cambiar el signo de Z y la prueba de profundidad no es más que cambiar una <comparación por otra >. Entonces, si entiendo correctamente y el autor no está mintiendo o inventando cosas, cambiar <a >solía ser una optimización vital para muchos juegos.

¿El autor está inventando cosas, estoy malentendiendo algo o es el caso que alguna vez <fue más lento ( vitalmente , como dice el autor) que >?

¡Gracias por aclarar este asunto bastante curioso!

Descargo de responsabilidad: soy plenamente consciente de que la complejidad del algoritmo es la fuente principal para las optimizaciones. Además, sospecho que hoy en día definitivamente no haría ninguna diferencia y no estoy pidiendo que esto optimice nada. Soy extremadamente, dolorosamente, tal vez prohibitivamente curioso.

Armen Tsirunyan
fuente
66
El enlace a este tutorial parece haberse (recientemente) muerto. :(
TZHX
@TZHX: Dado que la respuesta aceptada la escribió el autor del tutorial, esperamos encontrarla nuevamente. Ver mi último comentario a su respuesta :)
Armen Tsirunyan
3
El tutorial de OpenGL al que se hace referencia está disponible aquí .
Fons
(a <b) es idéntico a (b> a), por lo que no es absolutamente necesario implementar ambas operaciones de comparación en hardware. La diferencia en el rendimiento es el resultado de lo que sucede como resultado de la operación de comparación. Este es un camino largo y sinuoso para explicar todos los efectos secundarios, pero aquí hay algunos consejos. Los juegos solían llenar el búfer de profundidad para evitar el procesamiento de fragmentos más costoso para los fragmentos que fallaron la prueba de profundidad. Quake solía dividir el rango de profundidad en dos mitades para evitar borrar el búfer de cuadros porque el juego siempre llenaba cada píxel en la pantalla, etc.
t0rakka
2
@Fons parece que el enlace está muerto, nuevamente :(
nalzok

Respuestas:

350

Si entiendo correctamente, en cuanto al rendimiento, cambiar el signo de Z y la prueba de profundidad no es más que cambiar una comparación <comparación a>. Entonces, si entiendo correctamente y el autor no está mintiendo o inventando cosas, entonces cambiar <a> solía ser una optimización vital para muchos juegos.

No expliqué eso particularmente bien, porque no era importante. Simplemente sentí que era un poco interesante de trivia agregar. No tenía la intención de revisar el algoritmo específicamente.

Sin embargo, el contexto es clave. Nunca dije que una comparación <fuera más rápida que una> comparación. Recuerde: estamos hablando de pruebas de profundidad de hardware de gráficos, no de su CPU. No operator<.

A lo que me refería era a una vieja optimización específica en la que usarías un marco GL_LESS con un rango de [0, 0.5]. En el siguiente cuadro, se renderiza con GL_GREATERun rango de [1.0, 0.5]. Usted va y viene, literalmente "volteando el signo de Z y la prueba de profundidad" en cada cuadro.

Esto pierde un poco de precisión de profundidad, pero no tuvo que borrar el búfer de profundidad, que alguna vez fue una operación bastante lenta. Dado que la limpieza en profundidad no solo es gratuita en estos días, sino que en realidad es más rápida que esta técnica, la gente ya no lo hace.

Nicol Bolas
fuente
1
La razón por la que la limpieza del búfer de profundidad es más rápida en estos días tiene dos razones, ambas basadas en el hecho de que la GPU usa un búfer de profundidad jerárquico. Por lo tanto, solo tiene que borrar los estados de mosaico para borrar (lo que es rápido), sin embargo, cambiar el signo de comparación de profundidad significa que todo el búfer HiZ necesita ser vaciado porque solo almacena un valor mínimo o máximo dependiendo del signo de comparación.
Jasper Bekkers
3
@NicolBolas: comentario de PerTZHX, el enlace a su tutorial en mi pregunta se ha apagado. ¿Podría decirnos dónde se mueven los tutoriales y, opcionalmente, editar la pregunta, por favor?
Armen Tsirunyan
2
Los tutoriales están disponibles en el archivo web. Si @NicolBolas lo permite, sería útil para la comunidad si pudiéramos trasladarlos a una ubicación más accesible. Tal vez GitHub o algo así. web.archive.org/web/20150215073105/http://arcsynthesis.org/…
ApoorvaJ
3

La respuesta es casi seguro que para cualquier encarnación de chip + driver utilizado, el Z jerárquico solo funcionaba en una dirección: este era un problema bastante común en el pasado. El ensamblaje / ramificación de bajo nivel no tiene nada que ver con esto: el almacenamiento en búfer Z se realiza en hardware de función fija y está canalizado, no hay especulación y, por lo tanto, no hay predicción de ramificación.

Crowley9
fuente
0

Una optimización como esta afectará el rendimiento en muchas soluciones gráficas integradas porque hará que la resolución de framebuffer sea menos eficiente. Borrar un búfer es una señal clara para el conductor de que no necesita almacenar y restaurar el búfer al binning.

Poca información de fondo: un rasterizador de mosaico / agrupación procesa la pantalla en una cantidad de mosaicos muy pequeños que caben en la memoria del chip. Esto reduce las escrituras y las lecturas en la memoria externa, lo que reduce el tráfico en el bus de memoria. Cuando se completa un marco (se llama a swap, o los FIFO se vacían porque están llenos, los enlaces de framebuffer cambian, etc.) se debe resolver el framebuffer; Esto significa que cada contenedor se procesa a su vez.

El controlador debe asumir que los contenidos anteriores deben conservarse. La preservación significa que el contenedor debe escribirse en la memoria externa y luego restaurarse desde la memoria externa cuando el contenedor se procesa nuevamente. La operación clear le dice al conductor que el contenido del bin está bien definido: el color clear. Esta es una situación que es trivial para optimizar. También hay extensiones para "descartar" el contenido del búfer.

t0rakka
fuente
-8

Tiene que ver con bits de bandera en un ensamblaje altamente sintonizado.

x86 tiene instrucciones jl y jg, pero la mayoría de los procesadores RISC solo tienen jl y jz (no jg).

Joshua
fuente
2
Si esa es la respuesta, plantea nuevas preguntas. ¿Se "tomó la rama" más lentamente que la "rama ignorada" en los primeros procesadores RISC? Ciertamente, no es así ahora de ninguna manera medible hasta donde yo sé. ¿Se suponía que escribir forbucles con una rama incondicional hacia atrás y una rama condicional, rara vez llevada hacia adelante para salir del bucle entonces? Suena raro
Pascal Cuoq
54
-1: Esta pregunta no tiene nada que ver con las CPU . GL_LESS y GL_GREATER son operaciones de comparación de profundidad, que se ejecutan en GPU.
Nicol Bolas
8
Es curioso cuánto representante puede obtener por una respuesta que sea correcta para el título pero que tenga muy poco que ver con la pregunta real.
Joshua
77
+1 No, esta respuesta es correcta al menos para parte de la pregunta. La pregunta es: "¿El autor está inventando cosas, estoy malinterpretando algo, o es el caso que alguna vez <fue más lento (vitalmente, como dice el autor) que>?". Hay tres opciones dadas. Esta respuesta responde a la posibilidad de la opción 3. En ninguna parte del artículo se proporciona la tecnología de la CPU / GPU, ni que debe ser una GPU (primeros juegos 3D en CPU). Ok ... No creo que haya muchos juegos en 3D en RISC :-)
xanatos
3
(y la etiqueta de la GPU se agregó a las 20:34. La primera revisión tenía solo la etiqueta de la CPU. Esta respuesta se escribió a las 18:44)
xanatos