Winit: Web worker support

Created on 27 Mar 2020  路  3Comments  路  Source: rust-windowing/winit

Since web workers support canvas via OffscreenCanvas, would it be possible to make winit run in a web worker?

Main issues are these:

  • OffscreenCanvas implements EventTarget so events are not a problem. Although they will have to be forwarded from the main canvas via whatever worker implementation is used. Probably not a winit concern.
  • OffscreenCanvas is different type than HtmlCanvasElement and can not be converted in rust. However, since javascript is an interpreted language, inserting OffscreenCanvas instead of HtmlCanvasElement from js side does not cause a problem. Although browser throws an error due to missing functions (style(), request_fullscreen(), set_attribute()), adding empty stubs fixes the issue and it works happily. This is a bit hacky, but other option would require replacing backend::RawCanvasType with enum, which would require a lot of rewrites.
  • A lot of functions use web_sys::window() and panic on web worker. Could they instead of panicking return default value? Main offenders are scale_factor() and is_fullscreen() which both are not essential. However, if they return default value would it make debugging harder for regular canvas?

Maybe there's no point in running winit in web worker, because the only usable feature without additional glue is the event loop. But I opened this for discussion, as this is relevant for projects that use winit and trying to support wasm.

WebAssembly needs discussion question

Most helpful comment

I think for now it doesn't quite make sense for winit to actually do anything special for OffscreenCanvas. The winit event loop must run on the "main thread" to handle the DOM eevnts. While winit has control over the size of the canvas, the actual rendering is handled by the user. If the user would like to call transferControlToOffscreen and pass the OffscreenCanvas to a web worker, it's totally fine. The user is responsible for sending the winit events to the worker if the rendering code needs them.

This should be kind of similar to how OpenGL rendering on its own thread works on native. The user passes the OpenGL context to another thread and do the rendering over there, but the winit event loop still stays on the thread it is started on. The user will also need to send the winit events over with an MPSC or whatever.

IMO The current event handling and threading model on web makes it quite complicated to run the winit event loop on a web worker. I'm not convinced that running winit on a web worker is really a good approach.

All 3 comments

I guess my question would be why would you want to point winit at an offscreen canvas? Is it possible for that canvas to receive events?

It does implement EventEmitter, but I believe input events would have to be forwarded from the main canvas via worker postMessage.

I just opened this issue to maybe explore possibilities and get ideas from other people on best practices with web assembly. There is a big issue with wasm that it supports threads (under web workers), with one big exception that you can't atomic wait (mutex, lock, sleep, etc) in main thread. This renders many native libraries and projects unable to run on wasm without major rewrites. So running entire application in a web worker is one way to overcome this problem.

We explored this option for https://github.com/amethyst/amethyst and had a PoC running with OffscreenCanvas so it is possible. However, web workers do not support audio and we had to abbandon this plan. Maybe this information will be useful for others attempting to port their projects into wasm and this issue can be closed. Or it could be left open as a low priority feature request.

I think for now it doesn't quite make sense for winit to actually do anything special for OffscreenCanvas. The winit event loop must run on the "main thread" to handle the DOM eevnts. While winit has control over the size of the canvas, the actual rendering is handled by the user. If the user would like to call transferControlToOffscreen and pass the OffscreenCanvas to a web worker, it's totally fine. The user is responsible for sending the winit events to the worker if the rendering code needs them.

This should be kind of similar to how OpenGL rendering on its own thread works on native. The user passes the OpenGL context to another thread and do the rendering over there, but the winit event loop still stays on the thread it is started on. The user will also need to send the winit events over with an MPSC or whatever.

IMO The current event handling and threading model on web makes it quite complicated to run the winit event loop on a web worker. I'm not convinced that running winit on a web worker is really a good approach.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

felixrabe picture felixrabe  路  4Comments

dhardy picture dhardy  路  3Comments

swiftcoder picture swiftcoder  路  3Comments

francesca64 picture francesca64  路  4Comments

nvzqz picture nvzqz  路  5Comments