emscripten-core / emscripten

Emscripten: An LLVM-to-WebAssembly Compiler
Other
25.89k stars 3.32k forks source link

Why isn't there a `WebGPU.wasm` module or similar? #15710

Open qgcarver opened 2 years ago

qgcarver commented 2 years ago

One of the major sells of wasm is to be able to instantiate different services with different modules to service different embedders (JS, WASI-compatible runtimes etc.) such that you can create different modules that serve other modules, configured by the host/embedder, or serve the embedder directly.

You can generate wasm from LLVM raw, but the glue code is still needed to interact with JS APIs like WebGPU or WebGL, I want to be clear that I am not suggesting that wasm should have JS APIs available to Wasm inherently.

What I am confused about is why the modularity benefits aren't even available as a premade option with Emscripten. It would seem that the WebGPU or WebGL (etc) APIs should be available as modules to be linked with your application when you instantiate with the WebAssembly JS API, such that if you were to move your wasm module to a different embedder/runtime (such as wasmtime or the like) you would just swap in webgpu_wasi.wasm in place of the webgpu_js.wasm and library to instantiate it and provide the functions webgpu.js or something.

I can understand just swapping out the posix-style APIs for porting jobs, but it seems strange to target OS apis if I am creating a new web-capable, cross-platform application.

The WebGPU API, for instance, changes very often, and uses Dawn's generator to make it all work, shouldn't this just be made an upgradeable wasm module within one's browser application that is linked with your cross-platform/platform non-specific wasm module? Can this functionality be added to Emscripten? (or if it already exists, is there any documentation on this?)

Notably, nothing about doing this would make porting jobs not work, unless there is some objection to having more than one module, which seems to really miss the point of wasm's benefits, or if Emscripten is being sold as a way to not have to worry about JS, ostensibly the number of modules won't matter to the user. (And of course this option could be not only optional, but a different tool altogether which is only optionally used or something to that effect.)

All of the glue code for wasm under library_webgpu.js etc is there, but I don't know why this isn't a package or easily usable tool, given the updates will be frequent and regeneration will be required.

kripken commented 2 years ago

IIUC you are proposing that a WebGPU.wasm be created, which contains calls in some high-level format to the WebGPU API. That could be linked against a JS module that calls those APIs on the Web, or on another platform some other wasm module could be linked in that calls the proper APIs there, etc. Is that the idea you have?

This could become possible with Interface Types eventually, as they will provide a high-level format in which to do calls across wasm modules. Right now there is no mechanism for that, so we define low-level ABIs between wasm and JS and implement those on both sides.

Note that there are open questions about how well Interface Types can help here - it is under development and still changing. One particular issue is the efficiency across the boundary: IT is designed to not share memory between the different sides, but our various bindings definitely do that, and quite a lot. And in general it's possible to write a handcrafted ABI between wasm and JS (as we do today) that would outperform a generic API between wasm and anything else.

qgcarver commented 2 years ago

I guess I was under the impression that wasm modules could be linked together, putting aside how well the webgpu.js file supports the object.

My understanding was that wasm modules have a callable exports, and I further thought that wasm modules could interact with another module's exports. So I guess the point of interface types is not to import JS objects (or others) into wasm modules as inputs to functions, but predominantly to allow wasm modules to call one another's exports? (my understanding was that because wasm modules don't have a notion of js objects inherently, all they could do was intern the references to js functions)

So I suppose the interface types both apply to exports and to inputs,

But since you have the js glue code anyway, it's not obvious you can't just do the equivalent of having glue code between wasm modules as well. Obviously interface types are preferred, but it in the meantime you have pointers and numbers. I just figured you guys already had the machinery to make the conversion. In any case it seems like the modules just directly calling one another's exports is part of the interface types idea, which I thought was just about having wasm be able to "speak" js objects in addition to the normal u32s and function references etc.

But I suppose that modules using one another's exports (regardless of whether it has more sophisticated types like records and variants) is also part of the proposal?

qgcarver commented 2 years ago

As I mentioned, it seems like the capability is there.

https://emscripten.org/docs/compiling/Dynamic-Linking.html

Although, without interface types, the relevance is unclear if you wanted to have proper modularity (such that a webgpu.wasm module could easily have variations for the different embedders)

That could be linked against a JS module that calls those APIs on the Web, or on another platform some other wasm module could be linked in that calls the proper APIs there, etc. Is that the idea you have?

Also, to be clear, my interest is more in wasm modules being able to be loaded together as described in the link above, swapping out the wasm module for a different platform. So not a copy of the webgpu browser API being redundantly called by a 'JS module', but from a wasm module which may get the API from JS, but also from a different platform. The application module using webgpu can be platform non-specific, even if the webgpu provider module is platform specific. (To analogize to the terminology in the link above, main and side modules, although it would be more like webgpu being some kind of main module, or at least a part of some platform-specific layer, while the main app is a "side module" in that terminology.)

Although again without interface types, the modularity in practice is unclear. Maybe if you were the one to also provide the wasi_webgpu.wasm module, but that would be out of scope of emscripten.

kripken commented 2 years ago

A wasm module could import another's exports, and that can work with low level exports in theory. So yes, someone could write a wasm file B that replaces the JS side that a wasm file A would normally be interfaced with. Writing such a wasm file could then interface with a different set of APIs than Web APIs, so that could be useful.

In practice Web APIs are the main use case we focus on here, so we've not added much aside from support for them. But someone else could if they wanted, you are right.