use webgl2 when available
Motivation
It would be nice to allow custom layers to use webgl2 features even if mapbox-gl-js does not depend on webgl2. My use-case is that i need half-float textures in a custom layer. Under android chrome browser (Huawei ANE-LX1) they are available with webgl2 but not with webgl1.
Design
Use webgl2 where it is available and fall back to webgl1 if not.
Implementation
changes to the source code ( here )
const gl = this._canvas.getContext('webgl2', attributes) ||
this._canvas.getContext('webgl', attributes) ||
this._canvas.getContext('experimental-webgl', attributes);
and other minor changes to "gl.getExtension" calls since extension names can be different in webgl2.
the end-user could then check for webgl2 like this
if (gl instanceof WebGL2RenderingContext) { .... }
@marco333333 for half-float textures, can you use an extension for WebGL 1? This is how they're used for the heatmaps layer in GL JS core:
https://github.com/mapbox/mapbox-gl-js/blob/097aad1a5173a538e286e37ec4490e1cb878a14f/src/gl/context.js#L112
@mourner thanks for the quick response. sadly that extension is not supported on that device.
here are the webglreport screenshots for device "Huawei ANE-LX1" on browser "android chrome 75" screencap_webgl1 screencap_webgl2
I wonder if there are compatibility issues we should be aware of when switching to WebGL 2.0 where available — there could be subtle differences we risk hitting with the change. Meanwhile, as a hacky workaround, I guess you could override this private method through Map prototype before instantiating a map:
https://github.com/mapbox/mapbox-gl-js/blob/097aad1a5173a538e286e37ec4490e1cb878a14f/src/ui/map.js#L1615-L1633
i tried a different device "Honor BND-L21" with the exact same results.
also the heatmap example under https://docs.mapbox.com/mapbox-gl-js/example/heatmap-layer/ seems to work on both devices even though the webgl1 extension "OES_texture_half_float" is not available.
about the difference between webgl1 and webgl2 i found this resource, but i dont know if its realy complete.
i will try to override the _setupPainter() function for now, even if its hacky
also the heatmap example under https://docs.mapbox.com/mapbox-gl-js/example/heatmap-layer/ seems to work on both devices even though the webgl1 extension "OES_texture_half_float" is not available.
The heatmap layer falls back to RGB textures (and lower-resolution heatmaps) when the half float extension is not available.
about the difference between webgl1 and webgl2 i found this resource, but i dont know if its realy complete.
Looks like we would have to update the shader generation code in addition to extension usage, which might be quite a bit of effort.
the official WebGL 2.0 Specification may be a better resource for changes between webgl1 and webgl2.
according to section 4.3 webgl2 still supports "glsl 100" shaders, so there is no explicit need to update them to "glsl 300 es" like the webgl2fundamentals.org post suggests (this also matches my experience using my custom layer with webgl2 (outside of mapbox) and the same shaders as for webgl1).
i know this is not the right place to ask, but i'm having trouble overriding the _setupPainter function. getting all kinds of "not defined" errors when i try to replace it like this:
mapboxgl.Map.prototype._setupPainter = function() { ... }
i guess i'm not in the right context and so cant access objects like the "Painter()", but my javascript knowhow is not that good and my google skills are letting me down. can someone please provide a little example?
@marco333333 oh, you're right, overriding isn't easy because of the internal classes... I guess what we could do is to cut out these two lines into it's own method (e.g. map._setupContext(attributes), returning the gl object):
https://github.com/mapbox/mapbox-gl-js/blob/097aad1a5173a538e286e37ec4490e1cb878a14f/src/ui/map.js#L1622-L1623
That would enable hooking up to it and customizing both the context and any additional attributes.
i've found this approach to work well based on @mourner's proposal to override the _setupPainter function if someone has use for it:
//include webgl2 in mapboxgl
if (mapboxgl.Map.prototype._setupPainter.toString().indexOf("webgl2") == -1) {
var _setupPainter_old = mapboxgl.Map.prototype._setupPainter;
mapboxgl.Map.prototype._setupPainter = function() {
getContext_old = this._canvas.getContext;
this._canvas.getContext = function(name, attrib) {
return getContext_old.apply(this, ["webgl2", attrib]) ||
getContext_old.apply(this, ['webgl', attrib]) ||
getContext_old.apply(this, ['experimental-webgl', attrib]);
}
_setupPainter_old.apply(this);
this._canvas.getContext = getContext_old;
};
}
i do still hope that one day webgl2 will be supported natively.
Yep, we should do this and it shouldn't be much too much work
Its worth pointing out that Webkit/Safari is switching its implementation of WebGL to ANGLE (Google) - meaning Safari, the lone major holdout, will soon be 100% WebGL2 compliant. See:
https://bugs.webkit.org/show_bug.cgi?id=198948
Having WebGL 2 context will mean we can integrate all the cool DeckGL layers into MapBox GL-JS maps and it will run everywhere including iOS Safari soon.
One more thing to note is that WebGL 2.0 has Uniform Buffer Objects feature that allows setting uniforms in a typed array and uploading it at once instead of doing hundreds of uniform* calls. This might help with performance quite a lot.
Hi, any update on this issue?
Are there any plans to support WebGL2 in the future?
I was asking because I was experimenting with using Webgl2 ThreeJs shaders through a custom layer.
Experimental support is developed within https://github.com/mapbox/mapbox-gl-js/pull/12514. That PR won't close the issue here since the feature would be experimental, and prone to changes, and not something that we'd advertise as production quality, yet.
ThreeJS will stop supporting WebGL1 soon https://github.com/mrdoob/three.js/wiki/Migration-Guide#152--153 Is there any updates for the above or we should just look for another provider?
@kresli just pass useWebGL2: true in Map options if you need GL JS to be powered by WebGL2. There is no performance difference, only compatibility considerations. GL JS intends to switch to WebGL2 as default and drop support for WebGL1 some time later this year.
WebGL2 is default after https://github.com/mapbox/mapbox-gl-js/commit/849edfb3a68c4526c9aa539c8183f65d1530ccf7.