Start · Sprachen · JavaScript · Referenz · WEBGL_lose_context extension

WEBGL_lose_context extension

Schnittstelle

WebGL-Erweiterung, mit der man den Verlust und die Wiederherstellung eines WebGL-Kontexts gezielt auslösen kann, etwa zum Testen oder zum Freigeben von GPU-Ressourcen.

seit JavaScript Baseline: alle modernen Browser (WebGL 1 und WebGL Kategorie: webapi

Signatur

interface WEBGL_lose_context

Beschreibung

Die Erweiterung WEBGL_lose_context gehört zur WebGL API. Mit ihr lässt sich der Verlust eines WebGLRenderingContext bzw. WebGL2RenderingContext nachbilden und der Kontext danach wiederherstellen. Ein echter Kontextverlust passiert z. B. nach einem Absturz des GPU-Treibers, beim Wechsel der Grafikkarte, bei zu hohem Speicherverbrauch oder wenn der Browser zu viele aktive WebGL-Kontexte hat. Robuste Anwendungen müssen auf diesen Fall reagieren. Mit der Erweiterung kann man das gezielt testen.

Das Erweiterungsobjekt bekommt man über gl.getExtension('WEBGL_lose_context'). Es hat zwei Methoden:

  • loseContext() – simuliert den Verlust des Kontexts. Auf dem Canvas wird das Ereignis webglcontextlost ausgelöst.
  • restoreContext() – simuliert die Wiederherstellung. Danach wird webglcontextrestored ausgelöst.

Die Methoden haben keine Parameter und geben undefined zurück. Nach einem Verlust sind alle WebGL-Objekte ungültig: Texturen, Puffer, Shader, Programme und Framebuffer. Im Handler für webglcontextrestored muss die Anwendung sie komplett neu anlegen. Damit eine Wiederherstellung überhaupt möglich ist, muss im Handler für webglcontextlost die Methode event.preventDefault() aufgerufen werden.

In der Praxis wird loseContext() auch genutzt, um GPU-Ressourcen sofort freizugeben, wenn ein Canvas nicht mehr gebraucht wird, z. B. beim Abbauen einer Komponente in einer Single-Page-App. Darauf verlassen sich unter anderem Three.js (renderer.forceContextLoss()) und andere Bibliotheken.

Rückgabewert

Typ
WEBGL_lose_context | null
Beschreibung
gl.getExtension('WEBGL_lose_context') gibt das Erweiterungsobjekt zurück. Wenn die Erweiterung nicht unterstützt wird oder der Kontext bereits verloren ist, gibt der Aufruf null zurück.

Beispiele

Erweiterung abrufen und Kontextverlust simulieren

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
const ext = gl.getExtension('WEBGL_lose_context');

canvas.addEventListener('webglcontextlost', (event) => {
  event.preventDefault(); // Voraussetzung für die Wiederherstellung
  console.log('Kontext verloren:', gl.isContextLost());
});

canvas.addEventListener('webglcontextrestored', () => {
  console.log('Kontext wiederhergestellt:', !gl.isContextLost());
});

ext.loseContext();
// Nach einer Sekunde wiederherstellen
setTimeout(() => ext.restoreContext(), 1000);
Kontext verloren: true Kontext wiederhergestellt: true

Ressourcen nach Wiederherstellung neu anlegen

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
let buffer = null;

const initResources = () => {
  buffer = gl.createBuffer();
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 1, -1, -1, 1, -1]), gl.STATIC_DRAW);
  console.log('Ressourcen initialisiert');
};

let frameId = 0;
const render = () => {
  gl.clearColor(0.1, 0.2, 0.3, 1);
  gl.clear(gl.COLOR_BUFFER_BIT);
  frameId = requestAnimationFrame(render);
};

canvas.addEventListener('webglcontextlost', (e) => {
  e.preventDefault();
  cancelAnimationFrame(frameId); // Render-Schleife anhalten
  buffer = null; // alte Objekte sind ungültig
});

canvas.addEventListener('webglcontextrestored', () => {
  initResources();
  render();
});

initResources();
render();

// Testweise Verlust auslösen
const ext = gl.getExtension('WEBGL_lose_context');
ext?.loseContext();
setTimeout(() => ext?.restoreContext(), 500);
Ressourcen initialisiert Ressourcen initialisiert

GPU-Speicher beim Aufräumen sofort freigeben

const destroyWebGLCanvas = (canvas) => {
  const gl = canvas.getContext('webgl2') ?? canvas.getContext('webgl');
  gl?.getExtension('WEBGL_lose_context')?.loseContext();
  canvas.width = canvas.height = 0; // Zeichenpuffer verkleinern
  canvas.remove();
  console.log('Canvas entfernt, Kontext freigegeben');
};

destroyWebGLCanvas(document.querySelector('#viewer'));
Canvas entfernt, Kontext freigegeben

// Wichtig · Fallstricke

  • preventDefault() ist Pflicht: Wird im Handler für webglcontextlost nicht event.preventDefault() aufgerufen, stellt der Browser den Kontext nicht wieder her. restoreContext() löst dann den Fehler INVALID_OPERATION aus.
  • Falsche Reihenfolge: restoreContext() ohne vorherigen Verlust erzeugt ebenfalls INVALID_OPERATION. Ein zweiter Aufruf von loseContext() auf einem bereits verlorenen Kontext hat keine Wirkung.
  • Erweiterung früh abrufen: Das Erweiterungsobjekt sollte man vor dem Verlust holen und aufbewahren. Nach dem Verlust gibt getExtension() null zurück.
  • Ereignisse kommen asynchron: webglcontextrestored wird nicht synchron ausgelöst. Neu anlegen sollte man Ressourcen deshalb nur im Ereignis-Handler.
  • Alle Objekte ungültig: Nach dem Verlust gibt jeder WebGL-Aufruf still Standardwerte zurück (z. B. null oder 0). Mit gl.isContextLost() lässt sich der Zustand prüfen.
  • Kompatibilität: Die Erweiterung wird von allen modernen Browsern für WebGL 1 und WebGL 2 unterstützt. Trotzdem sollte man den Rückgabewert auf null prüfen, z. B. mit optionaler Verkettung ?..