Start · Sprachen · JavaScript · Referenz · GPUBuffer.getMappedRange()

GPUBuffer.getMappedRange()

Methode

Gibt einen <code>ArrayBuffer</code> zurück, über den du direkt auf den gemappten Speicherbereich eines <code>GPUBuffer</code> lesend oder schreibend zugreifst.

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

Signatur

GPUBuffer.prototype.getMappedRange(offset, size)

Beschreibung

getMappedRange() ist die Brücke zwischen JavaScript und dem GPU-Speicher: Solange ein GPUBuffer gemappt ist, liefert die Methode einen ArrayBuffer, dessen Inhalt dem angegebenen Bereich des Puffers entspricht. Über typisierte Arrays wie Float32Array oder Uint32Array schreibst du Daten hinein (Upload) oder liest Ergebnisse aus (Readback).

Ein Puffer ist in zwei Situationen gemappt:

  • direkt nach dem Erzeugen mit device.createBuffer({ …, mappedAtCreation: true }) – ideal, um Vertex-, Index- oder Uniform-Daten einmalig zu befüllen;
  • nachdem das Promise von buffer.mapAsync(GPUMapMode.READ | GPUMapMode.WRITE) erfüllt wurde – typisch für Staging-Puffer mit MAP_READ bzw. MAP_WRITE.

Sobald du fertig bist, gibst du den Puffer mit unmap() wieder an die GPU zurück. Dabei werden alle zuvor von getMappedRange() gelieferten ArrayBuffer detached – ihre byteLength ist dann 0, und jeder Zugriff über typisierte Arrays läuft ins Leere. Daten, die du länger brauchst, musst du also vorher kopieren (z. B. mit .slice()).

Du kannst mehrere Teilbereiche abrufen, solange sie sich nicht überlappen. Der Bereich muss vollständig innerhalb des bei mapAsync() angegebenen Mapping-Bereichs liegen und die Ausrichtungsregeln erfüllen (Offset: Vielfaches von 8, Größe: Vielfaches von 4).

Parameter

Name Typ Default Beschreibung
$offset number 0 Startposition in Bytes innerhalb des Puffers. Muss ein Vielfaches von 8 sein und innerhalb des gemappten Bereichs liegen.
$size number buffer.size - offset Länge des Bereichs in Bytes. Muss ein Vielfaches von 4 sein; offset + size darf das Ende des gemappten Bereichs nicht überschreiten.

Rückgabewert

Typ
ArrayBuffer
Beschreibung
Ein ArrayBuffer mit den Inhalten des angeforderten Bereichs. Er bleibt nur bis zum nächsten unmap() (oder destroy()) gültig und wird danach detached.

Beispiele

Vertex-Puffer beim Erzeugen befüllen (mappedAtCreation)

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

// Dreieck: drei 2D-Punkte
const vertices = new Float32Array([0.0, 0.5, -0.5, -0.5, 0.5, -0.5]);

const vertexBuffer = device.createBuffer({
  size: vertices.byteLength, // 24 Bytes – Vielfaches von 4
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
  mappedAtCreation: true,
});

// Gemappten Speicher als Float32Array beschreiben
new Float32Array(vertexBuffer.getMappedRange()).set(vertices);

// Puffer für die GPU freigeben
vertexBuffer.unmap();
console.log('Vertex-Puffer bereit:', vertexBuffer.size, 'Bytes');
Vertex-Puffer bereit: 24 Bytes

GPU-Ergebnis über einen Staging-Puffer zurücklesen

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

// Quellpuffer (z. B. Ergebnis eines Compute-Shaders)
const source = device.createBuffer({
  size,
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC,
  mappedAtCreation: true,
});
new Uint32Array(source.getMappedRange()).set([1, 2, 3, 4]);
source.unmap();

// Staging-Puffer, der von der CPU gelesen werden darf
const staging = device.createBuffer({
  size,
  usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});

const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(source, 0, staging, 0, size);
device.queue.submit([encoder.finish()]);

await staging.mapAsync(GPUMapMode.READ);
// .slice() kopiert die Daten – sie bleiben nach unmap() erhalten
const result = new Uint32Array(staging.getMappedRange()).slice();
staging.unmap();

console.log(result);
Uint32Array(4) [1, 2, 3, 4]

Teilbereiche, Überlappung und Detach nach unmap()

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

const buffer = device.createBuffer({
  size: 64,
  usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.COPY_SRC,
});
await buffer.mapAsync(GPUMapMode.WRITE);

const head = buffer.getMappedRange(0, 32);  // Bytes 0–31
const tail = buffer.getMappedRange(32, 32); // Bytes 32–63
new Uint8Array(head).fill(0xff);
new Uint8Array(tail).fill(0x00);

try {
  buffer.getMappedRange(16, 16); // überlappt mit head
} catch (err) {
  console.log(err.name);
}

buffer.unmap();
console.log(head.byteLength, tail.byteLength);
OperationError 0 0