Along with dropped support for NaCl, Magnum now has first-class WebAssembly support. I also took this opportunity to overhaul the outdated Show­case page with WebAssembly builds and there is a bunch more Emscripten-related goodies all over the place!

As (P)Na­Cl was deemed dead by its cre­ators, I axed all sup­port for it from all re­pos. Frankly, it was quite a weird plat­form, some­thing in-be­tween OpenGL ES 2.0 and We­bGL 1.0, hav­ing very spe­cial ug­ly C++ API and shar­ing a lot of C++11 work­arounds with An­droid (sigh). In the Mag­num repos­i­to­ry alone, the amount of delet­ed code was al­most 5k lines.

On the oth­er hand, adding sup­port for We­bAssem­bly was al­most too easy. With Em­scripten 1.37.9 and new­er it just boils down to adding one new com­pil­er and link­er flag, dif­fer­ent files are gen­er­at­ed (but they are still load­ed au­to­mat­i­cal­ly from the main *.js file), and ev­ery­thing else stays the same as with the clas­sic asm.js com­pi­la­tion.

But how?

If you pull lat­est re­vi­sions of Mag­num repos­i­to­ries, build­ing for We­bAssem­bly in­stead of asm.js is just a mat­ter of spec­i­fy­ing dif­fer­ent toolchain — Emscripten-wasm.cmake in­stead of Emscripten.cmake. Note that I had to use some new­er CMake func­tion­al­i­ty to make the dif­fer­ence, so you’ll need at least CMake 3.7 to com­pile for Em­scripten now. I hope that’s not a prob­lem for you — in the worst case you can al­ways down­load a pre­built bi­na­ry ar­chive of CMake, ex­tract and run it from what­ev­er lo­ca­tion. More in­fo about build­ing for We­bAssem­bly is in the docs. If you are on Arch­Lin­ux like me, there are al­so new PKGBUILD-emscripten-wasm and PKGBUILD-emscripten-wasm-webgl2 pack­age scripts in package/archlinux di­rec­to­ry of each repos­i­to­ry to make your life eas­i­er.

In or­der to prop­er­ly de­ploy your We­bAssem­bly app, you’ll need to change your install() step. With the OPTIONAL key­word you can sup­port both the asm.js case (sep­a­rate *.js.mem file) and We­bAssem­bly case (sep­a­rate *.wasm file). Al­so, there is a new MAG­NUM_DE­PLOY_PRE­FIX vari­able that can be used to dif­fer­en­ti­ate in­stall lo­ca­tion for the fi­nal app from in­stall lo­ca­tion for sys­tem files (so, for ex­am­ple, you can set MAGNUM_DEPLOY_PREFIX to point to a lo­ca­tion used by your web­serv­er while CMAKE_INSTALL_PREFIX still points to sys­tem lo­ca­tion where li­braries are stored):

        MyApplication.html EmscriptenApplication.js WebApplication.css

Note that in or­der to make full use of all the new fea­tures, you might want to up­date your copies of EmscriptenApplication.js and WebApplication.css from the repos­i­to­ry.

Show me what you got

The most ex­cit­ing about We­bAssem­bly and web things in gen­er­al is that you don’t have to get up from your com­put­er, go to the app store across the street and tell them to down­load and in­stall a new app on your ma­chine. We­bAssem­bly demos are just one click away — head over to the ful­ly re­worked Show­case page! Apart from all ex­am­ples that were al­ready port­ed to Em­scripten and now they are just re­com­piled in We­bAssem­bly, there is al­so a fresh port of the Au­dio ex­am­ple:

Au­dio ex­am­ple
Shows how to play spa­tial­ized au­dio with Mag­num. Warn­ing: plays sound on load.

I aimed to make all the de­mo pages re­spon­sive and mo­bile-firend­ly, but no­body’s per­fect — if you see some­thing strange, don’t hes­i­tate to re­port a bug ei­ther on the web­site re­pos­i­to­ry or for a par­tic­u­lar ex­am­ple. Feed­back wel­come, as al­ways.

Brows­er sup­port

Even though We­bAssem­bly is not that new, it may hap­pen that the above ex­am­ples didn’t work on your ma­chine. Here’s a list of browsers that sup­port it:

Brows­er Sup­port state
In­ter­net Ex­plor­er Se­ri­ous­ly? No. Sor­ry.
Edge Since ver­sion 16 (Win­dows 10 Cre­ators Up­date)
Fire­fox Since ver­sion 52
Opera Since ver­sion 45
Vi­val­di Since ver­sion 1.9
Chrome Since ver­sion 58
An­droid Chrome Since ver­sion 56
Sa­fari Since ver­sion 11 (mac­OS 10.13)
iOS Sa­fari Since ver­sion 11 (iOS 11)

Win­dow­less ap­pli­ca­tions

In or­der to make prop­er brows­er test­ing pos­si­ble in the fu­ture, “win­dow­less” ap­pli­ca­tions are now sup­port­ed in Em­scripten as well. In prac­tice it means that in­stead of show­ing a can­vas, the web app is show­ing its tex­tu­al out­put. This al­so makes the Mag­num In­fo util­i­ties fi­nal­ly avail­able on the web:

Mag­num In­fo
Text util­i­ty print­ing out var­i­ous in­for­ma­tion about Mag­num and the OpenGL / We­bGL im­ple­men­ta­tion it’s run­ning on. Ver­sions for We­bGL 1 and We­bGL 2 are avail­able.
Mag­num AL In­fo
Text util­i­ty print­ing out var­i­ous in­for­ma­tion about Mag­num and the Ope­nAL im­ple­men­ta­tion it’s run­ning on.

Win­dow­less ap­pli­ca­tions for Em­scripten are us­ing the Plat­form::Win­dow­lessEglAp­pli­ca­tion class, see its doc­u­men­ta­tion for de­tailed us­age guide. There is al­so a new win­dow­less-em­scripten boot­strap project.

“Com­mand-line” ar­gu­ments

Along with win­dow­less ap­pli­ca­tions be­ing sup­port­ed, it’s now pos­si­ble to pass “com­mand-line” ar­gu­ments to apps run­ning in the brows­er. This was pos­si­ble since ev­er when run­ning com­mand-line apps through Node.js, but now this can be done with the brows­er apps as well. Just pass the ar­gu­ments as URL GET pa­ram­e­ters. On­ly long named ar­gu­ments and bool­ean op­tions are sup­port­ed. For ex­am­ple, hav­ing the URL as

/my-app/?enable-msaa&magnum-disable-extensions=GL_OES_vertex_array_object GL_EXT_texture_filter_anisotropic

is equiv­a­lent to call­ing the com­mand-line ver­sion of the ap­pli­ca­tion as

./my-app --enable-msaa --magnum-disable-extensions "GL_OES_vertex_array_object GL_EXT_texture_filter_anisotropic"

The pro­gram name is prepend­ed to the ar­gu­ment list (to be­come argv[0]) au­to­mat­i­cal­ly by Em­scripten and is hard­cod­ed to ./this.program. All --magnum-* op­tions sup­port­ed by the en­gine are work­ing on Em­scripten-com­piled ap­pli­ca­tions as well. More in­fo in the docs.

Size com­par­i­son to asm.js

The dif­fer­ence is very mi­nor — but that’s large­ly due to the fact that all bi­na­ry da­ta in the (op­ti­mized) asm.js ver­sion were in a sep­a­rate bi­na­ry file (in­stead of be­ing rep­re­sent­ed in text) and a very ag­gres­sive clo­sure com­pil­er step was ap­plied to the gen­er­at­ed JS file to mini­fy it. Com­press­ing the da­ta makes the dif­fer­ence even small­er — there’s sim­ply the same amount of in­for­ma­tion, just en­cod­ed dif­fer­ent­ly. Here’s a ta­ble show­ing size of the gen­er­at­ed *.js and *.js.mem / *.wasm files for the Tri­an­gle ex­am­ple:

Tri­an­gle ex­am­ple build Size
asm.js, un­com­pressed 720.3 kB
wasm, un­com­pressed 590.1 kB
asm.js, gzipped 179.9 kB
wasm, gzipped 165.9 kB

Be­cause com­press­ing the da­ta re­al­ly makes a dif­fer­ence, en­abling it on the serv­er is cru­cial for fast down­load times. There’s one prob­lem, though: by de­fault, the servers are con­fig­ured to com­press on­ly tex­tu­al da­ta such as *.js, *.html or *.txt files, ex­clud­ing the very-nice­ly-com­press­ible *.wasm da­ta. Be­cause We­bAssem­bly is quite new, re­ly­ing on its MIME-type might be prob­lem­at­ic and so it’s best to just re­ly on file ex­ten­sions in your Apache con­fig­u­ra­tion or .htaccess file:

AddOutputFilter DEFLATE html css js wasm

An­oth­er pos­si­bil­i­ty is re­nam­ing the *.wasm files to e.g. *.wasm.txt, which is a so­lu­tion when you don’t have the pos­si­bil­i­ty to over­ride your serv­er con­fig­u­ra­tion. But note that then the We­bAssem­bly files won’t get load­ed au­tomag­i­cal­ly and you need to sup­ply your own async load­ing code.

~ ~ ~

Okay, that’s all! There’s still quite a lot Em­scripten-re­lat­ed fea­tures, demos and im­prove­ments in my buf­fer, so ex­pect an­oth­er blog post lat­er!