Start · Sprachen · JavaScript · Referenz · GPUCommandBuffer

GPUCommandBuffer

Schnittstelle

Repräsentiert eine fertig aufgezeichnete, unveränderliche Liste von GPU-Befehlen, die per <code>GPUQueue.submit()</code> zur Ausführung an die GPU übergeben wird.

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

Signatur

interface GPUCommandBuffer

Beschreibung

GPUCommandBuffer ist das Ergebnis einer Befehlsaufzeichnung in WebGPU. Man erzeugt ihn nicht direkt über einen Konstruktor. Zuerst zeichnet man mit einem GPUCommandEncoder Befehle auf, etwa Render-Passes, Compute-Passes oder Kopiervorgänge zwischen Puffern und Texturen. Danach ruft man GPUCommandEncoder.finish() auf und erhält einen GPUCommandBuffer.

Der Befehlspuffer wird mit device.queue.submit([commandBuffer]) an die Warteschlange des Geräts übergeben. Die GPU arbeitet die Befehle dann asynchron ab. In einem submit()-Aufruf kann man mehrere Befehlspuffer auf einmal übergeben; sie werden in der Reihenfolge des Arrays ausgeführt.

Das Interface selbst ist sehr schlank. Es hat nur die Eigenschaft label, eine Zeichenkette zur Fehlersuche. Sie erscheint in Fehlermeldungen und in Debugging-Werkzeugen. Wichtig: Ein GPUCommandBuffer kann nur einmal übermittelt werden. Nach dem submit() ist er verbraucht. Für jeden Frame zeichnet man daher einen neuen Befehlspuffer auf.

Parameter

Name Typ Default Beschreibung
$label string "" Eigenschaft (lesbar und schreibbar): Bezeichnung für Debugging-Zwecke. Man setzt sie meist über den Deskriptor von encoder.finish({ label }).

Rückgabewert

Typ
GPUCommandBuffer
Beschreibung
Wird von GPUCommandEncoder.finish() zurückgegeben. Es gibt keinen öffentlichen Konstruktor.

Beispiele

Befehlspuffer erzeugen und übermitteln (Bildschirm löschen)

const canvas = document.querySelector('canvas');
const adapter = await navigator.gpu?.requestAdapter();
if (!adapter) throw new Error('WebGPU nicht verfügbar');
const device = await adapter.requestDevice();

const context = canvas.getContext('webgpu');
const format = navigator.gpu.getPreferredCanvasFormat();
context.configure({ device, format });

// Befehle aufzeichnen
const encoder = device.createCommandEncoder({ label: 'Frame-Encoder' });
const pass = encoder.beginRenderPass({
  colorAttachments: [{
    view: context.getCurrentTexture().createView(),
    clearValue: { r: 0.1, g: 0.2, b: 0.4, a: 1 },
    loadOp: 'clear',
    storeOp: 'store'
  }]
});
pass.end();

// Aufzeichnung abschließen, GPUCommandBuffer erhalten
const commandBuffer = encoder.finish({ label: 'Frame-Befehle' });
console.log(commandBuffer instanceof GPUCommandBuffer, commandBuffer.label);

// zur Ausführung übermitteln
device.queue.submit([commandBuffer]);
true "Frame-Befehle"

Neuer Befehlspuffer pro Frame in der Render-Schleife

const frame = () => {
  const encoder = device.createCommandEncoder();
  const pass = encoder.beginRenderPass({
    colorAttachments: [{
      view: context.getCurrentTexture().createView(),
      clearValue: { r: Math.abs(Math.sin(performance.now() / 1000)), g: 0, b: 0, a: 1 },
      loadOp: 'clear',
      storeOp: 'store'
    }]
  });
  pass.end();
  // Jeder Frame braucht einen eigenen Befehlspuffer
  device.queue.submit([encoder.finish()]);
  requestAnimationFrame(frame);
};
requestAnimationFrame(frame);

Compute- und Kopierbefehle, dann Ergebnis zurücklesen

const size = 16;
const storage = device.createBuffer({
  size,
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
});
const readback = device.createBuffer({
  size,
  usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(storage, 0, new Uint32Array([1, 2, 3, 4]));

const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(storage, 0, readback, 0, size);
const cmd = encoder.finish({ label: 'Readback' });

device.queue.submit([cmd]);
await readback.mapAsync(GPUMapMode.READ);
console.log(Array.from(new Uint32Array(readback.getMappedRange())));
readback.unmap();
[1, 2, 3, 4]

// Wichtig · Fallstricke

  • Nur einmal übermittelbar: Wird derselbe GPUCommandBuffer ein zweites Mal an submit() übergeben, entsteht ein Validierungsfehler, und die Übermittlung wird verworfen. Es wird keine Ausnahme ausgelöst. Sichtbar wird der Fehler in der Konsole, über device.pushErrorScope() oder über das uncapturederror-Event.
  • Ungültige Puffer: Ist bei der Aufzeichnung ein Fehler passiert, zum Beispiel ein nicht beendeter Pass vor finish(), liefert finish() trotzdem ein Objekt zurück. Dieses ist aber ungültig, und die Übermittlung schlägt fehl.
  • Nach finish() lässt sich der GPUCommandEncoder nicht weiter verwenden.
  • submit() ist asynchron zur GPU. Auf das Ende der Ausführung wartet man mit device.queue.onSubmittedWorkDone() oder buffer.mapAsync().
  • label sinnvoll vergeben: Das erleichtert die Fehlersuche deutlich.
  • Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht in allen Browsern bzw. auf allen Plattformen. Deshalb vorher navigator.gpu prüfen und eine Alternative vorsehen, etwa WebGL.