17

I'm reading about WebAssembly, and I was curious about how to port graphics programming like Vulkan or OpenGL to a canvas element. The documentation is long, and I think I'll figure this out eventually, but I was curious and not successful in searching for the answer on the spot.

So far, I know it can export functions to JS, and JS will do the dirty job of manipulating the DOM as usual.

I could write WebGL directly, but that's not my point. I have seen games ported to WebAssembly, and I'd like to know how it works. How WebAssembly can render anything if it does not have direct access to the DOM? Typically, graphics applications use an external Window Manager like GLFW or SDL to create a Window context to draw your stuff.

If I compile a program using libraries that expect an environment with a Window object, how do these instructions map to the canvas if there's no such concept in the DOM? Do I need to adapt my C++ program somehow?

Rafael Beckel
  • 2,199
  • 5
  • 25
  • 36
  • @ColinE I think your edit is technically correct, but it changes the question intent. At the moment I wrote it, I did not know it was Emscripten that actually generated the glue. I was reading WebAssembly specs and docs. Maybe a better phrasing would be "How a WebAssembly application maps its..." – Rafael Beckel Jan 21 '20 at 22:47

1 Answers1

16

OK, it turns out the answer was on the same page I was reading, but a little bit down further.

The answer is that it's necessary to have a Javascript "glue" code to load .wasm and convert native library calls to the DOM context, but you do not need to write it by hand. People use Emscripten, which includes filesystem emulation, porting to the most popular media libraries like SDL, and it generates both .wasm code and its JS glue counterpart.

From the Mozilla WebAssembly page:

The Emscripten tool is able to take just about any C/C++ source code and compile it into a .wasm module, plus the necessary JavaScript "glue" code for loading and running the module, and an HTML document to display the results of the code.

In a nutshell, the process works as follows:

  1. Emscripten first feeds the C/C++ into clang+LLVM — a mature open-source C/C++ compiler toolchain, shipped as part of XCode on OSX for example.
  2. Emscripten transforms the compiled result of clang+LLVM into a .wasm binary.
  3. By itself, WebAssembly cannot currently directly access the DOM; it can only call JavaScript, passing in integer and floating point primitive data types. Thus, to access any Web API, WebAssembly needs to call out to JavaScript, which then makes the Web API call. Emscripten therefore creates the HTML and JavaScript glue code needed to achieve this.

Limitations:

Emscripten only supports fully portable C and C++ code, and you need to enable some optimizations according to their Portability Guidelines.

Also, you need to keep in mind the inherent constraints of the Web platform and JS runtime, so you do not have direct access to the filesystem and you cannot make synchronous (blocking) networking calls, as detailed in API Limitations page.

OpenGL & Vulkan:

For OpenGL, specifically, as the code will eventually translate to a sandboxed WebGL context, you need to limit yourself to what WebGL offers (i.e OpenGL ES 2.0). According to Optimizing WebGL page, Emscripten will convert your code to WebGL 1 by default, with fewer capabilities and unfriendlier syntax, but supported by more platforms. However, you can also target WebGL 2, which offers a nicer API and a couple of hardware optimizations.

For Vulkan, there's currently no native support, but there is an ongoing discussion in W3C for publishing a WebGPU specification. This is their Github page with up-to-date information and the current browser support page.

There is also an experimental WebGPU Rust implementation by Mozilla, so we can already have a glimpse of the future.

UPDATE MAY 2023: Chrome has just released WebGPU

Rafael Beckel
  • 2,199
  • 5
  • 25
  • 36
  • Thanks for the wonderful answer! Are there any recent updates related to this? I'm curious how the webassembly is going to support for vulkan. Is webassembly progressing toward creating js glue code for each library of vulkan, mental, and d3d12? Or is it being developed in the direction of converting vlukan api to webgpu when converting native code to webassembly? – Sparkleholic Aug 06 '21 at 13:19
  • 1
    Standardization is a tedious, long process because it affects all browser vendors and a lot of people from all corners of the industry have a say on it. This is their Github page with ongoing work: https://github.com/gpuweb/gpuweb As of today, WebGPU is still a draft, but they are actively working on it. – Rafael Beckel Aug 07 '21 at 08:36
  • 1
    It seems they're working towards some kind of abstraction layer. You request an adapter to the browser, and the browser returns it. So you use the adapter to write your GPU code (it seems there's also a new wgsl shader language) and the browser can choose the backend (Vulkan / Metal / DirectX / OpenGL) depending on where it is running. – Rafael Beckel Aug 07 '21 at 08:59