WebGPU: como desbloquear o acesso moderno a GPUs no navegador

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

A nova API WebGPU oferece ganhos de desempenho significativos 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. Mas, primeiro, vamos contextualizar 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 permite experiências incríveis na Web, como o Google Earth, clipes de música 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. Muito tempo! E você pode imaginar que o hardware da GPU evoluiu significativamente desde então.

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

A WebGPU disponibiliza muitas possibilidades de programação novas com GPU no navegador. Ela reflete melhor o funcionamento do hardware moderno de GPU e estabelece uma base para recursos de GPU mais avançados no futuro. A API vem sendo incorporada no grupo "GPU para a Web" do W3C desde 2017 e é uma colaboração entre muitas empresas, como Apple, Google, Mozilla, Microsoft e Intel. Agora, após 6 anos de trabalho, estamos felizes em anunciar que uma das maiores adições à plataforma Web finalmente está disponível!

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

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

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

Os recursos da WebGPU, como os sombreadores de computação, permitem a portabilidade de novas classes de algoritmos na GPU. Por exemplo, algoritmos que adicionam detalhes dinâmicos às cenas, simulam fenômenos físicos e muito mais. Há até mesmo 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 dos cubos marchando sendo usado para triangular a superfície dessas metabolas. Nos primeiros 20 segundos do vídeo, o algoritmo, quando executado em JavaScript, tem dificuldade para manter a página em execução a 8 QPS, resultando em uma animação instável. Para manter o bom desempenho em JavaScript, precisaríamos diminuir bastante o nível de detalhes.

Quando movemos o mesmo algoritmo para um sombreador de computação, ocorre uma diferença entre noite e dia, que é mostrado no vídeo após 20 segundos. O desempenho melhora drasticamente, com a página sendo executada a 60 QPS sem problemas, e ainda há muito espaço para outros efeitos. Além disso, o loop JavaScript principal da página é completamente 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 conhecida 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, a demonstração usa um algoritmo avançado chamado Transformação de Fourier rápida. Em vez de representar todas as ondas como dados posicionais complexos, o modelo usa os dados espectrais, que são muito mais eficientes para fazer cálculos. Em seguida, cada quadro usa a transformação 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 machine learning, que se tornou um uso importante das GPUs nos últimos anos.

Há muito tempo, desenvolvedores criativos vêm reaproveitando 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 dos triângulos como forma de iniciar os cálculos e o empacotamento e a descompactação cuidadosos dos dados do tensor na textura, em vez de acessos à 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 WebGL.

Usar o WebGL dessa maneira exige que os desenvolvedores adaptem seu código de forma estranha às expectativas de uma API projetada somente para desenho. Combinada com a falta de recursos básicos, como acesso compartilhado à memória entre as computações, isso gera trabalho duplicado e desempenho abaixo do ideal.

Sombreadores de computação são o novo recurso principal da WebGPU e removem esses aspectos problemáticos. Os sombreadores 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 dos sombreadores de computação da WebGPU, incluindo cargas de memória compartilhadas, cálculos compartilhados e gravações flexíveis na memória.
Eficiências do sombreador de computação da WebGPU.

Os sombreadores de computação oferecem mais oportunidades para compartilhar dados e resultados de computação em grupos de trabalho de sombreador para melhorar a 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 de 3x em vários hardwares quando movido do WebGL para a WebGPU. Em alguns dos hardwares testados, a imagem foi renderizada em menos de 10 segundos. Como essa foi uma porta inicial, acreditamos que é possível fazer ainda mais melhorias na WebGPU e no TensorFlow.js. Confira O que há de novo no Web ML em 2023? sessão do Google I/O.

A WebGPU não tem apenas o objetivo de disponibilizar recursos da GPU para a Web.

Projetado para JavaScript primeiro

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

A WebGPU foi desenvolvida com base em mais de uma década de desenvolvedores que fazem um trabalho incrível com o WebGL. Conseguimos pegar os problemas que encontraram, os gargalos que encontraram e os problemas que surgiram e direcionamos todo esse feedback para essa nova API.

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

Soubemos que a depuração de aplicativos WebGL era difícil, então a WebGPU inclui mecanismos mais flexíveis de tratamento de erros que não prejudicam seu desempenho. Também nos esforçamos para garantir que cada mensagem recebida da API seja fácil de entender e útil.

Também vimos que frequentemente a sobrecarga de fazer muitas chamadas JavaScript era um gargalo para aplicativos WebGL complexos. Como resultado, a API WebGPU tem menos chato, permitindo que você faça mais com menos chamadas de função. Nosso foco é realizar a validação de pesos pesados antecipadamente, mantendo o loop de desenho 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 desenho antecipadamente e reproduzi-los com uma única chamada.

Para demonstrar a grande diferença que um recurso como os pacotes de renderização pode fazer, veja outra demonstração do Babylon.js. O renderizador WebGL 2 pode executar todas as chamadas 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 WebGPU ativa um recurso chamado de renderização de snapshot. 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, além de permitir que os aplicativos façam mais com JavaScript em paralelo.

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

O efeito colateral é que a WebGPU é fácil de aprender e usar. Ela depende dos recursos atuais da plataforma da Web para coisas como carregamento de imagem e vídeo e se baseia em padrões JavaScript conhecidos, como Promises, para operações assíncronas. Isso ajuda a minimizar a quantidade de código boilerplate necessária. Você pode colocar seu primeiro triângulo 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 ver todos os novos casos de uso legais que você 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 a WebGPU. A compatibilidade com a WebGPU está em andamento ou já está concluída em muitas bibliotecas WebGL JavaScript populares. Em alguns casos, o aproveitamento dos benefícios da WebGPU pode ser tão simples quanto alterar uma única sinalização.

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 às plataformas restantes, como Android e Linux, em breve.

E não é só a equipe do Chrome que está trabalhando no lançamento da WebGPU. Também há implementações em andamento no Firefox e no WebKit.

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

A WebGPU é uma API extensiva que desbloqueia um desempenho incrível se você investir nela. Hoje, só foi possível 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. Neste codelab, você criará uma versão em GPU do clássico "Game of Life" da Conway. Este codelab orienta você ao longo do processo para que você possa testá-lo mesmo que esta seja a primeira vez que você está desenvolvendo GPU.

Os exemplos da WebGPU também são bons para conhecer a API. Eles variam do tradicional "triângulo "hello" aos pipelines de renderização e computação mais completos, demonstrando diversas técnicas. Por fim, confira nossos outros recursos.