gfx-rs / wgpu

A cross-platform, safe, pure-Rust graphics API.
https://wgpu.rs
Apache License 2.0
12.41k stars 909 forks source link

Switching to winit 0.30 failed on macOS because of create_surface #5722

Open Alphapage opened 5 months ago

Alphapage commented 5 months ago

Hello,

I am trying to upgrade to win 0.30 without success:

use std::sync::Arc;

use winit::application::ApplicationHandler;
use winit::event::WindowEvent;
use winit::event_loop::{ActiveEventLoop, ControlFlow, EventLoop};
use winit::window::{Window, WindowId};

#[derive(Default)]
struct App {
    window: Option<Arc<Window>>,
}

impl ApplicationHandler for App {
    fn resumed(&mut self, event_loop: &ActiveEventLoop) {
        let window_attributes = Window::default_attributes()
            .with_title("&self.title")
            .with_inner_size(winit::dpi::LogicalSize::new(800, 600));
        self.window = Some(Arc::new(
            event_loop.create_window(window_attributes).unwrap(),
        ));

        let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::default());
        let surface = instance
            .create_surface(self.window.clone().unwrap())
            .unwrap(); // comment this line to watch the println
    }

    fn window_event(&mut self, event_loop: &ActiveEventLoop, id: WindowId, event: WindowEvent) {
        match event {
            WindowEvent::CloseRequested => {
                println!("The close button was pressed; stopping");
                event_loop.exit();
            }
            WindowEvent::RedrawRequested => {
                // Redraw the application.
                //
                // It's preferable for applications that do not render continuously to render in
                // this event rather than in AboutToWait, since rendering in here allows
                // the program to gracefully handle redraws requested by the OS.

                // Draw.
                println!("drawing");
                // Queue a RedrawRequested event.
                //
                // You only need to call this if you've determined that you need to redraw in
                // applications which do not always need to. Applications that redraw continuously
                // can render here instead.
                self.window.as_ref().unwrap().request_redraw();
            }
            _ => (),
        }
    }
}

fn main() {
    fn run_app() {
        let event_loop = EventLoop::new().unwrap();

        // ControlFlow::Poll continuously runs the event loop, even if the OS hasn't
        // dispatched any events. This is ideal for games and similar applications.
        event_loop.set_control_flow(ControlFlow::Poll);

        // ControlFlow::Wait pauses the event loop if no events are available to process.
        // This is ideal for non-game applications that only update in response to user
        // input, and uses significantly less power/CPU time than ControlFlow::Poll.
        event_loop.set_control_flow(ControlFlow::Wait);

        let mut app = App::default();
        event_loop.run_app(&mut app);
    }

    run_app();
}

If you comment the create_surface, then RedrawRequested is raised as expected.

Am I doing something wrong with this Arc ?

Thank you in advance for your help.

ErichDonGubler commented 4 months ago

Initial triage: I can reproduce this on my M1 Macbook. The workaround is pretty easy, AFAICT: just request a redraw, even before the create_surface call:

diff --git a/src/main.rs b/src/main.rs
index a260b1e..5dcfeaa 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -15,9 +15,9 @@ impl ApplicationHandler for App {
         let window_attributes = Window::default_attributes()
             .with_title("&self.title")
             .with_inner_size(winit::dpi::LogicalSize::new(800, 600));
-        self.window = Some(Arc::new(
-            event_loop.create_window(window_attributes).unwrap(),
-        ));
+        let window = Arc::new(event_loop.create_window(window_attributes).unwrap());
+        window.request_redraw();
+        self.window = Some(window);

         let instance = wgpu::Instance::new(wgpu::InstanceDescriptor::default());
         let surface = instance

This is an interesting intersection-of-platforms question, though. I don't see any explicit guarantees on the winit end that a redraw request event will be emitted after its initial creation in winit 0.30.0 docs. However, it seems obvious that most upstream examples (i.e., OP's example from root module docs., pump_events, control_flow) actually depend on this behavior to work correctly.

I don't have the time to work out why an event's delivery to the winit::App::window_event callback in this case, but perhaps this is a bug on our end?

Alphapage commented 4 months ago

Nice work around to solve the problem +1 Maybe if it is the correct behaviour, hello_world example should be updated quickly I think. Thank you very much @ErichDonGubler

Wumpf commented 4 months ago

Switch to winit 0.30 is inprogress over here