Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WebGL and wasm multithreading with web workers #2652

Closed
Tracked by #3674
expenses opened this issue May 11, 2022 · 6 comments
Closed
Tracked by #3674

WebGL and wasm multithreading with web workers #2652

expenses opened this issue May 11, 2022 · 6 comments
Labels
api: gles Issues with GLES or WebGL area: performance How fast things go type: enhancement New feature or request

Comments

@expenses
Copy link
Contributor

So this is something that seems pretty difficult to implement and the best bet is almost definitely to just wait until WebGPU becomes more widely available (I'm using WebXR which doesn't work with WebGPU yet).

In a couple of places we lie about wasm not having threads:

// SAFE: WASM doesn't have threads
#[cfg(target_arch = "wasm32")]
unsafe impl Sync for super::Device {}
#[cfg(target_arch = "wasm32")]
unsafe impl Send for super::Device {}

This is not true, as wasm has thread support via web workers, see https://web.dev/webassembly-threads/ https://rustwasm.github.io/docs/wasm-bindgen/examples/raytrace.html https://github.com/wngr/wasm-futures-executor etc.

There are a couple of limitations that make trying to use wgpu in a multthreaded way with the WebGL backend very difficult at the moment:

  1. You can't block on the main thread at all, and wgpu has internal Mutexes that try to block when shared across threads. An error for this looks like:
VM879:1284 RuntimeError: Atomics.wait cannot be called in this context
  at parking_lot::raw_mutex::RawMutex::lock_slow::h6c0cf413016f1347 (webxr_pbr_bg.wasm:0x1e9d17)
  at wgpu_core::device::<impl wgpu_core::hub::Global<G>>::texture_drop::h189d38f7cd4d16b8 (webxr_pbr_bg.wasm:0x1ff48e)
  at <wgpu::Texture as core::ops::drop::Drop>::drop::h80e5c76af149e025 (webxr_pbr_bg.wasm:0x302957)
  1. You can't access a lot of global properties in web workers. See https://developer.mozilla.org/en-US/docs/Web/API/DedicatedWorkerGlobalScope. This means that you can't run your main function in a web worker.

  2. Any wasm_bindgen javascript values that are passed across the thread boundary such as the WebGl2RenderingContext become undefined.

I did look into creating a more threadsafe device api that involved pushing tasks to a device in the main thread: https://gist.github.com/expenses/64a467b5f09462ad2441b9ceefe55b6f but I was not able to make this work fully.

It's possible that there are good ways around these issues and that it would end up being worthwhile. The idea of having a separate thread for WebGL rendering has been around for a while:

https://research.mozilla.org/2014/07/22/webgl-in-web-workers-today-and-faster-than-expected/

@cwfitzgerald cwfitzgerald added type: enhancement New feature or request area: performance How fast things go api: gles Issues with GLES or WebGL labels Jun 4, 2022
@haraldreingruber-dedalus
Copy link
Contributor

haraldreingruber-dedalus commented Jun 23, 2022

@expenses Do you think the Canvas.transferControlToOffscreen() workflow with a web-worker would be a small first step in that direction?

I've recently added OffscreenCanvas support for the WebGL backend, but I didn't yet try if it works also out of the box from a web worker or if there are further adaptions required.

It's not real multi-threading, but it can free up the main thread and avoid blocking one or the other.
three.js has an example that shows offscreen+webworker rendering while doing computations on the main JS thread (by clicking "start jank").

@expenses
Copy link
Contributor Author

@haraldreingruber-dedalus interesting! I absolutely have not looked into this, no. I'm hoping that WebGPU will be stable before looking into this becomes a good idea 😉 But busy at the moment to do that now unfortunately

@gilescope
Copy link

gilescope commented Dec 22, 2022

It's multi-processes rather than multi-threads alas. trunk has a nice example of using web-workers with wasm. It seems to work pretty well from my experience - I've had no problems using webworkers to do a lot of I/O and preprocessing and just pop the small amount of data required for rendering the graphics over to the main process. A bit fiddly to set up but once set up I've had no additional issues with it over the months. I'm no game dev but you can see it in action at http://dotsama.world

@cwfitzgerald
Copy link
Member

This is now solved and wgpu types are !Send !Sync on wasm.

@lee-orr
Copy link

lee-orr commented Dec 2, 2023

This is now solved and wgpu types are !Send !Sync on wasm.

That prevents causing the bug, but doesn't resolve the need/desire to support multi-threading in WASM... Should that be set up as a separate issue?

@cwfitzgerald
Copy link
Member

It's currently not possible. There's no way to send webgpu objects (or webgl objects) across threads.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
api: gles Issues with GLES or WebGL area: performance How fast things go type: enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

5 participants