Gráficos en Consolas Antiguas (XX): Nintendo64

Le toca el turno a la 64 bits de Nintendo y con ella terminamos la serie.

4-original-nintendo-64

Las entrañas de la consola se pueden ver en la siguiente imagen:

rev4n64smallselected

Las dos piezas rectangulares es la memoria RAM del sistema, la que esta justo encima es el Reality Co-Processor, el chip a la izquierda es la CPU del sistema.

CPU

El NEC VR43000, una versión del MIPS R4300i fabricada por NEC para Nintendo, era la CPU de N64. Con unos 93.75Mhz, dicha CPU estaba sobre el papel una generación por encima de la de PlayStation llegando a ser teóricamente más de tres veces más potente que la CPU del R3000A de PlayStation.

R4300i

Mientras que el R3000A de PlayStation tenía tres co-procesadores aquí solo tenemos uno (el COP0) que se encarga de dos funciones por un lado la MMU (no confundir con la unidad DMA) y por otro lado de las interrupciones del sistema. Dicho COP0 es muy similar a la unidad B/U del R3000A de PlayStation pero sin las funciones DMA de este ya que el controlador de memoria y la unidad DMA se encontraba en el RCP.

RAM del sistema.

N64 tiene unos 4 MB de memoria RAM del tipo RDRAM, la velocidad de reloj de la misma es de 250 Mhz pero con un ancho de banda de 9 bits y siendo el bus bidireccional (lectura+escritura) dando un ancho de banda de 562.5MB/seg sobre el papel.

El controlador de memoria y la unidad DMA se encontraban en el RCP. La consola podía expandir la memoria a 8MB a través del expansion pak, pero dicha memoria no aumentaba el ancho de banda de la misma.

El problema de la latencia.

El problema de la RDRAM es que su latencia depende de la distancia existente entre el procesador y el controlador de memoria, en el caso de N64 la CPU no tenía acceso directo a la memoria y tanto la unidad DMA (encargada de controlar el tráfico hacía la memoria de los diferentes procesadores) como el controlador de memoria RDRAM (encargado de realizar la comunicación de la unidad DMA con la RDRAM) se encuentran en otro chip. Esto añadía una latencia enorme para el acceso a la memoria por parte de la CPU. Sí encima a esto le añadiamos que la RDRAM solía tener una mayor latencia que la SDRAM pues teníamos una situación donde la potencia de la CPU quedaba altamente reducida por culpa de este problema.

PlayStation 2, otra consola en la historia que utilizo RDRAM tenía el controlador de memoria dentro del Emotion Engine para disminuir la latencia. En el caso de Gamecube esta heredo la arquitectura general de N64 pero escogio una RAM con menor latencia (1T-SRAM de MoSys) y añadió una cache de segundo nivel a la CPU para paliar el problema de la latencia.

¿Pero como afectaba esto al rendimiento gráfico? Pues teniendo en cuenta que la CPU es el primer componente en el pipeline gráfico, realmente mal. Hay que recordar que la primera etapa en el renderizado 3D es la de aplicación que depende de la CPU y una CPU con un cuello de botella en ese aspecto significa que las etapas posteriores se ven afectadas y en N64 se veían altamente afectadas y de ahí las tasas de fotogramas tan bajas en los juegos.

N64pipeline

El resultado eran juegos con una tasa de fotogramas por segundo muy baja en comparación con la competencia directa. Lo cual significa que el sistema era altamente defectuoso en cuanto al diseño y el funcionamiento del mismo y pese a su enorme potencia todo se iba por el fregadero por culpa del problema de la latencia.

Cartuchos.

La diferencia entre un cartucho y el CD-ROM es que el cartucho se puede tratar como una memoria más mientras que el CD-ROM requiere volcar los datos a memoria. En el desarrollo de Nintendo64 tuvieron el dilema de CD-ROM o más memoria y dado que SGI creía que la memoria no bajaría de precio pensaban que poner más memoria a la consola les daría una ventaja sobre la competencia. Esto lo comente en una entrada hace unos tres años.

La CPU y el RCP podían acceder a los datos de los cartuchos con un bus paralelo al de la memoria RAM. El ancho de banda de los cartuchos dependía de la velocidad de la ROM en estos, que podía ir de los 5MB/seg a los 20MB/seg dependiendo del tipo de ROM utilizada en los cartuchos. Lo habitual era copiar los datos del cartucho a la RAM del sistema pero si al ancho de banda de las ROMs era lo suficientemente alto entonces la CPU podía leer los datos que no son sensibles al ancho de banda desde el cartucho sin tener que pasar por la RAM.

RCP

El Reality Co-Processor funciona  a 62.5Mhz. El esquema del RCP es el siguiente:

1-2-3-2

Esta compuesto por tres piezas fundamentales dentro, la primera de ellas es el controlador de memoria y la unidad DMA de la consola, el segundo es el subsistema gráfico que esta compuesto por dos procesadores llamados Reality Signal Processor y Reality Display Processor,el tercero la unidad de E/S. Me centrare solo en el RCP y el RSP.

El RSP es un MIPS R4300i como la CPU pero su tarea no es hacer de CPU sino encargarse de:

  • La geometría de la escena
  • Generación del Audio de los juegos.
  • Procesador de Comandos del Sistema Gráfico.

No obstante no es igual a la CPU por varios motivos:

  • Carece de registros de 64 bits.
  • La unidad de prediccion de saltos ha sido eliminada.
  • Las instrucciones de multiplicación y división por enteros no se encuentran disponibles.
  • Como se puede ver en el diagrama de arriba su cache datos e instrucciones es mucho menor.

En cuanto a su configuración en co-procesadores es distinta a la de la CPU, el COP0 fue sustituido por una unidad vectorial. Este tipo de unidades permiten aplicar una misma instrucción por ciclo a una colección de datos por ciclo de reloj. Lo cual va muy bien en la manipulación de vertices ya que la mayoría de instrucciones de la geometría de escena se basan en aplicar la misma instrucción en diferentes operandos.

Aunque a simple vista su funcionalidad es la misma que la del GTE de PlayStation la diferencia es que la unidad vectorial del RSP es de proposito general y o específico por lo que no es una colección de máquinas de estado realizando una serie de operaciones de cara el 3D. Al ser una unidad de proposito general, y dado que el RSP es un R4300i modificado lo que hace es ejecutar una lista de instrucciones de forma recursiva que se encuentran en su cache de instrucciones. En este aspecto su comportamiento era muy parecido al de la GPU de Jaguar, ejecutaba un micro-código que marcaba como se tenía que comportar el RSP. A lo largo de la vida de la consola aparecieron varios micro-códigos distintos:

  • Fast3D: El oficial de SGI y Nintendo es el que es más preciso en cuanto a imagen pero el menos adecuado para un videojuegos debido a que sacrifica velocidad por precisión de imagen. No obstante los desarrolladores externos a Nintendo y Rare no pudieron acceder a las entrañas del RSP para modificar el micro-código hasta muy avanzada la vida de la consola.Su rendimiento era de 100K poligonos/segundo en modo “1-Cycle” y 50K poligonos/segundo en modo “2-Cycle”.
  • Turbo3D: No utilizado en los juegos, desactivaba el bufer de profundidad, la corrección de perspectiva y renderizaba solo en modo “1-Cycle” con un rendimiento de 600K pol/seg. Nintendo nunca dejo que este modo fuese utilizado en ningún juego comercial.
  • Micro-códigos específicos: Desarrolladores como Boss Game Studios, Factor5, Rare y otros llegaron a desarrollar sus propios micro-códigos.
  • Sprite 2D: Utilizado en los juegos en 3D de la consola.

La forma en que la CPU se comunicaba con el RSP para enviarle el microcódigo primero y las listas de pantalla no era a través de un bus de comunicación directo sino que escribía la lista de instrucciones y datos en la RDRAM, dada la latencia entre la CPU y la RDRAM esto era un problema enorme de rendimiento. Nintendo en Gamecube soluciono esto haciendo que la CPU se pudiese comunicar con el subsistema gráfico sin pasar por memoria.

Conexión RSP-RDP

Un bus de 128 bits a 62.5Mhz, esto significa una conexión de 1GB/seg, más que suficiente para pasarse datos sin ningún tipo de limitacion y/o cuello de botella.

Reality Display Processor

Rasterizer

N64 fue la primera consola de videojuegos en tener un rasterizador/triangle setup por hardware que realizaba dicha tarea de forma automática.

Z-Buffer

Cuando el rasterizador proyecta en un espacio 2D los datos 3D que le ha enviado el RSP tiene la opción de almacenar los datos de profundidad de cada pixel en un búfer de profundidad.  N64 no fue la primera consola en tener un búfer de profundidad, ese honor le pertenece a Jaguar. Pero la primera en tener una implementación que fue “usable” fue en N64.

El handicap del Z-Buffer en N64 es que de los 9 bits por ancho de banda de la RDRAM utilizaba el noveno para el dicho búfer. Teniendo en cuenta que la tasa de relleno del RCP es de 62.5 Mpixeles/seg y el Z-Buffer es de 2 bytes (16 bits) entonces se necesitarían unos 125 Mbytes/seg, pero el sistema de memoria de la consola solo otorgaba unos 62.5 Mbytes/seg para esta tarea por lo que la tasa de relleno general del sistema pasaba a ser de 31.5 Mpixels/seg ya que tanto el búfer de profundidad como el de color han de ser parejos y por tanto el uso del búfer de profundidad reducía la tasa de relleno a la mitad.

Texture Unit

El Texture Engine hace el mismo trabajo que el de cualquier otra unidad de texturas vista hasta ahora pero tiene la particularidad de que las texturas solo pueden ser de 4KB como máximo. El motivo por el cual N64 solo puede leer las texturas desde la cache de texturas para procesarlas tiene una explicación muy simple y es que el Texture Filter realiza el filtrado texturas bilineal y necesita unos 4 accesos a la memoria por pixel a procesar, si no se tuviese la cache de texturas entonces la RAM no podía dar el suficiente ancho de banda de lectura para aplicar este filtro gráfico.

La ventaja de PlayStation respecto a N64 es que si no encontraba la textura en la cache de texturas entonces se ponía a leerlas de la página de texturas de la VRAM sin perdida de rendimiento alguno. La cache de texturas de N64 tendría que haber sido capaz de almacenar texturas a una resolución de 256×256 pixeles y 16 bits de color. Esto son unos 128KB de cache de texturas, lo cual era prohibitivo para la época. La otra solución hubiese sido aumentar el ancho de banda de la consola hasta los 62.5*2*4 bytes de ancho de banda, lo cual también era prohibitivo. Por lo que la mejor opción hubiese sido colocar una cifra mayor que los 4KB de cache de texturas.

Con tal de paliar el problema de la cache de texturas los desarrolladores utilizaban varios trucos, en los juegos que no eran de corte realista se utilizaban texturas de 16 colores+Gouraud Shading, otros en cambio separaban las texturas en grupos pequeños en comparación a sus contrapartidas en otros sistemas.  Esto se ve muy bien comparando los assets de las versiones de Resident Evil 2 de N64 y PSX donde las texturas en el caso de N64 han sido fragmentadas en otras más pequeñas:

RE2N64

¿La ironía? En PSX y Saturn se utilizaban grandes cantidades de polígonos en N64 se utilizaba unos pocos pero muy grandes, el motivo de de ello es el texturizado con corrección de perspectiva, gracias a que N64 utilizaba un búfer de profundidad era posible texturizar poligonos de gran tamaño sin que esto se vieran distorsionados. La diferencia entre el texturizado con corrección de perspectiva y sin él se puede ver en el siguiente video:

Esto que en principio era una ventaja se convertía en una desventaja por los 4KB de texturas. Sabéis lo que ocurre cuando estiramos una imagen muy pequeña en un espacio muy grande? Pues esto es lo que le pasaba a N64 en areas donde utilizaba polígonos muy grandes. Dado que el tamaño máximo era solo de 32×32 pixeles esto perjudicaba la calidad de las texturas cuando estas se alargaban.

Color Combiner

El Color Combiner es unidad Fragment/Pixel Shader primitiva, para entender su funcionamiento tenemos que entender el concepto de los Shade Tree de Robert L. Cook.

captura-de-pantalla-2013-02-23-a-las-11-21-42-1

La idea de los Shade Tree es la de generar una textura de forma procedural a través de operaciones con sucesivos valores del color y el alpha hasta conseguir el resultado deseado. En el caso de Nintendo64, SGI implemento una pieza llamada Color Combiner en el pipeline gráfico.

Captura de pantalla 2013-05-16 a las 14.52.46Captura de pantalla 2013-05-16 a las 14.54.50Captura de pantalla 2013-05-16 a las 14.55.50

Uno de los efectos curiosos que permitía el Color Combiner era el Mario Metal de Super Mario 64.

246950-super-mario-64-nintendo-64-screenshot-metal-mario-in-hazy

El Color Combiner de N64 podía trabajar con una textura o con dos texturas para realizar sus operaciones.

Captura de pantalla 2013-05-16 a las 13.25.13

Captura de pantalla 2013-05-16 a las 12.09.09

El Color Combiner se encargaba de muchos de los efectos visuales de la consola y Nintendo lo hizo evolucionar en Gamecube siendo el conocido TEV de dicha consola. La diferencias respecto a su sucesor es que mientras Gamecube tenia una enorme cache de texturas desde la que operaba con varias texturas, en N64 solo se podía operar con una textura en memoria, esto significa que lo que se hacía era cargar la textura en la cache de texturas, procesarla y a continuación volverla a cargar en el siguiente ciclo. Esto obviamente reducía la tasa de relleno a la mitad y si tenemos en cuenta que la tasa de relleno ya se veía afectado por el búfer de profundidad entonces tenemos que utilizando el renderizado en dos ciclos la tasa de relleno acaba sien

Blender y Tasa de Relleno

Se le llama Blender por el hecho que trabajo es el mezclar los pixeles creados por la unidad de texturas con los píxeles del búfer de imagen. Es en esta etapa se realiza el Anti-Aliasing por un lado y por el otro el Alpha Blending (efectos de semi-transparencia). Hay que tener en cuenta que la aplicación de ambos efectos en los juegos reduce aún más la tasa de relleno de la consola y aquí es donde entra el problema que antes quería comentar.

El rendimiento de la tasa de relleno dependía directamente del modo gráfico utilizado:

N64Fillrate

Sí el RDP no tenía que texturizar nada (flat shading) o en su defecto la composición era de una imagen 2D entonces su tasa de relleno era de 250 Mpixeles/seg con 16 bits de color y 125 Mpixeles/seg con 32 bits de color. COPY se refiere a copiar un sprite/patrón/textura ya generado y en cuanto a 1CYCLE y 2CYCLE se refiere a la tasa de relleno respecto si utilizamos efectos gráficos que requieren uno o dos ciclos completos para generarse (ver la sección del Color Combiner de más arriba).

Hay que tener en cuenta que debido a la implementación del búfer de profundidad en el caso de los modos “1-Cycle” y “2-Cycle” la tasa de relleno se reducía directamente a la mitad. No es que N64 estuviese limitado por geometría sino que estaba limitado en cuanto a la tasa de relleno.

Resolución y Búfer de Imagen

La RDRAM era de doble canal por lo que el sistema soportaba doble búfer, así pues al igual que el resto de sistemas de la época podía generar el búfer de imagen mientras se estaba leyendo el generado previamente para ser enviado al televisor.

N64 soportaba las siguiente resoluciones:

  • 256×224
  • 320×240
  • 640×480 (no-entrelazado)

La última resolución se utilizaba con los juegos que utilizaban la expansión de memoria aprovechando la mayor densidad de memoria disponible en el sistema para almacenar los búfers de imagen.

En fin, con esta entrada termino la serie.

Anuncios