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:
- 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.
- Aplique o HTML como uma textura:
- Pré-alocar o armazenamento de textura da GPU.
- Faça upload do snapshot do DOM como uma textura.
- 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
- Entenda os principais conceitos técnicos por trás do HTML-in-Canvas.
- Saiba como renderizar HTML em um contexto 2D.
- Saiba como renderizar HTML em uma tela WebGL.
- Saiba mais sobre as estratégias de substituição.
- Registre um problema no GitHub para compartilhar seu feedback.
- Confira a coleção de demonstrações de HTML-in-Canvas da comunidade.