Comentario Original:

Caray, pues combinar esto con los ya mencionados decoupled shaders …

El tema de los Decoupled Shaders… Es algo complicado de aplicar por un motivo muy simple. Lo que hace el rasterizador es generar a partir de la geometría bloques de 8×8 pixeles.

8x8.png

Cada Shader Engine tiene un rasterizador que genera un bloque de 8×8 pixeles que es enviado para la étapa de los Fragment/Pixel Shaders a una Compute Unit, recordad cual es el pipeline actual de renderizado.

shader_full

Tenemos unos 64 elementos en total, lo que es el tamaño de una ola pero hemos de tener en cuenta que los Pixel/Fragment Shaders se almacenan de 2×2 por lo que se acaban organizando en 4 Work-Groups de 16 items cada uno. Teniendo en cuenta que la CU tiene unos 4 unidades SIMD16 entonces cada unidad SIMD se encarga de realizar las operaciones pertinentes.

¿Y que información traen los fragmentos consigo? Pues ni más ni menos que la posición en la que se encuentra la posición en la memoria en la que se encuentra la textura que se va a aplicar cubriendo la superficie.

UVMapping

En algunos casos particulares en vez de crear una textura enorme que costaría eones mover a la memoria y que seria cuasi imposible se utilizan texturas más pequeñas de manera repetitiva. Aunque hoy en día hay técnicas como el Virtual Texturing que dan una enorme variedad al texturizado incluso dentro de un mismo fotograma hay valores que se repiten dentro de una escena, pero hacerlo a nivel de escena es imposible por lo que se tiene que hacer a nivel de bloque de 8×8 pixeles.

¿Como lo hacemos? Durante la étapa de rasterizado y en el caso de las GPU de AMD es a partir de Vega donde se produce el Middle-Sort y la generacion del Z-Buffer en esa etapa, lo que le permite al DSBR de Vega actuar.

siggraph_vega_architecture_41

De cada fragmento el DSBR conoce de antemano gracias a lo hecho en la etapa anterior cual es la posición Z de cada pixel en el bloque de 8×8 pixeles y descartar los que están cercanos o alejados. Dado que solo accede al Z-Buffer y el Color Buffer no se ha generado aún ni tampoco tiene acceso a la RAM para leer las texturas por motivos de velocidad desconoce por completo a que referencia hace cada pixel a nivel de texturizado y por saber, no sabe si el pixel es opaco o semi-transparente. ¿Lo ideal? Que el DSBR fuese capaz de acceder a las texturas de la escena y que tuviese la suficiente velocidad como para leerlas con soltura y marcar las posiciones en cada pixel, pero no han implementado esto en el DSBR aún que recordemos que es una unidad de función fija.

¿Otra posibilidad? Crear una especie de Object ID Buffer que no se ha de confundir con el ID Buffer convencional. En este OID Buffer no nos haría falta en absoluto saber las texturas sino que lo único que necesitamos marcar es cada objeto con un valor indexado, de tal manera que cada tipo de objeto en la escena que comparte información sobre su mapa UV es marcado de antemano y al resolver el texturizado de un solo objeto se resolverían automáticamente el resto… ¿Es así no? Pues no, porque una vez un bloque de 8×8 entra en una Compute Unit esta no es consciente de lo que ocurre al resto de las Compute Units que tiene alrededor y por tanto la técnica de OID Buffer no funcionaria a este nivel. En realidad viendo las ultimas patentes yo descartaría por completo los Decoupled Shaders, era una propuesta encima de la mesa pero su ejecución sobre-complica enormemente las cosas a nivel de arquitectura de la GPU.

Lo que si que es interesante con la nueva patente es la Operand Destination Cache, en toda ALU solemos trabajar con una serie de registros a la hora de realizar las operaciones, da igual si es de una CPU, GPU, DSP… Esto que voy a explicar ahora es general para todo tipo de procesadores, pero antes una referencia a lo que es el registro acumulador.

En una CPU de computadora, el acumulador es un registro en el que son almacenados temporalmente los resultados aritméticos y lógicos intermedios que serán tratados por el circuito operacional de la unidad aritmético-lógica (ALU).

Sin un registro como un acumulador, sería necesario escribir el resultado de cada cálculo, como adiciónmultiplicación, desplazamiento,etc…. en la memoria principal, quizás justo para ser leída inmediatamente otra vez para su uso en la siguiente operación. El acceso a la memoria principal es significativamente más lento que el acceso a un registro como el acumulador porque la tecnología usada para la memoria principal es más lenta y barata que la usada para un registro interno del CPU.

Si hacemos una operación entre A y B sea del tipo que sea, entonces lo habitual es que el resultado de la operación entre ambos se almacena en A con tal de que una operación sucesiva tome el resultado convertido en el primer operando de la nueva operación y esta cadena continuara hasta que se le cambie el valor a A.

¿Y que ocurre cuando se carga un Wavefront/ola nueva en la unidad SIMD? El resultado simplemente se pierde… ¿Y como podemos almacenarlo? Haciendo uso de un registro destino, el cual no es un acumulador pero nos encontramos que al final de cada Wavefront de la cadena dicho registro destino también es eliminado. Tened en cuenta que el registro destino almacena resultados de una operación por lo que en el caso habitual de los Fragment/Pixel Shaders almacenaría la version final del pixel que iría a parar a los RBE/ROPS y de ahí se escribiría en memoria para ser recuperado para un Compute Shader.

Pero con esto podemos dejar la información en la Operand Destination Cache y utilizar los resultados para un futuro Shader sea del tipo que sea por lo que los resultados del Pixel/Fragment Shader no van a los RBE/ROPS sino que pueden ser aprovechados dentro de la misma cadena de Wavefronts para el post-procesado directo con un impacto cero en la memoria. La misma patente nos dice que por ciclo de reloj se puede almacenar en la Operand Destinacion Cache la informacion para 2 SIMD4, dado que se opera en precisión FP32 esto son unos 128 bits*2 y por tanto 256 bits/32 bytes lo que significa que podemos almacenar los 8 MRT de un pixel de manera directa en la ODC… ¿Por qué esto es importante? Pues porque en Deferred el calculo de la iluminación actualmente se hace con los Compute Shaders y a posteriori.

deferred_overview

Es decir, el truco es que el G-Buffer no toque la memoria externa de tal manera que el ahorro en el ancho de banda con la memoria principal es enorme. Pensad que por pixel la cantidad de información necesaria para el G-Buffer es como mínimo de 16 bytes por pixel, es una técnica que consume una enorme cantidad de ancho de banda y esto es una técnica ideal para ahorrar en ancho de banda. ¿Otro ejemplo? El Forward+ donde no se utiliza un G-Buffer pero donde se desacopla el cálculo de la iluminación también. El Forward+ no es más que Tile Based Forward Rendering, y si lo pensaís bien con el Operand Destination Cache acercamos mucho el funcionamiento de la GPU a lo que es un Tile Renderer.

forward-eurographics-2012-10-638

En fin, sigamos con el comentario.

… y renderizado reyes sería alucinante…

El problema del renderizado via REYES es que tal y como funcionan las unidades de texturas estas funcionan en bloques de 2×2 siempre y no menos que eso, por lo que yo trabajo con micropoligonos que 1 pixel de tamaño entonces lo que harán las unidades de texturas es cuadriplicarme el trabajo. Este es uno de los motivos por los cuales en muchos juegos actuales las partículas se procesan a posteriori de la escena principal y por eso hay una disonancia en la iluminación producida por dichas particulas, esto se hace además porque cada fuente de luz adicional cambia el color de los pixeles y si tenemos en cuanta el algoritmo Z-Buffer es un consumo enorme de la tasa de texturizado.

Además de tener potencia suficiente para la voxelización (que se haga es otra cosa, como siempre).

¿Se podría meter en cada CU una ALU escalar adicional que se encargase de recorrer los octrees?

Ahora que lo dices…

thinking-guy-meme

Me pregunto si será posible colocar una instrucción escalar en formato VLIW2 y tener 2 ALUs disponibles para ello. En todo caso había un paper sobre eso…

Pero es algo diferente a la unidad Super-SIMD pero bien que podría tener relación, en todo caso la unidad escalar tiene su propio contador de programa. No se si ambas tienen una relación en común si soy sincero y ando muy justo de tiempo para compararlas. Os dejo el paper y hacedlo vosotros mismos a ver que conclusiones sacáis. Yo creo que por el VLIW2 pueden tener relación, pero no lo puedo asegurar.