Handling Lost Context in WebGL

WebGL makes the amazing power of your GPU available to JavaScript to do all kinds of fancy and wonderful things. Unfortunately the GPU is a shared resource and as such there are times when it might be taken away from your program. Examples: Another page does something that takes the GPU too long and the browser or the OS decides to reset the GPU to get control back. 2 or more pages use too many resources and the browser decides to tell all the pages they lost the context and then restore it only to the front page for now. The user switches graphics cards (Turns on/off one or more in the control panel) or updates their driver (no reboot required on Windows7)

In all these cases and more your program may lose its WebGL context. By default when a WebGL program loses the context it never gets it back. To recover from a lost context you must take the following steps

1) add a lost context handler and tell it to prevent the default behavior

At the point that setupWebGLStateAndResources is called the browser has reset all state to the default WebGL state and all previously allocated resources are invalid. So, you need to re-create textures, buffers, framebuffers, renderbuffers, shaders, programs, and setup your state (clearColor, blendFunc, depthFunc, etc...)

For many programs this is a simple matter of calling your init or setup function again.

We went through the demos in the Khronos WebGL SDK and made them handle lost context. Below are some of the issues we ran into and the solutions we used.

Don’t check for null on creation

varprogram=gl.createProgram();if(program===null)// BAD!!!

You should really only get null from these functions if the context is lost and in that case there’s no reason to check. WebGL is designed so that for the most part everything just runs as normal even when a program or shader is null.

Don’t put attributes on WebGL resource objects

vartex=gl.createTexture();tex.image=newImage();// BAD!!!

‘tex’ will be null if the context is lost and you’ll get a JavaScript exception trying to add a field to null.

Why didn’t this work with context lost/restored? Because the anonymous function in the event listener was using the object bound to the variable mouseUniformLocation that was created the first time through init. When the context is restored, the second time through init, mouseUniformLocation is pointing to a new object but the anonymous function assigned to the listener was still looking at the object that was there AT THE TIME IT WAS ORIGINALLY BOUND.

There are lots of solutions to this issue. The one I chose was to take make the function named instead of anonymous, then I could remove them like this

Deal with outstanding asynchronous requests

You ask the browser to load 5 images, before they finish loading you lose the context. Two cases come to mind. One, they finish loading before the context is restored. Two, they finish loading after the context has been restored. In either case you probably need to do something.

The simplest solution might just be to make sure those requests are ignored when they complete.

Use the context lost simulator to help find issues

You can lose the context AT ANY TIME! In otherwords, you can lose the context part way through initialization. You can also lose the context immediately after calling canvas.getContext. You can lose the context between any 2 WebGL function calls.

You need to check your code for subtle bugs that, for example, only happen if the context is lost between the Nth and Nth+1 calls in your program.