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

WebGL2RenderingContext.invalidateSubFramebuffer()

Methode

Teilt der GPU mit, dass der Inhalt bestimmter Framebuffer-Anhänge in einem rechteckigen Bereich nicht mehr gebraucht wird und verworfen werden darf.

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

Signatur

WebGL2RenderingContext.prototype.invalidateSubFramebuffer(target, attachments, x, y, width, height)

Beschreibung

Mit invalidateSubFramebuffer() teilst du dem Treiber mit, dass die Pixeldaten in einem bestimmten Rechteck eines oder mehrerer Framebuffer-Anhänge (Farbe, Tiefe, Stencil) nicht mehr benötigt werden. Der Inhalt dieses Bereichs ist danach undefiniert. Die GPU muss ihn also weder aufbewahren noch in den Speicher zurückschreiben.

Das lohnt sich vor allem auf Tile-basierten GPUs, wie sie in Mobilgeräten üblich sind. Dort spart das Verwerfen nicht mehr benötigter Tiefen- oder Stencil-Daten teure Schreibzugriffe auf den Hauptspeicher. Ein typischer Fall: Nach einem Render-Durchgang braucht man den Tiefenpuffer nicht mehr, weil nur das Farbergebnis weiterverwendet wird. Oder man zeichnet einen Teilbereich im nächsten Frame ohnehin komplett neu.

Die Methode ist die Variante von invalidateFramebuffer() für einen Teilbereich. Das Rechteck wird in Fensterkoordinaten angegeben, der Ursprung liegt unten links. Es handelt sich nur um einen Hinweis: Implementierungen dürfen den Aufruf ignorieren. Du darfst dich also nie darauf verlassen, dass die Daten tatsächlich gelöscht werden.

Parameter

Name Typ Default Beschreibung
$target Pflicht GLenum Framebuffer-Ziel: gl.FRAMEBUFFER, gl.DRAW_FRAMEBUFFER oder gl.READ_FRAMEBUFFER. gl.FRAMEBUFFER bedeutet dasselbe wie gl.DRAW_FRAMEBUFFER.
$attachments Pflicht Array<GLenum> Liste der Anhänge, die ungültig werden sollen. Bei einem eigenen Framebuffer: gl.COLOR_ATTACHMENT0 bis gl.COLOR_ATTACHMENTn, gl.DEPTH_ATTACHMENT, gl.STENCIL_ATTACHMENT, gl.DEPTH_STENCIL_ATTACHMENT. Beim Standard-Framebuffer (null): gl.COLOR, gl.DEPTH, gl.STENCIL.
$x Pflicht GLint Linke Kante des Rechtecks in Pixeln.
$y Pflicht GLint Untere Kante des Rechtecks in Pixeln (Ursprung unten links).
$width Pflicht GLsizei Breite des Rechtecks in Pixeln. Ein negativer Wert erzeugt gl.INVALID_VALUE.
$height Pflicht GLsizei Höhe des Rechtecks in Pixeln. Ein negativer Wert erzeugt gl.INVALID_VALUE.

Rückgabewert

Typ
void
Beschreibung
Kein Rückgabewert (undefined). Fehler meldest du über gl.getError() ab.

Beispiele

Tiefen- und Stencil-Puffer nach dem Rendern verwerfen

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl2');

// Offscreen-Framebuffer mit Farbtextur und Depth-Stencil-Renderbuffer anlegen
const fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);

const colorTex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, colorTex);
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA8, 512, 512);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, colorTex, 0);

const depthRb = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthRb);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, 512, 512);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, depthRb);

gl.viewport(0, 0, 512, 512);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
// ... Szene zeichnen ...

// Tiefe/Stencil werden nicht mehr gebraucht, nur die Farbtextur zählt
gl.invalidateSubFramebuffer(gl.FRAMEBUFFER, [gl.DEPTH_STENCIL_ATTACHMENT], 0, 0, 512, 512);

console.log(gl.getError() === gl.NO_ERROR);
true

Nur einen Teilbereich des Standard-Framebuffers verwerfen

const gl = document.querySelector('canvas').getContext('webgl2');

// Standard-Framebuffer (Canvas) binden
gl.bindFramebuffer(gl.FRAMEBUFFER, null);

// Linke Bildhälfte wird im nächsten Schritt ohnehin komplett neu gezeichnet
const halfWidth = Math.floor(gl.drawingBufferWidth / 2);
gl.invalidateSubFramebuffer(
  gl.FRAMEBUFFER,
  [gl.COLOR, gl.DEPTH],   // beim Standard-Framebuffer: COLOR/DEPTH/STENCIL
  0, 0,
  halfWidth, gl.drawingBufferHeight
);

gl.enable(gl.SCISSOR_TEST);
gl.scissor(0, 0, halfWidth, gl.drawingBufferHeight);
gl.clearColor(0.1, 0.2, 0.3, 1);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);
gl.disable(gl.SCISSOR_TEST);

Fehlerfall: falscher Anhang-Typ

const gl = document.querySelector('canvas').getContext('webgl2');
gl.bindFramebuffer(gl.FRAMEBUFFER, null);

// COLOR_ATTACHMENT0 ist beim Standard-Framebuffer nicht erlaubt
gl.invalidateSubFramebuffer(gl.FRAMEBUFFER, [gl.COLOR_ATTACHMENT0], 0, 0, 100, 100);

const err = gl.getError();
console.log(err === gl.INVALID_ENUM || err === gl.INVALID_OPERATION);
true

// Wichtig · Fallstricke

  • Nur ein Hinweis: Der Browser oder Treiber darf den Aufruf ignorieren. Danach ist der Inhalt des Bereichs undefiniert. Er kann also erhalten bleiben oder verloren sein. Lies einen verworfenen Bereich nie mit readPixels() oder als Textur aus, bevor du ihn neu beschrieben hast.
  • Die Konstanten hängen vom Framebuffer ab: Beim Standard-Framebuffer (null) gelten gl.COLOR, gl.DEPTH und gl.STENCIL. Bei eigenen Framebuffern gelten die *_ATTACHMENT-Konstanten. Wer beides vermischt, erhält INVALID_ENUM oder INVALID_OPERATION.
  • Eine negative width oder height führt zu INVALID_VALUE. Rechtecke, die über den Framebuffer hinausragen, werden auf seine Grenzen zugeschnitten.
  • Leistung: Der größte Nutzen zeigt sich auf Tile-basierten Mobil-GPUs. Auf Desktop-GPUs ist der Effekt oft kaum messbar. Wenn du den ganzen Framebuffer verwerfen willst, ist invalidateFramebuffer() meist die bessere Wahl.
  • Die Methode gibt es nur in WebGL 2 (WebGL2RenderingContext), nicht im WebGLRenderingContext von WebGL 1. Alle aktuellen Browser mit WebGL-2-Unterstützung (Chrome, Firefox, Safari 15+, Edge) bieten sie an.