Signatur
Beschreibung
createBuffer() reserviert auf einem GPUDevice einen linearen GPU-Speicherblock. Solche Puffer sind die Grundlage fast jeder WebGPU-Anwendung: Sie enthalten Vertex- und Indexdaten für Render-Pipelines, Uniform-Werte (z. B. Transformationsmatrizen), Daten für Compute-Shader oder dienen als Zwischenspeicher zum Zurücklesen von Ergebnissen auf die CPU.
Welche Operationen ein Puffer erlaubt, wird beim Erstellen über das Bitfeld usage festgelegt und lässt sich danach nicht mehr ändern. Die Flags stammen aus GPUBufferUsage (z. B. VERTEX, INDEX, UNIFORM, STORAGE, COPY_SRC, COPY_DST, MAP_READ, MAP_WRITE) und werden mit dem bitweisen ODER | kombiniert.
Um Daten in einen Puffer zu bekommen, gibt es drei übliche Wege: mappedAtCreation: true (Puffer ist direkt nach dem Erstellen per getMappedRange() beschreibbar, danach unmap()), GPUQueue.writeBuffer() (bequem für regelmäßig aktualisierte Daten, benötigt COPY_DST) oder ein Kopierbefehl aus einem anderen Puffer. Zum Auslesen auf der CPU nutzt man einen separaten Puffer mit MAP_READ | COPY_DST und mapAsync().
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $descriptor Pflicht | GPUBufferDescriptor | Objekt, das den Puffer beschreibt, mit folgenden Eigenschaften:
|
Rückgabewert
GPUBuffer-Objekt. Bei ungültigem Deskriptor wird ein ungültiger Puffer zurückgegeben und ein Validierungsfehler auf dem Gerät gemeldet (keine Exception).Beispiele
Vertex-Puffer mit mappedAtCreation befüllen
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
// Drei Eckpunkte eines Dreiecks (x, y)
const vertices = new Float32Array([
0.0, 0.5,
-0.5, -0.5,
0.5, -0.5,
]);
const vertexBuffer = device.createBuffer({
label: 'Dreieck-Vertices',
size: vertices.byteLength, // 24 Bytes, Vielfaches von 4
usage: GPUBufferUsage.VERTEX,
mappedAtCreation: true,
});
// Daten direkt in den gemappten Bereich kopieren
new Float32Array(vertexBuffer.getMappedRange()).set(vertices);
vertexBuffer.unmap(); // erst jetzt ist der Puffer für die GPU nutzbar
console.log(vertexBuffer.size, vertexBuffer.mapState);
Uniform-Puffer per writeBuffer aktualisieren
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const uniformBuffer = device.createBuffer({
label: 'Frame-Uniforms',
size: 16, // z. B. vec4<f32>
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
});
const frame = (time) => {
const data = new Float32Array([time / 1000, 0, 0, 0]);
device.queue.writeBuffer(uniformBuffer, 0, data);
// ... Render-Pass mit Bind-Group, die uniformBuffer enthält
requestAnimationFrame(frame);
};
requestAnimationFrame(frame);
Compute-Ergebnis auf die CPU zurücklesen
const adapter = await navigator.gpu.requestAdapter();
const device = await adapter.requestDevice();
const size = 4 * 4; // vier Float32-Werte
// Speicher, in den ein Compute-Shader schreibt
const storageBuffer = device.createBuffer({
size,
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC | GPUBufferUsage.COPY_DST,
});
device.queue.writeBuffer(storageBuffer, 0, new Float32Array([1, 2, 3, 4]));
// Lese-Puffer: MAP_READ darf nur mit COPY_DST kombiniert werden
const readBuffer = device.createBuffer({
size,
usage: GPUBufferUsage.MAP_READ | GPUBufferUsage.COPY_DST,
});
const encoder = device.createCommandEncoder();
encoder.copyBufferToBuffer(storageBuffer, 0, readBuffer, 0, size);
device.queue.submit([encoder.finish()]);
await readBuffer.mapAsync(GPUMapMode.READ);
const result = new Float32Array(readBuffer.getMappedRange().slice(0));
readBuffer.unmap();
console.log(result);
// Wichtig · Fallstricke
- Keine Exceptions bei Validierungsfehlern: Ein ungültiger Deskriptor (z. B.
MAP_READzusammen mit etwas anderem alsCOPY_DST, odersizeüberdevice.limits.maxBufferSize) erzeugt einen ungültigen Puffer und einen Fehler, den man perdevice.pushErrorScope('validation')/popErrorScope()oder über dasuncapturederror-Event abfangen kann. Nur eine ungültigeusage-Kombination oder ein Fehlschlagen vonmappedAtCreationwegen Speichermangel kann einenRangeErrorauslösen. - Vielfache von 4: Bei
mappedAtCreation: truemusssizedurch 4 teilbar sein.writeBuffer()und Kopierbefehle verlangen ebenfalls auf 4 Bytes ausgerichtete Offsets und Größen. - Uniform-Layout: WGSL-Uniforms folgen strengen Alignment-Regeln (z. B.
vec3<f32>belegt 16 Bytes). Gib lieber zu viel als zu wenig Größe an. - Nicht vergessen:
unmap()– ein gemappter Puffer darf in keinem eingereichten Befehl verwendet werden. - Speicher freigeben: Nicht mehr benötigte Puffer mit
buffer.destroy()freigeben, statt auf die Garbage Collection zu warten. - Kompatibilität: WebGPU gibt es nur in sicheren Kontexten und noch nicht in allen Browsern bzw. auf allen Plattformen. Vorher
'gpu' in navigatorprüfen und beachten, dassrequestAdapter()nullliefern kann.