Nieuw in WebGPU (Chrome 121)

François Beaufort
François Beaufort

WebGPU ondersteunen op Android

Het Chrome-team kondigt met trots aan dat WebGPU nu standaard aanstaat in Chrome 121 op apparaten met Android 12 en hoger die worden aangedreven door Qualcomm- en ARM-GPU's.

De ondersteuning wordt geleidelijk uitgebreid naar een breder scala aan Android-apparaten, waaronder apparaten met Android 11 in de nabije toekomst. Deze uitbreiding is afhankelijk van verdere tests en optimalisatie om een naadloze functionaliteit te garanderen voor een breder scala aan hardwareconfiguraties. Ga naar issue chromium:1497815.

Screenshot van een WebGPU-voorbeeld dat wordt uitgevoerd in Chrome voor Android.
WebGPU-voorbeeld dat wordt uitgevoerd in Chrome voor Android.

DXC gebruiken in plaats van FXC voor shadercompilatie in Windows

Chrome gebruikt nu de kracht van DXC (DirectX Compiler) om shaders te compileren op Windows D3D12-machines met SM6+-grafische hardware. Eerder was WebGPU afhankelijk van FXC (FX Compiler) voor shadercompilatie in Windows. FXC was functioneel, maar had niet de functies en prestatieoptimalisaties van DXC.

Uit eerste tests blijkt dat de compilatiesnelheid van berekeningsshaders gemiddeld 20% hoger is als je DXC gebruikt in vergelijking met FXC.

Tijdstempelquery's in berekenings- en weergavefasen

Met tijdstempelquery's kunnen WebGPU-apps precies (tot op de nanoseconde) meten hoeveel tijd hun GPU-opdrachten nodig hebben om berekenings- en weergaveprocessen uit te voeren. Ze worden veel gebruikt om inzicht te krijgen in de prestaties en het gedrag van GPU-workloads.

Als de functie "timestamp-query" beschikbaar is in een GPUAdapter, kun je nu het volgende doen:

  • Vraag een GPUDevice aan met de functie "timestamp-query".
  • Maak een GPUQuerySet van het type "timestamp".
  • Gebruik GPUComputePassDescriptor.timestampWrites en GPURenderPassDescriptor.timestampWrites om te definiëren waar tijdstempelwaarden moeten worden geschreven in GPUQuerySet.
  • Tijdstempelwaarden omzetten in een GPUBuffer met resolveQuerySet().
  • Lees tijdstempelwaarden terug door de resultaten van de GPUBuffer naar de CPU te kopiëren.
  • Tijdstempelwaarden decoderen als een BigInt64Array.

Bekijk het volgende voorbeeld en geef dawn:1800 uit.

const adapter = await navigator.gpu.requestAdapter();
if (!adapter.features.has("timestamp-query")) {
  throw new Error("Timestamp query feature is not available");
}
// Explicitly request timestamp query feature.
const device = await adapter.requestDevice({
  requiredFeatures: ["timestamp-query"],
});
const commandEncoder = device.createCommandEncoder();

// Create a GPUQuerySet which holds 2 timestamp query results: one for the
// beginning and one for the end of compute pass execution.
const querySet = device.createQuerySet({ type: "timestamp", count: 2 });
const timestampWrites = {
  querySet,
  beginningOfPassWriteIndex: 0, // Write timestamp in index 0 when pass begins.
  endOfPassWriteIndex: 1, // Write timestamp in index 1 when pass ends.
};
const passEncoder = commandEncoder.beginComputePass({ timestampWrites });
// TODO: Set pipeline, bind group, and dispatch work to be performed.
passEncoder.end();

// Resolve timestamps in nanoseconds as a 64-bit unsigned integer into a GPUBuffer.
const size = 2 * BigInt64Array.BYTES_PER_ELEMENT;
const resolveBuffer = device.createBuffer({
  size,
  usage: GPUBufferUsage.QUERY_RESOLVE | GPUBufferUsage.COPY_SRC,
});
commandEncoder.resolveQuerySet(querySet, 0, 2, resolveBuffer, 0);

// Read GPUBuffer memory.
const resultBuffer = device.createBuffer({
  size,
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ,
});
commandEncoder.copyBufferToBuffer(resolveBuffer, 0, resultBuffer, 0, size);

// Submit commands to the GPU.
device.queue.submit([commandEncoder.finish()]);

// Log compute pass duration in nanoseconds.
await resultBuffer.mapAsync(GPUMapMode.READ);
const times = new BigInt64Array(resultBuffer.getMappedRange());
console.log(`Compute pass duration: ${Number(times[1] - times[0])}ns`);
resultBuffer.unmap();

Vanwege zorgen over timingaanvallen worden tijdstempelquery's gekwantiseerd met een resolutie van 100 microseconden. Dit is een goed compromis tussen nauwkeurigheid en beveiliging. In de Chrome-browser kun je kwantisatie van tijdstempels uitzetten door de flag WebGPU Developer Features aan te zetten op chrome://flags/#enable-webgpu-developer-features tijdens de ontwikkeling van je app. Ga naar Kwantisatie van tijdstempelquery's voor meer informatie.

Omdat GPU's de tijdstempelcounter af en toe kunnen resetten, wat kan leiden tot onverwachte waarden zoals negatieve delta's tussen tijdstempels, raad ik je aan de git diff-wijzigingen te checken die ondersteuning voor tijdstempelquery's toevoegen aan het volgende Compute Boids-voorbeeld.

Screenshot van het Compute Boids-voorbeeld met een query voor een tijdstempel.
Voorbeeld van Compute Boids met een tijdstempelquery.

Standaard startpunten voor shadermodules

Je kunt nu de entryPoint van je shader-module weglaten als je een berekenings- of weergavepijplijn maakt. Zo verbeter je de ontwikkelaarservaring. Als er geen uniek toegangspunt voor de shaderfase wordt gevonden in de shadercode, wordt er een GPUValidationError geactiveerd. Bekijk het volgende voorbeeld en probleem dawn:2254.

const code = `
    @vertex fn vertexMain(@builtin(vertex_index) i : u32) ->
      @builtin(position) vec4f {
       const pos = array(vec2f(0, 1), vec2f(-1, -1), vec2f(1, -1));
       return vec4f(pos[i], 0, 1);
    }
    @fragment fn fragmentMain() -> @location(0) vec4f {
      return vec4f(1, 0, 0, 1);
    }`;
const module = myDevice.createShaderModule({ code });
const format = navigator.gpu.getPreferredCanvasFormat();
const pipeline = await myDevice.createRenderPipelineAsync({
  layout: "auto",
  vertex: { module, entryPoint: "vertexMain" },
  fragment: { module, entryPoint: "fragmentMain", targets: [{ format }] },
  vertex: { module },
  fragment: { module, targets: [{ format }] },
});

Ondersteuning voor display-p3 als GPUExternalTexture-kleurruimte

Je kunt nu de "display-p3"bestemmingskleurruimte instellen als je een GPUExternalTexture importeert uit HDR-video's met importExternalTexture(). Ontdek hoe WebGPU kleurruimten verwerkt. Raadpleeg het volgende voorbeeld en het probleem chromium:1330250.

// Create texture from HDR video.
const video = document.querySelector("video");
const texture = myDevice.importExternalTexture({
  source: video,
  colorSpace: "display-p3",
});

Informatie over geheugen-heaps

requestAdapterInfo() biedt nu memoryHeaps-informatie, zoals de grootte en het type geheugen-heaps die beschikbaar zijn op de adapter. Zo kun je tijdens de ontwikkeling van je app rekening houden met geheugenbeperkingen als je grote hoeveelheden toewijst. Deze experimentele functie is alleen toegankelijk als de flag WebGPU Developer Features (WebGPU-ontwikkelaarsfuncties) op chrome://flags/#enable-webgpu-developer-features aanstaat. Bekijk het volgende voorbeeld en probleem dawn:2249.

const adapter = await navigator.gpu.requestAdapter();
const adapterInfo = await adapter.requestAdapterInfo();

for (const { size, properties } of adapterInfo.memoryHeaps) {
  console.log(size); // memory heap size in bytes
  if (properties & GPUHeapProperty.DEVICE_LOCAL)  { /* ... */ }
  if (properties & GPUHeapProperty.HOST_VISIBLE)  { /* ... */ }
  if (properties & GPUHeapProperty.HOST_COHERENT) { /* ... */ }
  if (properties & GPUHeapProperty.HOST_UNCACHED) { /* ... */ }
  if (properties & GPUHeapProperty.HOST_CACHED)   { /* ... */ }
}
Screenshot van https://webgpureport.org met geheugen-heaps in adapterinformatie.
Geheugen-heaps met adapterinformatie getoond op https://webgpureport.org.

Updates voor Dawn

De methoden HasWGSLLanguageFeature en EnumerateWGSLLanguageFeatures op wgpu::Instance zijn toegevoegd om WGSL-taalfuncties te verwerken. Ga naar probleem dawn:2260.

Met de niet-standaard functie wgpu::Feature::BufferMapExtendedUsages kun je een GPU-buffer maken met wgpu::BufferUsage::MapRead of wgpu::BufferUsage::MapWrite en een andere wgpu::BufferUsage. Bekijk het volgende voorbeeld en het probleem dawn:2204.

wgpu::BufferDescriptor descriptor = {
  .size = 128,
  .usage = wgpu::BufferUsage::MapWrite | wgpu::BufferUsage::Uniform
};
wgpu::Buffer uniformBuffer = device.CreateBuffer(&descriptor);

uniformBuffer.MapAsync(wgpu::MapMode::Write, 0, 128,
   [](WGPUBufferMapAsyncStatus status, void* userdata)
   {
      wgpu::Buffer* buffer = static_cast<wgpu::Buffer*>(userdata);
      memcpy(buffer->GetMappedRange(), data, sizeof(data));
   },
   &uniformBuffer);

De volgende functies zijn gedocumenteerd: ANGLE Texture Sharing, D3D11 multithread protected, Implicit Device Synchronization, Norm16 texture formats, Timestamp Query Inside Passes, Pixel Local Storage, Shader Features en Multi Planar Formats.

Het Chrome-team heeft een officiële GitHub-repository voor Dawn gemaakt.

Dit zijn maar enkele van de belangrijkste punten. Neem de uitgebreide lijst met doorvoeringen door.

Wat is er nieuw in WebGPU?

Een lijst met alles wat is behandeld in de serie Nieuw in WebGPU.

Chrome 155-156

Chrome 153-154

Chrome 151-152

Chrome 149-150

Chrome 147-148

Chrome 146

Chrome 145

Chrome 144

Chrome 143

Chrome 142

Chrome 141

Chrome 140

Chrome 139

Chrome 138

Chrome 137

Chrome 136

Chrome 135

Chrome 134

Chrome 133

Chrome 132

Chrome 131

Chrome 130

Chrome 129

Chrome 128

Chrome 127

Chrome 126

Chrome 125

Chrome 124

Chrome 123

Chrome 122

Chrome 121

Chrome 120

Chrome 119

Chrome 118

Chrome 117

Chrome 116

Chrome 115

Chrome 114

Chrome 113