Una GPU cualquier lo que hace es crear una imagen a partir de la descripción de una escena que le entrega la GPU, esto lo hace varias veces por segundo para crear lo que llamamos «gráficos a tiempo real» y dar la sensación de cinemática. En esta entrada hablare solo del pipeline geométrico, que es el primero de todo el pipeline.

Cuando se envia la lista de dibujado para componer la escena, respecto al pipeline geométrico, lo que recibe la parte geométrica del pipeline es lo siguiente:

  • Las primitivas de la geometría ques e veran en la escena.
  • Descripción de las luces que iluminan la escena.
  • Como cada objeto refleja la luz
  • La posición y la orientación del espectador respecto a la escena (cámara).

Para generar la imagen final se utiliza un pipeline, un proceso fijo de varia etapas programables y/o de función fija (automatizadas). Dicho pipeline dependerá de la API utilizada y es algo fijo e inmutable ya que describe cual es el camino que iran siguiendo los datos en las diferentes etapas del proceso. La primera etapa de la composición de la escena es lo que llamamos el pipeline geometrico o «World Space Pipeline» y en su definición más simple se trata de transformar cada objeto con su propio sistema de coordenadas en un sistema de coordenadas común.

Para hacer esto y aseguraros de que los triángulos no queden transformados en superficies curvas sobre las que no podríamos trabajar simple y llanamente utilizamos transformaciones afines como rotaciones, traslaciones, escalados y similares durante el proceso.

Las coordenadas de un punto en el espacio se definen con (X,Y,Z) que son unos tres componentes, pero dado que la unidades vectoriales (SIMD, VLIW… ) que tienen los sistemas encargados de la geometría (hoy en día las GPUs pero en el pasado no era así) no se pueden construir con 3 operandos lo que se hace es añadir un cuarto operando llamado W al que se le da el valor de 1. Pero sobretodo la inclusión del cuarto elemento nos permite definir operaciones de este vector por una matriz de 4×4.

Podemos diferenciar dos tipos de matrices, las primeras de ellas sirven para manipular el objeto en si…

Las segundas son la conversión de lo diferentes objetos de la escena en un sistema de coordenadas común.

Se utilizan las mismas matrices en todas los sistemas independientemente de la configuración del hardware y la API utilizada.

Ahora bien, el pipeline geométrico ha ido evolucionando durante los últimos años una barbaridad hasta convertirse en sumamente rigido y complejo en su funcionamiento. Al contrario que el pipeline de rasterizado que es la parte posterior del pipeline gráfico y que trabaja ya no con vertices y primitivas en un espacio tridimensional sino con fragmentos que se ha mantenido relativamente poco cambiado, hemos ido viendo una evolución de más y más complejidad en el número de etapas y paradojicamente aquello que es la parte más fácil de calcular por la menor cantidad de información se ha acabado estancando en un pipeline estático e ineficiente que no aprovecha la enorme potencia de los sistemas de hoy en día, y es precisamente uno de los problemas que tenemos ahora mismo, que el pipeline gráfico es fijo en cuanto al camino que siguen los datos por las diferentes étapas.

Esto significa que si escribimos un programa en el Vertex Shader si estámos en modo DX11/DX12 o similar automáticamente lo que se hará por orden del procesador de comandos que esta controlado por el driver será enviar
los datos de salida como datos de entrada para la siguiente étapa que es el Hull Shader sin que el desarrollador pueda decidir absolutamente nada.

Esta limitación en la versatilidad del camino de datos es sorprendente frente a la paradoja de hacer las GPUs más flexibles en cuanto a programabilidad con el tiempo. Recientemente con tal de solventar este problema han aparecido nuevos tipos de shader con tal de acortar la cantidad de etapas.

  • El Task/Surface Shader que reemplaza a la combinación Vertex+Hull a una sola étapa.
  • Mesh/Primitive Shader que reemplaza el Domain+Geometry Shader también a una sola étapa.

¿Pero que pasaría que os dijese que esto solo es marketing y que realmente el cambio que se ha hecho es mucho más profundo? Aparte de los shaders gráficos tenemos un tipo de Shader para la computación de propósito general desde la GPU al que llamamos Compute Shaders, los programas bajo este tipo de shader tienen un pipeline tan complejo como este:

El Compute Shader opera fuera del pipeline gráfico, puede realizar trabajos fuera del renderizado aunque también se utiliza para estos. Por ejemplo los juegos 2D actuales debido a que no requieren ciertas etapas del pipeline 3D son puro Compute Shader, efectos de Post-Procesado son puro Compute Shader. En realidad excepto el Fragment/Pixel Shader todos y cada uno de los shaders operan con un solo tipo de dato en concreto durante una etapa concreta del pìpeline y la paradoja es que todos ellos podrían reemplazarse por un Compute Shader al que le pudieramos dar la posibilidad de decidir hacia donde exporta los datos, si hacía otra etapa shader o a un elemento de función fija.

Lo que vamos a ver en un futuro es el retorno al pasado más primigenio con la potencia del futuro, a la eradonde a través de una CPU o un DSP dedicado se tenía completo control sobre la étapa geométrica del pipeline y no había un driver por el medio controlando el funcionamiento. Vamos a ir a una era donde el pipeline geométrico va a desaparecer por completo para convertirse en un pipeline de computación con la capacidad de exportar a la étapa de rasterizado. ¿Y como es eso posible? Pues por el hecho que si
tenemos en cuenta la naturaleza de lo diferentes tipos de Shader en la étapa geométrica nos daremos cuanta que todos ellos funcionan con un solo dato por instrucción.

Pe… pero Urian… ¿no eran SIMD?

Esto significa que un Compute Shader al menos puede actuar como si fuese cualquier otro Shader sin problemas y solo necesitamos darle la capacidad de exportar a cualquier étapa del pipeline gráfico para darle total versatilidad sobre el pipeline al desarrollado hasta el punto en que él/ella
pueda crear su propio pipeline gráfico y aplicar nuevas metodologías de renderizado fuera de la tradicional o hacer sistemas híbridos.

¿Cual ha sido la primera aplicación de esto? Entre otras cosas la creación del pipeline para el Raytracing generando nuevos tipos de shader que no son otra cosa que Compute Shaders para este método de renderizado combinados con nuevas étapas de función fija… Pero podemos aplicar otro tipo de pipelines, por ejemplo podemos aplicar el método REYES desde una GPU convencional…

Componer una escena a partir de voxeles…

La versatilidad que permite esto que estoy explicando enlas GPUs más contemporaneas es enorme en comparación con lo que hemos tenido hasta ahora. Los desarrolladores podrán buscar nuevas formas de renderizar la escena. Antes las GPUs estabán pensadas para renderizar escenas compuestas por triangulos solamente y aprovechando un pipeline fijo y estático en cuanto a sus étapas.

Esto es algo que curiosamente ya hace una década, Tim Sweeney de Epic Games y arquitecto del Unreal Engine ya comento, que en el futuro el pipeline gráfico no sería fijo sino definible por el desarrollador.

La diapositiva habla de Larrabee que no eran otra cosa que núcleos Pentium con unidad SIMD ultralarga… Obviamente el Larrabee carecía de las unidades de función fija de las GPUs… ¿De que nos suena eso? Pues de esto:

Una unidad de procesamiento tensorial o TPU (del inglés tensor processing unit) es un circuito integrado acelerador de IA desarrollado por Google específicamente para el aprendizaje automático.
En comparación con las unidades de procesamiento gráfico (que a partir de 2016 se usan con frecuencia para las mismas tareas), estas unidades están diseñadas implícitamente para un mayor volumen de cálculo de precisión reducida (por ejemplo, desde 8 bits de precisión) y carecen de hardware para la rasterización/cartografía de textura.12​ El término ha sido acuñado para un chip específico diseñado para el marco Tensor Flow de Google. 

Es decir, basicamente una TPU no es más que una GPU sin las unidades de función fija por lo que una GPU si descarta el uso de las unidades de función fija y de la capacidad de trabajar con menor precisión puede comportarse como una TPU en su definición más simple… Curioamente esta es una de las particularidades de la arquitectura RDNA de AMD, aunque no de Navi 10 (RX 5700) que como mucho puede operar en FP16 pero si de posteriores GPUs que implementaran eso.

El caso es que existe un dilema sobre las unidades de función fija de cara al futuro, esta claro que en consolas se mantendrán, pero en PC existen malas lenguas que afirman que las GPUs serán reemplazadas por TPU al cargar el trabajo de lo que antes era función fija sobre las ALUs que ejecutan los shaders, uno de estos cambios es posible por el cambio en la forma de organización de las ALUs que vamos a tener en un futuro donde se pasará de una organización SIMD a otro tipo de organización que ya hemos visto en los Tensor Cores de Nvidia y que permtie el calculo de matrices entre si.

Este tipo de organización a nivel funcional Nvidia la presento hace unos meses en la GTC de este mismo año…

Lo que tenemos es que cada ALU o conjunto de ALUS (PE en diagrama) tiene un router asignado que le permite comunicarse con el resto de las ALUs de la malla de manera directa. A esto se le llama NoC y permite realizar operaciones que antes no eran posibles y al mismo tiempo hace posible su funcionamiento como unidad SIMD para la compatibilidad hacía atrás.

Nvidia por ejemplo, en la serie TU11x, que son las Turing GTX ha convertido los Tensor Cores en una amalgaba de unidades FP16 y les ha quitado la funcionalidad al cambiar la forma en la que están conectados. De ahí a que a la hora de hacer ciertos algoritmos sea mucho más ineficientes que los de la TU10x.

El concepto en el fondo es el mismo que el del Larrabee, pero en el Larrabee de Intel teníamos como núcleo un Intel Pentium modificado que podía realizar 2 instrucciones por ciclo, la idea era hacer una de las instrucciones en la unidad SIMD y la otra de manera convencional. Todo sistema informático requiere dos mecanismos de ejecución, uno para el código en paralelo y el otro para el código serial. Fijaos como Nvidia para el código serial, aquel que no se puede paralelizar, incluye un núcleo completo RISC-V… Es decir, tenemos una CPU completa dentro de cada CU/SM haciendo el trabajo que antes en una GPU realizaba la ALU escalar. Esto que parece una tontería no lo es en absoluto, precisamente parte del camino a crear un pipeline completamente versatil es la destrucción de la dependencia de los lenguajes shader convencionales para poder aplicar definiciones con lenguajes de programación más genéricos, algo de lo que se lleva MUCHO TIEMPO hablando pero que por limitaciones del comportamiento de la GPU no se ha podido realizar.

¿Y cual es esa limitación? La existencia del entramado del Procesador de Comandos que es el que gestiona y dirige al 100% todo el funcionamiento de la GPU desde el puente de mando de la misma. Tu no puedes controlar una GPU directamente ni esta ejecuta programas sino que los Procesadores de Comando cogen las listas de comandos y operan a partir de estas. Para tener la total versatilidad el procesador de comandos y cia han de desaparecer por completo y darle total versatilidad a los desarrolladores o en su defecto mantenerlos para la compatibilidad hacía atrás con juegos antiguos o para quien prefiera utilizarlos, pero la realidad es que las GPUs tal y como las conocemos con lo año desaparecerán, siendo el primer paso para ello la capacidad de poder definir el pipeline gráfico como uno quiera a través de los Compute Shaders y el segundo paso será la eliminación progresiva de las unidades de función fija con el proceso intermedio de la transformación de las unidades SIMD por configuracione NoC con tal de darle la capacidad a las ALUs de poder realizar operaciones matriciales.

Esto es todo, como siempre tenéis el Discord y los comentarios de la misma entrada para comentar el contenido de la misma.