Signatur
Beschreibung
getBufferSubData() ist das Gegenstück zu bufferSubData(): Statt Daten in einen WebGL-Puffer zu schreiben, liest die Methode Daten aus dem Puffer zurück, der gerade an einem Bindungspunkt (z. B. gl.ARRAY_BUFFER oder gl.TRANSFORM_FEEDBACK_BUFFER) hängt. Die Bytes ab srcByteOffset landen in einer vorher angelegten ArrayBufferView wie Float32Array oder Uint8Array.
Typische Einsatzfälle sind Transform Feedback (Vertex-Shader berechnet Werte wie Partikelpositionen, die man auf der CPU weiterverarbeiten will), das Zurücklesen von Pixeldaten über einen PIXEL_PACK_BUFFER nach readPixels() sowie Debugging und Tests von Pufferinhalten.
Wichtig: Der Aufruf ist synchron. Muss die GPU noch an Befehlen arbeiten, die den Puffer beschreiben, blockiert der Haupt-Thread, bis alles fertig ist (Pipeline-Stall). Für flüssige Anwendungen kombiniert man die Methode deshalb mit einem Fence (fenceSync() / clientWaitSync()) und liest erst, wenn die GPU den Befehl abgeschlossen hat.
Die Anzahl der gelesenen Elemente ergibt sich aus length bzw. – wenn weggelassen oder 0 – aus der Länge von dstBuffer abzüglich dstOffset. dstOffset und length werden in Elementen des Typed Arrays gezählt, srcByteOffset dagegen in Bytes.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $target Pflicht | GLenum | Bindungspunkt, dessen Puffer gelesen wird: gl.ARRAY_BUFFER, gl.ELEMENT_ARRAY_BUFFER, gl.COPY_READ_BUFFER, gl.COPY_WRITE_BUFFER, gl.TRANSFORM_FEEDBACK_BUFFER, gl.UNIFORM_BUFFER, gl.PIXEL_PACK_BUFFER oder gl.PIXEL_UNPACK_BUFFER. |
|
| $srcByteOffset Pflicht | GLintptr (number) | Start-Offset im Quellpuffer in Bytes. Negative Werte erzeugen INVALID_VALUE. |
|
| $dstBuffer Pflicht | ArrayBufferView | Ziel-Typed-Array (z. B. Float32Array, Uint8Array), in das die Daten kopiert werden. Darf auf einem SharedArrayBuffer basieren. |
|
| $dstOffset | GLuint (number) | 0 | Start-Index im Ziel-Array, gezählt in Elementen. |
| $length | GLuint (number) | 0 | Anzahl zu kopierender Elemente. Bei 0 wird bis zum Ende von dstBuffer gelesen. |
Beispiele
Pufferinhalt zurücklesen (Debugging)
const canvas = document.createElement('canvas');
const gl = canvas.getContext('webgl2');
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([1.5, 2.5, 3.5, 4.5]), gl.STATIC_READ);
// Alle vier Floats zurücklesen
const result = new Float32Array(4);
gl.getBufferSubData(gl.ARRAY_BUFFER, 0, result);
console.log(result);
Teilbereich mit Byte-Offset und Ziel-Offset lesen
const gl = document.createElement('canvas').getContext('webgl2');
const buf = gl.createBuffer();
gl.bindBuffer(gl.COPY_READ_BUFFER, buf);
gl.bufferData(gl.COPY_READ_BUFFER, new Uint32Array([10, 20, 30, 40, 50]), gl.STATIC_READ);
const out = new Uint32Array(4); // [0, 0, 0, 0]
// Ab Byte 8 (= drittes Element) zwei Elemente lesen, im Ziel ab Index 1 ablegen
gl.getBufferSubData(gl.COPY_READ_BUFFER, 2 * Uint32Array.BYTES_PER_ELEMENT, out, 1, 2);
console.log(out);
Transform-Feedback-Ergebnis nicht-blockierend mit Fence lesen
// Voraussetzung: gl, Transform-Feedback-Programm und tfBuffer sind eingerichtet
const readTransformFeedback = async (gl, tfBuffer, count) => {
const sync = gl.fenceSync(gl.SYNC_GPU_COMMANDS_COMPLETE, 0);
gl.flush();
// Warten, bis die GPU fertig ist, ohne den Thread zu blockieren
while (gl.clientWaitSync(sync, 0, 0) === gl.TIMEOUT_EXPIRED) {
await new Promise(requestAnimationFrame);
}
gl.deleteSync(sync);
const data = new Float32Array(count);
gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, tfBuffer);
gl.getBufferSubData(gl.TRANSFORM_FEEDBACK_BUFFER, 0, data);
gl.bindBuffer(gl.TRANSFORM_FEEDBACK_BUFFER, null);
return data;
};
// const positions = await readTransformFeedback(gl, tfBuffer, 300);
// Wichtig · Fallstricke
- Performance: Der Aufruf ist synchron und kann die GPU-Pipeline anhalten. Nicht in jedem Frame ohne Fence (
fenceSync()/clientWaitSync()) verwenden; Firefox und Chrome geben sonst Performance-Warnungen in der Konsole aus. - Einheiten:
srcByteOffsetzählt in Bytes,dstOffsetundlengthin Elementen des Typed Arrays – ein häufiger Fehler. - Fehler:
INVALID_OPERATION, wenn kein Puffer antargetgebunden ist, der Puffer gerade für aktives Transform Feedback genutzt wird (undtargetnicht passt) oder der Bereich über das Pufferende hinausgeht;INVALID_VALUEbei negativem Offset oder zu großemdstOffset/length. - Puffer, die man zurücklesen will, idealerweise mit einem
*_READ-Usage-Hint (z. B.gl.STREAM_READ) anlegen. - Nur in WebGL 2 verfügbar – in einem WebGL-1-Kontext existiert die Methode nicht. Unterstützt von allen aktuellen Browsern (Safari ab 15).