Start · Sprachen · JavaScript · Referenz · WebGL2RenderingContext.getBufferSubData()

WebGL2RenderingContext.getBufferSubData()

Methode

Liest Daten aus dem an <code>target</code> gebundenen GPU-Puffer ab einem Byte-Offset und kopiert sie synchron in eine übergebene <code>ArrayBufferView</code>.

seit JavaScript WebGL 2 – Baseline: alle modernen Browser (seit 20 Kategorie: webapi

Signatur

WebGL2RenderingContext.prototype.getBufferSubData(target, srcByteOffset, dstBuffer, dstOffset, length)

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);
Float32Array(4) [1.5, 2.5, 3.5, 4.5]

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);
Uint32Array(4) [0, 30, 40, 0]

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: srcByteOffset zählt in Bytes, dstOffset und length in Elementen des Typed Arrays – ein häufiger Fehler.
  • Fehler: INVALID_OPERATION, wenn kein Puffer an target gebunden ist, der Puffer gerade für aktives Transform Feedback genutzt wird (und target nicht passt) oder der Bereich über das Pufferende hinausgeht; INVALID_VALUE bei negativem Offset oder zu großem dstOffset/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).