Signatur
Beschreibung
mapAsync() fordert an, dass ein Bereich eines GPUBuffer für die CPU zugänglich gemacht wird. Das zurückgegebene Promise wird erfüllt, sobald die GPU alle vorher eingereihten Arbeiten auf diesem Puffer abgeschlossen hat. Danach liefert getMappedRange() einen ArrayBuffer, über den du die Daten liest (GPUMapMode.READ) oder schreibst (GPUMapMode.WRITE).
Typische Anwendungsfälle sind das Zurücklesen von Ergebnissen eines Compute-Shaders und das Hochladen von Daten über einen Staging-Puffer. Dazu muss der Puffer mit GPUBufferUsage.MAP_READ bzw. GPUBufferUsage.MAP_WRITE erzeugt worden sein. MAP_READ lässt sich nur mit COPY_DST kombinieren, MAP_WRITE nur mit COPY_SRC. Deshalb kopiert man Daten meist per copyBufferToBuffer() zwischen einem GPU-Arbeitspuffer und einem mappbaren Staging-Puffer.
Solange ein Puffer gemappt ist oder das Mapping noch läuft, darf die GPU ihn nicht verwenden. Nach der Arbeit rufst du unmap() auf. Dadurch werden alle mit getMappedRange() erhaltenen ArrayBuffer getrennt (detached) und der Puffer steht der GPU wieder zur Verfügung.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $mode Pflicht | number (GPUMapModeFlags) | Zugriffsart: GPUMapMode.READ oder GPUMapMode.WRITE. Es muss genau eines von beiden gesetzt sein, passend zu den usage-Flags des Puffers. |
|
| $offset | number | 0 | Startposition des Bereichs in Bytes. Muss ein Vielfaches von 8 sein. |
| $size | number | buffer.size - offset | Länge des Bereichs in Bytes. Muss ein Vielfaches von 4 sein. offset + size darf buffer.size nicht überschreiten. |
Rückgabewert
OperationError- bzw. AbortError-DOMException abgelehnt, wenn die Validierung fehlschlägt, das Gerät verloren geht oder vorher unmap()/destroy() aufgerufen wird.Beispiele
Ergebnis eines Compute-Shaders zurücklesen
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const SIZE = 16; // 4 Floats
// Arbeitspuffer (z. B. Ausgabe eines Compute-Shaders)
const output = device.createBuffer({
size: SIZE,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST
});
device.queue.writeBuffer(output, 0, new Float32Array([1.5, 2.5, 3.5, 4.5]));
// Staging-Puffer zum Auslesen
const staging = device.createBuffer({
size: SIZE,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
});
const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(output, 0, staging, 0, SIZE);
device.queue.submit([encoder.finish()]);
await staging.mapAsync(GPUMapMode.READ);
// Kopie anlegen, da der ArrayBuffer nach unmap() getrennt wird
const result = new Float32Array(staging.getMappedRange().slice(0));
staging.unmap();
console.log(result);
Daten über einen MAP_WRITE-Puffer hochladen
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const upload = device.createBuffer({
size: 16,
usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC
});
await upload.mapAsync(GPUMapMode.WRITE);
new Uint32Array(upload.getMappedRange()).set([10, 20, 30, 40]);
upload.unmap();
console.log(upload.mapState);
Nur einen Teilbereich mappen und Fehler behandeln
const readTail = async (buffer) => {
try {
// Bytes 8–15 lesen (offset: Vielfaches von 8, size: Vielfaches von 4)
await buffer.mapAsync(GPUMapMode.READ, 8, 8);
const part = new Uint32Array(buffer.getMappedRange(8, 8).slice(0));
buffer.unmap();
return part;
} catch (err) {
console.error('Mapping fehlgeschlagen:', err.name, err.message);
return null;
}
};
// Wichtig · Fallstricke
- Kein Überlappen: Ein zweiter
mapAsync()-Aufruf, solangemapStatenicht"unmapped"ist, schlägt fehl. Prüfe vorherbuffer.mapState. - Getrennte ArrayBuffer: Nach
unmap()sind alle Views auf den gemappten Bereich unbrauchbar (Länge 0). Wenn du die Daten länger brauchst, kopiere sie mit.slice(0). - Nutzung durch die GPU: Wird ein gemappter Puffer in
queue.submit()verwendet, entsteht ein Validierungsfehler. - Ausrichtung:
offsetmuss ein Vielfaches von 8 sein,sizeein Vielfaches von 4. Sonst wird das Promise abgelehnt. - Performance: Warte nicht in jedem Frame mit
awaitauf das Mapping, das bremst die Pipeline aus. Besser ist ein Ring aus mehreren Staging-Puffern. Für einfache Uploads istdevice.queue.writeBuffer()meist bequemer. - Kompatibilität: WebGPU steht nur in sicheren Kontexten (HTTPS) zur Verfügung und wird noch nicht überall unterstützt. Prüfe deshalb vorher, ob
navigator.gpuvorhanden ist.