Start · Sprachen · JavaScript · Referenz · GPUComputePassEncoder

GPUComputePassEncoder

Schnittstelle

Kodiert Befehle für einen Compute-Pass der WebGPU-API: Pipeline setzen, Bind Groups binden und Compute-Shader-Arbeitsgruppen per <code>dispatchWorkgroups()</code> starten.

seit JavaScript WebGPU; Chrome/Edge 113+, Firefox 141+ (Windows), Kategorie: webapi

Signatur

interface GPUComputePassEncoder

Beschreibung

GPUComputePassEncoder ist Teil der WebGPU-API und steht für einen einzelnen Compute-Pass innerhalb eines Befehlspuffers. Man erhält eine Instanz nicht über einen Konstruktor, sondern über GPUCommandEncoder.beginComputePass(). Innerhalb des Passes legt man fest, welche GPUComputePipeline (also welcher Compute-Shader) ausgeführt wird, welche Ressourcen (Buffer, Texturen, Sampler) über Bind Groups verfügbar sind und wie viele Arbeitsgruppen gestartet werden.

Wichtige Methoden und Eigenschaften:

  • setPipeline(pipeline) – legt die zu verwendende GPUComputePipeline fest.
  • setBindGroup(index, bindGroup, dynamicOffsets?) – bindet eine GPUBindGroup an den Index @group(n) im WGSL-Shader.
  • dispatchWorkgroups(x, y?, z?) – startet ein Raster von Arbeitsgruppen (Standard für y und z: 1).
  • dispatchWorkgroupsIndirect(indirectBuffer, indirectOffset) – wie oben, die Anzahl der Gruppen wird aber aus einem GPU-Buffer gelesen.
  • pushDebugGroup(label), popDebugGroup(), insertDebugMarker(label) – Beschriftungen für Debugging-Werkzeuge.
  • end() – schließt den Pass ab; danach ist der Encoder nicht mehr nutzbar.
  • label – frei wählbarer Name, der in Fehlermeldungen erscheint.

Typische Einsatzgebiete sind GPGPU-Aufgaben direkt im Browser: Bildfilter, Partikelsimulationen, Physik, Matrixmultiplikation oder Inferenz neuronaler Netze. Der Ablauf ist immer gleich: Command Encoder anlegen → Compute-Pass beginnen → Pipeline und Bind Groups setzen → dispatchen → end() → commandEncoder.finish() → an device.queue.submit() übergeben.

Parameter

Name Typ Default Beschreibung
$descriptor (von beginComputePass) GPUComputePassDescriptor {} Optionales Objekt für GPUCommandEncoder.beginComputePass() mit label (string) und timestampWrites (für Zeitmessung, benötigt das Feature "timestamp-query").
$workgroupCountX Pflicht number Parameter von dispatchWorkgroups(): Anzahl der Arbeitsgruppen in X-Richtung.
$workgroupCountY number 1 Anzahl der Arbeitsgruppen in Y-Richtung.
$workgroupCountZ number 1 Anzahl der Arbeitsgruppen in Z-Richtung.

Rückgabewert

Typ
GPUComputePassEncoder
Beschreibung
GPUCommandEncoder.beginComputePass() liefert eine neue Instanz. Die Methoden des Encoders selbst geben undefined zurück; Fehler werden asynchron als Validierungsfehler des GPUDevice gemeldet.

Beispiele

Compute-Pass anlegen und Werte in einem Buffer verdoppeln

const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU wird nicht unterstützt');
const device = await adapter.requestDevice();

const module = device.createShaderModule({
  code: `
    @group(0) @binding(0) var<storage, read_write> data: array<f32>;

    @compute @workgroup_size(64)
    fn main(@builtin(global_invocation_id) id: vec3u) {
      if (id.x < arrayLength(&data)) {
        data[id.x] = data[id.x] * 2.0;
      }
    }
  `
});

const pipeline = device.createComputePipeline({
  layout: 'auto',
  compute: { module, entryPoint: 'main' }
});

const input = new Float32Array([1, 2, 3, 4, 5]);
const storage = device.createBuffer({
  size: input.byteLength,
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(storage, 0, input);

const bindGroup = device.createBindGroup({
  layout: pipeline.getBindGroupLayout(0),
  entries: [{ binding: 0, resource: { buffer: storage } }]
});

const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass({ label: 'Verdoppeln' });
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroups(Math.ceil(input.length / 64));
pass.end();

// Ergebnis in einen lesbaren Buffer kopieren
const readback = device.createBuffer({
  size: input.byteLength,
  usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
});
encoder.copyBufferToBuffer(storage, 0, readback, 0, input.byteLength);
device.queue.submit([encoder.finish()]);

await readback.mapAsync(GPUMapMode.READ);
console.log(Array.from(new Float32Array(readback.getMappedRange())));
readback.unmap();
[2, 4, 6, 8, 10]

2D-Dispatch für die Bildverarbeitung mit Debug-Gruppen

// Annahme: device, pipeline und bindGroup existieren bereits (Shader mit @workgroup_size(8, 8))
const width = 1920;
const height = 1080;

const encoder = device.createCommandEncoder({ label: 'Bildfilter' });
const pass = encoder.beginComputePass({ label: 'Graustufen-Pass' });

pass.pushDebugGroup('Graustufen');
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.insertDebugMarker('Dispatch startet');
pass.dispatchWorkgroups(Math.ceil(width / 8), Math.ceil(height / 8));
pass.popDebugGroup();

pass.end();
device.queue.submit([encoder.finish()]);
console.log(`${Math.ceil(width / 8) * Math.ceil(height / 8)} Arbeitsgruppen gestartet`);
32400 Arbeitsgruppen gestartet

Indirekter Dispatch – Gruppenanzahl aus einem Buffer

// Drei u32-Werte: x, y, z – können auch von einem vorherigen Shader geschrieben werden
const indirect = device.createBuffer({
  size: 12,
  usage: GPUBufferUsage.INDIRECT | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(indirect, 0, new Uint32Array([16, 1, 1]));

const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
pass.setPipeline(pipeline);
pass.setBindGroup(0, bindGroup);
pass.dispatchWorkgroupsIndirect(indirect, 0);
pass.end();
device.queue.submit([encoder.finish()]);

Validierungsfehler abfangen

device.pushErrorScope('validation');

const encoder = device.createCommandEncoder();
const pass = encoder.beginComputePass();
// Fehler: dispatch ohne vorher gesetzte Pipeline
pass.dispatchWorkgroups(1);
pass.end();
device.queue.submit([encoder.finish()]);

const error = await device.popErrorScope();
if (error) console.warn('Validierungsfehler:', error.message);
Validierungsfehler: ... (browserabhängige Meldung)