最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to handle WebGL CONTEXT_LOST_WEBGL errors more gracefully in PixiJS? - Stack Overflow

programmeradmin3浏览0评论

I have a React application that uses a data visualization library that uses PixiJS.

I occasionally get frustrating CONTEXT_LOST_WEBGL errors in Chrome that force the user to manually reload the page, in order for the page to be (re)rendered.

I cannot often or reliably reproduce the error, but I know that it happens as other people tell me the application occasionally shows no data. The situations that raise this error seem very context-dependent and therefore difficult to recapitulate — low-powered graphics adapters, or lots of tabs open at once, etc.

The end user would only know that there are CONTEXT_LOST_WEBGL errors if that user has the Developer Tools console window open. Otherwise, the web page just looks blank.

I have tried the following to set up my React application to reload the window without manual user intervention, when a webglcontextlost event occurs:

ponentDidMount() {
  ...
  window.addEventListener("webglcontextlost", (e) => { window.location.reload(); });
  ...
}

I'm not sure it is working correctly, i.e., if the webglcontextlost event is being handled elsewhere. Or perhaps I am trying to subscribe to the wrong event?

Otherwise, to try to handle this more gracefully, is there a way in raw Javascript, or via a third-party library, to periodically measure available memory for WebGL, and to use that measurement to instead reload the page, when the available memory reaches some arbitrary threshold that might predict an imminent CONTEXT_LOST_WEBGL error condition?

I have a React application that uses a data visualization library that uses PixiJS.

I occasionally get frustrating CONTEXT_LOST_WEBGL errors in Chrome that force the user to manually reload the page, in order for the page to be (re)rendered.

I cannot often or reliably reproduce the error, but I know that it happens as other people tell me the application occasionally shows no data. The situations that raise this error seem very context-dependent and therefore difficult to recapitulate — low-powered graphics adapters, or lots of tabs open at once, etc.

The end user would only know that there are CONTEXT_LOST_WEBGL errors if that user has the Developer Tools console window open. Otherwise, the web page just looks blank.

I have tried the following to set up my React application to reload the window without manual user intervention, when a webglcontextlost event occurs:

ponentDidMount() {
  ...
  window.addEventListener("webglcontextlost", (e) => { window.location.reload(); });
  ...
}

I'm not sure it is working correctly, i.e., if the webglcontextlost event is being handled elsewhere. Or perhaps I am trying to subscribe to the wrong event?

Otherwise, to try to handle this more gracefully, is there a way in raw Javascript, or via a third-party library, to periodically measure available memory for WebGL, and to use that measurement to instead reload the page, when the available memory reaches some arbitrary threshold that might predict an imminent CONTEXT_LOST_WEBGL error condition?

Share Improve this question edited Apr 4, 2020 at 2:59 Alex Reynolds asked Apr 3, 2020 at 21:07 Alex ReynoldsAlex Reynolds 97k59 gold badges250 silver badges351 bronze badges
Add a ment  | 

3 Answers 3

Reset to default 3

The following code helped restart my Pixijs web application, when the WebGL context is lost:

  addCanvasWebGLContextLossEventListener = () => {
    const canvases = document.getElementsByTagName("canvas");
    if (canvases.length === 1) {
      const canvas = canvases[0];
      canvas.addEventListener('webglcontextlost', (event) => {
        window.location.reload();
      });
    }
  }

  removeCanvasWebGLContextLossEventListener = () => {
    const canvases = document.getElementsByTagName("canvas");
    if (canvases.length === 1) {
      const canvas = canvases[0];
      canvas.removeEventListener('webglcontextlost');
    }
  }

For other applications with more than one canvas, some adjustments would be needed to add other listeners.

The following code helped me simulate a lost context condition (and to restore from it, via the webglcontextlost event):

  simulateWebGLContextLoss = () => {
    // 
    // simulate loss of WebGL context, for the purposes
    // of improving user experience when the browser is 
    // overwhelmed
    //
    const canvases = document.getElementsByTagName("canvas");
    if (canvases.length === 1) {
      setTimeout(() => {
        const canvas = canvases[0];
        const webgl2Context = canvas.getContext("webgl2", {});
        if (webgl2Context) {
          console.log(`losing webgl2 context...`);
          webgl2Context.getExtension('WEBGL_lose_context').loseContext();
        }
        else {
          const webglContext = canvas.getContext("webgl", {});
          if (webglContext) {
            console.log(`losing webgl context...`);
            webglContext.getExtension('WEBGL_lose_context').loseContext();
          }
        }
      }, 5000);
    }
  }

For React lifecycle setup:

  ponentDidMount() {
    setTimeout(() => { 
      this.addCanvasWebGLContextLossEventListener();
    }, 2500);
  }

  ponentWillUnmount() {
    this.removeCanvasWebGLContextLossEventListener();
  }

A timeout is required, as the canvas element is not yet available when the ponent mounts. For my purposes, the short 2.5s timer provides enough time for the event handler to latch onto the canvas.

is there a way in raw Javascript to periodically measure available memory for WebGL

No, just as there is no way to measure JavaScript memory

window.addEventListener("webglcontextlost", (e) => { window.location.reload(); });

Is wrong. It should be

someCanvas.addEventListener("webglcontextlost", (e) => { window.location.reload(); });

Each canvas can individually lose its context. Most browsers only allow 8 to 16 WebGL contexts at once. As soon as the limit is reached canvases start to lose their contexts.

As for recovering gracefully it's a lot of work. Basically you need recreate all WebGL resources which means you need to structure your code so that's posssible. Separate all the state of your app from the stuff releated to WebGL (or from pixi.js) and when you get a context lost event then prevent default and recreate all the WebGL stuff

let gl;

someCanvas.addEventListener("webglcontextlost", (e) => {
  e.preventDefault();  // allows the context to be restored
});
someCanvas.addEventListener("webglcontextrestored", (e) => {
  initWebGL(gl);
});

gl = someCanvas.getContext('webgl');
initWebGL(gl);

Note that pixi.js itself may or may not be designed to handle contextlost

I was facing the same error, one of the reliable things to do is to add

const {gl} = app.renderer;
gl.canvas.addEventListener('webglcontextlost', () => {
  console.error('WebGl context lost');
  window.location.reload();
});

Here, app is your pixi js application.

发布评论

评论列表(0)

  1. 暂无评论