Neu bei WebGPU (Chrome 121)

François Beaufort
François Beaufort

Unterstützung von WebGPU unter Android

Das Chrome-Team freut sich, Ihnen mitteilen zu können, dass WebGPU jetzt standardmäßig in Chrome 121 auf Geräten mit Android 12 und höher mit Qualcomm- und ARM-GPUs aktiviert ist.

Die Unterstützung wird nach und nach auf weitere Android-Geräte ausgeweitet, einschließlich Geräte mit Android 11. Diese Erweiterung hängt von weiteren Tests und Optimierungen ab, um eine reibungslose Nutzung auf einer breiteren Palette von Hardwarekonfigurationen zu ermöglichen. Siehe Problem chromium:1497815.

Screenshot eines WebGPU-Beispiels, das in Chrome für Android ausgeführt wird.
WebGPU-Beispiel, das in Chrome für Android ausgeführt wird

DXC anstelle von FXC für die Shaderkompilierung unter Windows verwenden

Chrome nutzt jetzt DXC (DirectX Compiler), um Shader auf Windows-D3D12-Computern zu kompilieren, die mit SM6+ Grafikhardware ausgestattet sind. Bisher wurde für die Shaderkompilierung unter Windows FXC (FX Compiler) verwendet. FXC war zwar funktionsfähig, aber es fehlten die Funktionen und Leistungsoptimierungen von DXC.

Erste Tests haben gezeigt, dass die Geschwindigkeit der Compute-Shader-Kompilierung bei Verwendung von DXC im Vergleich zu FXC durchschnittlich um 20% höher ist.

Zeitstempelabfragen in Compute- und Render-Tickets

Mit Zeitstempelabfragen können WebGPU-Anwendungen genau (bis auf die Nanosekunde) messen, wie viel Zeit ihre GPU-Befehle für die Ausführung von Compute- und Rendering-Passen benötigen. Sie werden häufig verwendet, um Einblicke in die Leistung und das Verhalten von GPU-Arbeitslasten zu erhalten.

Wenn die Funktion "timestamp-query" in einem GPUAdapter verfügbar ist, haben Sie jetzt folgende Möglichkeiten:

  • Fordern Sie ein GPUDevice mit der Funktion "timestamp-query" an.
  • Erstellen Sie eine GPUQuerySet vom Typ "timestamp".
  • Mit GPUComputePassDescriptor.timestampWrites und GPURenderPassDescriptor.timestampWrites können Sie festlegen, wo Zeitstempelwerte in GPUQuerySet geschrieben werden.
  • Lösen Sie Zeitstempelwerte mithilfe von resolveQuerySet() in eine GPUBuffer auf.
  • Lesen Sie Zeitstempelwerte zurück, indem Sie die Ergebnisse aus dem GPUBuffer in die CPU kopieren.
  • Dekodieren Sie Zeitstempelwerte als BigInt64Array.

Siehe das folgende Beispiel und geben Sie dawn:1800 ein.

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

Aus Sicherheitsgründen werden Zeitstempelabfragen aufgrund von Timing-Angriffen mit einer Auflösung von 100 Mikrosekunden quantisiert. Dies bietet einen guten Kompromiss zwischen Genauigkeit und Sicherheit. Im Chrome-Browser können Sie die Quantisierung von Zeitstempeln deaktivieren, indem Sie während der Entwicklung Ihrer App die Flagge „WebGPU Developer Features“ unter chrome://flags/#enable-webgpu-developer-features aktivieren. Weitere Informationen finden Sie unter Quantisierung von Zeitstempelabfragen.

Da GPUs den Zeitstempelzähler gelegentlich zurücksetzen können, was zu unerwarteten Werten wie negativen Deltas zwischen Zeitstempeln führen kann, empfehle ich Ihnen, sich die Git-Diff-Änderungen anzusehen, die dem folgenden Compute Boids-Beispiel die Unterstützung von Zeitstempelabfragen hinzufügen.

Screenshot des Beispiels „Compute Boids“ mit Zeitstempelabfrage
Compute Boids-Beispiel mit Zeitstempelabfrage.

Standardeinstiegspunkte für Shadermodule

Für eine bessere Nutzerfreundlichkeit können Sie beim Erstellen einer Compute- oder Renderpipeline jetzt die entryPoint Ihres Shadermoduls weglassen. Wenn im Shadercode kein eindeutiger Einstiegspunkt für die Shaderphase gefunden wird, wird eine GPUValidationError ausgelöst. Sehen Sie sich das folgende Beispiel und issue dawn:2254 an.

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

Unterstützung von Display-P3 als Farbraum für GPUExternalTexture

Du kannst jetzt den "display-p3"-Zielfarbraum festlegen, wenn du eine GPUExternalTexture aus HDR-Videos mit importExternalTexture() importierst. Weitere Informationen dazu, wie WebGPU mit Farbräumen umgeht Siehe das folgende Beispiel und das Problem chromium:1330250.

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

Informationen zu Arbeitsspeicher-Heaps

Damit Sie bei der Entwicklung Ihrer App Speichereinschränkungen bei der Zuweisung großer Mengen antizipieren können, werden in requestAdapterInfo() jetzt memoryHeaps-Informationen wie die Größe und der Typ der Speicherbereiche angezeigt, die auf dem Adapter verfügbar sind. Diese experimentelle Funktion ist nur verfügbar, wenn die Flagge „WebGPU Developer Features“ unter chrome://flags/#enable-webgpu-developer-features aktiviert ist. Weitere Informationen finden Sie im folgenden Beispiel und in Issue 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 von https://webgpureport.org mit Speicherheaps in den Adapterinformationen
Informationen zu Adapter-Speicher-Haufen unter https://webgpureport.org.

Dawn-Updates

Die Methoden HasWGSLLanguageFeature und EnumerateWGSLLanguageFeatures in wgpu::Instance wurden hinzugefügt, um WGSL-Sprachfunktionen zu verarbeiten. Siehe Problem dawn:2260.

Mit der nicht standardmäßigen wgpu::Feature::BufferMapExtendedUsages-Funktion können Sie einen GPU-Puffer mit wgpu::BufferUsage::MapRead oder wgpu::BufferUsage::MapWrite und einer beliebigen anderen wgpu::BufferUsage erstellen. Siehe Beispiel und Problem 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);

Die folgenden Funktionen wurden dokumentiert: Freigabe von ANGLE-Texturen, D3D11-Multithread-geschützt, implizite Gerätesynchronisierung, Norm16-Texturformate, Zeitstempelabfrage in Karten/Tickets, Lokaler Pixel-Speicher, Shader-Funktionen und Multiplanare Formate.

Das Chrome-Team hat ein offizielles GitHub-Repository für Dawn erstellt.

Hier werden nur einige der wichtigsten Vorteile behandelt. Eine vollständige Liste der Commits

Das ist neu bei WebGPU

Eine Liste aller Themen, die in der Reihe Was ist neu in WebGPU? behandelt wurden.

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