Signatur
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
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]);
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();
// Wichtig · Fallstricke
- Nur einmal übermittelbar: Wird derselbe
GPUCommandBufferein zweites Mal ansubmit()übergeben, entsteht ein Validierungsfehler, und die Übermittlung wird verworfen. Es wird keine Ausnahme ausgelöst. Sichtbar wird der Fehler in der Konsole, überdevice.pushErrorScope()oder über dasuncapturederror-Event. - Ungültige Puffer: Ist bei der Aufzeichnung ein Fehler passiert, zum Beispiel ein nicht beendeter Pass vor
finish(), liefertfinish()trotzdem ein Objekt zurück. Dieses ist aber ungültig, und die Übermittlung schlägt fehl. - Nach
finish()lässt sich derGPUCommandEncodernicht weiter verwenden. submit()ist asynchron zur GPU. Auf das Ende der Ausführung wartet man mitdevice.queue.onSubmittedWorkDone()oderbuffer.mapAsync().labelsinnvoll 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.gpuprüfen und eine Alternative vorsehen, etwa WebGL.