HTML na tela da WebGPU

A renderização de HTML em uma tela da WebGPU oferece todos os benefícios do HTML em uma tela do WebGL, como aplicar efeitos de sombreador ao DOM ou integrar HTML interativo a cenas 3D. No entanto, a WebGPU oferece benefícios significativos em comparação com a WebGL.

Este guia demonstra como renderizar HTML em uma tela da WebGPU. Saiba mais sobre a HTML-in-Canvas na visão geral da API.

Para renderizar HTML em uma tela da WebGPU, siga estas etapas:

  1. Prepare sua tela. Defina os atributos certos de forma declarativa para que o navegador saiba que deve renderizar o HTML em uma tela. Essa configuração é idêntica nos contextos 2D, WebGL e WebGPU. Saiba como configurar sua tela e como declarar elementos HTML para serem desenhados de forma independente.
  2. Aplique o HTML como uma textura:
    1. Pré-alocar o armazenamento de textura da GPU.
    2. Faça upload do snapshot do DOM como uma textura.
  3. Sincronize o DOM e os pixels.

Desenhar um elemento HTML como uma textura da WebGPU

Na WebGPU, os elementos HTML são enviados para a GPU como texturas 2D usando drawElementImageToTexture().

Pré-alocar armazenamento de textura

A WebGPU exige alocação de memória explícita. Antes de copiar pixels do DOM para uma textura, é necessário reservar a VRAM da GPU usando o método device.createTexture():

const context = canvas.getContext("webgpu");

// Pre-allocate the texture size as needed
// For example: HTML element CSS size × devicePixelRatio
const size = canvas.getElementImageDefaultSize(myElement);
const myElementWidth = Math.ceil(size.width);
const myElementHeight = Math.ceil(size.height);

// Pre-allocate the GPUTexture backing (run once during setup)
const myTexture = device.createTexture({
  size: {
    width: myElementWidth,
    height: myElementHeight,
    depthOrArrayLayers: 1, // optional (defaults to 1)
  },
  format: "rgba8unorm",
  usage:
    GPUTextureUsage.TEXTURE_BINDING |
    GPUTextureUsage.COPY_DST |
    GPUTextureUsage.RENDER_ATTACHMENT,
});

Desenhar imagem do elemento HTML

Na WebGPU, o método drawElementImageToTexture() desenha o snapshot do elemento HTML. O método usa dois objetos de dicionário: source e destination.

source define o elemento DOM de origem a ser rasterizado e as coordenadas opcionais de recorte de subretângulo que permitem copiar apenas uma parte do elemento para a textura, em vez de todo o nó DOM:

Propriedade Tipo Descrição
source: obrigatório Element ou ElementImage O elemento DOM de destino (ou instância ElementImage pré-capturada) para desenhar na textura.
sourceX opcional (todos os quatro ou nenhum) float O deslocamento horizontal da coordenada X (em pixels CSS) que define o canto superior esquerdo da fatia do subretângulo de origem.
sourceY opcional (todos os quatro ou nenhum) float O deslocamento vertical da coordenada Y (em pixels CSS) que define o canto superior esquerdo da fatia do subretângulo de origem.
sourceWidth opcional (todos os quatro ou nenhum) float A largura (em pixels CSS) do subretângulo de origem para cortar e rasterizar.
sourceHeight opcional (todos os quatro ou nenhum) float A altura (em pixels CSS) do subretângulo de origem a ser cortado e rasterizado.

destination define a textura da GPU de destino que recebe o snapshot do DOM renderizado, além de deslocamentos de destino opcionais, níveis de mip e dimensões de cópia para colocar os pixels em uma região específica da textura:

Propriedade Tipo Descrição
texture: obrigatório GPUTexture A textura de destino pré-alocada da WebGPU que vai receber o snapshot de pixel do DOM renderizado.
Opcionais: size GPUExtent3D A largura e a altura (em pixels de textura física, por exemplo, { width, height }) para dimensionar e rasterizar o elemento na textura de destino.
Opcionais: origin GPUOrigin3D O deslocamento de destino 3D (x, y, z) na textura em que os pixels rasterizados serão gravados. O valor padrão é [0, 0, 0].
Opcionais: mipLevel GPUIntegerCoordinate O nível de mipmap específico da textura de destino em que será feita a gravação. O valor padrão é 0.
Opcionais: aspect GPUTextureAspect Especifica qual aspecto de textura será copiado ("all", "stencil-only" ou "depth-only"). O padrão é "all".
Opcionais: colorSpace PredefinedColorSpace O espaço de cores de destino (por exemplo, "srgb", "display-p3") para conversão de cores no upload. O valor padrão é "srgb".
Opcionais: premultipliedAlpha booleano Se o alfa precisa ser pré-multiplicado nos canais de cores durante o upload. O valor padrão é false.

Faça upload do elemento na textura dentro do evento paint chamando o método drawElementImageToTexture():

canvas.addEventListener("paint", (event) => {
  const sourceDict = {
    source: myElement,
    // Optional sub-rectangle crop in CSS pixels
    // (defaults to full element if omitted):
    sourceX: 0,
    sourceY: 0,
    sourceWidth: myElement.offsetWidth,
    sourceHeight: myElement.offsetHeight,
  };

  const destDict = {
    texture: myTexture,
    size: { width: myElementWidth, height: myElementHeight },
  };

  // Upload the latest DOM snapshot into the pre-allocated GPUTexture
  device.queue.drawElementImageToTexture(sourceDict, destDict);
});

Sincronizar geometria

Para alinhar os testes de hit do DOM e os anéis de foco de acessibilidade com a saída de tela renderizada, crie uma transformação DOMMatrix e aplique-a com o método updateElementGeometry():

// Construct a transform as needed in CSS pixels
// relative to the canvas, for example:
// 1/8 of the canvas width from the left edge, vertically centered.
// scaleX, scaleY: canvas grid pixels per CSS pixel (from resize observer)
const canvasCssWidth = canvas.width / scaleX;
const canvasCssHeight = canvas.height / scaleY;
const elementCssHeight = canvas.getElementImageDefaultSize(myElement).height / scaleY;
const x = canvasCssWidth / 8;
const y = (canvasCssHeight - elementCssHeight) / 2;
const transform = new DOMMatrix().translate(x, y);

// Synchronize the element's DOM hit-testing and accessibility geometry
canvas.updateElementGeometry(myElement, { canvasTransform: transform });

Próximas etapas