A nova API de GPU do SDL3 foi mesclada
(github.com/libsdl-org)- O PR #9312 da nova API de GPU do SDL3 foi mesclado em 29 de agosto de 2024 e, com o SDL 3.0 se aproximando, o processo avançou rapidamente com uma abordagem baseada no Refresh para receber mais revisão
- A proposta adotava o Refresh, componente gráfico do MoonWorks, como candidato final de API para o SDL_gpu, com suporte a Vulkan e à API gráfica do PS5, enquanto o suporte a D3D11 deferred context ainda estava em andamento
- O design da API usa um modelo moderno de renderização que divide o trabalho em render pass, compute pass e copy pass, e as operações de escrita em recursos podem fazer cycle internamente para evitar dependências entre frames
- No lado dos shaders, a proposta inicial centrada em compilação offline foi ajustada para validar suporte à geração de shaders em tempo de execução, e discutiu-se uma estrutura em que o próprio SDL não encapsula um compilador de shaders, mas recebe formatos de IR específicos de cada backend
- Logo após a mesclagem, seguiram-se ajustes em nomes de funções da API, macros de configuração de build, UTF-8 BOM e na limitação de 60 FPS do swapchain no D3D12, e thatcosmonaut recebeu permissão de commit
Ponto de partida do PR e estado da mesclagem
- O PR #9312 começou como uma nova proposta de API de GPU para que o SDL_gpu pudesse ser revisado rapidamente
- O objetivo era conseguir “mais olhos” o quanto antes, com o SDL 3.0 se aproximando
- Em 29 de agosto de 2024, ele foi mesclado após a confirmação
It's merged
- Logo após a mesclagem, houve um pedido para pausar mudanças por um momento e prosseguir com revisão e ajustes
- Depois disso, chegou-se ao estado
everything is merged, com o aviso de que mudanças do lado de GPU podiam voltar a ser mescladas - thatcosmonaut foi adicionado com permissão de commit porque havia grande chance de revisar as mudanças recebidas
- Depois disso, chegou-se ao estado
Refresh como candidato de API
- O centro da proposta era usar o Refresh, componente gráfico do MoonWorks, como candidato final de API para o SDL_gpu
- O MoonWorks foi apresentado como um projeto mais próximo de um sucessor do XNA do que de uma reimplementação do XNA como o FNA
- O Refresh é semelhante ao FNA3D, mas voltado para APIs modernas como Vulkan
- Na época, o Refresh suportava Vulkan e a API gráfica do PS5
- O suporte a D3D11 deferred context ainda estava em desenvolvimento
- Foi apresentado como usado em produção em Samurai Gunn 2 para PC e consoles
- O autor do PR informou que thatcosmonaut seria o principal ponto de contato, e que a equipe principal do FNA também participaria do andamento
Design da API e tratamento de recursos
- A API é composta como uma API moderna de renderização centrada em deferred context
- O trabalho é dividido em render pass, compute pass e copy pass
- O restante da API foi descrito como um formato padrão, próximo de chamadas de binding, render e compute dispatch
- Toda operação que escreve em recursos pode evitar dependências entre frames por meio de cycle
- Handles de recursos gráficos como
GpuBuffersfuncionam como contêineres para ciclar referências internas de recursos - Depois, o conceito de cycle foi simplificado para um bool, e vários enums
WriteOptionsforam removidos
- Handles de recursos gráficos como
- Inicialmente, existiam vários enums
WriteOptionspor causa de problemas de comportamento da API de dados ligados a drivers AMD no D3D11- Foi explicado que não era possível contornar completamente o fato de a API de dados do D3D11 não funcionar como esperado na AMD
- Depois, essa parte foi simplificada e a forma de funcionamento passou a ser documentada no código
Discussão sobre o sistema de shaders
- A solução inicial para shaders era um script chamado
shaderbuild.py- Ele funcionava como camada frontal para ferramentas de build offline de shaders na máquina do cliente
- A estrutura agrupava vários formatos e os entregava de acordo com cada backend de renderização
- Esse método foi descrito como um design que não impede a compilação online de shaders
- Foi explicado que, no futuro, seria possível embutir código-fonte SDLSL no binário e convertê-lo imediatamente no bytecode necessário para o backend em
CreateShaderModule - A vantagem apontada era permitir compilação online sem quebrar a API pública
- Foi explicado que, no futuro, seria possível embutir código-fonte SDLSL no binário e convertê-lo imediatamente no bytecode necessário para o backend em
- Em feedback externo, surgiu a preocupação de que compilação puramente offline não combinaria com certas engines
- Apontou-se que exigir Python,
glslcespirv-crossno PATH poderia ser incômodo para desenvolvedores - Também houve a opinião de que, no ecossistema SDL, uma ferramenta de compilação offline de shaders em forma de biblioteca satélite separada poderia ser mais natural
- Apontou-se que exigir Python,
- Depois, o sistema de shaders foi ajustado para distinguir entre shaders “raw” e “portable”
- Um port do FNA3D foi usado como teste de estresse para suporte à geração de shaders em tempo de execução
- Foi mencionada uma configuração que usa o emissor SPIR-V do MojoShader para envio direto no Vulkan e conversão nos outros backends via a biblioteca opcional separada SDL_shader
- O objetivo era que o próprio SDL não soubesse nem se importasse com a origem do shader
Backends e andamento dos testes
- A implementação inicial baseada no Refresh foi vista como forte por já ter um backend Vulkan pronto
- Houve a avaliação de que o backend Vulkan tinha alto desempenho com base no Refresh 2.0
- O fato de compute ser um recurso de primeira classe também foi apontado como uma diferença importante em relação ao rascunho anterior do SDL_GPU
- Do fim de março ao início de abril de 2024, foram compartilhados vários casos reais de execução de jogos
- Foi dito que se chegou a um estado funcional sem compilação offline de shaders
- Foi compartilhada a revisão atual em que Streets of Rage 4 inicializa
- Wizorb roda no Metal
- Celeste entra em estado in-game em boa parte do trace database
- A adição de recursos também avançou em paralelo
- Foi mencionado que suporte a hardware instancing seria adicionado no próximo push
- Depois, instancing e occlusion queries entraram, e foi compartilhado que ainda faltava completar a implementação no Metal
Questões de build, API e plataforma levantadas na revisão
- Por causa da ordem dos includes de Vulkan, ocorreram erros de redefinição de typedef de
VkInstanceeVkSurfaceKHR- Foi proposta uma correção trocando a ordem de inclusão dos headers Vulkan e
SDL_vulkan.hemSDL_gpu_vulkan.c - Também foi proposta uma correção para silenciar o aviso de que
suitableQueueFamilyIndexpoderia não estar inicializado, inicializando-o com 0
- Foi proposta uma correção trocando a ordem de inclusão dos headers Vulkan e
- Também foi levantada a necessidade de atualizar o dynapi
- Foi informado que a atualização ocorre executando
gendynapi.pyemsrc/dynapi/ - Houve também o aviso de que aparecem muitos alertas de documentação ausente durante a execução
- Foi informado que a atualização ocorre executando
- Houve uma proposta para mudar o tipo de tamanho em bytes na assinatura das funções da API para
size_t, mas a conclusão foi manterUint32na API de GPU- Comentou-se que tamanhos de buffer muito grandes poderiam dificultar a compatibilidade simultânea entre 32 e 64 bits
Uint64foi mencionado como alternativa, mas no fim prevaleceu a posição de manterUint32
Ajustes posteriores à mesclagem
- Após a mesclagem, vários ajustes foram feitos em #10622
- Foi informado que os novos nomes de funções seriam mesclados primeiro para que usuários beta pudessem recebê-los
- O problema em que, na configuração de build, macros à direita como
SDL_GPU_VULKAN SDL_VIDEO_VULKANeSDL_GPU_METAL SDL_VIDEO_METALprecisavam estar definidas foi corrigido em #10622 - O problema de UTF-8 BOM nos arquivos-fonte da GPU também foi corrigido em #10622
- No lado do D3D12, foi identificado que
D3D12_ClaimWindow()configurava o swapchain com VSYNC, limitandotestspritea 60 FPS- Foi explicado que o comportamento pretendido era um workflow em que o swapchain é criado na etapa de claim window com parâmetros de suporte universal, SDR e VSYNC, e depois
SetSwapchainParametersé chamado após consultar o suporte - Mesmo com o render driver chamando
SetSwapchainParametersapós o claim, a limitação a 60 FPS continuava no driver D3D12 e passou a ser alvo de investigação
- Foi explicado que o comportamento pretendido era um workflow em que o swapchain é criado na etapa de claim window com parâmetros de suporte universal, SDR e VSYNC, e depois
1 comentários
Comentários no Hacker News
O SDL3 ainda está em fase de preview, mas a nova API de GPU foi mesclada ao branch principal, e os mantenedores do SDL3 estão fazendo os ajustes finais
Pelo que entendi, o ponto central dessa nova API de GPU é permitir escrever o código gráfico e os shaders uma vez e fazê-los funcionar em várias plataformas, incluindo consoles, sem muita dor de cabeça. Antes, isso exigia Unity, Unreal ou alguma solução própria personalizada
O WebGPU/WGSL também é uma stack gráfica multiplataforma parecida, mas, até onde sei, ninguém criou um backend para consoles. Em contrapartida, a API de GPU do SDL3 aparentemente não oferece suporte ao WebGPU como backend no momento
Estou animado com o SDL3 porque ele introduz abstração para consoles, então a API de GPU não precisará de dependências adicionais. Além disso, o Godot oferece suporte oficial ao Steam Deck, e espero que no futuro também passe a oferecer suporte a mais consoles. Relacionado a isso, Miguel de Icaza está promovendo a adoção de Swift no Godot e também está portando o editor para SwiftUI no iPad. O progresso [3] é interessante
[1] https://bkaradzic.github.io/bgfx/overview.html
[2] https://github.com/bgbernovici/myndsmith
[3] https://blog.la-terminal.net/xogot-code-editing/
Há mais contexto aqui: https://icculus.org/finger/flibitijibibo?date=2024-06-15&time=13-14-16
Estou curioso para ver como essa linha vai se consolidar. No fim, seria bom ter mais opções para criar engines de jogo e apps customizados
Ando estudando Vulkan a fundo recentemente, e embora aprender seja divertido e traga vários insights, por causa da própria natureza do Vulkan o progresso parece lento. Se o SDL3 existisse quando comecei, provavelmente eu teria escolhido esse caminho com gosto e teria mais resultado visível pelo tempo investido
Só o tempo dirá se essa API é realmente utilizável. Especialmente, a sincronização de recursos e a forma de renomear objetos serão decisivas
Também resta ver se ela terá desempenho melhor que o WebGPU ou outras abstrações. E se continuará pequena mesmo em situações em que precise contornar bugs de driver
Também estou cético em relação ao novo bytecode para a linguagem de shading. No WebGPU, o parsing de shaders em tempo de execução nunca foi uma preocupação e é muito rápido. A geração de shaders nativos também é rápida [1]. O que é lento é a criação de pipelines, e esse bytecode não ajuda nisso
[1] http://kvark.github.io/naga/shader/2022/02/17/shader-translation-benchmark.html
Fico curioso sobre como conseguiram fazer isso tão rápido. O WebGPU nativo levou muito tempo para ser desenvolvido e ainda nem foi finalizado, então o API de GPU do SDL, por suportar mais plataformas, parecia que levaria ainda mais tempo
Existe um projeto irmão [1] para uma linguagem de sombreamento multiplataforma e outro projeto [2] para converter linguagens existentes entre si, mas eles ficam prontos quando ficarem prontos, e o restante da API não precisa esperar por isso
O WebGPU é o resultado de um comitê formado por vendors e advogados de linguagem, ou talvez advogados de padrões, produzido em meio a política e burocracia, e isso aparece. O SDL_GPU foi feito antes de tudo por desenvolvedores de jogos que priorizam praticidade, e por isso às vezes é menosprezado pela torre de marfim
[1]: https://github.com/libsdl-org/SDL_shader_tools
[2]: https://github.com/flibitijibibo/SDL_gpu_shadercross
Feliz por ter contribuído na parte de dx12 :)
Talvez eu experimente. Sempre achei o SDL um software de alta qualidade. Compila rápido, compila facilmente em várias plataformas e sempre funciona bem. Então estou animado com essa nova API também
No geral, sou um grande fã do SDL
Quando procurei uma biblioteca de jogos multiplataforma, o SDL e sua API pareceram ter o equilíbrio certo. Eu só queria uma biblioteca C/C++ que eu pudesse chamar para criar janelas e contextos gráficos, junto com um framework rápido de renderização de sprites. Não precisava de uma IDE inteira nem de uma biblioteca inchada, e também não queria aprender uma linguagem nova
O SDL3 dá a sensação de estar sofrendo do efeito do segundo sistema. Como o SDL2 era mais próximo do SDL1 com handles de janela explícitos, o SDL3 seria o segundo sistema, não o terceiro. O SDL1/2 era uma camada fina que encapsulava o boilerplate específico de cada plataforma para abrir janelas e processar eventos de entrada, permitindo chegar rápido ao código de renderização OpenGL que você realmente queria escrever
Mas, se quiser suportar também os sistemas operacionais da Apple, fica preso ao OpenGL 4.1. Como a Apple o marcou oficialmente como obsoleto há 5 anos, não dá para usar recursos modernos de GPU como compute shaders
Dá para seguir pelo caminho do Vulkan e usar MoltenVK nos sistemas da Apple, mas o Vulkan é consideravelmente mais complexo que o OpenGL. Como as pessoas costumam dizer, é um nível de “1000 linhas de código para um triângulo”. O objetivo da API de GPU do SDL3 é oferecer uma alternativa mais acessível, mas ainda suficientemente flexível
Nos consoles provavelmente é uma história parecida
Muita gente pediu “dá para adicionar suporte a shaders que funcione em todas as plataformas, tipo SDL_render?”, e dizem que esse foi o ponto de partida
O SDL3 também adiciona uma API de áudio de nível mais alto, mas não entendo bem qual é a vantagem dela
Além disso, o SDL2 evoluiu bastante depois do 2.0.0, e o SDL3 continua essa evolução permitindo mudanças que quebram compatibilidade de API. O SDL3 não foi reescrito do zero e, do ponto de vista de um usuário de SDL, não deve ser tão difícil migrar do SDL2 para o SDL3
E o SDL1/2 também nunca foi “só” fino a ponto de não ter um sistema gráfico próprio de mais alto nível. É útil ter algo embutido para que usuários novos ou básicos consigam colocar alguma coisa na tela imediatamente
Como o ahefner apontou, o SDL1 era bem “fino” pelos padrões modernos, mas ainda oferecia o suficiente para desenhar coisas básicas na tela sem escrever matemática de pixels na mão, e isso ajudava bastante nos anos 90
Ainda assim, essa abstração pode permitir atender a demandas que vão além de jogos 2D simples, mirando um ecossistema de APIs gráficas que infelizmente está cada vez mais fragmentado. O sonho de um futuro OpenGL(Next) universal desapareceu. Só que a parte mais difícil, a conversão de shaders, ainda parece não existir
Nunca usei essa biblioteca, mas, se entendi corretamente a thread linkada, agora quero ver exemplos do recurso de compute multiplataforma de GPU que ela oferece. Gostaria de saber se alguém tem recomendações de por onde começar