Emscripten provides three OpenGL modes:
This topic provides information about the modes, and how they are enabled.
Tip
We highly recommend using the WebGL-friendly subset of OpenGL for new code, and porting existing code to this subset if possible. The other two modes are much less efficient, and should only be considered for large codebases that rely heavily on those features.
Emscripten supports the WebGL-friendly subset of OpenGL by default. This is the set of commands that map directly to WebGL, so that each GL command becomes a direct call to WebGL. It includes almost all of OpenGL ES 2.0, with the notable exception of client-side arrays.
This mode is used by default because it is stable, predictable and fast.
This mode provides a full OpenGL ES 2.0 environment — specifically it emulates client-side arrays that were missing [1] from the WebGL-friendly subset of OpenGL.
This allows you to use glDrawArrays etc. without a bound buffer, and Emscripten’s GL bindings will set up the buffer automatically (WebGL requires that a buffer be bound).
This mode is not as efficient as the WebGL-friendly subset, because Emscripten cannot predict the optimal pattern for buffer creation/sizing/etc. We therefore have to make more (costly) data uploads from the CPU to the GPU than are actually needed.
To enable OpenGL ES 2.0 emulation, specify the emcc option -s FULL_ES2=1 when compiling the project.
This OpenGL mode enables support for a number of legacy GL 1.x features and commands (for example “immediate mode” and glNormalPointer).
While the emulation is by no means “complete”, it has been sufficient to port the Sauerbraten 3D game (BananaBread project) and several other real-world codebases using Emscripten.
To enable this mode, specify the emcc option -s LEGACY_GL_EMULATION=1 when compiling the project.
Warning
This mode adds significant emulation overhead.
When porting code, it should be noted that desktop OpenGL, OpenGL ES and WebGL each have their own extension registryes. This means that neither desktop OpenGL or OpenGL ES extensions are automatically also WebGL extensions, although some amount of parity does exist. See the WebGL 1.0 extension registry for the full list of registered extensions.
Additionally, in WebGL, unlike in desktop or mobile OpenGL, extensions must be activated first before the features they expose take effect. If you use one of the native APIs SDL, EGL, GLUT or GLFW to create your GL context, this will be done automatically for most extensions. If instead you use the HTML5 WebGL context creation API, you must explicitly choose whether to autoenable WebGL extensions. If an extension was not automatically enabled at context creation time, the HTML5 API function emscripten_webgl_enable_extension can be used to activate it. Debugging related extensions, draft extensions and vendor-prefixed extensions (MOZ_*, WEBKIT_*) are never enabled automatically at context creation time, but must always be activated manually.
In this mode (-s LEGACY_GL_EMULATION=1), there are a few extra flags that can be used to tune the performance of the GL emulation layer:
The files in tests/glbook provide a number of simple examples that use only the WebGL-friendly subset of OpenGL.
The other modes are covered in various tests, including several in tests/test_browser.py. The best way to locate the tests is to search the source code for the appropriate compiler flags: FULL_ES2, LEGACY_GL_EMULATION etc.
File a bug report (with test case) and we will review.
Footnotes:
[1] | Client-side arrays are missing from WebGL because they are less efficient than properly using GPU-side data. |