HTML di kanvas WebGPU

Merender HTML di dalam kanvas WebGPU menawarkan semua manfaat yang dimiliki HTML di kanvas WebGL, seperti menerapkan efek shader ke DOM atau mengintegrasikan HTML interaktif ke dalam scene 3D. Namun, WebGPU menawarkan manfaat yang signifikan dibandingkan dengan WebGL.

Panduan ini menunjukkan cara merender HTML ke dalam kanvas WebGPU. Pelajari lebih lanjut HTML-in-Canvas di ringkasan API.

Merender HTML di kanvas WebGPU memerlukan langkah-langkah berikut:

  1. Siapkan kanvas Anda. Tetapkan atribut yang tepat secara deklaratif untuk memberi tahu browser bahwa browser harus merender HTML ke dalam kanvas. Penyiapan ini identik di seluruh konteks 2D, WebGL, dan WebGPU. Pelajari cara menyiapkan kanvas dan cara mendeklarasikan elemen HTML yang akan digambar secara independen.
  2. Terapkan HTML sebagai tekstur:
    1. Pra-alokasikan penyimpanan tekstur GPU.
    2. Upload snapshot DOM sebagai tekstur.
  3. Menyinkronkan DOM dan piksel.

Menggambar elemen HTML sebagai tekstur WebGPU

Di WebGPU, elemen HTML diupload ke GPU sebagai tekstur 2D menggunakan drawElementImageToTexture().

Melakukan pra-alokasi penyimpanan tekstur

WebGPU memerlukan alokasi memori eksplisit. Sebelum menyalin piksel DOM ke dalam tekstur, Anda harus mencadangkan VRAM GPU menggunakan metode 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,
});

Menggambar gambar elemen HTML

Di WebGPU, metode drawElementImageToTexture() menggambar snapshot elemen HTML. Metode ini menggunakan dua objek kamus: source dan destination.

source menentukan elemen DOM sumber yang akan dirasterisasi dan koordinat pemangkasan sub-persegi panjang opsional yang memungkinkan Anda menyalin hanya sebagian elemen ke tekstur, bukan seluruh node DOM:

Properti Jenis Deskripsi
source diperlukan Element atau ElementImage Elemen DOM target (atau instance ElementImage yang telah diambil sebelumnya) untuk digambar ke dalam tekstur.
sourceX opsional (keempatnya atau tidak sama sekali) float Offset koordinat X horizontal (dalam piksel CSS) yang menentukan sudut kiri atas potongan sub-persegi panjang sumber.
sourceY opsional (keempatnya atau tidak sama sekali) float Offset koordinat Y vertikal (dalam piksel CSS) yang menentukan sudut kiri atas potongan sub-persegi panjang sumber.
sourceWidth opsional (keempatnya atau tidak sama sekali) float Lebar (dalam piksel CSS) sub-persegi panjang sumber yang akan dipangkas dan dirasterisasi.
sourceHeight opsional (keempatnya atau tidak sama sekali) float Tinggi (dalam piksel CSS) sub-persegi panjang sumber yang akan dipangkas dan dirasterisasi.

destination menentukan tekstur GPU target yang menerima snapshot DOM yang dirender, beserta offset tujuan opsional, level mip, dan dimensi salinan untuk menempatkan piksel ke dalam region tekstur tertentu:

Properti Jenis Deskripsi
texture diperlukan GPUTexture Tekstur WebGPU tujuan yang telah dialokasikan sebelumnya yang akan menerima snapshot piksel DOM yang dirender.
size opsional GPUExtent3D Lebar dan tinggi (dalam piksel tekstur fisik, misalnya, { width, height }) untuk menskalakan dan merasterisasi elemen dalam tekstur tujuan.
origin opsional GPUOrigin3D Offset tujuan 3D (x, y, z) dalam tekstur tempat piksel yang dirasterisasi akan ditulis. Default-nya adalah [0, 0, 0].
mipLevel opsional GPUIntegerCoordinate Level mipmap tertentu dari tekstur tujuan yang akan ditulis. Default-nya adalah 0.
aspect opsional GPUTextureAspect Menentukan aspek tekstur yang akan disalin ("all", "stencil-only", atau "depth-only"). Default-nya adalah "all".
colorSpace opsional PredefinedColorSpace Ruang warna tujuan (misalnya, "srgb", "display-p3") untuk konversi warna saat upload. Default-nya adalah "srgb".
premultipliedAlpha opsional boolean Apakah alfa harus diprakalikan ke dalam saluran warna selama upload. Default-nya adalah false.

Upload elemen ke tekstur Anda di dalam peristiwa paint dengan memanggil metode 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);
});

Menyinkronkan geometri

Untuk menyelaraskan hit-testing DOM dan cincin fokus aksesibilitas dengan output kanvas yang dirender, buat transformasi DOMMatrix dan terapkan dengan metode 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 });

Langkah berikutnya