This article describes how to deal with WebGL context losses in LuciadRIA.

What is a WebGL context loss?

LuciadRIA makes use of WebGL, a JavaScript API for rendering 2D and 3D graphics in a web browser. A "WebGL context" is a JavaScript object that represents the current WebGL state. It contains various resources, such as buffers, shader programs and textures. Sometimes, a WebGL context becomes unavailable. This is called a WebGL context loss. When this happens, LuciadRIA can no longer display graphics.

Various reasons can cause a webGL context loss. The system may be using too much memory, for example.

When does a WebGL context loss occur?

A context loss can happen for several reasons, including:

  • Resource constraints: the system may be running low on GPU memory or other resources. In response, the browser forcibly frees up resources by dropping the WebGL context.

  • System errors: hardware or driver issues, or software bugs, might lead to the loss of the WebGL context.

  • Browser-specific behavior: some browsers might have built-in limitations, or user-configured settings, which can cause them to lose the WebGL context under certain conditions.

To handle context loss events, WebGL provides the 'webglcontextlost' event.

How to detect a WebGL context loss in LuciadRIA?

You can access the WebGL context of a WebGLMap through WebGLMap.webGLContext. To detect WebGL context loss events in LuciadRIA, you register a listener for the 'webglcontextlost' event on WebGLMap.webGLContext. This code snippet shows how to register a WebGL context loss listener:

Program: Listening for WebGL context losses on the map.
map.webGLContext?.canvas.addEventListener("webglcontextlost", () => {
  console.log("Map's WebGL context was lost");

How to recover from a WebGL context loss in LuciadRIA?

To recover from a WebGL context loss, you must 'reboot' the map by calling WebGLMap.reboot(). This call re-creates the WebGL context and re-initializes the map. This code snippet shows how to reboot the map:

Program: Rebooting the map after a WebGL context loss.
map.webGLContext?.canvas.addEventListener("webglcontextlost", () => {

Note that the WebGLMap creates a new WebGL context when it reboots. You must update your 'webglcontextlost' listeners to listen for context loss events on the new WebGL context.

Program: Updating the 'webglcontextlost' listeners after a WebGLMap reboot.
const map = new WebGLMap("map");

const handleContextLoss = () => {
  // reboot immediately, or show a "reboot" button in an overlay, so the end user can decide when to reboot the map

let currentWebGLContext: WebGL2RenderingContext | null = map.webGLContext;
currentWebGLContext?.canvas.addEventListener("webglcontextlost", handleContextLoss);

const updateWebGLContextListeners = () => {
  currentWebGLContext?.canvas.removeEventListener("webglcontextlost", handleContextLoss);
  currentWebGLContext = map.webGLContext;
  currentWebGLContext?.canvas.addEventListener("webglcontextlost", handleContextLoss);
map.on("WebGLContextChanged", updateWebGLContextListeners);

When the WebGL context was lost, LuciadRIA interrupted any ongoing camera animations. If you want to continue an ongoing camera animation after rebooting the map, you’ll have to re-schedule it on the AnimationManager.

When to reboot the map after a WebGL context loss?

Automatically rebooting the map in response to a WebGL context loss event can be a double-edged sword. On one hand, it can be useful for trying to recover from a context loss and continue rendering without requiring any user intervention. On the other hand, it might result in an infinite loop of context losses and reboots if the underlying issue causing the context loss isn’t resolved. It’s essential to consider the reasons for context loss before deciding whether to automatically reboot the map.

Context losses can occur due to various reasons, such as GPU driver crashes, system running out of memory, or even a software bug. Sometimes, rebooting the map might successfully restore the context and allow your application to continue working as expected. In other situations though, rebooting the map might result in more system resources being used, which just leads to another context loss, creating an endless loop.

Instead of automatically rebooting the map, it might be a better idea to inform the user about the context loss. You can provide them with an option to attempt a manual reboot by clicking a button or interacting with a UI element. This approach gives users more control and allows them to decide whether to try rebooting the map or not. In the LuciadRIA samples, we also use that approach. You can find an example in samples/common/components/overlay/WebGLContextLostOverlay.tsx.

webgl context loss overlay
Figure 1. LuciadRIA samples show an error overlay when the WebGL context is lost. The overlay offers a manual reboot option. It allows the user to take action before rebooting the map.

In addition, you could implement a limited number of automatic reboot attempts with a delay between each attempt. This way, your application might recover after a few retries, if the issue causing the context loss is temporary. However, if the problem persists, the automatic reboot attempts will stop. You can then display an error message or a manual reboot option to the user. In summary, automatically rebooting the map can be helpful in certain cases, but carefully consider the potential consequences and user experience. Providing users with more control or implementing a limited retry mechanism with a delay can offer a more balanced and user-friendly approach to handling WebGL context losses.