I'm currently working on a website with a list of items. Each item has a thumbnail, and I'm adding a shader effect on all of them using PixiJS. The problem is that there's more than 16 items on the list, so I'm getting the following error :
WARNING: Too many active WebGL contexts. Oldest context will be lost.
Is there a way to increase this limit ? I can't make the whole page on WebGL, and the usage is so limited (no interaction, lite effect) that I think more WebGL contexts will not make the page laggy or something.
Mobile browsers have a limit of eight WebGL contexts.
The WebGL context is a JavaScript object that stores the current state of the graphics library. WebGL is a state machine. That means that if you set a WebGL variable to a specific value, that value will not change until you change it. For example, you can set the color used to clear the canvas background once.
Not it is not possible to increase the limit. (well you could write your own browser).
To make a list of items you can use solutions like in this Q&A
Multiple WebGL models on the same page
which are detailed in this article for WebGL and this article for three.js
Here are 3 solutions.
(fastest) Use a single WebGL canvas that covers the page. Use place holder elements to mark where you want to draw things. Loop through those elements calling element.getBoundingClientRect
and use the viewport and scissor settings to draw in those places, only drawing the ones that are visible (some may be offscreen and don't need to be drawn). This is the soution shown in the links above.
Use a single offscreen WebGL canvas. Put 2D canvases in your page. Draw each item to the offscreen canvas and use drawImage to draw it to the correct 2D canvas. this solution is slightly more flexible since the 2D canvas elements can be more freely styled but it's slower than the previous solution and uses more memory.
Note: it's probably best to make the WebGL canvas the size of the largest 2D canvas, then for each 2D canvas, set gl.viewport to the size of that 2D canvas and then use the full form of drawImage
to select a portion of the WebGL the correct size portion of the WebGL canvas to draw the current 2D canvas. Resizing a canvas is a heavy operation I believe. In other words something like:
for each 2D canvas
webgl canvas size = max(webgl canvas size, 2D canvas size) // for each dimension
gl.viewport(0, 0, 2D canvas size);
draw scene for canvas
ctx.drawImage(
0, 0, 2D canvas size,
0, webgl canvas height - 2d canvas height, 2D canvas size)
Use a virtual webgl context which you can implement on your own or use a library. Not recommended (slowest) but it is a quick solution.
Note: having multiple contexts is not a recommended solution. Textures, vertices, and shaders can not be shared between WebGL contexts. That means if you use the same image in 2 or more contexts it has to be loaded into memory once for each context. Similarly for each context a shader is used it has to be compliled and linked for each context. In other words using multiple contexts uses more memory and increases startup time significantly.
Unfortunately since you tagged your questions both WebGL and pixi.js this answer is probably irrelevant to you. I have no idea if this is possible in pixi.js. I see no documentation to suggest how to do it efficiently.
There is an alternative solution in case you control the browser being used. Chrome has the following command line switch to control the maximum amount of active contexts.
--max-active-webgl-contexts=<number>
You can setup a shortcut with this argument to have a Chrome browser that's less limited.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With