WebGPU: como desbloquear o acesso moderno a GPUs no navegador

Saiba como a WebGPU usa o poder da GPU para acelerar o desempenho do aprendizado de máquina e melhorar a renderização gráfica.

A nova API WebGPU proporciona ganhos enormes de desempenho em cargas de trabalho de gráficos e machine learning. Este artigo explora como a WebGPU é uma melhoria em relação à solução atual de WebGL, com uma prévia de desenvolvimentos futuros. Antes, no entanto, vamos explicar por que a WebGPU foi desenvolvida.

Contexto na WebGPU

O WebGL chegou ao Chrome em 2011. Ao permitir que os aplicativos da Web aproveitem as GPUs, o WebGL proporciona experiências incríveis na Web, desde o Google Earth até vídeos musicais interativos, tutoriais de imóveis em 3D e muito mais. O WebGL foi baseado na família de APIs OpenGL (link em inglês), desenvolvida pela primeira vez em 1992. Faz muito tempo! E você pode imaginar que o hardware da GPU evoluiu bastante desde então.

Para acompanhar essa evolução, uma nova safra de APIs foi desenvolvida para interagir de forma mais eficiente com os modernos hardwares de GPU. APIs como Direct3D 12, Metal e Vulkan. Essas novas APIs deram suporte a casos de uso novos e exigentes para programação de GPU, como a explosão do machine learning e os avanços nos algoritmos de renderização. A WebGPU é a sucessora da WebGL, levando os avanços dessa nova classe de APIs modernas para a Web.

A WebGPU desbloqueia muitas novas possibilidades de programação de GPU no navegador. Ela reflete melhor como o hardware moderno da GPU funciona e serve de base para recursos mais avançados da GPU no futuro. Ela faz parte do grupo GPU for the Web do W3C desde 2017 e é uma colaboração entre muitas empresas, como Apple, Google, Mozilla, Microsoft e Intel. Agora, após seis anos de trabalho, temos o prazer de anunciar que uma das maiores novidades da plataforma da Web finalmente está disponível.

A WebGPU já está disponível no Chrome 113 para ChromeOS, macOS e Windows. Outras plataformas serão lançadas em breve. Agradecemos imensamente a outros colaboradores do Chromium e à Intel, em particular, que ajudaram a tornar isso realidade.

Agora vamos conhecer alguns dos casos de uso interessantes que a WebGPU permite.

Desbloqueie novas cargas de trabalho da GPU para renderização

Recursos da WebGPU, como sombreadores de computação, permitem a portabilidade de novas classes de algoritmos na GPU. Por exemplo, algoritmos que podem adicionar detalhes mais dinâmicos às cenas, simular fenômenos físicos e muito mais! Até mesmo cargas de trabalho que antes só podiam ser feitas em JavaScript, agora podem ser movidas para a GPU.

O vídeo a seguir mostra o algoritmo de cubos marcha sendo usado para triangular a superfície desses metaballs. Nos primeiros 20 segundos do vídeo, o algoritmo, quando executado em JavaScript, tem dificuldade para acompanhar a página sendo executada a apenas 8 QPS, resultando em animações instáveis. Para manter o bom desempenho em JavaScript, precisaríamos diminuir bastante o nível de detalhes.

Quando mudamos o mesmo algoritmo para um sombreador de computação, ocorre uma diferença noturna, o que é mostrado no vídeo após 20 segundos. O desempenho melhora drasticamente, com a página sendo executada a 60 QPS, e ainda há bastante espaço para outros efeitos. Além disso, o loop JavaScript principal da página fica totalmente liberado para outras tarefas, garantindo que as interações com a página permaneçam responsivas.

Demonstração dos metaballs

A WebGPU também permite efeitos visuais complexos que antes não eram práticos. No exemplo a seguir, criado na conhecida biblioteca Babylon.js, a superfície do oceano é simulada inteiramente na GPU. A dinâmica realista é criada a partir de muitas ondas independentes adicionadas umas às outras. Mas simular cada onda diretamente seria muito caro.

Demonstração do oceano

É por isso que a demonstração usa um algoritmo avançado chamado Transformação rápida de Fourier. Em vez de representar todas as ondas como dados posicionais complexos, ele usa os dados espectrais, que são muito mais eficientes para realizar cálculos. Em seguida, cada frame usa a transformação de Fourier para converter dados espectrais em dados posicionais que representam a altura das ondas.

Inferência mais rápida de ML

A WebGPU também é útil para acelerar o machine learning, que se tornou o principal uso das GPUs nos últimos anos.

Há muito tempo, os desenvolvedores de criativos reformulam a API de renderização do WebGL para realizar operações que não são de renderização, como cálculos de aprendizado de máquina. No entanto, para isso, é necessário desenhar os pixels dos triângulos como uma forma de iniciar os cálculos e empacotar e descompactar cuidadosamente os dados do tensor na textura, em vez de acessos à memória de uso geral.

Uma ilustração das ineficiências na execução de um único operador de ML com WebGL, incluindo cargas de memória redundantes, cálculos redundantes e poucos valores gravados por linha de execução.
Uma única execução de operador de ML com WebGL.

Dessa forma, o uso do WebGL exige que os desenvolvedores adaptem o código de maneira estranha às expectativas de uma API projetada apenas para desenho. Combinado à falta de recursos básicos, como acesso à memória compartilhada entre cálculos, isso leva a trabalho duplicado e desempenho abaixo do ideal.

Os sombreadores de computação são o novo recurso principal da WebGPU e removem esses pontos problemáticos. Os sombreadores de computação oferecem um modelo de programação mais flexível que aproveita a natureza extremamente paralela da GPU, sem serem limitados pela estrutura rígida das operações de renderização.

Os vários ganhos de eficiência nos sombreadores de computação da WebGPU, incluindo cargas de memória compartilhadas, cálculos compartilhados e gravações flexíveis na memória.
Eficiência do sombreador de computação da WebGPU.

Os sombreadores de computação oferecem mais oportunidades de compartilhar dados e resultados computacionais dentro de grupos de trabalho de sombreador para melhorar a eficiência. Isso pode gerar ganhos significativos em relação às tentativas anteriores de usar o WebGL com o mesmo propósito.

Como exemplo dos ganhos de eficiência que isso pode trazer, uma porta inicial de um modelo de difusão de imagens no TensorFlow.js mostra um ganho de desempenho de 3x em vários hardwares quando movida do WebGL para a WebGPU. Em alguns dos hardwares testados, a imagem foi renderizada em menos de 10 segundos. Como essa é uma porta inicial, acreditamos que é possível melhorar ainda mais a WebGPU e o TensorFlow.js. Confira O que há de novo no Web ML em 2023? sessão do Google I/O.

Mas a WebGPU não trata apenas de levar recursos da GPU para a Web.

Desenvolvido primeiro para JavaScript

Os recursos que permitem esses casos de uso estão disponíveis para desenvolvedores de computadores e dispositivos móveis específicos da plataforma há algum tempo, e tem sido um desafio expô-los de uma forma que pareça uma parte natural da plataforma da Web.

A WebGPU foi desenvolvida com o benefício da retrospectiva de mais de uma década de desenvolvedores que fizeram um trabalho incrível com o WebGL. Conseguimos analisar os problemas enfrentados, os gargalos encontrados e os problemas levantados, e afunilamos todo esse feedback para essa nova API.

Vimos que o modelo de estado global do WebGL tornou difícil e frágil a criação de bibliotecas e aplicativos combináveis robustos. Portanto, a WebGPU reduz drasticamente a quantidade de estados que os desenvolvedores precisam monitorar ao enviar os comandos da GPU.

Ouvimos dizer que depurar aplicativos WebGL é um problema. Por isso, a WebGPU inclui mecanismos mais flexíveis de tratamento de erros que não prejudicam seu desempenho. E nos esforçamos para garantir que cada mensagem recebida da API seja fácil de entender e possa ser transformada em ações.

Também vimos que frequentemente a sobrecarga de fazer muitas chamadas JavaScript era um gargalo para aplicativos WebGL complexos. Como resultado, a API WebGPU é menos intensa, então você pode fazer mais com menos chamadas de função. Nosso foco é realizar uma validação de peso pesado antecipadamente, mantendo o loop de desenho crítico o mais enxuto possível. Além disso, oferecemos novas APIs, como Render Bundles, que permitem gravar um grande número de comandos de desenho com antecedência e reproduzi-los com uma única chamada.

Para demonstrar a grande diferença que um recurso como pacotes de renderização pode fazer, veja aqui outra demonstração da Babylon.js. O renderizador WebGL 2 pode executar todas as chamadas JavaScript para renderizar essa cena da galeria de arte cerca de 500 vezes por segundo. O que é muito bom!

A galeria de arte

No entanto, o renderizador WebGPU ativa um recurso chamado renderização de snapshots. Criado sobre pacotes de renderização de WebGPUs, esse recurso permite que a mesma cena seja enviada mais de 10 vezes mais rápido. Essa sobrecarga significativamente reduzida permite que a WebGPU renderize cenas mais complexas, ao mesmo tempo em que permite que os aplicativos façam mais com o JavaScript em paralelo.

As APIs gráficas modernas são conhecidas pela complexidade, trocando a simplicidade por oportunidades extremas de otimização. A WebGPU, por outro lado, se concentra na compatibilidade entre plataformas, lidando com tópicos tradicionalmente difíceis, como a sincronização automática de recursos, na maioria dos casos.

Isso gera o efeito colateral feliz de que a WebGPU é fácil de aprender e usar. Ela conta com recursos existentes da plataforma da Web para coisas como carregamento de imagens e vídeos e se alinha a padrões JavaScript conhecidos, como promessas para operações assíncronas. Isso ajuda a minimizar a quantidade necessária de código boilerplate. Seu primeiro triângulo aparece na tela com menos de 50 linhas de código.

<canvas id="canvas" width="512" height="512"></canvas>
<script type="module">
  const adapter = await navigator.gpu.requestAdapter();
  const device = await adapter.requestDevice();

  const context = canvas.getContext("webgpu");
  const format = navigator.gpu.getPreferredCanvasFormat();
  context.configure({ device, format });

  const code = `
    @vertex fn vertexMain(@builtin(vertex_index) i : u32) ->
      @builtin(position) vec4f {
       const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1));
       return vec4f(pos[i], 0, 1);
    }
    @fragment fn fragmentMain() -> @location(0) vec4f {
      return vec4f(1, 0, 0, 1);
    }`;
  const shaderModule = device.createShaderModule({ code });
  const pipeline = device.createRenderPipeline({
    layout: "auto",
    vertex: {
      module: shaderModule,
      entryPoint: "vertexMain",
    },
    fragment: {
      module: shaderModule,
      entryPoint: "fragmentMain",
      targets: [{ format }],
    },
  });
  const commandEncoder = device.createCommandEncoder();
  const colorAttachments = [
    {
      view: context.getCurrentTexture().createView(),
      loadOp: "clear",
      storeOp: "store",
    },
  ];
  const passEncoder = commandEncoder.beginRenderPass({ colorAttachments });
  passEncoder.setPipeline(pipeline);
  passEncoder.draw(3);
  passEncoder.end();
  device.queue.submit([commandEncoder.finish()]);
</script>

Conclusão

É empolgante ver todas as novas possibilidades que a WebGPU traz para a plataforma da Web. Estamos ansiosos para conhecer todos os novos casos de uso interessantes que você encontrará para a WebGPU.

Um ecossistema vibrante de bibliotecas e frameworks foi construído em torno do WebGL, e esse mesmo ecossistema está ansioso para adotar a WebGPU. O suporte para a WebGPU está em andamento ou já está completo em muitas bibliotecas JavaScript WebGL populares. Em alguns casos, aproveitar os benefícios da WebGPU pode ser tão simples quanto alterar uma única flag.

Babylon.js, Build 3, Google Earth, Google Meet, PlayCanvas, Sketchfab, Three.JS, TensorFlow.js e Unity.
Frameworks, aplicativos e bibliotecas com portas WebGPU concluídas ou em andamento.

E esta primeira versão no Chrome 113 é apenas o começo. Embora nossa versão inicial seja para Windows, ChromeOS e MacOS, planejamos levar a WebGPU para as outras plataformas, como Android e Linux, em breve.

E não é apenas a equipe do Chrome que está trabalhando no lançamento da WebGPU. Implementações também estão em andamento no Firefox e no WebKit.

Além disso, novos recursos já estão sendo projetados no W3C que podem ser expostos quando disponíveis no hardware. Por exemplo: no Chrome, planejamos ativar o suporte para números de ponto flutuante de 16 bits em sombreadores e a classe de instruções DP4a (links em inglês) em breve para ainda mais melhorias no desempenho do aprendizado de máquina.

A WebGPU é uma API extensa que oferece um desempenho incrível se você investir nela. Hoje só abordaremos os benefícios de forma geral, mas se você quiser começar a usar a WebGPU, confira nosso codelab introdutório, Seu primeiro app WebGPU. Neste codelab, você vai criar uma versão GPU do clássico "Game of Life" do Conway. Este codelab oferece um processo passo a passo para que você possa testá-lo mesmo que seja a primeira vez que desenvolve uma GPU.

As amostras da WebGPU também são um bom lugar para conhecer a API. Elas vão do tradicional "hello triângulo", e pipelines de computação e renderização mais completos, com diversas técnicas. Por fim, confira nossos outros recursos.