pixijs: Too many active WebGL contexts

I’m building an app integrated with React which loads several individual experiments, in pixi.js, three.js etc. Because I can’t use an iframe to load the experiments, I need to clean after myself.

Every time there is a navigation to a new experiment, I’m checking if the a renderer exists, or not, and if it does I’m destroying it).

dummy code

if renderer
    renderer.destroy(true);
    renderer = null

renderer = new PIXI.autoDetectRenderer ......

It seems that I’m correctly cleaning my webgl renderer, however after 16 pages get loaded, I get the warning saying WARNING: Too many active WebGL contexts. Oldest context will be lost. This shouldnt be a problem on desktop as we only have a warning, but on the ipad it crashes the browser and a message appears: X A problem occurred with this web page, so it was reloaded..

I was looking at threejs and how they implement a solution for this, and they have the following code

Am I doing anything silly?

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Comments: 29 (22 by maintainers)

Most upvoted comments

I think I found a good solution. This allows me to have map overlay React components that don’t have to know about each other and allow’s React to own the DOM.

It uses this technique to force the context loss:

gl.getExtension('WEBGL_lose_context').loseContext();

Here’s a full example:

var document = require('global/document');
var PIXI = require('pixi.js');

// I want to keep this canvas / renderer around. For example, this might be a bottom layer PIXI / React map overlay.
var canvas1 = document.createElement('canvas');
document.body.appendChild(canvas1);
createRenderer(0xff0000, canvas1);

function createRenderer(color, canvas) {
  canvas = canvas || document.createElement('canvas');
  var renderer = new PIXI.WebGLRenderer(800, 600, {view: canvas});
  var stage = new PIXI.Container();
  var graphics = new PIXI.Graphics();
  graphics.beginFill(color, 0.5);
  graphics.drawCircle(0, 0, 200);
  graphics.endFill();
  stage.addChild(graphics);
  renderer.render(stage);
  return {renderer: renderer, stage: stage, graphics: graphics};
}

// Simulate frequent adding / removing of lots of PIXI / React map overlays on top.
for (var i = 0; i < 16; i++) {
  var canvas = document.createElement('canvas');
  document.body.appendChild(canvas);
  var scene = createRenderer(0x00ff00, canvas);
  // Uncomment to see that the original canvas isn't removed.
  /* scene.renderer.currentRenderTarget.gl
      .getExtension('WEBGL_lose_context').loseContext(); */
  scene.renderer.destroy();
  scene.stage.removeChild(scene.graphics);
  document.body.removeChild(canvas);
}

Maybe PIXI should add this to its own “destroy” method?

Alright, detaching and reappending the view instead of destroying it solved my issue, thanks for the help guys.

This might be useful: lose_context() is only a simulation (according to the spec) but in this thread (Public WebGL: WEBGL_lose_context we learn (from mozilla developer Jeff Gilbert) that in Firefox loseContext() is a byword for “release this context and its resources” .

The problem is that other browsers handle this differently. There are comments from a Google developer (Ken Russell) recommending : Please use the explicit delete* APIs on the WebGLRenderingContext to release GPU resources that your application is no longer using.

I have to admit I haven’t experimented with any of this but it looks like any solution is going to be browser specific.

In the function isWebGLSupported() (source/core/utils/index.js) replacing return !!(gl && gl.getContextAttributes().stencil);

with var success = !!(gl && gl.getContextAttributes().stencil); gl.getExtension('WEBGL_lose_context').loseContext(); gl = undefined; return success;

fixed the problem for me. It was most prominent in Google Chrome - Firefox worked either way. As I’m a bit of a WebGL noob I’d be really grateful for comment on this approach.