Alcanzando los 212 FPS en el M4
¿Cuánto tiempo se tarda en lograr que Minecraft corra a 212fps en un Mac Mini M4, o en hacer que WebGL renderice fluidamente en un navegador? Escribir drivers de Linux para Apple Silicon solía ser un maratón agotador: el driver del kernel de la era M1 fue creado a base de fuerza bruta por Asahi Lina trabajando 12 horas al día. Ahora, los desarrolladores Cody Ho y Niklas han comprimido esta hazaña de ingeniería de varios años en un solo mes, levantando desde cero un driver de GPU compatible con OpenGL ES 3.0.
Aquí no hay filtración de secretos comerciales. Emplearon ingeniería inversa de sala limpia, sin examinar ningún binario de Apple, basándose únicamente en sus propios shaders y en los rastros de ejecución del hardware. En un ecosistema de caja negra, siempre que puedas interceptar las señales de ejecución reales, la comunidad puede construir una alternativa.
Figura: Chrome y Firefox renderizando normalmente con este driver. Fuente: codyho.dev
Apple partió el driver en dos
El mayor obstáculo para escribir drivers en el Apple Silicon moderno es la ABI (Interfaz Binaria de Aplicaciones) de firmware patentada de Apple. Los drivers de kernel tradicionales hablan directamente con el hardware, pero el enfoque de Apple divide el driver en dos: una mitad está incrustada como firmware dentro de un sistema operativo personalizado llamado RTKit, mientras que la otra mitad se comunica con el host a través de estructuras de datos en la memoria compartida.
En los chips M4 y A18 Pro, este mecanismo de comunicación es aún más enrevesado que en la era M1. Las estructuras de datos han aumentado 1,5 veces, los punteros se han duplicado y el flujo de trabajo para enviar trabajos de renderizado es como un laberinto. Los campos propiedad del firmware y los campos controlados por el host están fuertemente entrelazados, lo que dificulta enormemente desenmarañarlo.
El enfoque de fuerza bruta superó a la lectura de manuales
¿Cómo se desentraña este mecanismo? Cody Ho sacó un hipervisor de desarrollo propio para grabar con precisión el comportamiento real del hardware de macOS. Luego, un agente de modelo de lenguaje grande (LLM) fue puesto en la línea de montaje para realizar pruebas a ciegas.
La operación del Agente fue muy directa: esperar a que apareciera el primer evento visible para el firmware y guardar todo el estado de la memoria de la GPU. Después de reiniciar, copiar el estado exacto de vuelta en la memoria del host, desencadenar la ejecución y observar fijamente los cambios de memoria en la página de salida.
Si fallaba, se ajustaban los punteros y los campos, y se volvía a ejecutar. A medida que avanzaban los experimentos, la cantidad de páginas de memoria que requerían copias exactas disminuía, hasta que todo pudo construirse desde cero mediante código. El desarrollo del driver de la GPU pasó de ser una deducción lógica agotadora a un ciclo de ensayo y error de alta frecuencia.
Figura: Minecraft alcanzando 212fps en un Mac Mini M4. Fuente: codyho.dev
Los datos limpios importan más que la potencia de cálculo
Sin embargo, este enfoque de ensayo y error chocó contra un muro en el módulo de Computación (Compute). Bajo una interfaz gráfica, los trabajos de computación siempre se ponen en cola detrás de una enorme cantidad de tareas de renderizado, lo que resulta en rastros de ejecución grabados de hasta 336MB, llenos completamente de ruido irrelevante. El Agente pasó más de una semana intentando construir objetos por sí mismo sin ningún progreso.
La solución se redujo a la intuición de ingeniería: Cody Ho apagó la interfaz gráfica, entró en modo de usuario único y ejecutó un programa diminuto en el instante en que la interfaz gráfica estuvo disponible. Esto capturó un rastro de ejecución de computación puro y mínimo. Estos datos limpios se analizaron en cuestión de horas y el módulo de computación estuvo funcionando con éxito en pocos días. Alimentar a un Agente con 300MB de datos sucios es mucho peor que pasar unas horas construyendo un andamio que genere resultados deterministas.
El bloqueo se convirtió en un acelerador
Apple endureció la cadena de arranque, obligando a la comunidad de código abierto a construir drivers personalizados para poder ejecutar Linux en los Mac. Este camino, que parecía el más difícil, irónicamente se convirtió en un atajo gracias a los mecanismos de grabación y reproducción y a las herramientas automatizadas.
Comprimir años de desarrollo de un equipo en un mes no fue porque el modelo alcanzara de repente una epifanía de bajo nivel. Fue porque los desarrolladores utilizaron un hipervisor para convertir la caja negra de un sistema complejo en un campo de pruebas experimental que podía restablecerse infinitamente con resultados inmediatos. El camino de leer la documentación cerrada del firmware estaba bloqueado, pero el camino de las pruebas a ciegas a través de ciclos de retroalimentación ultrarrápidos estaba completamente abierto.
Referencias:
- Cody Ho: Construyendo un driver de GPU desde cero en un mes
- Proyecto Asahi Linux (Contexto del driver del kernel M1/M2)