Neu bei WebGPU (Chrome 121)

François Beaufort
François Beaufort

WebGPU auf Android unterstützen

Das Chrome-Team freut sich, bekannt zu geben, dass WebGPU jetzt in Chrome 121 auf Geräten mit Android 12 und höher, die von Qualcomm- und ARM-GPUs unterstützt werden, standardmäßig aktiviert ist.

Die Unterstützung wird nach und nach auf eine größere Auswahl an Android-Geräten ausgeweitet, darunter auch Geräte mit Android 11. Diese Erweiterung hängt von weiteren Tests und Optimierungen ab, um eine nahtlose Nutzung auf einer größeren Bandbreite von Hardwarekonfigurationen zu gewährleisten. Weitere Informationen finden Sie unter 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 Shader-Kompilierung unter Windows verwenden

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

Erste Tests zeigen, dass die Kompilierungsgeschwindigkeit von Compute-Shadern bei Verwendung von DXC im Vergleich zu FXC durchschnittlich um 20% gesteigert wird.

Zeitstempelabfragen in Compute- und Render-Passes

Mit Zeitstempelabfragen können WebGPU-Anwendungen genau (bis auf die Nanosekunde) messen, wie viel Zeit die Ausführung von Compute- und Render-Passes für ihre GPU-Befehle in Anspruch nimmt. 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 einen GPUDevice mit der Funktion "timestamp-query" an.
  • Erstellen Sie ein GPUQuerySet vom Typ "timestamp".
  • Mit GPUComputePassDescriptor.timestampWrites und GPURenderPassDescriptor.timestampWrites können Sie definieren, wo Zeitstempelwerte in GPUQuerySet geschrieben werden sollen.
  • Lösen Sie Zeitstempelwerte mit resolveQuerySet() in eine GPUBuffer auf.
  • Lesen Sie Zeitstempelwerte zurück, indem Sie die Ergebnisse von der GPUBuffer auf die CPU kopieren.
  • Zeitstempelwerte als BigInt64Array decodieren.

Sehen Sie sich das folgende Beispiel an 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 Gründen der Timing-Attacke werden Zeitstempelabfragen mit einer Auflösung von 100 Mikrosekunden quantisiert. Dies bietet einen guten Kompromiss zwischen Genauigkeit und Sicherheit. Im Chrome-Browser können Sie die Zeitstempelquantisierung deaktivieren, indem Sie während der Entwicklung Ihrer App das Flag „WebGPU Developer Features“ unter chrome://flags/#enable-webgpu-developer-features aktivieren. Weitere Informationen

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, mit denen die Unterstützung für Zeitstempelabfragen zum folgenden Compute Boids-Beispiel hinzugefügt wird.

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

Standardeinstiegspunkte für Shadermodule

Um die Entwicklerfreundlichkeit zu verbessern, können Sie jetzt beim Erstellen einer Compute- oder Render-Pipeline das entryPoint Ihres Shader-Moduls weglassen. Wenn im Shader-Code kein eindeutiger Einstiegspunkt für die Shader-Phase gefunden wird, wird ein 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 GPUExternalTexture-Farbraum

Beim Importieren einer GPUExternalTexture aus HDR-Videos mit importExternalTexture() kann jetzt der Zielfarbraum "display-p3" festgelegt werden. Informationen zur Verarbeitung von Farbräumen in WebGPU Sehen Sie sich das folgende Beispiel und das Problem chromium:1330250 an.

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

Informationen zu Speicher-Heaps

Damit Sie Speicherbeschränkungen bei der Zuweisung großer Mengen während der Entwicklung Ihrer App besser vorhersehen können, werden in requestAdapterInfo() jetzt memoryHeaps-Informationen wie die Größe und der Typ der auf dem Adapter verfügbaren Speicher-Heaps angezeigt. Diese experimentelle Funktion ist nur verfügbar, wenn das Flag „WebGPU Developer Features“ unter chrome://flags/#enable-webgpu-developer-features aktiviert ist. Sehen Sie sich das folgende Beispiel und Problem dawn:2249 an.

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 Speicher-Heaps in den Adapterinformationen.
Auf https://webgpureport.org angezeigte Informationen zum Adapter-Arbeitsspeicher.

Dawn-Updates

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

Mit der nicht standardmäßigen Funktion wgpu::Feature::BufferMapExtendedUsages können Sie einen GPU-Puffer mit wgpu::BufferUsage::MapRead oder wgpu::BufferUsage::MapWrite und einem beliebigen anderen wgpu::BufferUsage erstellen. Sehen Sie sich das folgende Beispiel und das Problem dawn:2204 an.

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: ANGLE Texture Sharing, D3D11 multithread protected, Implicit Device Synchronization, Norm16 texture formats, Timestamp Query Inside Passes, Pixel Local Storage, Shader Features und Multi Planar Formats.

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

Dies sind nur einige der wichtigsten Neuerungen. Vollständige Liste der Commits

Neues zu WebGPU

Eine Liste mit allen Themen, die in der Reihe Neu in WebGPU behandelt wurden.

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