Signatur
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
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);
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);
// 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) geltengl.COLOR,gl.DEPTHundgl.STENCIL. Bei eigenen Framebuffern gelten die*_ATTACHMENT-Konstanten. Wer beides vermischt, erhältINVALID_ENUModerINVALID_OPERATION. - Eine negative
widthoderheightführt zuINVALID_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 imWebGLRenderingContextvon WebGL 1. Alle aktuellen Browser mit WebGL-2-Unterstützung (Chrome, Firefox, Safari 15+, Edge) bieten sie an.