Signatur
Beschreibung
Das Ereignis webglcontextrestored wird an einem HTMLCanvasElement ausgelöst, wenn der Browser den Zeichenpuffer eines WebGLRenderingContext bzw. WebGL2RenderingContext wiederhergestellt hat. Davor kommt immer ein webglcontextlost-Ereignis. Einen Kontextverlust gibt es z. B. bei einem Treiber-Reset der GPU, wenn zu viele WebGL-Kontexte offen sind, bei Energiesparmaßnahmen auf Mobilgeräten oder beim Wechsel der Grafikkarte.
Wichtig: Der Browser stellt den Kontext nur wieder her, wenn im webglcontextlost-Handler event.preventDefault() aufgerufen wurde. Ohne diesen Aufruf bleibt der Kontext dauerhaft verloren, und webglcontextrestored wird nie ausgelöst.
Nach der Wiederherstellung sind alle GPU-Ressourcen ungültig: Shader, Programme, Puffer, Texturen, Framebuffer, Renderbuffer und aktivierte Erweiterungen. Im Handler muss die Anwendung sie deshalb neu erzeugen, die Uniform-Locations neu abfragen und die Render-Schleife wieder starten. Das Kontextobjekt selbst (Rückgabewert von getContext()) bleibt dieselbe Instanz und kann weiterverwendet werden.
Einen Handler registriert man mit addEventListener("webglcontextrestored", handler) oder über die Eigenschaft canvas.onwebglcontextrestored. Das Ereignisobjekt ist ein WebGLContextEvent (erbt von Event); es blubbert nicht und kann nicht abgebrochen werden.
Parameter
| Name | Typ | Default | Beschreibung |
|---|---|---|---|
| $type Pflicht | string | Der Ereignisname "webglcontextrestored". |
|
| $handler Pflicht | (event: WebGLContextEvent) => void | Callback, der nach der Wiederherstellung aufgerufen wird. event.statusMessage ist in der Regel ein leerer String. |
|
| $options | boolean | AddEventListenerOptions | false | Optionale Listener-Optionen wie once, signal oder capture. |
Rückgabewert
addEventListener gibt nichts zurück. Der Handler bekommt ein WebGLContextEvent.Beispiele
Kontextverlust und Wiederherstellung behandeln
const canvas = document.querySelector('#scene');
const gl = canvas.getContext('webgl2');
let rafId = 0;
let resources = null;
const initResources = () => {
const vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, `#version 300 es
in vec2 pos; void main(){ gl_Position = vec4(pos, 0.0, 1.0); }`);
gl.compileShader(vs);
const fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, `#version 300 es
precision mediump float; out vec4 c; void main(){ c = vec4(1.0, 0.4, 0.0, 1.0); }`);
gl.compileShader(fs);
const program = gl.createProgram();
gl.attachShader(program, vs);
gl.attachShader(program, fs);
gl.linkProgram(program);
const buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([0, 0.8, -0.8, -0.8, 0.8, -0.8]), gl.STATIC_DRAW);
const loc = gl.getAttribLocation(program, 'pos');
gl.enableVertexAttribArray(loc);
gl.vertexAttribPointer(loc, 2, gl.FLOAT, false, 0, 0);
return { program, buffer };
};
const render = () => {
gl.clearColor(0.1, 0.1, 0.1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(resources.program);
gl.drawArrays(gl.TRIANGLES, 0, 3);
rafId = requestAnimationFrame(render);
};
canvas.addEventListener('webglcontextlost', (event) => {
event.preventDefault(); // Pflicht, damit eine Wiederherstellung erfolgt
cancelAnimationFrame(rafId);
console.log('Kontext verloren');
});
canvas.addEventListener('webglcontextrestored', () => {
console.log('Kontext wiederhergestellt – Ressourcen werden neu erzeugt');
resources = initResources();
render();
});
resources = initResources();
render();
Kontextverlust mit WEBGL_lose_context simulieren (Test)
const canvas = document.createElement('canvas');
document.body.append(canvas);
const gl = canvas.getContext('webgl');
const ext = gl.getExtension('WEBGL_lose_context');
canvas.addEventListener('webglcontextlost', (e) => {
e.preventDefault();
console.log('verloren, isContextLost():', gl.isContextLost());
setTimeout(() => ext.restoreContext(), 1000);
});
canvas.addEventListener('webglcontextrestored', () => {
console.log('wiederhergestellt, isContextLost():', gl.isContextLost());
});
ext.loseContext();
Handler über die on-Property setzen und wieder entfernen
const canvas = document.querySelector('canvas');
canvas.onwebglcontextrestored = (event) => {
console.log(`Ereignis: ${event.type}`);
};
// Später, z. B. beim Abbau der Komponente:
canvas.onwebglcontextrestored = null;
// Variante mit addEventListener und AbortController
const controller = new AbortController();
canvas.addEventListener('webglcontextrestored', () => console.log('neu initialisieren'), { signal: controller.signal });
controller.abort(); // entfernt den Listener
// Wichtig · Fallstricke
- Ohne
preventDefault()imwebglcontextlost-Handler gibt es keine Wiederherstellung. Das ist der häufigste Grund, warumwebglcontextrestorednie ausgelöst wird. - Alle alten WebGL-Objekte (
WebGLTexture,WebGLBuffer,WebGLProgram,WebGLUniformLocation…) sind danach ungültig. Sie müssen neu erzeugt werden, statt sie weiterzuverwenden. Auch Erweiterungen muss man mitgetExtension()erneut aktivieren. - Texturdaten erneut hochladen: Halten Sie Quellbilder oder Daten auf der CPU-Seite vor oder laden Sie sie neu. Der GPU-Speicher ist weg.
- Zwischen Verlust und Wiederherstellung geben WebGL-Aufrufe keine Fehler aus, sondern sie werden stillschweigend ignoriert.
gl.isContextLost()gibttruezurück. - Ob und wann der Browser wiederherstellt, entscheidet er selbst. Im Hintergrund oder nach wiederholten GPU-Abstürzen blockieren manche Browser WebGL für die Seite ganz.
- Zum Testen eignet sich die Erweiterung
WEBGL_lose_contextmitloseContext()undrestoreContext(). - Das Ereignis gibt es auch an
OffscreenCanvas, etwa in Workern. Die Unterstützung ist in aktuellen Chromium-, Firefox- und Safari-Versionen vorhanden.