AMIGALANDIA

AMIGALANDIA --- Blog Retrospectivo Amiga/MorphOS

sábado, 4 de agosto de 2012

Aros y gráficos 3D


Introducción

En este artículo se describe la historia  del estado actual para del soporte de gráficos 3D compatibles con OpenGL en AROS.

Situación a mediados de  2008

En el mundo del código abierto, la implementación compatible con el API de OpenGL más conocida es la librería Mesa3D. Una librería utilizada en Linux o BSD , implementada de tal modo que portarla a otra sistema sea lo más sencillo posible. Nick Andrews fue el artífice de la librería Mesa3D para AROS. Este port está basado en el de StormMesa creado para AmigaOS.
Estaba basado en la versión 6.5 de Mesa3D y emplea un controlador por sfotware para AROS que emplea la función gráfica WritePixelArray para generar imágenes en ventanas y pantallas de AROS. A pesar de ser el primer intento de ofrecer el API OpenGL, presentaba varios contratiempos.
En primer lugar, mientras que la CPU x86 corría a 1,6 GHz, no era aún suficiente para que el controlador por software rindiese lo necesario hasta para que los juegos más sencillos fueran jugables. Segundo, el port de Mesa3D estaba disponible como librería linkada estáticamente, por ello las aplicaciones  linkadas con esta librería, se debían publicar de nuevo si aparecía un nuevo avance de Mesa3D. Debido a estos problemas, se excluyó el port de la librería Mesa3D de los nightly builds de AROS, no estando tampoco disponible para desarrolladores terceras partes.

La versión Mesa 7.0

A mediados de 2008, me fui interesando por los gráficos 3D OpenGL bajo AROS. Se trataba de una motivación bastante inocente - pretendía correr en AROS el juego MMORPG Eternal Lands de modo que fuera el primer sistema Amiguero en tener un juego MMORPG. Sin embargo había un problema - Eternal Lands es un juego OpenGL, y AROS carecía de soporte OpenGL (de serie).
El primer paso fue recuperar el código de Mesa3D del respositorio de AROS. Tras hablar con Nick y después de varias sesiones de pruebas y fallos, compilé el port existente solamente para darme cuenta de que el cliente de Eternal Lands precisa funciones OpenGL no disponibles en Mesa3D 6.5 . Debía portar la versión más reciente disponible, la 7.0.
Pero las cosas no eran tan sencillas. Las interfaces internas fueron modificadas y el controlador de AROS que funcionaba con la versión Mesa3D 6.5, ya no lo hacía con la 7.0. Esto me llevó a escribir las primeras líneas de código de Mesa para AROS.  Tomando como cimientos el controlador de Nick, implementé un nuevo controlador compatible con la versión 7.0. También modifiqué el modo de dibujado, acelerándolo a expensas de un mayor consumo de memoria. Cuando todo compiló sin problemas y vi "Gears" en pantalla, volví al interés por el cliente Eternal Lands...
... todo para descubrir que el rendimiento no era siquiera aceptable. En una CPU a 1.6 GHz rendía de 1 a 4 cuadros, mientras que usuarios con CPUs más potentes obtenían hasta 15 cuadros por segundo como máximo. Al principio pensé que serían errores obvios en el código, pero al ampliar la búsqueda llegué a la conclusión de que no había nada erróneo. Lo que consume tanto tiempo son las miles y miles de operaciones de coma flotante - algo para lo que una GPU no va a tener problemas, y que una FPU apenas puede manejar.
De un modo eventual publiqué un cliente Eternal Lands para AROS que era jugable en mi equipo, pero debido a las simplificaciones y trucos llevados a cabo la calidad gráfica era muy pobre. Retiré la versión 7.0 de Mesa3D, eliminando su disponibilidad para terceras partes.

Mesa como librería compartida

El año siguiente me centré en varios elementos de AROS. Por Julio de 2009 sin embargo, inspirado por algunos prototipos de Nick, comencé a pensar en publicar mesa como librería compartida. La razón era que mientras que por entonces no disponíamos de controladores por hardware para aplicaciones OpenGL, se podrían tener en un futuro. Si ofrecíamos Mesa3D como librería compartida, los programadores podrían comenzar a trabajar en aplicaciones 3D que aprovecharían las ventajas de "futuribles" controladores por hardware.
Lo primero por hacer era portar la última versión de Mesa3D (7.5). Eran pocos los cambios requeridos y enseguida publicamos una versión de la librería linkada estáticamente. En este momento las cosas se pusieron interesantes.
Mesa3D hace uso de una variable global para representar un contexto de generación de imágenes. Así funciona en Linux y otros sistemas, puesto que el subsistema de librerías compartidas de estos sistemas se encarga automáticamente de generar copias de dichos objetos globales para cada usuario de la librería. En AROS no sucede así -aquí la misma librería debe implementarse de manera que se encargue ella de los objetos de los clientes. Suponía un serio problema. Mesa3D presupone que exista un contexto de generación global, pero el contexto debe ser entonces diferente para cada cliente.
La solución partió de una idea de Nick y del trabajo de Staff Verhaegen en ABI V1. Consistía en crear este contexto de generación global mediante un cliente de la librería Mesa3D para luego hacerlo disponible a la librería en el registro de la CPU. Aunque haya cambios de tarea durante la ejecución de código de la librería Mesa3D, el registro de CPU queda preservado y restaurado más tarde. De este modo ABI V1 hace que la base de la librería este disponible para todas las funciones.
En Agosto de 2009 se publicó la versión compartida de mesa.library. Desde entonces el desarrollo se aceleró.

Gallium3D controlador softpipe

Otra de las sugerencias de Nick fue Gallium3D. Se trata de una novedosa arquitectura de controlador 3D que se suponía sería tremendamente portable e independiente de sistema. Alentado por el éxito de la librería Mesa3D me centré en el controlador softpipe de Gallium3D. Es un controlador por software, semejante al controlador que teníamos en AROS. Pero pensé que al ser una nueva arquitectura, el controlador sería más rápido que el que estábamos empleando. Comencé a portarlo tomando Xlib binding como ejemplo para AROS. Pronto me topé con el primer obstáculo.
Gallium3D softpipe utliza comandos SSE para acelerar los cálculos de coma flotante. El problema sin embargo, es que la versión linux-i386 de AROS que empleaba para casi todos los desarrollos no soportaba el almacenado del estado de los registros SSE. Cada vez que se hacían llamadas a un comando SSE, el controlador se colgaba. Lo positivo es que la versión de AROS pc-i386 sí que tenía soporte para estas instrucciones, y al cabo de unos días porté esta funcionalidad a la versión linux-i386.
El trabajo restante no supuso grandes problemas y a finales de Septiembre de 2009, el controlador softpipe funcionaba.
Era dos veces más lento que el controlador original de AROS. No había lugar para el fracaso, así que sólo había que seguir una dirección - intentar portar estos "extremadamente portables e independientes " controladores por hardware.

Controlador Gallium3D nouveau - Botín Gallium3D

La primera decisión fue - qué controlador había que portar: Intel, nVidia o Radeon. Por entonces, no tenía ni remota idea de cómo funcionaban las tarjetas gráficas de modo que parecía un trabajo gigantesco. Elegí nVidia porque siempre me gustaron esas tarjetas... o quizá por el nombre.  Fuese el motivo que fuese, con la perspectiva del paso del tiempo me doy cuenta de que eran los controladores más sencillos de portar - ideales para comenzar.
Lo primero que descubrí fue que los controladores nVidia de la librería Mesa3D no se hablan directamente con el hardware. Requieren otra capa - denominada (D)irect (R)endering (M)anager. Los controladores Mesa3D compilaron sin problemas puesto que el código drm era específico del SO. La segunda decisión que tomé fue - portar drm o crearlo desde cero para AROS. En principio quise crearlo desde cero basándome en nvidia.hidd, pero según me adentraba en el código, me daba cuenta de que no era la opción acertada. En primer lugar, el código drm contenía soporte para bajo nivel e inicialización de toda la familia de tarjetas nVidia - algo que no existe por ahora en nvidia.hidd. En segundo lugar, el código drm para nVidia está en fase beta aún y contiene muchos errores. Aunque tuviera tiempo de reescribirlo desde el comienzo, actualizar a una nueva de versión de códigos drm sería una auténtica pesadilla. Así decidí portar drm a AROS.
Como el objetivo era portar el código drm para aprovechar las ventajas de futuras actualizaciones, debería facilitarme la aplicación de tales actualizaciones. Por eso pensé en modificar el código lo mínimo posible - implementando funciones del kernel Linux requeridas por ese código. Por fortuna eran pocas las funciones necesarias a implementar - muchas menos de las que yo esperaba.
Realizado el trabajo, y tras varias pruebas con tarjetas nVidia, publiqué una versión alpha de mesa.library con aceleración por hardware en Enero de 2010. Ofrecía soporte para las familias GeForce 5XXX, 6XXX y 7XXX . A los pocos días, ya se habían portado varios juegos 3D, demostrando el potencial de la aceleración 3D en AROS incluso con unos controladores en estado alpha carentes de algunas funcionalidades.

Añadiendo soporte AGP

Tras la primera versión, me tomé un tiempo de descanso en el botín para trabajar en algo que había atrapado mi interés. Durante los tres primeros meses de trabajo con los controladores nVidia, aprendí lo suficiente sobre aspectos de bajo nivel como para comprender cómo funcionaban los controladores con tarjetas PCI. Lo que me intrigaba era cómo funcionaban los controladores con el bus AGP.
Me llevó cierto tiempo estudiar los códigos AGP de Linux. El código varía en función de los fabricantes de placas, pero contaba con partes en común que aparentemente resultaban sencillas - más de lo que pensaba.
La primera vez traté de hacer funcionar AGP en una placa madre SiS. Cotejando los fuentes de Linux, implementé soporte nativo en AROS y en una semana tenía una GeForce 6200 funcionando en modo AGP. Tras este avance, solicité colaboración a la comunidad AROS para ofrecer soporte de otros chipsets. Podía aprender de los fuentes de Linux, pero no podía hacer todas las pruebas  en mi equipo. Gracias a la respuesta de la comunidad, incluí soporte para chips VIA e Intel. Aprendí bastante sobre cachés de CPU lo que me ayudó bastante a la hora de solventar algunos problemas persistentes en el controlador nVidia.
En Febrero de 2009 se incluyó soporte AGP en mesa.library y fue publicado en la comunidad AROS.

Hacer que funcione, y hacerlo bien...

El resultado publicado, si bien funcionaba y era de utilidad para la comunidad AROS, desde el punto de vista del diseño de software era poco aceptable. El controlador por hardware estaba unido físicamente a mesa.library y lo que es peor - funcionaba en paralelo al controlador VESA existente, quizá por mera casualidad. Debía extraer el controlador hardware en un módulo aparte siguiente el sistema de controladores HIDD de AROS. El rasterizador de software (softpipe) debía posicionarse en otro módulo e incorporar una lógica para cuando utilizar el controlador por hardware y cuando volver al controlador por software.
El punto natural de separación entre Mesa y el controlador Gallium3D es la interfaz de Gallium3D. Mesa incorpora un tracker de estado que opera sobre la interfaz de Gallium3D. Se compone de una serie de estructuras con punteros a funciones - una forma muy decente para modelar interfaces en C. Pero este modo no está en la línea del concepto OOP del sistema HIDD. Observando la complejidad de la interfaz Gallium3D y los frecuentes cambios, rechacé la idea de reescribir el sistema HIDD - sería una pesadilla mantener nuevas versiones de Mesa y Gallium3D. En su lugar, opté por una sencilla interfaz HIDD que ofreciera solamente dos funciones principales - crear un nuevo pipe_screen Gallium3D y blit pipe_surface a BitMap. Una vez que Mesa o cualquier cliente Gallium adquiriese pipe_screen mediante el sistema HIDD, seguiría utilizándolo directamente tal y como fue diseñado Gallium3D. Un equilibrio perfecto entre seguir el modelo de diseño de AROS, y facilitar la simplicidad del sistema a la hora de incluir nuevas versiones.

El controlador 2D

El controlador 3D por hardware ya era un módulo separado pero seguía funcionando sólo en modo VESA. Pronto comprendí que sería incapaz de unir el controlador nouveau 3D con el controlador 2D nVidia de AROS. Tendría que ofrecer un nuevo controlador nVidia basado en DRM backbone. Pensé que sería un largo trabajo - lo bueno es que no fue así.
Para comprobar que el controlador 3D funcionaba, porté una gran parte de código DRM a AROS. Al escribir el controlador 2D resultó que casi todo cuadraba. Restaba la inicialización de BIOS y soporte para lectura de datos vía I2C. Era sencillo añadir estos componentes y rápidamente tuve una versión del controlador 2D. Era tremendamente lento...todas las operaciones se realizaban pixel a pixel - sin tipo alguno de aceleración. Hoy es una de las características del sistema de controladores 2D de AROS - esta clase implementa todas las operaciones complejas por medio de los métodos PutPixel/GetPixel - aunque es lento, posibilita la creación de un controlador en poco tiempo.
Una vez estabilizado el controlador, reemplacé las funciones "por pixel" con sus versiones aceleradas. La implementación se basaba en el controlador AROS existente y en el controlador EXA X86. En poco tiempo la comunidad AROS contaba con un controlador 2D acelerado por hardware que funcionaba en tarjetas nVidia desde la GeForce 1 hasta la más nueva GTS250. Gracias al equipo nouveau por vuestro trabajo, por hacerlo código libre y permitir que AROS lo arpoveche.
Unos días después, finalicé el trabajo integrando el controlador 3D en el controlador 2D. Gracias a este cambio se pudo añadir soporte para la familia GeForce 8XXX y superiores. El código estaba presente, pero no funcionaba en modo VESA. Al hacerlo funcionar en una tarjeta controlada por DRM se pudo utlizar correctamente la aceleración 3D.
El 30 de Mayo de 2010, se publicaron dichos módulos.

Estado final

AROS cuenta con nuevos componentes que aprovechan la potencia de las tarjetas gráficas nVidia modernas:
  • mesa.library - implementación del API OpenGL
  • gallium.library - módulo empleado por clientes Gallium3D para adquirir objetos pipe_screen. Por ahora empleado por mesa.library, pero en un futuro - quién sabe ¿ Quizá OpenVG, OpenCL y Cairo?
  • nouveau.hidd - controlador 2D y 3D para tarjetas nVidia
  • softpipe.hidd - controlador por software utilizable en sistemas no nVidia
Aunque el trabajo de este botín ha finalizado, tengo intención de seguir portando nuevas versiones de estos componentes. Siempre que sean desarrollados por sus respectivos equipos, se incorporarán en AROS.

Traducción - Lizard7