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

Windowing chapter won’t work on some platforms #532

Open
JoeOsborn opened this issue Feb 7, 2024 · 4 comments
Open

Windowing chapter won’t work on some platforms #532

JoeOsborn opened this issue Feb 7, 2024 · 4 comments

Comments

@JoeOsborn
Copy link

JoeOsborn commented Feb 7, 2024

According to winit’s developers, it’s not permitted to create a surface on many platforms (Mac and android for example) until the Event::Resumed winit event is posted. This is a bummer because it means you need a mini state machine (I like to use an enum for this) to determine what phase in the initialization life cycle you’re in and you probably need a future executed for its side effect on web which means you need a OnceCell or something :/

I solved this a couple different ways in my modular renderer:

  1. if you have an executor already you can do something like the code sample below.
  2. If you are ok driving the single initialization future with the event loop you can do something like https://github.com/JoeOsborn/frenderer/blob/071beb5e547d3de2a6a03681926ca340bf5fbb75/frenderer/src/events.rs#L137 .
  3. It's also possible to put the GPU state behind a cell and just early-exit the closure if it hasn't been initialized yet, or lazily initialize the surface behind an option
    let mut builder = Some(builder);
    let fut = async {
        let mut state = None;
        let elp = winit::event_loop::EventLoop::new().unwrap();
        let mut init: Option<State> = None;

        elp.run(move |event, target| {
            if let winit::event::Event::Resumed = event {
                if let Some(builder) = builder.take() {
                    let window = Arc::new(builder.build(target).unwrap());
                    // maybe add canvas to window
                    // do state init and use .await freely in here
                    state = Some(...initialize Wgpu state and surface...)
                }
            }
            if let Some(state) = state {
                // match on event, do regular winit lifecycle stuff
            }
        })
        .unwrap();
    };
    #[cfg(target_arch = "wasm32")]
    {
        wasm_bindgen_futures::spawn_local(fut);
    }
    #[cfg(not(target_arch = "wasm32"))]
    {
        pollster::block_on(fut);
    }

The async block could instead just cover the WGPU initialization.

@sotrh
Copy link
Owner

sotrh commented Mar 29, 2024

I'm pretty sure that you can't use .await in the run funciton as it's not async. We technically only need to async block to get the Adapter , Device and Queue, so I could split up creating state into creating a Context and creating the Display.

@JoeOsborn
Copy link
Author

Yeah, you’re totally right. I had mis-copied some code from another project. I think spawning a future on the resumed event (using wasm bindgen futures or a native executor or using the event loop itself to poll the future) which writes into a oncecell is one good option.

It’s really a pain that creating the surface must happen after the resumed event, and that sometimes creating an adapter without providing a surface causes issues too. If it weren’t for the latter you could make the adapter before entering the event loop, and lazily create the surface. But that can get you the wrong adapter sometimes.

@sotrh
Copy link
Owner

sotrh commented Mar 30, 2024

I'm going to have to circle back to this. I'm working on updating to 0.19 and they changed Surface to use the lifetime of the window. I tried use OnceCell, but the borrow checker didn't approve. Once I get the 0.19 stuff working, I'll revisit this.

@JoeOsborn
Copy link
Author

I think if your Window is an Arc, the surface gets a ‘static lifetime and is easier to work with.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants