1 pontos por GN⁺ 2024-08-31 | 1 comentários | Compartilhar no WhatsApp
  • 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

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 GpuBuffers funcionam como contêineres para ciclar referências internas de recursos
    • Depois, o conceito de cycle foi simplificado para um bool, e vários enums WriteOptions foram removidos
  • Inicialmente, existiam vários enums WriteOptions por 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
  • Em feedback externo, surgiu a preocupação de que compilação puramente offline não combinaria com certas engines
    • Apontou-se que exigir Python, glslc e spirv-cross no 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
  • 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 VkInstance e VkSurfaceKHR
    • Foi proposta uma correção trocando a ordem de inclusão dos headers Vulkan e SDL_vulkan.h em SDL_gpu_vulkan.c
    • Também foi proposta uma correção para silenciar o aviso de que suitableQueueFamilyIndex poderia não estar inicializado, inicializando-o com 0
  • Também foi levantada a necessidade de atualizar o dynapi
    • Foi informado que a atualização ocorre executando gendynapi.py em src/dynapi/
    • Houve também o aviso de que aparecem muitos alertas de documentação ausente durante a execução
  • 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 manter Uint32 na API de GPU
    • Comentou-se que tamanhos de buffer muito grandes poderiam dificultar a compatibilidade simultânea entre 32 e 64 bits
    • Uint64 foi mencionado como alternativa, mas no fim prevaleceu a posição de manter Uint32

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_VULKAN e SDL_GPU_METAL SDL_VIDEO_METAL precisavam 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, limitando testsprite a 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 SetSwapchainParameters após o claim, a limitação a 60 FPS continuava no driver D3D12 e passou a ser alvo de investigação

1 comentários

 
GN⁺ 2024-08-31
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

    • Unreal/Unity não são as únicas soluções. Também existe o bastante popular bgfx(https://github.com/bkaradzic/bgfx) e, até onde conheço, também há o sokol gfx(https://github.com/floooh/sokol). Claro, há muitos outros menos conhecidos também
    • Já integrei antes o bgfx [1], que permite escrever código gráfico e shaders uma vez e ainda dá suporte a consoles, com uma stack SDL2 e Swift [2]. Foi uma experiência bem boa, mesmo do ponto de vista de quem nunca tinha usado esse tipo de ferramenta
      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/
    • Vale notar que o Godot também tem shaders multiplataforma. A linguagem GDShader é fortemente baseada na linguagem de shaders do OpenGL, mas não é uma cópia 1:1, e é compilada de acordo com a plataforma de destino. No entanto, para PS5 e Xbox é preciso colaborar com empresas terceiras. Também houve quem disponibilizasse builds para Nintendo para pessoas que assinaram o NDA da Nintendo
    • Mas por que a API do SDL seria necessária em vez de gfx-rs / wgpu? Fico me perguntando se realmente era preciso criar mais uma
  • 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

    • O motivo de o WebGPU ter demorado tanto é que decidiram criar uma linguagem de sombreamento própria em vez de usar SPIR-V. O SDL não cometeu esse erro e deixou que o usuário trouxesse o compilador de shaders e as ferramentas de conversão
      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
    • Os principais contribuidores do projeto SDL3 GPU têm experiência com duas camadas de abstração de GPU multiplataforma, FNA3D e Refresh, ou seja, camadas voltadas tanto para PC quanto para consoles. Esse conhecimento e o código open source já existente serviram de base para montar algo rápido e com boa qualidade
    • Porque não havia comitê, e havia desenvolvedores motivados que precisavam do resultado para seus próprios projetos. Especialmente o pessoal do FNA
    • Simples. O SDL GPU deixou de fora o resto da coruja, ou seja, a parte de converter shaders em um formato comum para representações intermediárias específicas de cada API
  • Feliz por ter contribuído na parte de dx12 :)

    • Ótimo. A ideia é mirar em HLSL moderno, então no começo provavelmente vou usar esse backend. Espero que o DXC consiga gerar um SPIR-V decente no final
    • Que materiais você recomendaria para aprender 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

    • Se você só precisa suportar Windows/Linux/Android, dá para argumentar que a API de GPU do SDL é inchada sem necessidade
      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
    • O SDL2 não foi só “SDL1 com handles de janela explícitos”. Houve várias mudanças e novos recursos em toda a API e, assim como no SDL3, também houve grandes mudanças no subsistema gráfico. O SDL1 usava renderização por software, e o SDL2 adicionou aceleração por hardware
      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
    • O problema é que o OpenGL está praticamente morto, e o Vulkan é um substituto ruim do OpenGL em termos de usabilidade
    • A API de renderização já era um inchaço desnecessário para muitos usuários de SDL. O SDL2 também já ficou consideravelmente maior que o SDL1 em termos de tamanho binário
      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