HTML w obszarze roboczym WebGPU

Renderowanie kodu HTML w elemencie canvas WebGPU zapewnia wszystkie korzyści, jakie daje kod HTML w elemencie canvas WebGL, takie jak stosowanie efektów cieniowania do DOM czy integrowanie interaktywnego kodu HTML ze scenami 3D. WebGPU oferuje jednak znaczne korzyści w porównaniu z WebGL.

Z tego przewodnika dowiesz się, jak renderować kod HTML na elemencie canvas WebGPU. Więcej informacji o HTML-in-Canvas znajdziesz w omówieniu interfejsu API.

Renderowanie kodu HTML w elemencie canvas WebGPU wymaga wykonania tych czynności:

  1. Przygotuj obszar roboczy. Deklaratywnie ustaw odpowiednie atrybuty, aby poinformować przeglądarkę, że powinna renderować kod HTML w elemencie canvas. Ta konfiguracja jest identyczna w kontekstach 2D, WebGL i WebGPU. Dowiedz się, jak skonfigurować obszar roboczy i jak zadeklarować elementy HTML, które mają być rysowane niezależnie.
  2. Zastosuj kod HTML jako teksturę:
    1. Wstępnie przydziel miejsce na tekstury GPU.
    2. Prześlij zrzut DOM jako teksturę.
  3. Zsynchronizuj DOM i piksele.

Rysowanie elementu HTML jako tekstury WebGPU

W WebGPU elementy HTML są przesyłane do GPU jako tekstury 2D za pomocą drawElementImageToTexture().

Wstępne przydzielanie miejsca na tekstury

WebGPU wymaga jawnej alokacji pamięci. Zanim skopiujesz piksele DOM do tekstury, musisz zarezerwować pamięć VRAM GPU za pomocą metody 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,
});

Rysowanie obrazu elementu HTML

W WebGPU metoda drawElementImageToTexture() rysuje zrzut elementu HTML. Metoda przyjmuje 2 obiekty słownikowe: source i destination.

source definiuje źródłowy element DOM do rasteryzacji i opcjonalne współrzędne przycinania prostokąta podrzędnego, które umożliwiają skopiowanie tylko części elementu do tekstury, a nie całego węzła DOM:

Właściwość Typ Opis
Wymagana liczba: source Element lub ElementImage Docelowy element DOM (lub wstępnie przechwycona instancja ElementImage), który ma zostać narysowany w teksturze.
sourceX – opcjonalny (wszystkie 4 lub żaden) liczba zmiennoprzecinkowa Przesunięcie poziome współrzędnej X (w pikselach CSS) określające lewy górny róg wycinka podprostokąta źródłowego.
sourceY – opcjonalny (wszystkie 4 lub żaden) liczba zmiennoprzecinkowa Przesunięcie pionowe współrzędnej Y (w pikselach CSS) określające lewy górny róg wycinka źródłowego prostokąta podrzędnego.
sourceWidth – opcjonalny (wszystkie 4 lub żaden) liczba zmiennoprzecinkowa Szerokość (w pikselach CSS) źródłowego prostokąta podrzędnego do przycięcia i rasteryzacji.
sourceHeight – opcjonalny (wszystkie 4 lub żaden) liczba zmiennoprzecinkowa Wysokość (w pikselach CSS) źródłowego podprostokąta do przycięcia i rasteryzacji.

destination definiuje docelową teksturę GPU, która otrzymuje wyrenderowany zrzut DOM, wraz z opcjonalnymi przesunięciami docelowymi, poziomami mip i wymiarami kopiowania, aby umieścić piksele w określonym regionie tekstury:

Właściwość Typ Opis
Wymagana liczba: texture GPUTexture Wstępnie przydzielona docelowa tekstura WebGPU, która otrzyma wyrenderowany zrzut pikseli DOM.
Opcjonalne: size GPUExtent3D Szerokość i wysokość (w pikselach fizycznej tekstury, np. { width, height }) do skalowania i rasteryzacji elementu w teksturze docelowej.
Opcjonalne: origin GPUOrigin3D Przesunięcie miejsca docelowego 3D (x, y, z) w teksturze, w której zostaną zapisane piksele zrasteryzowane. Domyślna wartość to [0, 0, 0].
Opcjonalne: mipLevel GPUIntegerCoordinate Konkretny poziom mipmapy tekstury docelowej, do której mają być zapisywane dane. Domyślna wartość to 0.
Opcjonalne: aspect GPUTextureAspect Określa, który aspekt tekstury ma zostać skopiowany ("all", "stencil-only" lub "depth-only"). Wartość domyślna to "all".
Opcjonalne: colorSpace PredefinedColorSpace Docelowa przestrzeń barw (np. "srgb", "display-p3") do konwersji kolorów podczas przesyłania. Domyślna wartość to "srgb".
Opcjonalne: premultipliedAlpha wartość logiczna Określa, czy podczas przesyłania kanały kolorów mają być wstępnie mnożone przez kanał alfa. Domyślna wartość to false.

Prześlij element do tekstury w ramach zdarzenia paint, wywołując metodę 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);
});

Synchronizowanie geometrii

Aby dopasować testy pozycji wskaźnika DOM i pierścienie zaznaczenia ułatwień dostępu do wyrenderowanych danych wyjściowych elementu canvas, utwórz przekształcenie DOMMatrix i zastosuj je za pomocą metody 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 });

Dalsze kroki