Parallel Raytracing - The wasm-bindgen Guide (original) (raw)

The `wasm-bindgen` Guide

Parallel Raytracing

View full source code or view the compiled example online

This is an example of using threads with WebAssembly, Rust, and wasm-bindgen, culminating in a parallel raytracer demo. There's a number of moving pieces to this demo and it's unfortunately not the easiest thing to wrangle, but it's hoped that this'll give you a bit of a taste of what it's like to use threads and Wasm with Rust on the web.

Building the demo

One of the major gotchas with threaded WebAssembly is that Rust does not ship a precompiled target (e.g. standard library) which has threading support enabled. This means that you'll need to recompile the standard library with the appropriate rustc flags, namely-C target-feature=+atomics,+bulk-memory,+mutable-globals. Note that this requires a nightly Rust toolchain.

To do this you can use the RUSTFLAGS environment variable that Cargo reads:

export RUSTFLAGS='-C target-feature=+atomics,+bulk-memory,+mutable-globals'

To recompile the standard library it's recommended to use Cargo's-Zbuild-stdfeature:

cargo build --target wasm32-unknown-unknown -Z build-std=panic_abort,std

Note that you can also configure this via .cargo/config.toml:

[unstable]
build-std = ['std', 'panic_abort']

[build]
target = "wasm32-unknown-unknown"
rustflags = '-Ctarget-feature=+atomics,+bulk-memory,+mutable-globals'

After this cargo build should produce a WebAssembly file with threading enabled, and the standard library will be appropriately compiled as well.

The final step in this is to run wasm-bindgen as usual, and wasm-bindgenneeds no extra configuration to work with threads. You can continue to run it through wasm-pack, for example.

Running the demo

Currently it's required to use the --target no-modules or --target web flag with wasm-bindgen to run threaded code. This is because the WebAssembly file imports memory instead of exporting it, so we need to hook initialization of the wasm module at this time to provide the appropriate memory object. This demo uses --target no-modules, because Firefox does not support modules in workers.

With --target no-modules you'll be able to use importScripts inside of each web worker to import the shim JS generated by wasm-bindgen as well as calling the wasm_bindgen initialization function with the shared memory instance from the main thread. The expected usage is that WebAssembly on the main thread will post its memory object to all other threads to get instantiated with.

Caveats

Unfortunately at this time running Wasm on the web with threads has a number of caveats, although some are specific to just wasm-bindgen. These are some pieces to consider and watch out for, although we're always looking for improvements to be made so if you have an idea please file an issue!

These caveats are all largely inherited from the web platform itself, and they're important to consider when designing an application for threading. It's highly unlikely that you can pull a crate off the shelf and "just use it" due to these limitations. You'll need to be sure to carefully plan ahead and ensure that gotchas such as these don't cause issues in the future. As mentioned before though we're always trying to actively develop this support so if folks have ideas about how to improve, or if web standards change, we'll try to update this documentation!

Browser Requirements

This demo should work in the latest Firefox and Chrome versions at this time, and other browsers are likely to follow suit. Note that threads andSharedArrayBuffer require HTTP headers to be set to work correctly. For more information see the documentation on MDNunder "Security requirements" as well as Firefox's rollout blog post. This means that during local development you'll need to configure your web server appropriately or enable a workaround in your browser.