Hacker News new | ask | show | jobs
by mattdesl 1956 days ago
So this is great but it might be worth pointing out that the library went from Canvas2D (slow) and ThreeJS (very general purpose) to pure WebGL calls tailored to the application, which alone probably would have been the significant driver behind the performance improvements. It’s hard to see exactly how much WASM has helped on top of that, and I wonder if a pure JS+WebGL version would perform about as well at the fraction of file size, complexity and parse speed.

Usually I wouldn’t recommend going WASM unless you have very hot CPU code paths, like physics across thousands of 3D bodies and collisions that is eating up your frame time. In the case of an image viewer I’m not sure that code is ‘hot’ enough in CPU terms to really warrant all this.

(I’d love to be proved wrong with benchmarks and find more general uses of wasm tho !)

Just my 2c. Really great write up and work nonetheless!

2 comments

Thanks for the comment! I agree that the change to a custom tailored engine probably made the biggest difference performance wise. At the end of the article I also briefly mention this.

However, having a monolithic compiled Wasm module which contains all of (and only) the rendering logic is really nice on a codebase-level.

Also, the Wasm part of Micrio is being used for a lot of realtime matrix4 calculations. While I didn't use this specific library, here is a bench page which shows that Wasm really kills JS performance here: https://maierfelix.github.io/glmw/mat4/ .

So it definitely makes a difference. If I had the time I would port the Wasm engine back to JS and do more benchmarking. But that's a big if :)

I hadn't seen glmw, thanks for sharing.

I can see how WASM definitely improves performance in those benchmarks (where we're talking about thousands of matrix operations). But I imagine your per-frame camera & matrix math is probably not taking up much time (within a 16ms budget), so a lot of these WASM optimizations may not have any real influence on the rendering performance. But, they could introduce more upfront parsing/loading time for your library (i.e. base64 decoding, WASM instantiation), and obviously a bring with them a lot more complexity (in authoring the module and supporting legacy devices).

Anyways, it's pretty cool that you can call GL functions directly from WASM, I hadn't realized that before and it probably would make for an epic game engine to have almost everything called from WASM land.

Regarding the "emscripten-imposed file size problem", I've written a couple of alternative cross-platform headers which might help in this case (e.g. avoiding SDL). These enable WASM apps in the "dozens of KBytes" range, and you get native-platform support "for free":

https://github.com/floooh/sokol

Check out these samples and have a look at the size in the browser devtools which are IMHO quite sensible:

https://floooh.github.io/sokol-html5/

https://floooh.github.io/tiny8bit/

PS: really great writeup btw :)

The binaryen toolkit comes with a wasm2js tool, you could translate the wasm back to js and see how performance compares ;)

It's possible that performance isn't all that different, because asm.js-style Javascript can be surprisingly fast (compared to "idiomatic" human-written Javascript).

Otherwise it's a completely pointless excercise of course, unless you need to support browsers without WASM support (which don't exist anymore AFAIK).

[1] https://github.com/WebAssembly/binaryen

It's unnecessary with AssemblyScript due to AS is just subset of TypeScript and can transpile to ordinal idiomtic javascript. Also AS already uses binaryen under the hood and can produce asm.js via --jsFile, -j command line.
You could (fairly) easily build a reduced test case to verify this. I'd be interested in seeing the results.