Trasladando de Wii U a NX (I): GPU

Esto lo he comentado varias veces, pero el diagrama que viene a continuación es de la GPU de Wii U… ¿Que particularidad tiene con lo anteriormente dicho? Vienen del SDK oficial de la consola, la primera información es acerca de la naturaleza de la GPU y cual es su arquitectura, algo que ya he demostrado varias veces en este blog, pero esta vez lo haré con fuentes primarias:

Captura de pantalla 2016-04-29 a las 13.25.27

El diagrama general de la GPU que se puede encontrar en el SDK es el siguiente:

GPU7BlockDiagram

Tenemos dos unidades de texturas, dos SIMD y 2 RB (Render Back-End) cada RB equivale a unos 4 ROPS por lo que la configuración es de 8 ROPS en total, pero por el momento lo que me interesa es la unidad SIMD:

GPU7SIMDDiagram¿Como se explica esto? Ya lo explique en su día, por lo que me voy a autocitar:

Ahora vayamos a la que utiliza Wii U, su GPU es de la familia R700 por lo que la configuración de sus Compute Units es distinta a la de la arquitectura GCN. Si miramos la configuración de la arquitectura R700:

RV770_2

Cada “núcleo” tiene 80 unidades, lo pongo entre comillas porque aquí núcleo no corresponde a Compute Unit y se puede confundir. El caso es que las 80 unidades están compuestas en unidades de 16 de estas:

shaderproc

Que son lo que la diapositiva de arriba llama ALUs. ¿Verdad que antes he dicho que los Wavefronts entran en grupos de 16? La diapositiva no es muy clara cuando habla del ratio 4:1 pero se refiere a que cada grupo de 5 Stream Processors (ALU) le toca una TMU, es decir… el ratio en la arquitectura R700 es de 20 ALUs por TMU, pero esto tiene una pequeña desventaja, dado que la gran mayoría de operaciones gráficas se hacen con cuatro componentes la mayoría de veces el quinto stream processor quedaba completamente en desuso por lo que AMD en arquitecturas posteriores decidió pasar al ratio 16:1 para las TMUs, tal y como se ve en la Compute Unit de la arquitectura GCN.

En Wii U tenemos 8 unidades compuestas cada una de ellas por una TMU y sus respectivas ALUs. Marcadas con la letra N en el Latte que es donde se encuentran las Compute Units de su GPU:

wiiudie_blocks

Cada N corresponde a una TMU distinta, por lo que en realidad tenemos 2 unidades SIMD por tanto 160 Stream Processors.

Es decir, la documentación oficial me da la razón sobre el número de unidades shader del sistema. En todo caso lo del número de Shaders y la configuración esta en la siguiente tabla:

Captura de pantalla 2016-04-29 a las 15.05.18

Sin salir de los Shaders hay que tener en cuenta que la GPU puede renderizar en dos modos distintos, con el Geometry Shader activado (OpenGL 3/DX10) o con este desactivado.

Captura de pantalla 2016-04-29 a las 13.46.47

El camino de datos en el caso de no utilizarse los Geometry Shaders es el siguiente:

NoGeometryShaderPath

Mientras que en el caso de utilizarse los GS la cosa cambia:

NoGeometryShaderPath

Ahora bien, el rendimiento de los shaders es diferente respecto al modo de usarse ya que la localización de recursos cambia por completo.

Captura de pantalla 2016-04-29 a las 13.50.05

¿Cual es dicha localización de recursos?

Captura de pantalla 2016-04-29 a las 13.50.19

Tenemos 192 hilos de ejecución en total, pero tenemos solamente unos 2 SIMD por lo que tenemos cargados dos wavefronts, uno por cada SIMD y el tercero en espera. Cada uno de los hilos de ejecución corresponden a una ALU distinta. Pero hay un elemento que me ha llamado poderosamente la atención y son los Compute Shaders… Dado que el R7xx no soporta OpenGL 4.x ni DX11 pensaba que no los íbamos a ver y están pero no de la forma estándar sino de una forma exclusiva y de una manera que me ha llamado poderosamente la atención:

Captura de pantalla 2016-04-29 a las 13.56.50

La parte importante es la que dice:

La GPU7 es incapaz de implementar la especificación completa de la extensión ARB GL_ARB_compute_shader. Proveemos una extensión para Café para que sea compatible hacía adelante compatible con la extensión ARB estándar pero aún tomando ventaja de las capacidades Compute Shader de la GPU7.

Es decir, no soporta el set completo de los Compute Shaders pero si una versión parcial. El problema es que no hay soporte de múltiples contextos en Wii U debido a que la versión vitaminada del OpenGL 3 que es el GX2 no añade la capacidad de crear multiples contextos en la GPU, al fin y al cabo la arquitectura R700 no trabaja con multiples contextos simultaneos al ser una GPU DX10/OpenGL3.

01 03

La diapositiva dice soporte gráfico al nivel DX10. La mención de DX10 respecto no al renderizado sino a los Compute Shaders se pueden leer en la siguiente parte del SDK:

Captura de pantalla 2016-04-29 a las 14.11.25

Dado que cada Compute Shader ocupan unos 64 hilo esto significa que ocupan un Wavefront entero y por tanto se comen el 50% del rendimiento, lo interesante es que están pensados para ser compatibles hacía adelante.  El otro tema relacionado con los shaders es el lenguaje en el que están escritos estos, GX2 es una API gráfica modelada a partir de OpenGL, en realidad se sobre-entiende que es OpenGL con extensiones para tomar ventaja del hardware de la consola, curiosamente en Wii U y al contrario de lo que yo pensaba que ocurría no existía OpenGL como API de alto nivel y GX2 como API de bajo nivel… Pues no, sino que como ocurre en el caso de PS4 con GNMX en alto nivel y GNM en alto nivel ambas son una misma API siendo la versión de alto nivel una parte de la de bajo nivel, dado que GX2 no es más que una versión vitaminada con extensiones de OpenGL 3.3 y a medida no nos debería extrañar ese detalle, pero hay un elemento que da soporte a dicha teoría y es el hecho que el lenguaje de los shaders de OpenGL  no es el HLSL sino el GLSL, bueno, en Wii U/Cafe se hace servir una versión extendida del GLSL, lo que marcaría el origen en OpenGL de la API GX2.

Captura de pantalla 2016-04-29 a las 15.17.07

Captura de pantalla 2016-04-29 a las 15.18.02

El hecho que GX2 sea una versión con extensiones de OpenGL explicaría el motivo por el cual Nintendo habría adoptado Vulkan de cara a NX, más que nada parece ser que Nintendo adopta APIs gráficas que son estándares abiertos y luego las adapta a bajo nivel y las necesidades de su hardware.

api-vulkan-nintendo-nintendon1 VulkanStatus

Curiosamente Nintendo separa la API de manejo de memoria (DMAE) de la API gráfica en Wii U pero el caso esta en que si Nintendo ha utilizado una versión de OpenGL modificada (la ventaja es que dicha API soporta extensiones y por tanto puedes hacerte un OpenGL a medida) y la política con Vulkan parece ser la misma, es decir, los diferentes fabricantes o poseedores de una plataforma pueden crear sus propios perfiles de Vulkan como ocurre en OpenGL.

VulkanFeatureSets

 

¿Cual es la importancia de esto? Las extensiones como los “Compute Shaders” para Wii U/Cafe están pensadas para ser compatibles hacía adelante y poderse llevar a una GPU más avanzada. Es decir, es muy posible que una GPU con arquitectura GCN tenga soporte completo para GX2 y por tanto en el aspecto gráfico Nintendo lo tenga muy fácil para portar los juegos. Hay que tener en cuenta que la API gráfica es la que comunica la GPU con el hardware gráfico y no tiene porque ser dependiente de un sistema operativo en concreto o incluso de una ISA de la CPU en concreto sino que son elementos completamente independientes, quiero decir que la API GX2 pueden ser ejecutadas una GPU más potente y avanzada que la GPU7 independientemente del conjunto de instrucciones de la CPU (x86, ARM, PPC, MIPS…) o del SO en el que se este ejecutando.

Ahora bien… ¿Como se traslada esto en un hardware más potente? Voy a intentar simplificar esto al máximo pero hay que tener en cuenta que las APIs OpenGL 4/DX11 en adelante trabajan con múltiples contextos, bueno… Si Vulkan es la referencia entonces estamos hablando de trabajar en múltiples listas de comandos en paralelo en vez de una sola.

Vulkan2

Por otro lado y esto no me lo esperaba (y esto es una edición después de hacer la entrada) por lo visto con GX2 se pueden realizar multiples listas de comandos con múltiples CPUs, el problema es que paradójicamente la GPU no esta diseñada para múltiples contextos:

Captura de pantalla 2016-04-29 a las 17.38.55

Esto ayuda enormemente a reducir la sobrecarga provocada por la CPU a la hora de crear las listas de comandos para la GPU tristemente no trabaja con ellas en paralelo:

Captura de pantalla 2016-04-29 a las 17.41.33

¿El motivo que hay detrás de que se puedan crear 3 listas de comandos gráficos distintas? No se trata de listas de computación… Bueno, esto tiene una explicación bien simple…

nintendo-wii-u-gamepad

La consola soporta hasta 2 DRC (nombre del Wii U Gamepad en el SDK de Wii U/Cafe) y se necesitan 3 listas de comandos gráficos, las cuales no van en paralelo, una para la TV, otra para el mando y otra para el hipotético segundo mando que nunca se ha utilizado en ningún juego.

Captura de pantalla 2016-04-29 a las 17.47.55

Es decir, GX2 es una variación de OpenGL 3 pensada para operar a nivel de CPU con múltiples listas de comandos, por lo que esta preparada en un futuro para un entorno multinúcleo a nivel de CPU en que cada núcleo realice una lista de comandos. Pero las dos listas de comandos para los 2 DRC las voy a dejar de lado por el momento y me voy a centrar solo en el pipeline principal que es el de la HDTV. De entrada si en Wii U/Cafe la GPU trabaja con 2 Wavefronts activos de 3, entonces es posible colocar un tercer Wavefront activo para la computación haciendo que sean 3 Wavefronts activos (2 para gráficos y 1 para computación) aunque esa no tiene porque ser siempre la organización y puede ser de 3+0 (Sin computación), 2+1, 1+2 o 0+3. La consola esta pensada para 720P por lo que…

(1920*1080)/(1280*720)= 2.25.

Como no podemos tener shaders parciales esto redondeando serían unos 448 hilos de ejecución simultaneos, o lo que es lo mismo, unas 7 CUs de la arquitectura GCN ejecutando código por lo que si el mínimo sería colocar los juegos de Wii U de 720P a 1080P con un simple cambio de resolución entonces una GPU con 7 CUs es suficiente, si en cambio se busca ir a los 1080P60 desde los 720P30 entonces estaríamos hablando de 14 CUs, pero se ha de tener en cuenta que la GPU7/GX2 funciona a 550Mhz por lo que puede ser que el número de CUs sea inferior a esa cifra de 14 o simplemente con tal de ahorrar en consumo la velocidad de reloj sea inferior.

En todo caso:

1080P30: 448 Shaders*2 (FMADD)*550 Mhz= 0.493 TFLOPS aprox.

1080P60: 896 Shaders*2 (FMADD)*550 Mhz= 0.986 TFLOPS aprox.

Aunque personalmente pienso que Nintendo va como mínimo a cumplir la especificación mínima del Unreal Engine 4 que es 1 TFLOP.

SweeneyTFLOPS

¿El motivo por el cual tomo los 550 Mhz? Ya os lo comentare más adelante en la segunda parte, por el momento quedaos con esto:

Captura de pantalla 2016-04-29 a las 16.09.21

Más que nada porque es un adelanto a la segunda parte.

Anuncios