Signatur
Beschreibung
Mit finish() beendet man die Aufzeichnung von GPU-Befehlen. Alles, was zuvor über den Encoder festgehalten wurde, landet in einem unveränderlichen GPUCommandBuffer: Render- und Compute-Durchläufe (beginRenderPass(), beginComputePass()), Kopiervorgänge (copyBufferToBuffer(), copyTextureToTexture() usw.), clearBuffer(), Zeitstempel-Abfragen oder resolveQuerySet(). Diesen Puffer übergibt man anschließend an device.queue.submit(), damit die GPU die Befehle ausführt.
Nach dem Aufruf ist der Encoder beendet und lässt sich nicht weiterverwenden. Für das nächste Einzelbild bzw. den nächsten Arbeitsschritt erzeugt man mit device.createCommandEncoder() einen neuen Encoder. Das ist günstig und in WebGPU so vorgesehen.
Wichtig: Alle geöffneten Durchläufe müssen vorher mit passEncoder.end() geschlossen sein. Ist das nicht der Fall oder war der Encoder aus einem anderen Grund ungültig, wirft finish() keine JavaScript-Ausnahme. Stattdessen entsteht ein Validierungsfehler auf dem GPUDevice, und der zurückgegebene Befehlspuffer ist ungültig. Ein submit() mit diesem Puffer erzeugt dann einen weiteren Fehler.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $descriptor | GPUCommandBufferDescriptor | {} | Optionales Konfigurationsobjekt. Zurzeit gibt es nur die Eigenschaft label (string). Dieser Name taucht in Fehlermeldungen und Debug-Werkzeugen auf. |
Rückgabewert
GPUCommandBuffer mit den aufgezeichneten Befehlen. Man übergibt ihn an GPUQueue.submit(). Jeder Befehlspuffer lässt sich nur einmal übermitteln.Beispiele
Einfacher Render-Durchlauf: Canvas einfärben
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU nicht verfügbar');
const device = await adapter.requestDevice();
const canvas = document.querySelector('canvas');
const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });
const encoder = device.createCommandEncoder({ label: 'Frame-Encoder' });
const pass = encoder.beginRenderPass({
colorAttachments: [{
view: context.getCurrentTexture().createView(),
clearValue: { r: 0.1, g: 0.3, b: 0.6, a: 1 },
loadOp: 'clear',
storeOp: 'store'
}]
});
pass.end(); // Durchlauf MUSS vor finish() beendet sein
const commandBuffer = encoder.finish({ label: 'Frame-Befehle' });
device.queue.submit([commandBuffer]);
console.log(commandBuffer.label);
Compute-Ergebnis in einen lesbaren Puffer kopieren
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const size = 16;
const src = device.createBuffer({
size,
usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(src, 0, new Float32Array([1, 2, 3, 4]));
const readback = device.createBuffer({
size,
usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ
});
const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(src, 0, readback, 0, size);
device.queue.submit([encoder.finish()]);
await readback.mapAsync(GPUMapMode.READ);
console.log(Array.from(new Float32Array(readback.getMappedRange())));
readback.unmap();
Validierungsfehler bei finish() abfangen
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
device.pushErrorScope('validation');
const encoder = device.createCommandEncoder();
encoder.beginComputePass(); // absichtlich KEIN pass.end()
const cb = encoder.finish({ label: 'fehlerhaft' });
const error = await device.popErrorScope();
if (error) {
console.warn('Validierungsfehler:', error.message);
} else {
device.queue.submit([cb]);
}
// Wichtig · Fallstricke
- Nur einmal aufrufen: Nach
finish()ist der Encoder beendet. Jeder weitere Befehl darauf und jeder zweitefinish()-Aufruf erzeugt einen Validierungsfehler. - Keine Ausnahmen: Fehler werden nicht als JavaScript-Ausnahme geworfen, sondern asynchron gemeldet. Man fängt sie mit
device.pushErrorScope()/popErrorScope()oder über das Ereignisuncapturederrorab. - Offene Durchläufe: Jeder mit
beginRenderPass()oderbeginComputePass()geöffnete Durchlauf muss vorher mitend()geschlossen werden. - Einmal übermitteln: Ein
GPUCommandBufferlässt sich nur einmal ansubmit()übergeben. Für wiederholte Render-Befehle eignen sichGPURenderBundles. - Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht auf allen Plattformen. Vorher mit
navigator.gpuprüfen, ob die API vorhanden ist. - Aussagekräftige
label-Werte erleichtern die Fehlersuche deutlich, weil Browser sie in Fehlermeldungen anzeigen.