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
This commit is contained in:
		
							parent
							
								
									01139b3472
								
							
						
					
					
						commit
						3d628a8191
					
				| @ -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.
 | ||||
| @ -262,6 +264,17 @@ struct WinitAppRunnerState { | ||||
|     last_update: Instant, | ||||
|     /// The time the next update is scheduled to start.
 | ||||
|     scheduled_update: Option<Instant>, | ||||
|     /// Number of "forced" updates to trigger on application start
 | ||||
|     startup_forced_updates: u32, | ||||
| } | ||||
| 
 | ||||
| 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)] | ||||
| @ -287,10 +300,13 @@ 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(), | ||||
|             scheduled_update: None, | ||||
|             // 3 seems to be enough, 5 is a safe margin
 | ||||
|             startup_forced_updates: 5, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -364,14 +380,56 @@ 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 mut 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 | ||||
|                     } | ||||
|                 }; | ||||
| 
 | ||||
|                 // 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; | ||||
|                 } | ||||
| 
 | ||||
|                 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); | ||||
|                     } | ||||
|                 } | ||||
|                 runner_state.redraw_requested = false; | ||||
|             } | ||||
|             Event::NewEvents(_) => { | ||||
|                 if let Some(t) = runner_state.scheduled_update { | ||||
| @ -638,7 +696,6 @@ pub fn winit_runner(mut app: App) { | ||||
|                         }); | ||||
|                     } | ||||
|                     WindowEvent::RedrawRequested => { | ||||
|                         runner_state.redraw_requested = false; | ||||
|                         run_app_update_if_should( | ||||
|                             &mut runner_state, | ||||
|                             &mut app, | ||||
| @ -659,14 +716,14 @@ 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; | ||||
|                 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 => { | ||||
|                 let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world); | ||||
| @ -700,7 +757,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, | ||||
| @ -793,6 +850,8 @@ fn run_app_update_if_should( | ||||
|     app_exit_event_reader: &mut ManualEventReader<AppExit>, | ||||
|     redraw_event_reader: &mut ManualEventReader<RequestRedraw>, | ||||
| ) { | ||||
|     runner_state.reset_on_update(); | ||||
| 
 | ||||
|     if !runner_state.active.should_run() { | ||||
|         return; | ||||
|     } | ||||
| @ -808,32 +867,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; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 François
						François