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, |     active: ActiveState, | ||||||
|     /// Is `true` if a new [`WindowEvent`] has been received since the last update.
 |     /// Is `true` if a new [`WindowEvent`] has been received since the last update.
 | ||||||
|     window_event_received: bool, |     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.
 |     /// Is `true` if the app has requested a redraw since the last update.
 | ||||||
|     redraw_requested: bool, |     redraw_requested: bool, | ||||||
|     /// Is `true` if enough time has elapsed since `last_update` to run another update.
 |     /// Is `true` if enough time has elapsed since `last_update` to run another update.
 | ||||||
| @ -262,6 +264,17 @@ struct WinitAppRunnerState { | |||||||
|     last_update: Instant, |     last_update: Instant, | ||||||
|     /// The time the next update is scheduled to start.
 |     /// The time the next update is scheduled to start.
 | ||||||
|     scheduled_update: Option<Instant>, |     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)] | #[derive(PartialEq, Eq)] | ||||||
| @ -287,10 +300,13 @@ impl Default for WinitAppRunnerState { | |||||||
|         Self { |         Self { | ||||||
|             active: ActiveState::NotYetStarted, |             active: ActiveState::NotYetStarted, | ||||||
|             window_event_received: false, |             window_event_received: false, | ||||||
|  |             device_event_received: false, | ||||||
|             redraw_requested: false, |             redraw_requested: false, | ||||||
|             wait_elapsed: false, |             wait_elapsed: false, | ||||||
|             last_update: Instant::now(), |             last_update: Instant::now(), | ||||||
|             scheduled_update: None, |             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 { |         match event { | ||||||
|             Event::AboutToWait => { |             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, _, _) = |                     let (_, winit_windows, _, _) = | ||||||
|                         event_writer_system_state.get_mut(&mut app.world); |                         event_writer_system_state.get_mut(&mut app.world); | ||||||
|                     for window in winit_windows.windows.values() { |                     if visible { | ||||||
|                         window.request_redraw(); |                         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(_) => { |             Event::NewEvents(_) => { | ||||||
|                 if let Some(t) = runner_state.scheduled_update { |                 if let Some(t) = runner_state.scheduled_update { | ||||||
| @ -638,7 +696,6 @@ pub fn winit_runner(mut app: App) { | |||||||
|                         }); |                         }); | ||||||
|                     } |                     } | ||||||
|                     WindowEvent::RedrawRequested => { |                     WindowEvent::RedrawRequested => { | ||||||
|                         runner_state.redraw_requested = false; |  | ||||||
|                         run_app_update_if_should( |                         run_app_update_if_should( | ||||||
|                             &mut runner_state, |                             &mut runner_state, | ||||||
|                             &mut app, |                             &mut app, | ||||||
| @ -659,14 +716,14 @@ pub fn winit_runner(mut app: App) { | |||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             Event::DeviceEvent { |             Event::DeviceEvent { event, .. } => { | ||||||
|                 event: DeviceEvent::MouseMotion { delta: (x, y) }, |                 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); | ||||||
|                 let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world); |                     event_writers.mouse_motion.send(MouseMotion { | ||||||
|                 event_writers.mouse_motion.send(MouseMotion { |                         delta: Vec2::new(x as f32, y as f32), | ||||||
|                     delta: Vec2::new(x as f32, y as f32), |                     }); | ||||||
|                 }); |                 } | ||||||
|             } |             } | ||||||
|             Event::Suspended => { |             Event::Suspended => { | ||||||
|                 let (mut event_writers, ..) = event_writer_system_state.get_mut(&mut app.world); |                 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_window_system_state.get_mut(&mut app.world); | ||||||
| 
 | 
 | ||||||
|                         create_windows( |                         create_windows( | ||||||
|                             &event_loop, |                             event_loop, | ||||||
|                             commands, |                             commands, | ||||||
|                             windows.iter_mut(), |                             windows.iter_mut(), | ||||||
|                             event_writer, |                             event_writer, | ||||||
| @ -793,6 +850,8 @@ fn run_app_update_if_should( | |||||||
|     app_exit_event_reader: &mut ManualEventReader<AppExit>, |     app_exit_event_reader: &mut ManualEventReader<AppExit>, | ||||||
|     redraw_event_reader: &mut ManualEventReader<RequestRedraw>, |     redraw_event_reader: &mut ManualEventReader<RequestRedraw>, | ||||||
| ) { | ) { | ||||||
|  |     runner_state.reset_on_update(); | ||||||
|  | 
 | ||||||
|     if !runner_state.active.should_run() { |     if !runner_state.active.should_run() { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| @ -808,32 +867,15 @@ fn run_app_update_if_should( | |||||||
|             event_loop.set_control_flow(ControlFlow::Wait); |             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 { |     if app.plugins_state() == PluginsState::Cleaned { | ||||||
|         // reset these on each update
 |  | ||||||
|         runner_state.wait_elapsed = false; |  | ||||||
|         runner_state.last_update = Instant::now(); |         runner_state.last_update = Instant::now(); | ||||||
| 
 | 
 | ||||||
|         app.update(); |         app.update(); | ||||||
| 
 | 
 | ||||||
|         // decide when to run the next 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) { |         match config.update_mode(focused) { | ||||||
|             UpdateMode::Continuous => { |             UpdateMode::Continuous => { | ||||||
|                 runner_state.redraw_requested = true; |                 runner_state.redraw_requested = true; | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user
	 François
						François