Start · Sprachen · JavaScript · Referenz · GPUCommandEncoder.finish()

GPUCommandEncoder.finish()

Methode

Schließt die Aufzeichnung der Befehle eines <code>GPUCommandEncoder</code> ab und gibt einen <code>GPUCommandBuffer</code> zurück, den man an <code>GPUQueue.submit()</code> übergeben kann.

seit JavaScript WebGPU – Chrome/Edge 113+, Safari 26+, Firefox 141 Kategorie: webapi

Signatur

GPUCommandEncoder.prototype.finish(descriptor)

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

Typ
GPUCommandBuffer
Beschreibung
Ein 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);
Frame-Befehle

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();
[1, 2, 3, 4]

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]);
}
Validierungsfehler: ... (Meldung browserabhängig, nennt das Label 'fehlerhaft')

// Wichtig · Fallstricke

  • Nur einmal aufrufen: Nach finish() ist der Encoder beendet. Jeder weitere Befehl darauf und jeder zweite finish()-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 Ereignis uncapturederror ab.
  • Offene Durchläufe: Jeder mit beginRenderPass() oder beginComputePass() geöffnete Durchlauf muss vorher mit end() geschlossen werden.
  • Einmal übermitteln: Ein GPUCommandBuffer lässt sich nur einmal an submit() übergeben. Für wiederholte Render-Befehle eignen sich GPURenderBundles.
  • Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht auf allen Plattformen. Vorher mit navigator.gpu prüfen, ob die API vorhanden ist.
  • Aussagekräftige label-Werte erleichtern die Fehlersuche deutlich, weil Browser sie in Fehlermeldungen anzeigen.