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

GPUCommandEncoder.copyBufferToBuffer()

Methode

Fügt dem Befehlspuffer einen Befehl hinzu, der einen Bytebereich von einem <code>GPUBuffer</code> in einen anderen kopiert. Der Befehl wird auf der GPU ausgeführt.

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

Signatur

GPUCommandEncoder.prototype.copyBufferToBuffer(source, sourceOffset, destination, destinationOffset, size)

Beschreibung

copyBufferToBuffer() zeichnet in einem GPUCommandEncoder einen Kopierbefehl auf. Der Befehl wird noch nicht ausgeführt, wenn die Methode aufgerufen wird. Die GPU führt ihn erst aus, nachdem der fertige GPUCommandBuffer mit device.queue.submit() übergeben wurde. Die Kopie findet vollständig auf der GPU statt. Dabei werden keine Daten zur CPU übertragen.

Typische Einsatzfälle sind:

  • Rücklesen: Ergebnisse eines Compute-Shaders aus einem STORAGE-Puffer in einen Puffer mit MAP_READ kopieren. Nur dieser kann anschließend mit mapAsync() auf der CPU gelesen werden.
  • Staging: Daten aus einem gemappten Upload-Puffer (MAP_WRITE) in einen Vertex-, Uniform- oder Storage-Puffer übertragen.
  • Umordnen oder Duplizieren von GPU-Daten, zum Beispiel für Ping-Pong-Puffer in Simulationen.

Der Quellpuffer braucht das Nutzungsflag GPUBufferUsage.COPY_SRC, der Zielpuffer das Flag GPUBufferUsage.COPY_DST. Beide Offsets und die Größe müssen Vielfache von 4 Byte sein. Außerdem müssen die kopierten Bereiche vollständig innerhalb der jeweiligen Puffer liegen. Verstößt ein Aufruf gegen diese Regeln, wirft die Methode keine JavaScript-Ausnahme. Stattdessen wird ein Validierungsfehler erzeugt, und der Encoder wird ungültig. Der Fehler zeigt sich erst bei finish() oder submit(). Er lässt sich über device.pushErrorScope() oder das Ereignis uncapturederror abfangen.

Parameter

Name Typ Default Beschreibung
$source Pflicht GPUBuffer Puffer, aus dem gelesen wird. Er muss mit GPUBufferUsage.COPY_SRC erstellt worden sein.
$sourceOffset Pflicht number Startposition im Quellpuffer in Byte. Muss ein Vielfaches von 4 sein.
$destination Pflicht GPUBuffer Puffer, in den geschrieben wird. Er muss mit GPUBufferUsage.COPY_DST erstellt worden sein und darf nicht derselbe Puffer wie source sein.
$destinationOffset Pflicht number Startposition im Zielpuffer in Byte. Muss ein Vielfaches von 4 sein.
$size number source.size - sourceOffset Anzahl der zu kopierenden Bytes. Muss ein Vielfaches von 4 sein. In der klassischen Form mit fünf Argumenten ist der Wert Pflicht. Nur bei der neueren Kurzform darf er entfallen.

Rückgabewert

Typ
undefined
Beschreibung
Kein Rückgabewert. Der Befehl wird lediglich im Encoder aufgezeichnet.

Beispiele

Compute-Ergebnis auf die CPU zurücklesen

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();

const byteSize = 16; // 4 × Float32

// Puffer, in den z. B. ein Compute-Shader schreibt
const resultBuffer = device.createBuffer({
  size: byteSize,
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(resultBuffer, 0, new Float32Array([1.5, 2.5, 3.5, 4.5]));

// Lesbarer Staging-Puffer
const readBuffer = device.createBuffer({
  size: byteSize,
  usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});

const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(resultBuffer, 0, readBuffer, 0, byteSize);
device.queue.submit([encoder.finish()]);

await readBuffer.mapAsync(GPUMapMode.READ);
const data = new Float32Array(readBuffer.getMappedRange().slice(0));
readBuffer.unmap();
console.log(data);
Float32Array(4) [1.5, 2.5, 3.5, 4.5]

Teilbereich mit Offsets kopieren

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();

const src = device.createBuffer({
  size: 32,
  usage: GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
});
const dst = device.createBuffer({
  size: 32,
  usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.COPY_SRC,
});

device.queue.writeBuffer(src, 0, new Uint32Array([0, 1, 2, 3, 4, 5, 6, 7]));

const encoder = device.createCommandEncoder();
// Elemente 4..7 (Byte 16–31) an den Anfang von dst kopieren
encoder.copyBufferToBuffer(src, 16, dst, 0, 16);
device.queue.submit([encoder.finish()]);

Validierungsfehler abfangen

const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();

const a = device.createBuffer({ size: 16, usage: GPUBufferUsage.COPY_SRC });
const b = device.createBuffer({ size: 16, usage: GPUBufferUsage.COPY_DST });

device.pushErrorScope('validation');
const encoder = device.createCommandEncoder();
// Fehler: size 6 ist kein Vielfaches von 4
encoder.copyBufferToBuffer(a, 0, b, 0, 6);
device.queue.submit([encoder.finish()]);

const error = await device.popErrorScope();
console.log(error ? `Fehler: ${error.message}` : 'OK');
Fehler: … (browserabhängige Meldung zur Ausrichtung von size)

// Wichtig · Fallstricke

  • Ausrichtung: sourceOffset, destinationOffset und size müssen Vielfache von 4 sein. Sonst entsteht ein Validierungsfehler und keine Ausnahme.
  • Gleicher Puffer: source und destination dürfen nicht derselbe Puffer sein, auch nicht bei Bereichen, die sich nicht überlappen.
  • Mapping-Zustand: Beide Puffer müssen zum Zeitpunkt von submit() ungemappt sein. Ein Puffer, der mit mappedAtCreation: true erstellt wurde, muss vorher mit unmap() freigegeben werden.
  • Grenzen: sourceOffset + size darf source.size nicht überschreiten. Entsprechend darf destinationOffset + size nicht größer als destination.size sein.
  • Kurzform: Neuere Versionen der Spezifikation erlauben zusätzlich copyBufferToBuffer(source, destination[, size]) mit Offset 0. Diese Form wird noch nicht überall unterstützt. Für breite Kompatibilität ist die Variante mit fünf Argumenten die bessere Wahl.
  • Kleine Uploads: Für einzelne Uploads von der CPU ist device.queue.writeBuffer() meist einfacher als ein eigener Staging-Puffer mit anschließendem Kopieren.
  • Verfügbarkeit: WebGPU steht nur in sicheren Kontexten (HTTPS) zur Verfügung. Die Unterstützung durch Browser und Plattformen ist noch nicht einheitlich. Vorher sollte man navigator.gpu prüfen.