From a4908d8ccfcecfed5c0c689707bdbdf14d375a56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 13 Jan 2024 06:34:57 +0100 Subject: [PATCH 1/5] check for update conditions outside of update --- crates/bevy_winit/src/lib.rs | 62 +++++++++++++++++++++++------------- 1 file changed, 39 insertions(+), 23 deletions(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 920f0103a2835..1a4c07cf612af 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -254,6 +254,8 @@ struct WinitAppRunnerState { active: ActiveState, /// Is `true` if a new [`WindowEvent`] has been received since the last update. window_event_received: bool, + /// Is `true` if a new [`DeviceEvent`] has been received since the last update. + device_event_received: bool, /// Is `true` if the app has requested a redraw since the last update. redraw_requested: bool, /// Is `true` if enough time has elapsed since `last_update` to run another update. @@ -264,6 +266,15 @@ struct WinitAppRunnerState { scheduled_update: Option, } +impl WinitAppRunnerState { + fn reset_on_update(&mut self) { + self.redraw_requested = false; + self.window_event_received = false; + self.device_event_received = false; + self.wait_elapsed = false; + } +} + #[derive(PartialEq, Eq)] enum ActiveState { NotYetStarted, @@ -287,6 +298,7 @@ impl Default for WinitAppRunnerState { Self { active: ActiveState::NotYetStarted, window_event_received: false, + device_event_received: false, redraw_requested: false, wait_elapsed: false, last_update: Instant::now(), @@ -364,14 +376,34 @@ pub fn winit_runner(mut app: App) { match event { Event::AboutToWait => { - if runner_state.redraw_requested { + let (config, windows) = focused_windows_state.get(&app.world); + let focused = windows.iter().any(|window| window.focused); + let should_update = match config.update_mode(focused) { + UpdateMode::Continuous => { + runner_state.redraw_requested + || runner_state.window_event_received + || runner_state.device_event_received + } + UpdateMode::Reactive { .. } => { + runner_state.wait_elapsed + || runner_state.redraw_requested + || runner_state.window_event_received + || runner_state.device_event_received + } + UpdateMode::ReactiveLowPower { .. } => { + runner_state.wait_elapsed + || runner_state.redraw_requested + || runner_state.window_event_received + } + }; + + if should_update { let (_, winit_windows, _, _) = event_writer_system_state.get_mut(&mut app.world); for window in winit_windows.windows.values() { window.request_redraw(); } } - runner_state.redraw_requested = false; } Event::NewEvents(_) => { if let Some(t) = runner_state.scheduled_update { @@ -638,7 +670,7 @@ pub fn winit_runner(mut app: App) { }); } WindowEvent::RedrawRequested => { - runner_state.redraw_requested = false; + runner_state.reset_on_update(); run_app_update_if_should( &mut runner_state, &mut app, @@ -667,6 +699,7 @@ pub fn winit_runner(mut app: App) { event_writers.mouse_motion.send(MouseMotion { delta: Vec2::new(x as f32, y as f32), }); + runner_state.device_event_received = true; } Event::Suspended => { let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world); @@ -808,32 +841,15 @@ fn run_app_update_if_should( event_loop.set_control_flow(ControlFlow::Wait); } } - let (config, windows) = focused_windows_state.get(&app.world); - let focused = windows.iter().any(|window| window.focused); - let should_update = match config.update_mode(focused) { - // `Reactive`: In order for `event_handler` to have been called, either - // we received a window or raw input event, the `wait` elapsed, or a - // redraw was requested (by the app or the OS). There are no other - // conditions, so we can just return `true` here. - UpdateMode::Continuous | UpdateMode::Reactive { .. } => true, - // TODO(bug): This is currently always true since we only run this function - // if we received a `RequestRedraw` event. - UpdateMode::ReactiveLowPower { .. } => { - runner_state.wait_elapsed - || runner_state.redraw_requested - || runner_state.window_event_received - } - }; - if app.plugins_state() == PluginsState::Cleaned && should_update { - // reset these on each update - runner_state.wait_elapsed = false; + if app.plugins_state() == PluginsState::Cleaned { runner_state.last_update = Instant::now(); app.update(); // decide when to run the next update - let (config, _) = focused_windows_state.get(&app.world); + let (config, windows) = focused_windows_state.get(&app.world); + let focused = windows.iter().any(|window| window.focused); match config.update_mode(focused) { UpdateMode::Continuous => { runner_state.redraw_requested = true; From 5235b004038155b0fb11f47e39f901b95f650f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 13 Jan 2024 06:53:19 +0100 Subject: [PATCH 2/5] don't ignore other device events --- crates/bevy_winit/src/lib.rs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 1a4c07cf612af..d2283ecf48659 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -691,15 +691,18 @@ pub fn winit_runner(mut app: App) { } } } - Event::DeviceEvent { - event: DeviceEvent::MouseMotion { delta: (x, y) }, - .. - } => { - let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world); - event_writers.mouse_motion.send(MouseMotion { - delta: Vec2::new(x as f32, y as f32), - }); + Event::DeviceEvent { event, .. } => { runner_state.device_event_received = true; + match event { + DeviceEvent::MouseMotion { delta: (x, y) } => { + let (mut event_writers, ..) = + event_writer_system_state.get_mut(&mut app.world); + event_writers.mouse_motion.send(MouseMotion { + delta: Vec2::new(x as f32, y as f32), + }); + } + _ => {} + } } Event::Suspended => { let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world); From e66a62889047482521ccec55d771e7e809a763cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 13 Jan 2024 07:01:27 +0100 Subject: [PATCH 3/5] clippy --- crates/bevy_winit/src/lib.rs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index d2283ecf48659..47c6ad2f57688 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -693,15 +693,11 @@ pub fn winit_runner(mut app: App) { } Event::DeviceEvent { event, .. } => { runner_state.device_event_received = true; - match event { - DeviceEvent::MouseMotion { delta: (x, y) } => { - let (mut event_writers, ..) = - event_writer_system_state.get_mut(&mut app.world); - event_writers.mouse_motion.send(MouseMotion { - delta: Vec2::new(x as f32, y as f32), - }); - } - _ => {} + if let DeviceEvent::MouseMotion { delta: (x, y) } = event { + let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world); + event_writers.mouse_motion.send(MouseMotion { + delta: Vec2::new(x as f32, y as f32), + }); } } Event::Suspended => { @@ -736,7 +732,7 @@ pub fn winit_runner(mut app: App) { ) = create_window_system_state.get_mut(&mut app.world); create_windows( - &event_loop, + event_loop, commands, windows.iter_mut(), event_writer, From 20cce3d11aa2f4b6f6d629c711f86f3f9935b84e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 13 Jan 2024 12:18:18 +0100 Subject: [PATCH 4/5] fixes for windows --- crates/bevy_winit/src/lib.rs | 33 +++++++++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 4 deletions(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 47c6ad2f57688..90351cad8cdb0 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -264,6 +264,8 @@ struct WinitAppRunnerState { last_update: Instant, /// The time the next update is scheduled to start. scheduled_update: Option, + /// Number of "forced" updates to trigger on application start + start_forced_updates: u32, } impl WinitAppRunnerState { @@ -303,6 +305,7 @@ impl Default for WinitAppRunnerState { wait_elapsed: false, last_update: Instant::now(), scheduled_update: None, + start_forced_updates: 5, } } } @@ -378,7 +381,7 @@ pub fn winit_runner(mut app: App) { Event::AboutToWait => { let (config, windows) = focused_windows_state.get(&app.world); let focused = windows.iter().any(|window| window.focused); - let should_update = match config.update_mode(focused) { + let mut should_update = match config.update_mode(focused) { UpdateMode::Continuous => { runner_state.redraw_requested || runner_state.window_event_received @@ -397,11 +400,32 @@ pub fn winit_runner(mut app: App) { } }; + if runner_state.start_forced_updates > 0 { + runner_state.start_forced_updates -= 1; + should_update = true; + } + if should_update { + let visible = windows.iter().any(|window| window.visible); let (_, winit_windows, _, _) = event_writer_system_state.get_mut(&mut app.world); - for window in winit_windows.windows.values() { - window.request_redraw(); + if visible { + for window in winit_windows.windows.values() { + window.request_redraw(); + } + } else { + // there are no windows, or they are not visible. + // Winit won't send events on some platforms, so trigger an update manually. + run_app_update_if_should( + &mut runner_state, + &mut app, + &mut focused_windows_state, + event_loop, + &mut create_window_system_state, + &mut app_exit_event_reader, + &mut redraw_event_reader, + ); + event_loop.set_control_flow(ControlFlow::Poll); } } } @@ -670,7 +694,6 @@ pub fn winit_runner(mut app: App) { }); } WindowEvent::RedrawRequested => { - runner_state.reset_on_update(); run_app_update_if_should( &mut runner_state, &mut app, @@ -825,6 +848,8 @@ fn run_app_update_if_should( app_exit_event_reader: &mut ManualEventReader, redraw_event_reader: &mut ManualEventReader, ) { + runner_state.reset_on_update(); + if !runner_state.active.should_run() { return; } From c243aaf012b07e6f40da4d8286844edda8b1264a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fran=C3=A7ois?= Date: Sat, 13 Jan 2024 18:17:48 +0100 Subject: [PATCH 5/5] rename and comment --- crates/bevy_winit/src/lib.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 90351cad8cdb0..d5785cb6754ee 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -265,7 +265,7 @@ struct WinitAppRunnerState { /// The time the next update is scheduled to start. scheduled_update: Option, /// Number of "forced" updates to trigger on application start - start_forced_updates: u32, + startup_forced_updates: u32, } impl WinitAppRunnerState { @@ -305,7 +305,8 @@ impl Default for WinitAppRunnerState { wait_elapsed: false, last_update: Instant::now(), scheduled_update: None, - start_forced_updates: 5, + // 3 seems to be enough, 5 is a safe margin + startup_forced_updates: 5, } } } @@ -400,8 +401,9 @@ pub fn winit_runner(mut app: App) { } }; - if runner_state.start_forced_updates > 0 { - runner_state.start_forced_updates -= 1; + // Ensure that an update is triggered on the first iterations for app initialization + if runner_state.startup_forced_updates > 0 { + runner_state.startup_forced_updates -= 1; should_update = true; }