Start · Sprachen · JavaScript · Referenz · HTMLCanvasElement: webglcontextrestored

HTMLCanvasElement: webglcontextrestored

Ereignis

Wird am <code>&lt;canvas&gt;</code> ausgelöst, sobald der Browser einen zuvor verlorenen WebGL-Kontext wiederhergestellt hat und Ressourcen neu angelegt werden können.

seit JavaScript Baseline: alle modernen Browser Kategorie: webapi

Signatur

canvas.addEventListener("webglcontextrestored", handler)

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

Typ
void
Beschreibung
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();
Kontext verloren Kontext wiederhergestellt – Ressourcen werden neu erzeugt

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();
verloren, isContextLost(): true wiederhergestellt, isContextLost(): false

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() im webglcontextlost-Handler gibt es keine Wiederherstellung. Das ist der häufigste Grund, warum webglcontextrestored nie 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 mit getExtension() 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() gibt true zurü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_context mit loseContext() und restoreContext().
  • Das Ereignis gibt es auch an OffscreenCanvas, etwa in Workern. Die Unterstützung ist in aktuellen Chromium-, Firefox- und Safari-Versionen vorhanden.