WebGPU: como desbloquear o acesso moderno a GPUs no navegador

Saiba como a WebGPU libera o poder da GPU para um desempenho mais rápido de aprendizado de máquina e uma melhor renderização de gráficos.

A nova API WebGPU oferece ganhos de performance enormes em cargas de trabalho de gráficos e aprendizado de máquina. Este artigo explora como a WebGPU é uma melhoria em relação à solução atual do WebGL, com uma prévia dos desenvolvimentos futuros. Mas primeiro, 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 oferece experiências incríveis na Web, como o Google Earth, videoclipes interativos, tours 3D de imóveis e muito mais. O WebGL foi baseado na família de APIs OpenGL, desenvolvida pela primeira vez em 1992. Isso foi há muito tempo! E você pode imaginar que o hardware de GPU evoluiu significativamente desde então.

Para acompanhar essa evolução, uma nova geração de APIs foi desenvolvida para interagir de maneira mais eficiente com o hardware de GPU moderno. APIs como Direct3D 12, Metal e Vulkan. Essas novas APIs oferecem suporte a casos de uso novos e exigentes para programação de GPU, como a explosão no aprendizado de máquina e os avanços nos algoritmos de renderização. A WebGPU é a sucessora da WebGL, trazendo os avanços dessa nova classe de APIs modernas para a Web.

A WebGPU oferece muitas novas possibilidades de programação de GPU no navegador. Ele reflete melhor como o hardware de GPU moderno funciona, além de estabelecer uma base para recursos de GPU mais avançados no futuro. A API está no grupo "GPU for the Web" do W3C desde 2017 e é uma colaboração entre muitas empresas, como Apple, Google, Mozilla, Microsoft e Intel. Depois de seis anos de trabalho, temos o prazer de anunciar que uma das maiores adições à plataforma da Web finalmente está disponível.

A WebGPU está disponível hoje no Chrome 113 no ChromeOS, macOS e Windows, e outras plataformas serão lançadas em breve. Agradecemos muito aos outros colaboradores do Chromium e à Intel, em particular, por ajudar a fazer isso acontecer.

Agora vamos conferir alguns dos casos de uso incríveis que a WebGPU possibilita.

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

Os recursos da WebGPU, como shaders de computação, permitem que novas classes de algoritmos sejam portadas para a GPU. Por exemplo, algoritmos que podem adicionar mais detalhes dinâmicos às cenas, simular fenômenos físicos e muito mais. Há até cargas de trabalho que antes só podiam ser feitas em JavaScript e agora podem ser movidas para a GPU.

O vídeo a seguir mostra o algoritmo de cubos de marcha sendo usado para triangular a superfície dessas metaesferas. Nos primeiros 20 segundos do vídeo, o algoritmo, quando executado em JavaScript, tem dificuldade para acompanhar a página que está sendo executada a apenas 8 QPS, resultando em uma animação instável. Para manter o desempenho em JavaScript, precisaríamos reduzir muito o nível de detalhes.

É uma grande diferença quando movemos o mesmo algoritmo para um sombreador de computação, que aparece no vídeo após 20 segundos. A performance melhora drasticamente, com a página funcionando a 60 QPS, e ainda há muito espaço para outros efeitos. Além disso, o loop principal de JavaScript da página fica totalmente liberado para outras tarefas, garantindo que as interações com a página continuem responsivas.

Demonstração de metaballs

A WebGPU também permite efeitos visuais complexos que não eram práticos antes. No exemplo a seguir, criado na popular biblioteca Babylon.js, a superfície do oceano é simulada inteiramente na GPU. A dinâmica realista é criada a partir de muitas ondas independentes que são 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 Transformada 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 transformada de Fourier para converter dados espectrais em dados posicionais que representam a altura das ondas.

Inferência de ML mais rápida

A WebGPU também é útil para acelerar o aprendizado de máquina, que se tornou um uso importante de GPUs nos últimos anos.

Por muito tempo, desenvolvedores criativos reaproveitaram 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, isso exige o desenho dos pixels de triângulos como uma forma de iniciar as computações e empacotar e desempacotar dados de tensor na textura com cuidado, em vez de acessos de memória de uso geral.

Ilustração das ineficiências em uma única execução de 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 o WebGL.

O uso do WebGL dessa maneira exige que os desenvolvedores ajustem o código às expectativas de uma API projetada apenas para renderização. Isso, combinado com a falta de recursos básicos, como o acesso à memória compartilhada entre as computações, leva a trabalhos duplicados e a um desempenho subótimo.

Os shaders de computação são o principal novo recurso do WebGPU e eliminam esses problemas. Os shaders de computação oferecem um modelo de programação mais flexível que aproveita a natureza massivamente paralela da GPU sem ser limitado pela estrutura rígida das operações de renderização.

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

Os shaders de computação oferecem mais oportunidades de compartilhamento de dados e resultados de computação em grupos de trabalho de shaders para maior eficiência. Isso pode levar a ganhos significativos em relação a tentativas anteriores de usar o WebGL para a mesma finalidade.

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 três vezes maior em vários hardwares quando movidos do WebGL para o WebGPU. Em alguns dos hardwares testados, a imagem foi renderizada em menos de 10 segundos. Como esse foi um port inicial, acreditamos que há ainda mais melhorias possíveis na WebGPU e no TensorFlow.js. Confira O que há de novo na ML da Web em 2023? Sessão do Google I/O.

Mas a WebGPU não se trata apenas de trazer recursos de GPU para a Web.

Projetado para JavaScript

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

A WebGPU foi desenvolvida com o benefício de retrospectiva de mais de uma década de desenvolvedores fazendo um trabalho incrível com o WebGL. Conseguimos usar os problemas que eles encontraram, os gargalos que enfrentaram e as questões que levantaram para direcionar todo esse feedback para essa nova API.

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

Sabemos que depurar aplicativos WebGL é uma dor de cabeça. Por isso, a WebGPU inclui mecanismos de manipulação de erros mais flexíveis que não prejudicam o desempenho. E nos esforçamos para garantir que todas as mensagens que você recebe da API sejam fáceis de entender e úteis.

Também observamos que, com frequência, o overhead de fazer muitas chamadas de JavaScript era um gargalo para aplicativos WebGL complexos. Como resultado, a API WebGPU é menos chata, então você pode fazer mais com menos chamadas de função. Focamos em realizar a validação pesada antecipadamente, mantendo o loop de renderização crítico o mais enxuto possível. Também oferecemos novas APIs, como os pacotes de renderização, que permitem gravar um grande número de comandos de exibição com antecedência e reproduzi-los com uma única chamada.

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

Galeria de arte

No entanto, o renderizador da WebGPU ativa um recurso chamado "Rendering Snapshot". Criado com base nos pacotes de renderização da WebGPU, esse recurso permite que a mesma cena seja enviada mais de 10 vezes mais rápido. Essa redução significativa da sobrecarga permite que a WebGPU renderize cenas mais complexas, além de permitir que os aplicativos façam mais com o JavaScript em paralelo.

As APIs gráficas modernas têm a reputação de serem complexas, trocando a simplicidade por oportunidades de otimização extremas. O WebGPU, por outro lado, se concentra na compatibilidade entre plataformas, processando de forma automática temas tradicionalmente difíceis, como a sincronização de recursos, na maioria dos casos.

Isso tem o efeito colateral positivo de que a WebGPU é fácil de aprender e usar. Ele depende de recursos existentes da plataforma da Web para coisas como carregamento de imagens e vídeos e usa padrões conhecidos do JavaScript, como promessas para operações assíncronas. Isso ajuda a manter a quantidade mínima de código boilerplate necessária. Você pode exibir seu primeiro triângulo na tela em 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

É muito legal ver todas as novas possibilidades que a WebGPU traz para a plataforma da Web. Estamos ansiosos para conhecer todos os novos casos de uso incríveis que você vai encontrar para a WebGPU.

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

Babylon.js, Construct 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 essa primeira versão do Chrome 113 é apenas o começo. Embora a versão inicial seja para Windows, ChromeOS e MacOS, planejamos trazer a WebGPU para as plataformas restantes, como Android e Linux, em breve.

E não é apenas a equipe do Chrome que está trabalhando no lançamento da WebGPU. As 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 e podem ser expostos quando estiverem disponíveis no hardware. Por exemplo, no Chrome, planejamos ativar o suporte a números de ponto flutuante de 16 bits em shaders e a classe de instruções DP4a em breve para melhorar ainda mais o desempenho do aprendizado de máquina.

A WebGPU é uma API extensa que oferece desempenho incrível se você investir nela. Hoje, só podemos abordar 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. Nele, você vai criar uma versão de GPU do clássico Game of Life da Conway. Este codelab explica o processo passo a passo para que você possa testá-lo, mesmo que seja sua primeira vez desenvolvendo para GPU.

Os exemplos da WebGPU também são um bom lugar para conhecer a API. Elas variam do tradicional "hello triangle" até pipelines de renderização e computação mais completos, demonstrando uma variedade de técnicas. Por fim, confira nossos outros recursos.