FyroxEngine / Fyrox

3D and 2D game engine written in Rust
https://fyrox.rs
MIT License
7.64k stars 343 forks source link

wasm error with condvar mutex #404

Closed GOVYANSONG closed 1 year ago

GOVYANSONG commented 1 year ago

I was able to run my game in editor and wasm_pack generated the wasm file without any issue. but when i run it in browser e.g. Chrome, it threw following errors:

panicked at 'condvar wait not supported', library/std/src/sys/wasm/../unsupported/locks/condvar.rs:21:9

panicked at 'assertion failed: (left == right) left: true, right: false: cannot recursively acquire mutex', library/std/src/sys/wasm/../unsupported/locks/mutex.rs:24:9

GOVYANSONG commented 1 year ago

more info: futures::executor::block_on vs. wasm_bindgen_futures::spawn_local. mainly used by sceneloader and various request methods in resourcemanager.

block_on allows return value. how to achieve the same with spawn_local/task?

invokermain commented 1 year ago

I'm running into the same thing, I'm guessing it's something that might be fixed by this bit in the wasm example? https://github.com/invokermain/Fyrox/blob/master/examples/wasm/src/lib.rs#L302

GOVYANSONG commented 1 year ago

I have been experimenting with various approaches. following is a working code snippet with tokio. I will run the real game and report further progress:

Updated to show nested async/await call chain: tokio runtime -> handle spawn blocking -> to_say() -> say_hello()

tokio = {version = "1.21.2", features=["rt"]}

[wasm_bindgen]

pub fn main_js() { set_once();

let rt = tokio::runtime::Builder::new_current_thread()
    .enable_all()
    .build()
    .unwrap();

rt.block_on(
   async {
        let handle = tokio::runtime::Handle::current();
        let res = handle.spawn(
            say_hello() 
        ).await.unwrap();
        Log::warn(format!("say_hello : {:?}", res));

        let handle = tokio::runtime::Handle::current();
        let res = handle.spawn(
            to_say() 
        ).await.unwrap();
        Log::warn(format!("to_say : {:?}", res));
    /*
                let mut executor = Executor::new();
        executor.add_plugin_constructor(GameConstructor);
        executor.run();
     */

    }
);

}

async fn say_hello() -> u8 { println!("Hello, world!"); 100 }

async fn to_say() -> u8 { println!("To say!"); say_hello().await + 100 }

GOVYANSONG commented 1 year ago

Update: SceneLoader::from_file() caused panic with the original error.

mrDIMAS commented 1 year ago

So, the issue is that executor is using block_on method on every platform. It should use fyrox::core::wasm_bindgen_futures::spawn_local() instead and wait until the scene is loaded in the main loop. It should be relatively easy to fix. Shame on me: I didn't test executor to run on WASM.

mrDIMAS commented 1 year ago

I'll try to fix that today.

mrDIMAS commented 1 year ago

So first steps to fix the issue were made. New AsyncSceneLoader works fine with WebAssembly, now it is time to improve fyrox-template - it needs a separate executor-wasm project for WebAssembly. executor itself cannot be modified (at least I don't see how to do it), because WebAssembly requires very specific project structure:

I hope I can add this today, this is interesting task and I'm eager to see some of my games (this one https://github.com/mrDIMAS/FishFolly specifically) working on WebAssembly targets.

GOVYANSONG commented 1 year ago

@mrDIMAS , thanks for the quick turnaround and awesome effort. what is the general approach to replace block_on with spawn_local?

mrDIMAS commented 1 year ago

The idea is to remove any platform-specific code from user code. WebAssembly does not support std::thread (at least on wasm32-unknown-unknown target) and it is only possible to spawn a background task with some custom actions. So AsyncSceneLoader is that cross-platform solution - internally it "off-threads" scene loading as a background task and provides fetch_result method that can be used to obtain actual loading result (when it is ready).

mrDIMAS commented 1 year ago

fyrox-template is now updated and generates executor-wasm crate alongside the executor. executor-wasm contains readme with build instructions. All you need to do is to re-generate project with the fyrox-template and follow build instructions in the readme. Also make sure to follow this guide https://fyrox-book.github.io/fyrox/beginning/scripting.html#using-latest-engine-version when trying to use the latest changes.

mrDIMAS commented 1 year ago

This is what I have after building executor-wasm and running it in Firefox: изображение

invokermain commented 1 year ago

I've updated my learning project to use the wasm changes above. It now tries to load!

But it doesn't run 100%, I just get a black screen and the following error messages in the console: image

My code doesn't do anything fancy, so I wonder if there is another wasm incompatibility within the library? My guess is something withing my scene that is failing to load?

Also in case it is of note, using the new generated wasm executor file I get quite a few errors/warnings from vscode (although it compiles just fine):

1

image

2

image

3

image

GOVYANSONG commented 1 year ago

Try to copy the rgs file from data folder (at root of project) to under executor-wasm e.g. executor-wasm/data/scene.rgs. this is in cargo.toml: fyrox = { git = "https://github.com/FyroxEngine/Fyrox", rev="23d81ed" }

invokermain commented 1 year ago

Try to copy the rgs file from data folder (at root of project) to under executor-wasm e.g. executor-wasm/data/scene.rgs. this is in cargo.toml: fyrox = { git = "https://github.com/FyroxEngine/Fyrox", rev="23d81ed" }

It's not that unfortunately, data is in there (the unable to load scene error is: [ERROR]: Unable to load data/scene.rgs override scene! Reason: NotSupportedFormat), I have just .gitignored it to not duplicate the assets in the repo, and Fyrox is up to date with latest as well.

GOVYANSONG commented 1 year ago

Update:

I have modified code to use the new async scene loader. it worked fine inside both editor and executor. but in browser, fetch_result never returned the scene from model file. At least, i can see a black screen in browser window now.

Update

for running with editor and executor, in the log output, there was warning about player.default and player.clone. for browser wasm, there was a panic: panicked at 'Attempt to borrow object using dangling handle [Idx: 0; Gen: 0]. Record has 1 generation!', /home/mk8s/.cargo/git/checkouts/fyrox-3b28ccbadb9683b5/23d81ed/fyrox-core/src/pool.rs:690:17 . For both browser and native linux, there are complaints about unable to load options file (not found) among others.

Update

I think that i narrowed down the issue with black screen. I modified the sample code with seemingly equivalent logic of my own:

fyrox sample code:

if let Some(loader) = self.loader.as_ref() { if let Some(result) = loader.fetch_result() {

my own code:

let loader = self.loader.as_ref(); if loader.is_none() {return;}

    let result = loader.unwrap().fetch_result();
    if result.is_none() {return;}

fyrox sample code correctly loaded and rendered the scene. my own logic failed with error and a black screen;

[INFO]: Shader RectangleShader linked successfully!

web.js:1412 Uncaught (in promise) Error: Using exceptions for control flow, don't mind me. This isn't actually an error! at imports.wbg.wbindgen_throw (web.js:1412:15) at web_bg.wasm:0x46700e at web_bg.wasm:0x45f2db at web_bg.wasm:0x3314bd at web_bg.wasm:0x45c167 at main_js (web.js:236:10) at HTMLButtonElement.run (main.js:17:28) imports.wbg.wbindgen_throw @ web.js:1412 $func9053 @ web_bg.wasm:0x46700e $func7686 @ web_bg.wasm:0x45f2db $func2311 @ web_bg.wasm:0x3314bd $main_js @ web_bg.wasm:0x45c167 main_js @ web.js:236 run @ main.js:17 web.js:354 [INFO]: Starting resolve...

mrDIMAS commented 1 year ago

It turns out that there's a handful of block_ons left in the engine code. I'll try to fix that today.

mrDIMAS commented 1 year ago

The issue should be fixed, I got @invokermain 's project running in both Firefox and Chrome: изображение

mrDIMAS commented 1 year ago

@GOVYANSONG looks like you're trying to get a reference to a non-loaded scene by a null-handle.

mrDIMAS commented 1 year ago

WebAssembly is kinda annoying, the fact that you cannot block to execute a future is sad. However, there's one good thing about this - having non-blocking code will make your app much better from user perspective. You can draw a progress bar, or some other stuff while game's assets are loading.

mrDIMAS commented 1 year ago

@invokermain If you have any improvements to executor-wasm template, please make a PR 🙏

GOVYANSONG commented 1 year ago

Finally, i was able to get scene and model all loaded and rendered in browser. cheers to all. but now, I cannot exit the game by setting *control_flow = ControlFlow::Exit in update method of plugin trait of game. Any thought? what is the expected behavior for browser?

GOVYANSONG commented 1 year ago

original issue is resolved