-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
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
Web Support #88
Comments
yeap, plz, i am waiting for, i am using the pathfinder now |
The most significant blocker for full web support is likely to be multithreading. An MVP for this probably needs to be single threaded. Some thought should be put into understanding what Bevy changes would be required to support asynchronous thread waiting, as it is not possible to block the main thread in web browsers. A couple alternative solutions may exist to this and I’ll leave them here for future discussion: Binaryen Asyncify, and rendering off the main thread using a worker and some combination of an offscreen canvas API and WebGPU. |
@lwansbrough what is about run thread in web work? |
@NateLing With the Canvas API we can transfer control from the main thread to a web worker. According to this comment WebGPU will (may already?) have the same capability to transfer control to a worker. Edit: I see now that WebGPU uses a canvas like const offscreen = document.querySelector('canvas').transferControlToOffscreen();
const worker = new Worker('myworkerurl.js');
worker.postMessage({ canvas: offscreen }, [offscreen]); from: https://developers.google.com/web/updates/2018/08/offscreen-canvas#unblock_main_thread (This page has several examples.) Then I suppose Bevy would then spawn additional WebAssembly threads from this main worker. I don't know what Bevy needs in order to work, but it sort of seems to me like the required browser features exist. Edit: So the issue here actually seems to be what happens once you start doing work in workers. Work done by the Amethyst team showed that browsers will not execute tasks until control is returned to the main thread. You can follow that issue here and Azriel made a demo which you can find here. |
Heya, one thing I'd like to share: It's quite difficult to integrate with the browser event loop unless one uses So, is it possible to use The answer is yes -- before I went back to work, I made this thing: https://nginee.rs/examples/event_loop_rate_limit.html
Also, worth noting that that currently uses a single threaded pool to run the tasks (futures), I hadn't tried integrating with web workers yet (not intending to promote -- please look at the code for how you would convince Rust to run |
An approach to working with There's an incomplete but workable implementation of this idea in It allows code like the following example to be written: async fn run(app: Application, events: Events) {
let mut _window = app.new_window().build().unwrap();
// Loop forever!
loop {
match events.next().await {
Event::WindowCloseRequested { .. } => app.quit(),
Event::Draw { .. } => {}
_ => {}
}
}
} |
Yet another approach is to run the entire engine off the main thread. This makes blocking a non-issue, as WASM Threads (Web Workers) are allowed to block. This is an example using WebGPU to render in an offscreen canvas hosted by a web worker. This should work once WebGPU contexts are supported by offscreen canvases. It sits beside a main thread canvas which is rendered using WebGPU. That part is working today in Chrome Canary with This is an active area of development. Support for WebGPU in offscreen canvases in Chrome is being tracked here and is currently blocked by a refactor. |
FYI the issue fixed by uuid-rs/uuid#477 was blocking compilation to WASI for several of Bevy's crates, but just got merged today. |
I attempted porting https://github.com/amethyst/web_worker WorkerPool implementation as a replacement TaskPool - it looked very promising and the changes are straightforward. The main issue I stumbled is that You can look at my change at: https://github.com/smokku/bevy/commit/2ad15d8e1830b891e76b73c92dab28a2dd911ee5 |
Is wrapping each of them in an |
Unfortunately the internals of these types are the issue. Arc protects the type, but not internals. |
Single threaded implementation works fine though. https://github.com/smokku/bevy/commit/72d672515584e7c865915c649a8759dcf3460b1b I will make it into a proper PR soon - just have a question:
|
I'd say if making TaskPools a separate feature makes this easier, definitely go for it. But if we can somehow make TaskPools work on web, then being able to assume that TaskPools are always available (an all platforms) would be nice. Web is the only platform on my radar that might have issue with threads (that i know of). This is really exciting. Great work 😄 |
It definitely is not easier. Once a Cargo feature is enabled, it is no way to disable it. We would have to maintain parallel default features sets for different targets. Been there - ugly. So, I will just make the cfg on target arch and if there comes a need for P.S. I would love to get wasm threads running too, but it currently is way over my league. This is just to get the wasm story started. |
Would transmuting the JsValue solve the problem? https://github.com/RSSchermer/web_glitz.rs/blob/8730f44108f89844eb303057f1b13118604a3e4f/web_glitz/src/util.rs#L10 |
It doesn’t look like it. |
The point where the TaskPool is converted to a resource is here (line 46). Send + Sync is required because it is expected that the TaskPool should be made available to all threads in the pool. In the context of the web, this implies that the TaskPool would be available as a resource to all web workers ("WASM threads"). The problem that arises is that as you discovered, JsValues are not Send/Sync. Why are JsValues not Send/Sync? Because JsValues (read: Javascript objects) are not allowed to be shared between web workers, with a few exceptions I believe (some primitives?) The documented ways around this are message passing via postMessage and of course the notorious SharedArrayBuffer. But lets get back to why this is a problem to begin with: why do you need to be sending JsValues between threads? I took a look at your code. The issue is you have an internal reference to a collection of Following this, one solution to the problem is to create a place for the One issue I can foresee is that workers may in the course of their execution be asked to create new workers. For example, a system may want to parallelized some asynchronous tasks. In this case (probably? I'm not familiar with the async task API), it would expect to be able to obtain a reference to the TaskPool so it can spin up new workers. It would likely be necessary for the web worker based TaskPool to defer worker creation to the main thread, so that these workers are not accidentally instantiated as grandchild workers (parented by the worker instead of the main thread.) Although again I'm not sure if this is a bad thing -- it probably depends on the expected lifetime of the workers. |
Regarding rendering support: with this little change: mrk-its@6145d85 (it removes spirv-reflect and bevy-glsl-to-spirv as @cart suggested some time ago) it is possible to build bevy with bevy_render. It allows enabling |
Dropping by to say that https://github.com/chemicstry/wasm_thread exists, in case people were exploring this. |
Dropping by to say SUPERMAN exists.
On Sun, Nov 8, 2020 at 12:35 PM Azriel Hoh ***@***.***> wrote:
Dropping by to say that https://github.com/chemicstry/wasm_thread exists,
in case people were exploring this.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#88 (comment)>, or
unsubscribe
<https://github.com/notifications/unsubscribe-auth/AHGK5THYHCWI7AK7ROKO5SDSOZC4HANCNFSM4PU7ZDMA>
.
--
Raza Amir
|
@azriel91 thanks for checking in and with a tip! We haven't kept this issue updated as well as we could. For an update on @mrk-its 's comment
The current progress of |
I just closed #613 as bevy_webgl2 is available as external plugin now (and should work with current bevy master branch): https://github.com/mrk-its/bevy_webgl2 |
Great work @mrk-its I'd like to share some findings:
Here's an example of
|
|
If it's not too much trouble, could somebody copy the comments by |
Also relevant: bevy-cheatbook/bevy-cheatbook#23 |
[4:28 PM] Cole Poirier: @true Doctor hi welcome to the bevy discord! Since bevy is very focussed on parallelism and thus would want to run in WASM multithreaded, can you share what you had to do to get your own wasm library to work multithreaded? |
Since threading has been brought up, see |
Thanks guys! Unfortunatley it looks like that's too in-depth for me to get into for now being that all current solutions require shared array buffers and for my game I'm trying to stay compatible with Safari ( 🙄 ) because I want it to work on iPhones. ( why must so popular a platform have such poor browser feature surpport ) |
Is this approach PoC only or is it tested under real load? My experiments with https://github.com/smokku/wrte shows that browsers severely limit the number of WebWorkers running at the same time. I was unable to reliably use it as a multiprocessing mechanism. |
Isn't the offscreen canvas also problematic because only Chromium supports that? https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas#browser_compatibility |
So, the ideal solution for multi-threading on web is one in which we can parallelize the Bevy scheduler parallel on web workers, but the more pressing need, in my case, is the fact that there are occasionally tasks that I need to run that cannot complete in the course of one frame, and that causes frame lags whenever I need to do them during gameplay. In my particular case I couldn't parse an OGG fast enough to prevent lags in the browser. In order to solve this particular problem, we don't need fully parallelized scheduler, we just need a blocking work pool. I think I can reasonably get a setup where you can spawn functions on a web worker pool as long as they have the signature The question is, would such a middle-ground be useful for Bevy? I can work it into my game without having to include it in Bevy, but I wanted to check whether or not that sounds like something we should try to include in Bevy. Conceptually it's pretty much similar to the Also, in my case I need to use the pool inside of an asset loader implementation because that is where I parse the OGG files, so having it as a Bevy resource might not be suitable for that use case: it might need to be a lazy static or a once_cell or something. Maybe we should create a separate issue to discuss this, but I figured I'd post here first because it's relevant to web support. |
This seems closely related to the async user story (see #1393), which we need to solve a bit more cleanly for users regardless of their platform. |
Note that Workers are quite heavyweight, and most things must be done on the main thread and thus cannot be parallelized. And the cost of synchronization can also be quite heavy, so in many cases single threaded code will be faster. In addition, threading in wasm-bindgen is extremely experimental, so you definitely should not be building anything on top of it right now. So I think it would be best to focus on making single threaded work, and add in multi-threading later. And even after multi-threading is enabled, there should still be a single threaded mode. If you use Also note that wasm-bindgen-futures is the officially supported way to spawn Futures on Wasm (using |
Btw I've been going through The goal here is to provide a drop in replacement for the single-threaded task pool used by WASM currently (which itself is a drop in replacement for the regular task pool.) How this works is it creates a pool of web workers which each share both the compiled module code and memory space with the main thread application. Assigning work requires obtaining a stack pointer for the desired work item (ie. a function) and setting the stack pointer for the instance of the application running on a given worker. The worker then runs the code to completion and returns itself to the worker pool. This should be very low overhead and quite fast. Actually putting it all together is where I'm at now and it's a struggle since I don't know any aspect of this very well. Once you understand what's happening it's less mad-sciencey than it sounds so I would encourage anyone with some experience with Bevy's task pool to take a look at the code. |
It's somewhat related it seems, but at the same time, in my exact use-case, I need to find a way to run blocking code in the That said, I haven't fully understood how the async systems in #1393 work yet.
Yes, the use-case I have right now I'm not trying to use workers to speed up the game but avoid blocking the main loop when doing compute-heavy tasks that can't complete in 1/60th of a second. Even if it were just a single extra worker I could send blocking, CPU-bound tasks to, that would be enough.
Yes, I would be avoiding WASM threading and just using normal Workers and
Bevy actually already uses
That sounds cool. :) That does require the experimental browser features, though, so I feel like there's still a need for a simple blocking work pool. I just don't know if there's a super great place in Bevy to put it, and it feels a little bit like a hack-ish workaround that's only needed if you are targeting web. I'm thinking that I'll just put my blocking work pool inside of my game/library for now and then if it seems like it could be useful for Bevy I could copy it into Bevy after I use it and see what it feels like. |
Do note:
|
It is possible to run Bevy Apps on the web ;) |
@alice-i-cecile I'm not sure this issue should be closed until Bevy's web support is as first class as our support for desktop. As it stands there are myriad issue that a user will encounter trying to run a bevy app on wasm, varying with required features like audio and logging. Most importantly, I don't think the current single-threaded 'make sure not to block the main thread'/AsyncTasks don't run on a separate thread, current level of support warrants the closing of this issue. |
Those are absolutely valid issues, but they can be addressed more conveniently in dedicated issue threads. To me, large threads such as this are for "feature MVP": web apps do work with Bevy now, just with some caveats. |
I agree with @alice-i-cecile. Better to have issues for specific problems at this point. |
I see your point, and am now in agreement with closing this issue. In discussing this on discord https://discord.com/channels/691052431525675048/692572690833473578/955299725123407872 @alice-i-cecile suggested that scoped issues regarding bevy's concrete web issue be organized into a project board. I think her proposal is a much better solution than a tracking issue, and have raised an issue about this here #4282. Alice also proposed that broader web platform UX issues that are not well-focused specific issues or are longer term - for example those that are waiting on the maturation of aspects of the web platform like WebGPU - are better handled in a discussion. I created a discussion for this here #4279, and will be migrating the insights from the still relevant comments on this issue to the new discussion so that we do not lose them. |
This reverts commit 4a87dde.
Added `on_enter`, `on_update` and `on_exit` methods to `System(Set)Config`
It should be possible to run Bevy Apps on the web
The text was updated successfully, but these errors were encountered: