HTML in WebGPU-canvas

HTML renderen in een WebGPU-canvas biedt alle voordelen van HTML in een WebGL-canvas, zoals shader-effecten toepassen op de DOM of interactieve HTML integreren in 3D-scènes. WebGPU biedt wel aanzienlijke voordelen ten opzichte van WebGL.

In deze handleiding wordt uitgelegd hoe je HTML rendert in een WebGPU-canvas. Meer informatie over HTML-in-Canvas in het API-overzicht.

Voor de weergave van HTML in een WebGPU-canvas zijn de volgende stappen vereist:

  1. Bereid je canvas voor. Stel de juiste kenmerken declaratief in om de browser te laten weten dat deze HTML moet renderen in een canvas. Deze instelling is identiek voor 2D-, WebGL- en WebGPU-contexten. Meer informatie over hoe je je canvas instelt en hoe je HTML-elementen declareert die onafhankelijk moeten worden getekend.
  2. Pas de HTML toe als textuur:
    1. Wijs GPU-textuuropslag vooraf toe.
    2. Upload de DOM-momentopname als een textuur.
  3. Synchroniseer het DOM en de pixels.

Een HTML-element tekenen als een WebGPU-textuur

In WebGPU worden HTML-elementen geüpload naar de GPU als 2D-texturen met drawElementImageToTexture().

Textuuropslag vooraf toewijzen

WebGPU vereist expliciete geheugentoewijzing. Voordat je DOM-pixels naar een textuur kopieert, moet je GPU VRAM reserveren met de methode 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,
});

Afbeelding van HTML-element tekenen

In WebGPU tekent de methode drawElementImageToTexture() de momentopname van het HTML-element. De methode gebruikt 2 woordenboekobjecten: source en destination.

source definieert het bron-DOM-element dat moet worden gerasterd en optionele subrechthoekige knipcoördinaten waarmee je alleen een deel van het element naar je textuur kunt kopiëren in plaats van de hele DOM-node:

Property Type Beschrijving
source vereist Element of ElementImage Het doel-DOM-element (of vooraf vastgelegde ElementImage-instantie) dat in de textuur moet worden getekend.
sourceX optioneel (alle 4 of geen) float De horizontale X-coördinaatverschuiving (in CSS-pixels) die de linkerbovenhoek van de subrechthoek van de bron definieert.
sourceY optioneel (alle 4 of geen) float De verticale Y-coördinaatverschuiving (in CSS-pixels) die de linkerbovenhoek van de subrechthoek van de bron definieert.
sourceWidth optioneel (alle 4 of geen) float De breedte (in CSS-pixels) van de bron-subrechthoek die moet worden bijgesneden en gerasterd.
sourceHeight optioneel (alle 4 of geen) float De hoogte (in css-pixels) van de bron-subrechthoek die moet worden bijgesneden en gerasterd.

destination definieert de doel-GPU-textuur die de gerenderde DOM-momentopname krijgt, samen met optionele bestemmingsoffsets, mip-niveaus en kopieerdimensies om de pixels in een specifieke regio van de textuur te plaatsen:

Property Type Beschrijving
texture vereist GPUTexture De vooraf toegewezen WebGPU-bestemmingstextuur die de gerenderde DOM-pixelmomentopname krijgt.
size optioneel GPUExtent3D De breedte en hoogte (in fysieke textuurpixels, bijvoorbeeld { width, height }) om het element te schalen en te rasteren binnen de bestemmingstextuur.
origin optioneel GPUOrigin3D De 3D-bestemmingsverschuiving (x, y, z) binnen de textuur waar de gerasterde pixels worden geschreven. De standaardwaarde is [0, 0, 0].
mipLevel optioneel GPUIntegerCoordinate Het specifieke mipmap-niveau van de bestemmingstextuur waarnaar moet worden geschreven. De standaardwaarde is 0.
aspect optioneel GPUTextureAspect Geeft aan naar welk textuuraspect moet worden gekopieerd ("all", "stencil-only" of "depth-only"). De standaardwaarde is "all".
colorSpace optioneel PredefinedColorSpace De bestemmingskleurruimte (bijvoorbeeld "srgb", "display-p3") voor kleurconversie bij uploaden. De standaardwaarde is "srgb".
premultipliedAlpha optioneel booleaans Of alfa vooraf moet worden vermenigvuldigd in de kleurkanalen tijdens de upload. De standaardwaarde is false.

Upload het element naar je textuur in de gebeurtenis paint door de methode drawElementImageToTexture() aan te roepen:

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);
});

Geometrie synchroniseren

Als je DOM-hit-testing en focusringen voor toegankelijkheid wilt uitlijnen met de gerenderde canvasuitvoer, maak je een DOMMatrix-transformatie en pas je deze toe met de updateElementGeometry()-methode:

// 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 });

Volgende stappen