Skip to content

Commit 3d628a8

Browse files
authored
Fix Reactive and ReactiveLowPower update modes (#11325)
# Objective - Partial fix for #11235 - Fixes #11274 - Fixes #11320 - Fixes #11273 ## Solution - check update mode to trigger redraw request, instead of once a redraw request has been triggered - don't ignore device event in case of `Reactive` update mode - make sure that at least 5 updates are triggered on application start to ensure everything is correctly initialized - trigger manual updates instead of relying on redraw requests when there are no window or they are not visible
1 parent 01139b3 commit 3d628a8

File tree

1 file changed

+76
-34
lines changed

1 file changed

+76
-34
lines changed

crates/bevy_winit/src/lib.rs

Lines changed: 76 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,8 @@ struct WinitAppRunnerState {
254254
active: ActiveState,
255255
/// Is `true` if a new [`WindowEvent`] has been received since the last update.
256256
window_event_received: bool,
257+
/// Is `true` if a new [`DeviceEvent`] has been received since the last update.
258+
device_event_received: bool,
257259
/// Is `true` if the app has requested a redraw since the last update.
258260
redraw_requested: bool,
259261
/// Is `true` if enough time has elapsed since `last_update` to run another update.
@@ -262,6 +264,17 @@ struct WinitAppRunnerState {
262264
last_update: Instant,
263265
/// The time the next update is scheduled to start.
264266
scheduled_update: Option<Instant>,
267+
/// Number of "forced" updates to trigger on application start
268+
startup_forced_updates: u32,
269+
}
270+
271+
impl WinitAppRunnerState {
272+
fn reset_on_update(&mut self) {
273+
self.redraw_requested = false;
274+
self.window_event_received = false;
275+
self.device_event_received = false;
276+
self.wait_elapsed = false;
277+
}
265278
}
266279

267280
#[derive(PartialEq, Eq)]
@@ -287,10 +300,13 @@ impl Default for WinitAppRunnerState {
287300
Self {
288301
active: ActiveState::NotYetStarted,
289302
window_event_received: false,
303+
device_event_received: false,
290304
redraw_requested: false,
291305
wait_elapsed: false,
292306
last_update: Instant::now(),
293307
scheduled_update: None,
308+
// 3 seems to be enough, 5 is a safe margin
309+
startup_forced_updates: 5,
294310
}
295311
}
296312
}
@@ -364,14 +380,56 @@ pub fn winit_runner(mut app: App) {
364380

365381
match event {
366382
Event::AboutToWait => {
367-
if runner_state.redraw_requested {
383+
let (config, windows) = focused_windows_state.get(&app.world);
384+
let focused = windows.iter().any(|window| window.focused);
385+
let mut should_update = match config.update_mode(focused) {
386+
UpdateMode::Continuous => {
387+
runner_state.redraw_requested
388+
|| runner_state.window_event_received
389+
|| runner_state.device_event_received
390+
}
391+
UpdateMode::Reactive { .. } => {
392+
runner_state.wait_elapsed
393+
|| runner_state.redraw_requested
394+
|| runner_state.window_event_received
395+
|| runner_state.device_event_received
396+
}
397+
UpdateMode::ReactiveLowPower { .. } => {
398+
runner_state.wait_elapsed
399+
|| runner_state.redraw_requested
400+
|| runner_state.window_event_received
401+
}
402+
};
403+
404+
// Ensure that an update is triggered on the first iterations for app initialization
405+
if runner_state.startup_forced_updates > 0 {
406+
runner_state.startup_forced_updates -= 1;
407+
should_update = true;
408+
}
409+
410+
if should_update {
411+
let visible = windows.iter().any(|window| window.visible);
368412
let (_, winit_windows, _, _) =
369413
event_writer_system_state.get_mut(&mut app.world);
370-
for window in winit_windows.windows.values() {
371-
window.request_redraw();
414+
if visible {
415+
for window in winit_windows.windows.values() {
416+
window.request_redraw();
417+
}
418+
} else {
419+
// there are no windows, or they are not visible.
420+
// Winit won't send events on some platforms, so trigger an update manually.
421+
run_app_update_if_should(
422+
&mut runner_state,
423+
&mut app,
424+
&mut focused_windows_state,
425+
event_loop,
426+
&mut create_window_system_state,
427+
&mut app_exit_event_reader,
428+
&mut redraw_event_reader,
429+
);
430+
event_loop.set_control_flow(ControlFlow::Poll);
372431
}
373432
}
374-
runner_state.redraw_requested = false;
375433
}
376434
Event::NewEvents(_) => {
377435
if let Some(t) = runner_state.scheduled_update {
@@ -638,7 +696,6 @@ pub fn winit_runner(mut app: App) {
638696
});
639697
}
640698
WindowEvent::RedrawRequested => {
641-
runner_state.redraw_requested = false;
642699
run_app_update_if_should(
643700
&mut runner_state,
644701
&mut app,
@@ -659,14 +716,14 @@ pub fn winit_runner(mut app: App) {
659716
}
660717
}
661718
}
662-
Event::DeviceEvent {
663-
event: DeviceEvent::MouseMotion { delta: (x, y) },
664-
..
665-
} => {
666-
let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world);
667-
event_writers.mouse_motion.send(MouseMotion {
668-
delta: Vec2::new(x as f32, y as f32),
669-
});
719+
Event::DeviceEvent { event, .. } => {
720+
runner_state.device_event_received = true;
721+
if let DeviceEvent::MouseMotion { delta: (x, y) } = event {
722+
let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world);
723+
event_writers.mouse_motion.send(MouseMotion {
724+
delta: Vec2::new(x as f32, y as f32),
725+
});
726+
}
670727
}
671728
Event::Suspended => {
672729
let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world);
@@ -700,7 +757,7 @@ pub fn winit_runner(mut app: App) {
700757
) = create_window_system_state.get_mut(&mut app.world);
701758

702759
create_windows(
703-
&event_loop,
760+
event_loop,
704761
commands,
705762
windows.iter_mut(),
706763
event_writer,
@@ -793,6 +850,8 @@ fn run_app_update_if_should(
793850
app_exit_event_reader: &mut ManualEventReader<AppExit>,
794851
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
795852
) {
853+
runner_state.reset_on_update();
854+
796855
if !runner_state.active.should_run() {
797856
return;
798857
}
@@ -808,32 +867,15 @@ fn run_app_update_if_should(
808867
event_loop.set_control_flow(ControlFlow::Wait);
809868
}
810869
}
811-
let (config, windows) = focused_windows_state.get(&app.world);
812-
let focused = windows.iter().any(|window| window.focused);
813-
let should_update = match config.update_mode(focused) {
814-
// `Reactive`: In order for `event_handler` to have been called, either
815-
// we received a window or raw input event, the `wait` elapsed, or a
816-
// redraw was requested (by the app or the OS). There are no other
817-
// conditions, so we can just return `true` here.
818-
UpdateMode::Continuous | UpdateMode::Reactive { .. } => true,
819-
// TODO(bug): This is currently always true since we only run this function
820-
// if we received a `RequestRedraw` event.
821-
UpdateMode::ReactiveLowPower { .. } => {
822-
runner_state.wait_elapsed
823-
|| runner_state.redraw_requested
824-
|| runner_state.window_event_received
825-
}
826-
};
827870

828-
if app.plugins_state() == PluginsState::Cleaned && should_update {
829-
// reset these on each update
830-
runner_state.wait_elapsed = false;
871+
if app.plugins_state() == PluginsState::Cleaned {
831872
runner_state.last_update = Instant::now();
832873

833874
app.update();
834875

835876
// decide when to run the next update
836-
let (config, _) = focused_windows_state.get(&app.world);
877+
let (config, windows) = focused_windows_state.get(&app.world);
878+
let focused = windows.iter().any(|window| window.focused);
837879
match config.update_mode(focused) {
838880
UpdateMode::Continuous => {
839881
runner_state.redraw_requested = true;

0 commit comments

Comments
 (0)