Platform-specific guides » HTML5 and WebGL

Building, testing and deploying HTML5 and WebGL projects.

The following guide explains basic workflow of using Emscripten for deploying HTML5 apps using WebGL.

See also Platform::Sdl2Application for more information.

Differences between WebGL and OpenGL ES

WebGL is subset of OpenGL ES with some specific restrictions, namely requirement for unique buffer target binding, aligned buffer offset and stride and some other restrictions. The most prominent difference is that while the following was enough on desktop:

GL::Buffer vertices, indices;

On WebGL (even 2.0) you always have to initialize the buffers like this (and other target hints for UBOs etc.):

GL::Buffer vertices{GL::Buffer::TargetHint::Array},
    indices{GL::Buffer::TargetHint::ElementArray};

See GL::Buffer, GL::Mesh, GL::*Texture::setSubImage(), GL::Mesh::addVertexBuffer(), GL::Renderer::setStencilFunction(), GL::Renderer::setStencilMask() and GL::Renderer::setBlendFunction() documentation for more information. The corresponding sections in official WebGL specification provide even more detail:

Troubleshooting

First Emscripten run takes long or fails

Emscripten downloads and builds a lot of things on first startup or after upgrade. That's expected and might take quite some time. If you are calling Emscripten through the CMake toolchain, it might be attempting to bootstrap itself multiple times, taking extreme amounts of time, or even fail during the initial CMake compiler checks for various reasons such as

  File "/usr/lib/python2.7/subprocess.py", line 1025, in _execute_child
    raise child_exception
OSError: [Errno 13] Permission denied

The CMake toolchain might interfere with the bootstrap operation, causing it to fail. Solution is to wipe all Emscripten caches and trigger a rebuild of all needed libraries by compiling a minimal project, as shown in the shell snippet below — enter it into the console prior to building anything else. It will take a while to download and build various system libraries and random tools. The -s WASM=1 flag is needed in order to enable a rebuild of the binaryen tool as well:

cd /tmp
emcc --clear-cache
emcc --clear-ports
echo "int main() {}" > main.cpp
em++ -s WASM=1 main.cpp

CMake can't find _CORRADE_MODULE_DIR

If initial CMake configuration fails with

Could NOT find Corrade (missing: _CORRADE_MODULE_DIR)

The solution is to explicitly pass CMAKE_PREFIX_PATH pointing to directory where Corrade is installed, for example:

mkdir build-emscripten && cd build-emscripte
cmake .. \
    -DCMAKE_TOOLCHAIN_FILE=../toolchains/generic/Emscripten-wasm.cmake \
    -DCMAKE_PREFIX_PATH=/usr/lib/emscripten/system/ \
    -G Ninja

Application fails to load

Depending on what's the exact error printed in the browser console, the following scenarios are possible:

  • By default, the size of Emscripten heap is restricted to 16 MB. That might not be enough if you have large compiled-in resources or allocate large amount of memory. This can be solved either with:
    • Adding -s TOTAL_MEMORY=<bytes> to compiler/linker flags, where <bytes> is the new heap size
    • Adding -s ALLOW_MEMORY_GROWTH=1 to compiler/linker flags. This is useful in case you don't know how much memory you need in advance and might disable some optimizations.
    • Setting Module { TOTAL_MEMORY: <bytes>; } in the JavaScript driver file
  • Sometimes Chromium-based browsers refuse to create WebGL context on a particular page, while on other sites it works and the same page works in other browsers such as Firefox. This can be caused by Chromium running for too long, restart it and try again.
  • If you compile your application with a different set of compiler / linker flags or a different Emscripten version than your dependencies, it can fail to load for a variety of random reasons. Try to rebuild everything with the same set of flags.