Support for `wasm32-unknown-unknown` via binding with the provided emscripten wasm file
Opened this issue · 6 comments
CC @superdump
I've been working on writing bindings for the transcoder wasm that basis_universal provides so that I can parse and transcode basis files in wasm. I've got a repo for this here:
https://github.com/expenses/basis-universal-rs-wasm
It'd be fantastic if we could get support for this into this crate, so that wasm support just works. A couple of notes:
-
I had to set
EXPORT_ES6=1
in the emscripten link flags:I don't know if I strictly needed to do this, but it made binding with wasm-bindgen via
#[wasm_bindgen(js_name = default)]
a lot easier. -
The emscripten code loads the module asyncronously, which means you can't directly import the exports in wasm-bindgen because they're only created after initialisation. To work around this I had to use reflection to create the javascript classes: https://github.com/expenses/basis-universal-rs-wasm/blob/8274f56092c930bb0dfbb35b0386235a3c5a9813/src/lib.rs#L36-L38
-
By default the emscripten code attempts to load the wasm binary from a relative url. Because wasm-bindgen copies the referenced javascript module to a snippet such as
pkg/snippets/basis-universal-wasm-8dd816e8505190b7/basis_universal/webgl/transcoder/build/basis_transcoder.js
but does not copy anything else. this load fails.Luckily the code allows settings a
wasmBinary
key in the object that's passed in, so you can provide your own wasm file: https://github.com/expenses/basis-universal-rs-wasm/blob/master/src/lib.rs#L26-L31. I justinclude_bytes!
the file for ease of use. -
Because the wrapper API is quite different from the normal API, we're probably going to have to write our own wrapper to bring the APIs to parity.
This will all take a while, but I'll try to create good bindings for the .basisu
transcoder and work from there.
We should be able to use once_cell to safely make the module static: https://docs.rs/once_cell/latest/once_cell/
Awesome!!!
Nice work, thanks for writing all this down! I’m happy to consider merging something like this in.
When the time comes to review, anything we can do to keep the “native” use-case of the crate relatively simple and to minimize ongoing future maintenance will be appreciated. (I want this project to be sustainable!) If appropriate maybe we could have some of it (like the wrappers) in a downstream but in-tree crate? An extra review by someone more familiar with bindgen would also be very welcome!
So one think I've ran into is that (and I've love to be corrected on this if I'm wrong) it doesn't seem like you can create rust slices from javascript Uint8Array
s. You can only copy them into Vec<u8>
s (See https://docs.rs/js-sys/latest/js_sys/struct.Uint8Array.html#method.to_vec). This is a problem for trying to replicate the Transcoder
API (https://docs.rs/basis-universal/latest/basis_universal/transcoding/struct.Transcoder.html) as all the methods take &[u8]
slices and these would all need to be copied. As a result I think that I'll stick with the existing BasisFile
abstraction that only makes a single copy.
I think the main API to get into parity is the LowLevelUastcTranscoder
. That's the only thing that you need for ktx2 support anyway (See https://github.com/bevyengine/bevy/blob/00f83941b16e7a175c5c1503be81a648e23d81df/crates/bevy_render/src/texture/ktx2.rs#L117-L149)
I've worked on this a bit more today and have created some commits that let me use LowLevelUastcTranscoder
in the browser!
Firstly BinomialLLC/basis_universal@9177a09 expenses transcode_slice
in the basisu wasm, expenses/basis-universal-rs-wasm@009a82c adds it to my bindings and 613c4d3 hackily adds it to this crate. I'm going to work on merging in things soon.
I'm going to work on merging in things soon.