No hace mucho estaba mirando el siguiente video:

Que nos lleva al mismo tiempo a la siguiente presentación:

En la presentacíón se puede leer lo siguiente, que traducido significa lo siguiente.

La motivación principal es separar el dominio de la visibilidad del dominio del shading de tal manera que puedan ser tratados por separado. En el caso de la rasterización, las muestras de visibilidad son tipicamente fragmentos cubiertos por triangulos en el espacio de pantalla. En vez de realizar un shading por-fragmento, cada muestra de visibilidad es mapeada en el dominio del shading a una muetra de shading (ver Figura 2). Si este mapeado es una proyección de muchos a uno, el shading es eficientemente re-utilizado entre las diferentes muestras de visibilidad.

FIG2.PNG

El dominio del shader puede ser cualquier parametrización sobre las superficis renderizadas como las coordenadas de espacio de pantalla, parametros 2D e incluso una textura. Como ejemplo, considerad un triangulo que se mueve muy rápido el cual es muestreado durante un intervalo finito de tiempo utilizado rasterización estoica. Un algoritmo ingenuo determinaría las coordenadas baricentricas del triangulo por cada muestra de visibilidad y evaluaria el shading de manera acorde. En muchos casos, nosotros podemos asumir que el color visible de la superficie no cambia de manera relativa sobre el tiempo (por ejemplo un material moderadamente brillante). Por lo que podemos utilizar una imagen rasterizada del triangulo en un tiempo de shading fijo y utilizando los baricentricos de los puntos de interseccion de los rayros estoicos podemos encontrar las localizaciones de los shading por cada muestra de visibilidad mapeando estos a «pixeles» de esta imagen.

¿Complicado? Bueno, no lo es tanto, tecnicamente se basa en el hecho de que de un fotograma a otro el resultado de los shaders de cada pixel van a cambiar muy poco realmente por lo que tener que recalcular de nuevo toda la imagen por cada pixel es una tontería. ¿Que se hace entonces? Se marca cada pixel con un tag de tal manera que si este se mueve en el fotograma siguiente sea identificable y se le pueda aplicar directamente el resultado obtenido en el fotograma anterior. Ahora muchos os preguntaréis… ¿No es algo similar a la re-proyección de la que hablo Sony para poder adaptar ciertos juegos a la VR?reprojection

Pues es similar, aunque no es lo mismo y la gracia es que cuanto más pequeño es el tiempo de fotograma menos espacio habán recorrido las primitivas gráficas y más reciclable será la información del fotograma anterior, pero aquí hablan a nivel de fragmento y la información de los fragmentos una vez escrita en el búfer de imagen es descartada tan pronto como se envía como búfer frontal y si lo pensamos bien esto significaría almacenar múltiples búfers de imagen en memoria y el ancho de banda se vería altamente resentido.

Aquí el concepto es cambiar por completo la fase de rasterizado, pero no es algo lejano a lo que encontramos hoy en día.

FIG3

Para reutlizar muestras de shading, necesitamos identificarlos con indices únicos (ssID). Durante el renderizado, cada primitiva de shading almacena un rango ssID: un espacio de direccionamiento virtual que asegura que los indices de muestreo de los diferentes dominnios de shader no se superponen durante el fotograma. Este espacio de dirección no tiene ninguna relación con la memoria fisica, pero permite llaves de busqueda para que el sampler encuentre muestras ya existentes en el CG-Buffer. Si nos mantenemos en el ejemplo anterior del triangulo en movimiento, el rango ssID sería el número de pixeles que el triangulo cubriría en el dominio del shader.

¿De que me suena esto? Ah si…

IDBufferSDK

El ID Buffer por cierto se genera en PS4 Pro en el mismo momento que la rasterización, gracias a tener esto es posible coger un fragmento o un pixel y tenerlo identificado independientemente de cual sea su posición en el fotograma siguiente. ¿Y que tiene de especial esto? La técnica del Paper habla del Deferred Shading por lo que la iluminación es resultante en una segunda etapa y esto se produce en la primera etapa. ¿Y como funcionaría? Pues simplemente imaginaos que tenéis una textura determinada cuyo trabajo sobre ella es el mismo unas 100 veces en la escena, para no renderizarla unas 100 veces se le coloca un identificador y se guarda en una memoria cercana el programa para esa textura, se calcula la primera vez pero las otras 99 veces se toma como referencia el primer calculo y se aplica directamente sin tener que recalcular. Esto además permite almacenar los diferentes fragmentos en un búfer de los mismos en vez de ser uno a nivel de pantalla y es aquí donde entra el CG-Buffer

Los métodos de Defered Shading convencionales trivialmente unen los datos de visibilidad y superficie en el G-Buffer, resultando en un impacto en la memoria proporcional al número de muestras de visibilidad. Introducimos el Compact Geometry Buffer (a partir de ahora CG-Buffer) un almacenamiento desacoplado para el Deferred Shading. Esta estructura de datos tiene la misma funcionalidad que el G-Buffer, almacenando las entradas necesarias de los shaders para una evaluación conn retraso. Sin embargo,evita el almacenamiento de datos redundantes que corresponden a la misma superficie cuyos resultados y resulta en una salida del shader equivalente.

En vez de almacenar la información del shading en el búfer de imagen, una muestra de visibilidad almacena una referencia a la muestra de shading en un búfer lineal compacto (Figure 4). Multiples muestras de visibilidad pueden hacer referencia a la misma muestra de shading permitiendo su reutilización. El tamaño del  búfer de geometría (CG-Buffer) no crece con la densidad de supersampleo,pero es gobernada por el ratio de shading, esto elimina todas las ejecuciones redundante de los shaders que han sido la mayor sobrecarga en el deferred shading a nivel de imagen.

FIG4.PNG

Lo interesante viene ahora:

El algoritmo antes mencionada reutiliza el shading de manera global, encontrando las correspondientes muestras de visibilidad durante la rasterización. Sin embargo esto se aplica sobre la memoria global y se convierte en su principal cuello de botella. Nosotros ahora presentamos un camino alternativo, el cual esta motivado por el hecho que en muchos casos una muestra de shading no es visible en localizaciones arbitrarias en toda la pantalla entera, pero en regiones relativamente pequeñas. En muchas aplicaciones prácticas, la cantidad de motion blur o desenfoque se ajusta a esta suposición.

Con este zflojamiento de los requerimientos, poemos limitar el shading reuse a cierto bloques de pixeles. Nuestro segundo método divide la imagen en tiles uniformes y busca los duplicados dentro de esos tiles, procesando cada uno de ellos en paralelo. A una superficie se le aplica el shader de manera redundante si se encuentra en múltiples tiles, pero esto es solo una reducción marginal de la eficiencia, proveida con que los tiles son lo suficientemente grandes en comparación con la cantidad de blur.

Este algoritmo utiliza la misma estructura de datos en CG-uffer presentada en la Sección 4, pero la etapa de muestreo esta dividida en dos pasos de rasterización y uno de computación (Figure 5) . En el primer paso los fragment shaders no almacenan los datos para el shading en los compact buffers, pero solo el ssID de la muestra visible que se calcula, el cual es computado de la misma manera que el método anterior… Al final del primer paso, solo el ssID de la superficie visible es almacenado. Pero ahora podemos implementar el mismo mecanismo de cache pero en la memoria dentro del chip. La principal ventaja de esto es que este paso puede ser implementado como un paso completamente computacional donde el programa controla la ejecución del hilo.

FIG5.PNG

¿De que me suena esto? Ah si, lo he comentado miles de veces en el blog.

tiledcaching2tiledcaching3tilevega

De momento ninguna GPU de PC soporta el ID Buffer y la GPU de PS4 Pro no soporta rasterizado por Tiles pero en un futuro cercano esto se unirá. ¿Cual es la diferencia? que en vez de operar a nivel de pantalla con los problemas que hay para los shaders de latencia y de poder acceder a la memoria principal se procesa a nivel de un tile interno y se comprueba dentro del tile que fragmentos se repiten y se marca cada uno diferente con un tag en la primera etapa, es decir, se trata de almacenar un mini ID-Buffer en la Cache L2, luego después de hacer esto se aplica lo que es la eliminación de superficies no visibles para aplicar a continuación la texturización pero no teniendo que calcular por cada fragmento sino por cada fragmento diferente acelerando el tiempo de renderizado enormemente.

Fijaos en la siguiente imagen de Forza 7 y tened en cuenta como funciona el Deferred Shading donde la iluminación es calculada no en el primer paso sino en el segundo, por eso se llama «Diferido».

maxresdefault.jpg

Los fragmentos de la carretera, del cielo, de la carrocería del coche se repiten continuamente y se tienen que calcular una y otra vez. Con estos cambios en el pipeline de repente nos encontrariamos con una aceleración enorme del tiempo de renderizado. ¿La segunda etapa del Diferido? Se puede calcular a través de computación en el mismo Tile y generar con ello la imagen final de manera muy rápida pero para ello hacen falta unos cambios muy leves en el pipeline gráfico que serían posibles de aplicar a corto-medio plazo.

¿El otro elemento que no esta en las consolas de actual generación pero si en las GPUs de PC y que es esencial para esto?

Conrast

VegaConservative2

Por lo que es una técnica que si o si la vamos a ver aplicada en los juegos de PC con tal de acelerar la velocidad del renderizado y esto nos lleva a un elemento en concreto que es la generación de fotogramas a alta frecuencia que es ideal para la VR. Lo que voy a decir ahora no esta en la presentación pero estaría bien que se generasen dos ID Buffers, el primero a nivel de Tile y el segundo con la imagen ya generada donde cada fragmento tenga su posición en el ID Buffer de tal manera que al re-procesar la siguiente imagen sepamos directamente a que corresponde cada pixel y dado que los cambios van a ser mínimos de un fotograma a otro pues… Podemos obtener nuevos fotogramas intermedios rapidamente a partir de los segundos. ¿Lo único que cambía? la iluminación que depende de la posición de la cámara pero esto no es problema y se recalcula de nuevo teniendo en cuenta la nueva posición de la cámara, sería el primer paso del Diferido que saldría de manera cuasi gratuita y así los fotogramas sucesivos.

Pero esto conlleva consigo un problema añadido, imaginad que el fotograma#1 lo generamos en 16ms con un método normal y el fotograma #2 con el mismo tiempo, en el caso de la nueva técnica generamos el fotograma 2 en… digamos que unos 8 ms… Ahora supongamos que el fotograma#0 no lo mostramos pero si el resto consiguiendo una tasa de refresco de 120hz en una escena que de otra manera iría a 60hz.

 

La otra ventaja es de cara a las alta resoluciones… la diferencia entre una escena a 1080P y una 4K es la cantidad de información pero si cogiesemos en dos listas y clasificaramos la información sin repetir tendríamos la misma información directamente. Basicamente con esta técnica se puede desacoplar el coste del Shading del coste de la tasa de texturizado y de renderizado rompiendo por completo la famosa pirámide.

DiamondStructure

Obviamente al tener 4 veces la cantidad de pixeles y de texeles en pantalla las tasas aumentarían de la misma manera pero no los Shaders, es decir, no harían falta tantos FLOPS para conseguir la misma calidad de imagen utilizando la rasterización de toda la vida.