Mesh Shaders, el secreto de DX12 para conseguir gráficos Next-Gen en juegos como Alan Wake 2

La salida de Alan Wake 2 y sus requisitos técnicos han traído a la actualidad un término que hace tiempo teníamos aparentemente ignorado. El de los Mesh Shaders. ¿Qué son, que ventajas aportan a los juegos y por qué son una tecnología poco usada? Estas son las preguntas que vamos a responder en este artículo.

El mayor problema del mercado de los videojuegos en PC es su estancamiento tecnológico, lo cual ha provocado que tarjetas gráficas que ya deberían estar jubiladas sigan siendo utilizadas por sus usuarios. Esto ha provocado que tecnologías como la que es protagonista de este artículo no se hayan visto aplicadas en los videojuegos pese a los beneficios que reporta.

Origen y definición de los Mesh Shaders

Pipeline mesh shaders

La primera arquitectura de GPU en implementar los Mesh Shaders fue Turing, empleada en las tarjetas gráficas RTX 20 de NVIDIA, lo cual es paradójico por el hecho que fue planteada y puesta por primera vez encima de la mesa por parte de AMD, justo para hablar de una de las características de las futuras AMD Vega, en concreto el llamado NGG o Next Generation Geometry o Primitive Shaders, pero el Radeon Technology Group tuvo que esperar a RDNA para tener una implementación similar. Es más, la ventaja de tiempo de NVIDIA hizo que su propuesta terminara definiendo el estándar usado en DirectX 12 Ultimate y Vulkan.

El planteamiento detrás de los Mesh Shaders es claro, crear un tipo de shader universal para la etapa geométrica de la generación de una escena 3D por ordenador a tiempo real, justo en la que se operan con diferentes primitivas geométricas. La primera motivación de ello era la poca eficiencia de las etapas shader adicionales que en DirectX 10 en adelante, así como otras API equivalentes, se habían añadido y que apenas eran utilizadas. Cómo son los lentos e ineficientes Geometry Shaders en DirectX 10 y los Domain y Hull Shaders, pensados para interactuar con la teselación o subdivisión de primitivas por hardware.

Sin embargo, es importante conocer cuál es el problema para entender el motivo por el cual se desarrolló el concepto de los Mesh Shaders. Más que nada por el hecho de que nos ayudará a entender su utilidad y funcionamiento.

Ventajas de los Mesh Shaders

Alta geometría Mesh Shaders

El pipeline gráfico no son más que una serie de etapas ordenadas que se emplean para generar una escena en 3D. El método usado en los gráficos para ordenador se llama rasterización y fuera de algunas extensiones su organización básica se mantiene. Básicamente, tenemos dos etapas diferenciadas:

En la primera etapa se construye la escena a través de vértices y polígonos. En la segunda etapa y tras un cálculo que representa su proyección en una superficie en 2D, se trabaja con píxeles.

Es en la primera etapa donde actúan los Mesh Shaders, y es que en el fondo no son otra cosa que una reinvención del pipeline geométrico, el cual, tal y como hemos comentado antes, ha pasado muchos años recibiendo mejoras incrementales, cuando lo que requería realmente es una revolución. No obstante, estos no son solo un tipo de shader universal para primitivas geométricas, sino que va mucho más allá y trae consigo una serie de ventajas que eran imposible con el pipeline original.

Mejor uso de los recursos de la GPU

GPU NVIDIA VRAM

En una escena en 3D tradicional hay muchos más píxeles que polígonos, por lo que es en la etapa de los Píxel/Fragment Shader que consiste en calcular el color de cada uno de los puntos en pantalla, donde se encuentra buena parte de la carga computacional. Por lo que estos lo tienen fácil para ocupar un buen número de registros de los núcleos de la GPU y sacar todo el provecho de la misma. Sin embargo, la geometría en escena no, es muy difícil llegar a ocupar todos los huecos.

¿Qué significa esto? Las GPU se basan en unidades SIMD, realizan una misma instrucción con varios datos al mismo tiempo. Pues bien, si con los píxeles es fácil ocupar todas las ALU de una unidad de este tipo, con la geometría no ocurre, y, a no ser que tengamos un mecanismo implementado para que las ALU sobrantes se encarguen de otra instrucción, lo normal es que solo puedan ejecutar una instrucción de un tipo al mismo tiempo.

Y es aquí donde viene el nombre que tienen los Mesh Shaders, puesto que un mesh o una malla poligonal es un conjunto de vértices que forman un objeto en 3D. Esto permite ocupar mucho más fácilmente los registros de la GPU y sacar un mayor provecho de las unidades SIMD, sea cual sea la arquitectura de la que estemos hablando.

Orden de la geometría e Input Assembler

Alan Wake 2 Mesh Shaders Detalle

Uno de los problemas más grandes en una escena 3D es el overdraw, este se debe a cuando un mismo píxel en pantalla es calculado varias veces por el hecho que pese a que desde la perspectiva de la cámara se encuentra en diferentes posiciones según su profundidad, sí que lo están en ancho y alto. Es decir, que, si a la GPU le llega un polígono a procesar, que está opacado por otro, pero mucho antes que el que se encuentra cercano de la cámara, pues lo calculará, por el hecho que no renderiza los polígonos en un orden establecido, provocando un desgaste de recursos enormes.

Obviamente, pues hay formas de descartar los objetos no visibles, pero es ineficiente, ya que es una forma de malgastar recursos y una pesadilla para los programadores, por el hecho que tienen que pensar formas de poder eliminar esa geometría superflua y no visible en la escena que consumen recursos de computación, que no van a parar a los gráficos.

Otro de los puntos que dicen adiós con el nuevo pipeline geométrico es el Input Assembler. Dicha etapa del pipeline geométrico, no se encuentra por un shader, sino por una unidad de función fija. El trabajo de dicha unidad es leer los datos de las diferentes primitivas (puntos, líneas o triángulos) desde el Vertex Búfer y unirlos en primitivas que serán utilizadas en las diferentes etapas geométricas del pipeline 3D.

Sin embargo, su funcionalidad ha sido totalmente eliminada en el nuevo pipeline geométrico y en los Mesh Shaders ya no existe. El motivo de ello es simple: se trataba de uno de los mayores cuellos de botella del viejo pipeline geométrico.

Mesh Shaders vs. Vertex y Geometry Shaders

Mesh Shader topologías

Los Vertex Shaders son incapaces de crear nueva geometría, para ello requieren de los Geometry Shaders y la teselación por hardware. Es más, solo pueden operar con un número fijo de vértices, normalmente limitado por su caché interna.

En el caso de los Geometry Shaders, la cosa es más peliaguda. Son extremadamente lentos y un cuello de botella tan grande que los desarrolladores no los usan. Son el motivo por el cual la gran mayoría de juegos no utilizan DirectX 10. Lo peor de todo es que es incapaz de generar geometría nueva de forma procedural, si no solo de forma totalmente limitada. Algo que no ocurre con los Mesh Shaders que tienen la capacidad de generar cualquier forma poligonal que requieran los artistas y programadores.

Es decir, los Mesh Shaders permiten generar geometría de forma procedural, y, por tanto implementar una fórmula matemática o un algoritmo sobre un objeto en 3D y modificar su forma. Lo cual tiene una enorme cantidad de aplicaciones de cara a los videojuegos. Por ejemplo, permite tener animaciones mucho mejores y más realistas, deformaciones de objetos a tiempo real más detalladas, animaciones complejas en ropa y cabello de los personajes. Las aplicaciones son muchas y vienen por el hecho de que los desarrolladores no ven sus capacidades reducidas por las limitaciones del viejo pipeline.

Teselación vs. Amplification/Task/Object Shader

Mesh Shader ventajas

Los Mesh Shaders vienen acompañados de otro tipo de shader, el cual es totalmente opcional, pero viene a reemplazar a las unidades de subdivisión de primitivas o de teselación. Y es que dicha función se encargaban las unidades de función fija que no aportaban ningún control sobre la geometría resultante y en algunos casos podían ser hasta ineficientes.

Un Amplification/Task/Object Shader da la oportunidad de controlar el grado de generación de nueva geometría. Por ejemplo, un teselador no es consciente de la distancia en la que se encuentre un objeto y puede generar vértices de más que no son visibles en uno muy lejano. Todo ello permite hacer cosas como:

  • Eliminar objetos lo suficientemente pequeños en la distancia como para no ser visibles.
  • Poder generar niveles de detalle según la distancia del objeto a la cámara. Ahorrando tiempo de desarrollo y pesadillas a los grafistas 3D.

Este nuevo shader es opcional y se invoca antes de los Mesh Shaders, y nos sirve para escoger, simplemente, cuantos Mesh Shaders queremos invocar en cada momento. Lo cual da un mayor control sobre lo que ocurre en escena.

Pre-Culling con Mesh Shaders

Pre-Culling

Todo vértice no visible que no sea descartado será calculado como una serie de píxeles que no verá el usuario final, lo que se traduce en un malgasto de rendimiento. Una forma de hacerlo es renderizar la escena sin ningún tipo de shader y valor de color en los píxeles, ya que solo nos importa la posición de los polígonos, pero debido a que ha de pasar por las etapas de función fija, pues resulta ineficiente.

Por lo que se hace es generar un Compute Shader que se encargue del mismo trabajo, pues esto permite hacer bypass a las etapas de función fija del pipeline 3D y que no son necesarias para el Pre-Culling, el cual además se ha hecho clave para la generación del árbol BVH para el Ray Tracing y permite tener además conocer la posición de la geometría por escena.

Pues bien, los Mesh Shaders permiten tener todas las ventajas del Pre-Culling desde la propia lista de pantalla que genera la escena sin necesidad del Compute Shader previo. Lo cual es mucho más eficiente si buscamos tasas de frames por segundo muy altas. Ya que evita tener que preprocesar la escena, lo cual supone un ahorro importante en lo que a tiempo

Las desventajas de los Mesh Shaders

Demo Mesh Shaders NVIDIA Turing

Pese a su implementación en DirectX 12 Ultimate y llevar en una GPU comercial desde el 2018, solo Remedy Entertainment con Alan Wake 2 ha tomado la decisión de hacerlo. Una decisión polémica por el hecho que, en cuanto a hardware, todas las piezas necesarias para la implementación de los Mesh Shaders no se encuentran en modelos anteriores a las arquitecturas Turing en NVIDIA y RDNA 2 en AMD. Sin embargo, esta no es la única desventaja que traen consigo, las cuales en realidad pesan mucho menos que las ventajas explicadas en las secciones anteriores de este mismo artículo.

Meshlets

Dragon Meshlets

El uso de los Mesh Shaders requiere que las mallas poligonales de los objetos se organicen en grupos de 64 vértices, lo cual es el tamaño estándar de una ola que contiene todos los elementos sobre los que se ejecutará una misma instrucción. Por lo que se requiere almacenar la geometría de los diferentes objetos no en una sola malla general, sino en una serie "mallitas" o Meshlets, lo cual es un trabajo extra que antes no se tenía que hacer.

Además, el hecho de organizar la geometría de esta forma, pese a que permite un mayor uso de los recursos de la GPU hace que la compatibilidad de los juegos con las que no soportan Mesh Shaders se vaya al garete.

De ahí a que muchos desarrolladores decidan no usarlos en PC y en el contenido pensado para las consolas de anterior generación. Por lo que se puede decir que el uso de los Mesh Shaders es una de las características que definen por completo los gráficos de nueva generación y no solo el trazado de rayos. Sin embargo, su uso ha sido más bien limitado y por el

Más responsabilidad para los desarrolladores

Desarrollador videojuegos grafista

La frase “un gran poder requiere una gran responsabilidad” se aplica en los Mesh Shaders, y es que su versatilidad y potencia requieren un mayor control por parte de los programadores quienes tienen más probabilidades de dispararse a ellos mismos en el pie. Esto hace que muchos no quieran saber nada de su implementación en sus juegos. No por falta de conocimiento, ni por vagancia, sino más bien para evitar dolores de cabeza.

Esto no es muy diferente a cuando hablamos del procesamiento multihilo asimétrico de DirectX 12, muchos juegos no lo usan por el hecho que no aporta nada a nivel visual y si horas de trabajo solucionando problemas. Por lo que al final el uso de los Mesh Shaders se limita a desarrolladores con el conocimiento y las agallas suficientes para usar los Mesh Shaders. Eso sí, el resultado final merece la pena y es un salto enorme en lo que a calidad visual se refiere, claro está que fuerza a los usuarios a cambiar de hardware.