Signatur
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 mitMAP_READkopieren. Nur dieser kann anschließend mitmapAsync()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
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);
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');
// Wichtig · Fallstricke
- Ausrichtung:
sourceOffset,destinationOffsetundsizemüssen Vielfache von 4 sein. Sonst entsteht ein Validierungsfehler und keine Ausnahme. - Gleicher Puffer:
sourceunddestinationdü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 mitmappedAtCreation: trueerstellt wurde, muss vorher mitunmap()freigegeben werden. - Grenzen:
sourceOffset + sizedarfsource.sizenicht überschreiten. Entsprechend darfdestinationOffset + sizenicht größer alsdestination.sizesein. - 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.gpuprüfen.