Proper way to detect WebGL support?

JavascriptJqueryFirefoxCross BrowserWebgl

Javascript Problem Overview


I am attempting to detect WebGL support across multiple browsers and I've encountered the following scenario. The current version of Firefox appears to report positive support using the following check, even when the visitor's video card is black-listed and/or WebGL is disabled:

if (window.WebGLRenderingContext) {
    // This is true in Firefox under certain circumstances,
    // even when WebGL is disabled...
}

I've tried instructing my users to enable WebGL using the following steps. This has worked in some cases, but not always. Obviously, this is not something I can request of the general public:

  1. Type about:config in Firefox’s address bar
  2. To enable WebGL, set webgl.force-enabled to true

This has led me to create my own method for detecting support, which uses jQuery to inject a canvas element to detect support. This pulls on a number of techniques I found in various WebGL libraries and plugins. The trouble is, it is extremely difficult to test (any comments on whether the link below works for you are much appreciated!). To make this an objective question, I would like to know if there's a universally accepted way to detect WebGL support across all browsers.

TEST URL:

http://jsfiddle.net/Jn49q/5/

Javascript Solutions


Solution 1 - Javascript

The excellent Three library has, in fact, a mechanism for detecting the following:

  1. WebGL support
  2. File API support
  3. Workers support

For WebGL, particularly, here is the code that is used:

function webgl_support () { 
   try {
    var canvas = document.createElement('canvas'); 
    return !!window.WebGLRenderingContext &&
      (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
   } catch(e) {
     return false;
   }
 };

That code snippet is part of a Detector class which may also display the corresponding error messages to the user.

Solution 2 - Javascript

[Oct 2014] I've updated modernizrs example to match their current implementation, which is a cleaned up version from http://get.webgl.org/ further below.

Modernizr does,

var canvas;
var ctx;
var exts;

try {
  canvas = createElement('canvas');
  ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
  exts = ctx.getSupportedExtensions();
}
catch (e) {
  return;
}

if (ctx !== undefined) {
  Modernizr.webglextensions = new Boolean(true);
}

for (var i = -1, len = exts.length; ++i < len; ){
  Modernizr.webglextensions[exts[i]] = true;
}

canvas = undefined;

Chromium points to http://get.webgl.org/ for the canonical support implementation,

try { gl = canvas.getContext("webgl"); }
catch (x) { gl = null; }

if (gl == null) {
    try { gl = canvas.getContext("experimental-webgl"); experimental = true; }
    catch (x) { gl = null; }
}

Solution 3 - Javascript

As seen in http://www.browserleaks.com/webgl#howto-detect-webgl

> This is a proper javascript function to detect WebGL support, with all kind of experimental WebGL context names and with checking of special cases, such as blocking WebGL functions by NoScript or TorBrowser. > > It will report one of the three WebGL capability states: > > - WebGL is enabled — return TRUE, or return > - WebGL object, if the first argument was passed > - WebGL is disabled — return FALSE, you can change it if you need> > - WebGL is not implimented — return FALSE

function webgl_detect(return_context)
{
    if (!!window.WebGLRenderingContext) {
        var canvas = document.createElement("canvas"),
             names = ["webgl2", "webgl", "experimental-webgl", "moz-webgl", "webkit-3d"],
           context = false;

        for(var i=0;i< names.length;i++) {
            try {
                context = canvas.getContext(names[i]);
                if (context && typeof context.getParameter == "function") {
                    // WebGL is enabled
                    if (return_context) {
                        // return WebGL object if the function's argument is present
                        return {name:names[i], gl:context};
                    }
                    // else, return just true
                    return true;
                }
            } catch(e) {}
        }

        // WebGL is supported, but disabled
        return false;
    }

    // WebGL not supported
    return false;
}

Solution 4 - Javascript

In addition to @Andrew answer, there is also experimental mode which can be supported. I have written following snippet of code:

var canvasID = 'webgl',
    canvas = document.getElementById(canvasID),
    gl,
    glExperimental = false;

function hasWebGL() {
    
    try { gl = canvas.getContext("webgl"); }
    catch (x) { gl = null; }
    
    if (gl === null) {
        try { gl = canvas.getContext("experimental-webgl"); glExperimental = true; }
        catch (x) { gl = null; }
    }
    
    if(gl) { return true; }
    else if ("WebGLRenderingContext" in window) { return true; } // not a best way, as you're not 100% sure, so you can change it to false
    else { return false; }
}

Change canvasID variable according to your ID.

Tested on Chrome, Safari, Firefox, Opera and IEs (8 to 10). In case of Safari remember that it's available, but you need to enable WebGL explicitly (enable the developer menu and enable Web GL option after).

Solution 5 - Javascript

In order to detect browsers that support WebGL, but leaving out older browsers with may not support it well (as needed in https://stackoverflow.com/questions/41006612/webgl-detected-as-supported-when-it-is-actually-not/41029281 for ruling out Android 4.4.2 devices), I am adding a tighter, though unrelated check:

function hasWebGL() {
    var supported;

    try {
        var canvas = document.createElement('canvas');
        supported = !! window.WebGLRenderingContext && (canvas.getContext('webgl') || canvas.getContext('experimental-webgl'));
    } catch(e) { supported = false; }

    try {
        // let is by no means required, but will help us rule out some old browsers/devices with potentially buggy implementations: http://caniuse.com/#feat=let
        eval('let foo = 123;');
    } catch (e) { supported = false; }

    if (supported === false) {
        console.log("WebGL is not supported");
    }

    canvas = undefined;

    return supported;
},

Solution 6 - Javascript

// this code will detect WebGL version until WebGL Version maxVersionTest 
var
maxVersionTest = 5,
canvas = document.createElement('canvas'),
webglVersion = (canvas.getContext('webgl') || canvas.getContext('experimental-webgl')) ? 1 : null,
canvas = null; // free context

// range: if maxVersionTest = 5 makes [5, 4, 3, 2]
Array.apply(null, Array(maxVersionTest - 1))
.map(function (_, idx) {return idx + 2;})
.reverse()
.some(function(version){
	// cant reuse canvas, potential to exceed contexts or mem limit *
	if (document.createElement('canvas').getContext('webgl'+version))
		return !!(webglVersion = version);
});

console.log(webglVersion);

* re "potential to exceed contexts or mem limit" see https://bugs.chromium.org/p/chromium/issues/detail?id=226868

Solution 7 - Javascript

From MDN:

// Run everything inside window load event handler, to make sure
// DOM is fully loaded and styled before trying to manipulate it.
window.addEventListener("load", function() {
  var paragraph = document.querySelector("p"),
    button = document.querySelector("button");
  // Adding click event handler to button.
  button.addEventListener("click", detectWebGLContext, false);
  function detectWebGLContext () {
    // Create canvas element. The canvas is not added to the
    // document itself, so it is never displayed in the
    // browser window.
    var canvas = document.createElement("canvas");
    // Get WebGLRenderingContext from canvas element.
    var gl = canvas.getContext("webgl")
      || canvas.getContext("experimental-webgl");
    // Report the result.
    if (gl && gl instanceof WebGLRenderingContext) {
      paragraph.innerHTML =
        "Congratulations! Your browser supports WebGL.";
    } else {
      paragraph.innerHTML = "Failed to get WebGL context. "
        + "Your browser or device may not support WebGL.";
    }
  }
}, false);

body {
  text-align : center;
}
button {
  display : block;
  font-size : inherit;
  margin : auto;
  padding : 0.6em;
}

<p>[ Here would go the result of WebGL feature detection ]</p>
<button>Press here to detect WebGLRenderingContext</button>

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionDerek HunzikerView Question on Stackoverflow
Solution 1 - JavascriptoabarcaView Answer on Stackoverflow
Solution 2 - JavascriptAndrewView Answer on Stackoverflow
Solution 3 - JavascriptJuan AriasView Answer on Stackoverflow
Solution 4 - JavascriptKarolView Answer on Stackoverflow
Solution 5 - JavascriptJose GómezView Answer on Stackoverflow
Solution 6 - JavascriptekernerView Answer on Stackoverflow
Solution 7 - JavascriptTomasz MularczykView Answer on Stackoverflow