- El PR #9312 de la nueva API de GPU de SDL3 se fusionó el 29 de agosto de 2024, y con SDL 3.0 ya cerca, el proceso avanzó rápidamente con un enfoque basado en Refresh para recibir más revisión
- La propuesta consistía en tomar Refresh, el componente gráfico de MoonWorks, como candidato a API final de SDL_gpu; soportaba Vulkan y la API gráfica de PS5, y también estaba en marcha el soporte para D3D11 deferred context
- El diseño de la API usa un modelo moderno de renderizado que divide el trabajo en render pass, compute pass y copy pass, y las operaciones de escritura de recursos están preparadas para hacer cycle internamente y evitar dependencias entre frames
- En la parte de shaders, la propuesta se ajustó desde un enfoque inicial centrado en compilación offline hacia validar soporte para generación de shaders en tiempo de ejecución, y se discutió una estructura donde SDL no envuelva su propio compilador de shaders sino que reciba formatos IR por backend
- Justo después de la fusión continuaron ajustes posteriores como nombres de funciones de la API, macros de configuración de compilación, UTF-8 BOM y el límite de 60 FPS del swapchain en D3D12, y se añadió permiso de commit a thatcosmonaut
Punto de partida del PR y estado de la fusión
- El PR #9312 comenzó como una propuesta de nueva API de GPU para SDL_gpu subida para poder revisarla rápido
- Con SDL 3.0 ya cerca, el objetivo era conseguir “más ojos” lo antes posible
- Se fusionó el 29 de agosto de 2024 tras la confirmación
It's merged
- Justo después de la fusión hubo una solicitud de pausar cambios por un momento y avanzar con revisión y ajustes
- Más tarde quedó en estado
everything is merged, y se indicó que ya se podían volver a fusionar cambios del lado de GPU - thatcosmonaut fue añadido con permiso de commit porque probablemente revisaría los cambios entrantes
- Más tarde quedó en estado
Candidato de API basado en Refresh
- El centro de la propuesta era tomar Refresh, el componente gráfico de MoonWorks, como candidato a API final de SDL_gpu
- MoonWorks se presentó como un proyecto más cercano a un sucesor de XNA que a una reimplementación de XNA como FNA
- Refresh es similar a FNA3D, pero apunta a APIs modernas como Vulkan
- En ese momento Refresh soportaba Vulkan y la API gráfica de PS5
- El soporte para D3D11 deferred context estaba en progreso
- Se mencionó que ya estaba en uso en producción en Samurai Gunn 2 para PC y consolas
- El autor del PR indicó que thatcosmonaut sería el contacto principal y que el equipo central de FNA también participaría en el proceso
Diseño de la API y manejo de recursos
- La API está compuesta como una API moderna de renderizado centrada en deferred context
- El trabajo se divide en render pass, compute pass y copy pass
- Se explicó que el resto de la API tiene una forma estándar cercana a llamadas de binding, render y compute dispatch
- Todas las operaciones que escriben a recursos pueden evitar dependencias entre frames mediante cycle
- Los handles de recursos gráficos como
GpuBufferscumplen el rol de contenedores para ciclar referencias internas a recursos - Más adelante, el concepto de cycle se simplificó a un bool y se eliminaron varios enum
WriteOptions
- Los handles de recursos gráficos como
- Al principio existían varios enum
WriteOptionspor problemas de comportamiento de la API de datos relacionados con drivers AMD para D3D11- Se explicó que no había sido posible esquivar por completo el hecho de que la API de datos de D3D11 no se comportara como se esperaba en AMD
- Más adelante esta parte se simplificó y el modo de funcionamiento quedó documentado en el código
Discusión del sistema de shaders
- La solución inicial para shaders era un script llamado
shaderbuild.py- Cumplía el rol de frontend para herramientas de compilación offline de shaders en la máquina del cliente
- La estructura agrupaba varios formatos y los entregaba según el backend de render correspondiente
- Se explicó que este enfoque no impedía la compilación de shaders en línea
- Se mencionó que en el futuro sería posible incluir fuentes SDLSL en el binario y convertirlas al vuelo al bytecode requerido por el backend en
CreateShaderModule - Se planteó como ventaja que permitiría compilación en línea sin romper la API pública
- Se mencionó que en el futuro sería posible incluir fuentes SDLSL en el binario y convertirlas al vuelo al bytecode requerido por el backend en
- En comentarios externos surgió la preocupación de que una compilación puramente offline no encajara con ciertos engines
- Se señaló que exigir Python,
glslcyspirv-crossen el PATH podía ser incómodo para desarrolladores - También surgió la opinión de que, dentro del ecosistema SDL, una herramienta de compilación offline de shaders como librería satélite separada podría sentirse más natural
- Se señaló que exigir Python,
- Después, el sistema de shaders se ajustó hacia una distinción entre shaders “raw” y shaders “portable”
- Se usó el port de FNA3D como prueba de estrés para validar el soporte de generación de shaders en tiempo de ejecución
- Se mencionó una configuración que usa el emisor SPIR-V de MojoShader para pasar directamente a Vulkan y convertir en otros backends mediante la librería opcional separada SDL_shader
- El objetivo era que SDL en sí no supiera ni tuviera que preocuparse por de dónde venían los shaders
Backends y avance de las pruebas
- La implementación inicial basada en Refresh fue valorada positivamente por contar ya con un backend de Vulkan
- Hubo opiniones de que el backend de Vulkan tenía buen rendimiento en Refresh 2.0
- También se señaló que compute fuera una capacidad de primera clase como una diferencia importante frente al borrador anterior de SDL_GPU
- Entre finales de marzo y principios de abril de 2024 se compartieron varios casos reales de ejecución de juegos
- Se explicó que ya se había llegado a un estado funcional sin compilación offline de shaders
- Se compartió una revisión actual en la que Streets of Rage 4 arrancaba
- Wizorb corría en Metal
- Celeste entraba en estado in-game en una parte considerable de la base de datos de trazas
- También avanzó la incorporación de funciones
- Se mencionó que el soporte para hardware instancing se añadiría en el siguiente push
- Más adelante se incorporaron instancing y occlusion queries, y se compartió que faltaba completar la implementación del lado de Metal
Problemas de compilación, API y plataforma surgidos en la revisión
- Por el orden de los include de Vulkan apareció un error de redefinición de typedef para
VkInstanceyVkSurfaceKHR- Se propuso como corrección cambiar el orden de include entre los headers de Vulkan y
SDL_vulkan.henSDL_gpu_vulkan.c - También se propuso una corrección para silenciar la advertencia de que
suitableQueueFamilyIndexpodría no estar inicializado, inicializándolo en 0
- Se propuso como corrección cambiar el orden de include entre los headers de Vulkan y
- También se planteó la necesidad de actualizar dynapi
- Se indicó que podía actualizarse ejecutando
gendynapi.pybajosrc/dynapi/ - Se añadió la advertencia de que al ejecutarlo aparecían muchos warnings por documentación faltante
- Se indicó que podía actualizarse ejecutando
- Se propuso cambiar el tipo de tamaño en bytes de las firmas de funciones de la API a
size_t, pero la conclusión fue mantenerUint32en la API de GPU- Hubo comentarios de que, cuando el tamaño del buffer fuera muy grande, podría volverse difícil mantener compatibilidad simultánea entre 32 y 64 bits
- Como alternativa se mencionó
Uint64, pero al final se planteó mantenerUint32
Ajustes posteriores a la fusión
- Después de la fusión, en #10622 se hicieron varios ajustes
- Se indicó que primero se fusionarían los nuevos nombres de funciones para que los usuarios beta pudieran recibirlos
- El problema de que en la configuración de compilación debían estar definidas las macros de la derecha, como
SDL_GPU_VULKAN SDL_VIDEO_VULKANySDL_GPU_METAL SDL_VIDEO_METAL, se corrigió en #10622 - El problema de UTF-8 BOM en los archivos fuente de GPU también se corrigió en #10622
- Del lado de D3D12 se confirmó que
D3D12_ClaimWindow()configuraba el swapchain con VSYNC, haciendo quetestspritequedara limitado a 60 FPS- Se explicó que el comportamiento esperado del workflow era crear el swapchain en la etapa de claim window con parámetros de soporte general como SDR y VSYNC, y luego consultar soporte antes de llamar a
SetSwapchainParameters - Aunque el render driver estaba llamando a
SetSwapchainParametersdespués del claim, el límite de 60 FPS seguía presente en el driver D3D12 y quedó bajo investigación
- Se explicó que el comportamiento esperado del workflow era crear el swapchain en la etapa de claim window con parámetros de soporte general como SDR y VSYNC, y luego consultar soporte antes de llamar a
1 comentarios
Opiniones de Hacker News
SDL3 todavía está en etapa de vista previa, pero la nueva API de GPU ya se fusionó en la rama principal y los mantenedores de SDL3 están haciendo los últimos ajustes.
Según entiendo, el punto central de esta nueva API de GPU es que permite escribir el código gráfico y los shaders una sola vez para que funcionen sin demasiadas complicaciones en varias plataformas, incluidas las consolas. Antes se necesitaba Unity, Unreal o alguna solución personalizada propia.
WebGPU/WGSL también es un stack gráfico multiplataforma similar, pero hasta donde sé nadie ha creado un backend para consolas. En cambio, parece que la API de GPU de SDL3 actualmente no admite WebGPU como backend.
Me entusiasma SDL3 porque introduce una abstracción para consolas, así que la API de GPU ya no necesitaría dependencias adicionales. Además, Godot soporta oficialmente Steam Deck, y espero que en el futuro soporte más consolas. Relacionado con eso, Miguel de Icaza está impulsando la adopción de Swift en Godot y también está trabajando en portar el editor a SwiftUI en iPad. El avance [3] es interesante.
[1] https://bkaradzic.github.io/bgfx/overview.html
[2] https://github.com/bgbernovici/myndsmith
[3] https://blog.la-terminal.net/xogot-code-editing/
Hay más contexto aquí: https://icculus.org/finger/flibitijibibo?date=2024-06-15&time=13-14-16
Tengo curiosidad por ver cómo se asentará esta tendencia. Al final, sería bueno tener más opciones para crear motores de juegos y apps personalizados.
Últimamente me estoy metiendo a fondo con Vulkan; aprenderlo es divertido y deja muchas enseñanzas, pero por la naturaleza de Vulkan el avance se siente lento. Si SDL3 hubiera existido cuando empecé, probablemente lo habría elegido con gusto, y creo que tendría más resultados para mostrar por el tiempo invertido.
Solo el tiempo dirá si esta API realmente es usable. En particular, serán clave la sincronización de recursos y la forma de renombrar objetos.
También habrá que ver si rinde mejor que WebGPU u otras abstracciones. Y habrá que observar si puede seguir manteniéndose pequeña incluso en situaciones donde haya que esquivar bugs de drivers.
También soy escéptico respecto del nuevo bytecode para lenguajes de shading. En WebGPU, el parseo de shaders en runtime no era una preocupación y es muy rápido. La generación de shaders nativos también es rápida [1]. Lo lento es la creación de pipelines, y este bytecode no ayuda con eso.
[1] http://kvark.github.io/naga/shader/2022/02/17/shader-translation-benchmark.html
Me pregunto cómo lo lograron tan rápido. WebGPU nativo lleva mucho tiempo en desarrollo y todavía no está finalizado, mientras que la API GPU de SDL soporta más plataformas, así que parecía que más bien iba a tardar más
Hay un proyecto hermano [1] para un lenguaje de sombreado multiplataforma y otro proyecto [2] para convertir entre lenguajes existentes, pero estarán listos cuando estén listos, y el resto de la API no necesita esperarlos
WebGPU es el resultado de un comité de proveedores y abogados del lenguaje, o abogados de estándares, creado entre política y burocracia, y se nota. SDL_GPU fue hecho por desarrolladores de juegos que valoran la practicidad por encima de todo, y por eso a veces se lo menosprecia desde la torre de marfil
[1]: https://github.com/libsdl-org/SDL_shader_tools
[2]: https://github.com/flibitijibibo/SDL_gpu_shadercross
Me alegra haber contribuido a la parte de dx12 :)
Quizá lo pruebe. SDL siempre me ha parecido software de buena calidad. Compila rápido, compila fácilmente en varias plataformas y siempre funciona bien. Así que tengo expectativas para esta nueva API
En general soy un gran fan de SDL
Cuando busqué una biblioteca de juegos multiplataforma, SDL y su API me parecieron el equilibrio justo. Solo quería una biblioteca C/C++ a la que pudiera llamar para crear una ventana y un contexto gráfico, y un framework rápido para renderizar sprites. No necesitaba un IDE completo ni una biblioteca enorme, y tampoco quería aprender un lenguaje nuevo
Siento que SDL3 está sufriendo el efecto del segundo sistema. SDL2 era básicamente SDL1 con manejadores de ventana explícitos, así que SDL3 es el segundo sistema, no el tercero. SDL1/2 eran una capa delgada que envolvía el boilerplate específico de cada plataforma para abrir una ventana y manejar eventos de entrada, y permitían llegar rápido al código de renderizado OpenGL que realmente quería escribir
Pero si además quieres soportar los sistemas operativos de Apple, quedas atado a OpenGL 4.1. Apple lo marcó oficialmente como obsoleto hace 5 años, así que no puedes usar funciones modernas de GPU como compute shaders
También podrías ir por la ruta de Vulkan y usar MoltenVK en sistemas Apple, pero Vulkan aumenta bastante la complejidad frente a OpenGL. Como suele decir la gente, es del nivel de “1000 líneas de código para un solo triángulo”. El objetivo de la API GPU de SDL3 es ofrecer una alternativa más accesible pero aun así suficientemente flexible
En consolas probablemente sea una historia parecida
Dicen que mucha gente pidió “algo como SDL_render, pero con soporte de shaders que funcione en todas las plataformas”, y ese fue el punto de partida
SDL3 también agrega una API de audio de más alto nivel, pero no conozco bien sus ventajas
Además, SDL2 evolucionó bastante desde 2.0.0, y SDL3 continúa esa evolución permitiendo cambios que rompen compatibilidad de API. SDL3 no fue reescrito desde cero, y creo que para los usuarios de SDL pasar de SDL2 a SDL3 no será tan difícil
Y SDL1/2 tampoco fueron nunca “solo delgados” al punto de no tener su propio sistema gráfico de alto nivel. Es útil que venga algo incluido para que usuarios nuevos o básicos puedan mostrar algo en pantalla de inmediato
Como señaló ahefner, SDL1 era bastante “delgado” según estándares modernos, pero ofrecía lo suficiente para dibujar cosas básicas en pantalla sin tener que escribir matemáticas de píxeles directamente, y en los 90 eso ayudaba bastante
Aun así, esta abstracción podría satisfacer necesidades que van más allá de juegos 2D simples, y permitir apuntar a un ecosistema de APIs gráficas que, por desgracia, está cada vez más fragmentado. El sueño de un futuro OpenGL(Next) universal desapareció. Aunque la parte más difícil, la conversión de shaders, parece que todavía no está ahí
Nunca he usado esta biblioteca, pero si entendí bien el hilo enlazado, ahora me gustaría ver ejemplos de la función de cómputo GPU multiplataforma que ofrece. Me pregunto si hay alguna recomendación sobre por dónde empezar