Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How a WebAssembly application maps its native Window / OpenGL / Vulkan calls to a canvas element in DOM?

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 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 do compile a program using such libraries that expect an environment with some Window object to fire up, how these instructions will get mapped to the canvas if there's no such concept in the DOM? Do I need to adapt my C++ program somehow?

like image 761
Rafael Beckel Avatar asked Jan 21 '20 18:01

Rafael Beckel


1 Answers

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.

like image 117
Rafael Beckel Avatar answered Oct 20 '22 06:10

Rafael Beckel