Signatur
Beschreibung
unmap() beendet den gemappten Zustand eines GPUBuffer. Ein Puffer ist entweder nach einem erfolgreichen mapAsync() gemappt oder direkt nach der Erstellung, wenn mappedAtCreation: true gesetzt war. Solange er gemappt ist, kann nur JavaScript auf seinen Speicher zugreifen, und zwar über getMappedRange(). Die GPU kann ihn in dieser Zeit nicht verwenden. Erst nach unmap() darf der Puffer wieder in Befehlen wie copyBufferToBuffer(), Bind-Groups oder queue.submit() vorkommen.
Beim Aufruf werden alle ArrayBuffer, die getMappedRange() geliefert hat, abgetrennt (detached). Ihre byteLength ist danach 0, und jeder Zugriff über ein Typed Array ergibt nichts mehr. Daten, die du später noch brauchst, musst du also vor dem Aufruf kopieren, zum Beispiel mit slice().
Typische Abläufe:
- Hochladen: Puffer mit
mappedAtCreation: trueerstellen, Daten ingetMappedRange()schreiben, dannunmap()aufrufen. - Zurücklesen: Ergebnis in einen Puffer mit
MAP_READ | COPY_DSTkopieren,await mapAsync(GPUMapMode.READ)ausführen, Daten kopieren, dannunmap()aufrufen.
Rufst du unmap() auf, während ein mapAsync()-Aufruf noch läuft, wird dessen Promise mit einem AbortError abgelehnt.
Rückgabewert
buffer.mapState) ist danach "unmapped".Beispiele
Vertex-Daten mit mappedAtCreation hochladen
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const vertices = new Float32Array([0, 0.5, -0.5, -0.5, 0.5, -0.5]);
const vertexBuffer = device.createBuffer({
size: vertices.byteLength,
usage: GPUBufferUsage.VERTEX,
mappedAtCreation: true
});
// Daten direkt in den gemappten Bereich schreiben
new Float32Array(vertexBuffer.getMappedRange()).set(vertices);
// Freigeben – ab jetzt darf die GPU den Puffer nutzen
vertexBuffer.unmap();
console.log(vertexBuffer.mapState);
Compute-Ergebnis zurücklesen und danach freigeben
// Annahme: device und outputBuffer (usage STORAGE | COPY_SRC) existieren bereits
const size = 16;
const readBuffer = device.createBuffer({
size,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
});
const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(outputBuffer, 0, readBuffer, 0, size);
device.queue.submit([encoder.finish()]);
await readBuffer.mapAsync(GPUMapMode.READ);
// Kopie anlegen, BEVOR unmap() den ArrayBuffer abtrennt
const result = new Float32Array(readBuffer.getMappedRange().slice(0));
readBuffer.unmap();
console.log(result);
Fallstrick: abgetrennter ArrayBuffer nach unmap()
const buf = device.createBuffer({
size: 8,
usage: GPUBufferUsage.COPY_SRC,
mappedAtCreation: true
});
const view = new Uint32Array(buf.getMappedRange());
view[0] = 42;
buf.unmap();
console.log(view.length); // Ansicht ist jetzt leer
console.log(view.buffer.byteLength);
Laufendes mapAsync() abbrechen
const staging = device.createBuffer({
size: 64,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST
});
const pending = staging.mapAsync(GPUMapMode.READ);
staging.unmap(); // bricht das ausstehende Mapping ab
try {
await pending;
} catch (err) {
console.log(err.name);
}
// Wichtig · Fallstricke
- Abgetrennte Puffer: Nach
unmap()sind alle vongetMappedRange()geliefertenArrayBufferunbrauchbar. Du bekommst dabei keine Fehlermeldung, die Ansicht ist einfach leer. Brauchst du die Daten weiter, kopiere sie vorher mitslice()oderstructuredClone(). - unmap() nicht vergessen: Wird ein gemappter Puffer in
queue.submit(),writeBuffer()oder einer Bind-Group verwendet, entsteht ein Validierungsfehler. Der Befehlspuffer ist dann ungültig und die Befehle werden nicht ausgeführt. - Wird
unmap()für einen Puffer aufgerufen, der gar nicht gemappt ist, passiert nichts. Es wird keine Ausnahme geworfen. - Ist ein Puffer mit
mapAsync()im ModusWRITEgemappt, übernimmt erstunmap()die geschriebenen Daten in den GPU-Speicher. - Für wiederholte Lesevorgänge solltest du Staging-Puffer wiederverwenden (Map, Kopie, Unmap), statt jedes Mal neue anzulegen. Das spart Speicher und Rechenaufwand.
- Kompatibilität: WebGPU steht nur in sicheren Kontexten (HTTPS) zur Verfügung. Die Unterstützung ist je nach Browser und Plattform unterschiedlich. Prüfe deshalb vorher, ob
navigator.gpuvorhanden ist.