
# Objective - Upgrade winit to v0.30 - Fixes https://github.com/bevyengine/bevy/issues/13331 ## Solution This is a rewrite/adaptation of the new trait system described and implemented in `winit` v0.30. ## Migration Guide The custom UserEvent is now renamed as WakeUp, used to wake up the loop if anything happens outside the app (a new [custom_user_event](https://github.com/bevyengine/bevy/pull/13366/files#diff-2de8c0a8d3028d0059a3d80ae31b2bbc1cde2595ce2d317ea378fe3e0cf6ef2d) shows this behavior. The internal `UpdateState` has been removed and replaced internally by the AppLifecycle. When changed, the AppLifecycle is sent as an event. The `UpdateMode` now accepts only two values: `Continuous` and `Reactive`, but the latter exposes 3 new properties to enable reactive to device, user or window events. The previous `UpdateMode::Reactive` is now equivalent to `UpdateMode::reactive()`, while `UpdateMode::ReactiveLowPower` to `UpdateMode::reactive_low_power()`. The `ApplicationLifecycle` has been renamed as `AppLifecycle`, and now contains the possible values of the application state inside the event loop: * `Idle`: the loop has not started yet * `Running` (previously called `Started`): the loop is running * `WillSuspend`: the loop is going to be suspended * `Suspended`: the loop is suspended * `WillResume`: the loop is going to be resumed Note: the `Resumed` state has been removed since the resumed app is just running. Finally, now that `winit` enables this, it extends the `WinitPlugin` to support custom events. ## Test platforms - [x] Windows - [x] MacOs - [x] Linux (x11) - [x] Linux (Wayland) - [x] Android - [x] iOS - [x] WASM/WebGPU - [x] WASM/WebGL2 ## Outstanding issues / regressions - [ ] iOS: build failed in CI - blocking, but may just be flakiness - [x] Cross-platform: when the window is maximised, changes in the scale factor don't apply, to make them apply one has to make the window smaller again. (Re-maximising keeps the updated scale factor) - non-blocking, but good to fix - [ ] Android: it's pretty easy to quickly open and close the app and then the music keeps playing when suspended. - non-blocking but worrying - [ ] Web: the application will hang when switching tabs - Not new, duplicate of https://github.com/bevyengine/bevy/issues/13486 - [ ] Cross-platform?: Screenshot failure, `ERROR present_frames: wgpu_core::present: No work has been submitted for this frame before` taking the first screenshot, but after pressing space - non-blocking, but good to fix --------- Co-authored-by: François <francois.mockers@vleue.com>
113 lines
4.4 KiB
Rust
113 lines
4.4 KiB
Rust
use bevy_ecs::system::Resource;
|
|
use bevy_utils::Duration;
|
|
|
|
/// Settings for the [`WinitPlugin`](super::WinitPlugin).
|
|
#[derive(Debug, Resource, Clone)]
|
|
pub struct WinitSettings {
|
|
/// Determines how frequently the application can update when it has focus.
|
|
pub focused_mode: UpdateMode,
|
|
/// Determines how frequently the application can update when it's out of focus.
|
|
pub unfocused_mode: UpdateMode,
|
|
}
|
|
|
|
impl WinitSettings {
|
|
/// Default settings for games.
|
|
///
|
|
/// [`Continuous`](UpdateMode::Continuous) if windows have focus,
|
|
/// [`ReactiveLowPower`](UpdateMode::ReactiveLowPower) otherwise.
|
|
pub fn game() -> Self {
|
|
WinitSettings {
|
|
focused_mode: UpdateMode::Continuous,
|
|
unfocused_mode: UpdateMode::reactive_low_power(Duration::from_secs_f64(1.0 / 60.0)), // 60Hz,
|
|
}
|
|
}
|
|
|
|
/// Default settings for desktop applications.
|
|
///
|
|
/// [`Reactive`](UpdateMode::Reactive) if windows have focus,
|
|
/// [`ReactiveLowPower`](UpdateMode::ReactiveLowPower) otherwise.
|
|
///
|
|
/// Use the [`EventLoopProxy`](crate::EventLoopProxy) to request a redraw from outside bevy.
|
|
pub fn desktop_app() -> Self {
|
|
WinitSettings {
|
|
focused_mode: UpdateMode::reactive(Duration::from_secs(5)),
|
|
unfocused_mode: UpdateMode::reactive_low_power(Duration::from_secs(60)),
|
|
}
|
|
}
|
|
|
|
/// Returns the current [`UpdateMode`].
|
|
///
|
|
/// **Note:** The output depends on whether the window has focus or not.
|
|
pub fn update_mode(&self, focused: bool) -> UpdateMode {
|
|
match focused {
|
|
true => self.focused_mode,
|
|
false => self.unfocused_mode,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl Default for WinitSettings {
|
|
fn default() -> Self {
|
|
WinitSettings::game()
|
|
}
|
|
}
|
|
|
|
/// Determines how frequently an [`App`](bevy_app::App) should update.
|
|
///
|
|
/// **Note:** This setting is independent of VSync. VSync is controlled by a window's
|
|
/// [`PresentMode`](bevy_window::PresentMode) setting. If an app can update faster than the refresh
|
|
/// rate, but VSync is enabled, the update rate will be indirectly limited by the renderer.
|
|
#[derive(Debug, Clone, Copy, PartialEq)]
|
|
pub enum UpdateMode {
|
|
/// The [`App`](bevy_app::App) will update over and over, as fast as it possibly can, until an
|
|
/// [`AppExit`](bevy_app::AppExit) event appears.
|
|
Continuous,
|
|
/// The [`App`](bevy_app::App) will update in response to the following, until an
|
|
/// [`AppExit`](bevy_app::AppExit) event appears:
|
|
/// - `wait` time has elapsed since the previous update
|
|
/// - a redraw has been requested by [`RequestRedraw`](bevy_window::RequestRedraw)
|
|
/// - new [window](`winit::event::WindowEvent`), [raw input](`winit::event::DeviceEvent`), or custom
|
|
/// events have appeared
|
|
/// - a redraw has been requested with the [`EventLoopProxy`](crate::EventLoopProxy)
|
|
Reactive {
|
|
/// The approximate time from the start of one update to the next.
|
|
///
|
|
/// **Note:** This has no upper limit.
|
|
/// The [`App`](bevy_app::App) will wait indefinitely if you set this to [`Duration::MAX`].
|
|
wait: Duration,
|
|
/// Reacts to device events, that will wake up the loop if it's in a wait wtate
|
|
react_to_device_events: bool,
|
|
/// Reacts to user events, that will wake up the loop if it's in a wait wtate
|
|
react_to_user_events: bool,
|
|
/// Reacts to window events, that will wake up the loop if it's in a wait wtate
|
|
react_to_window_events: bool,
|
|
},
|
|
}
|
|
|
|
impl UpdateMode {
|
|
/// Reactive mode, will update the app for any kind of event
|
|
pub fn reactive(wait: Duration) -> Self {
|
|
Self::Reactive {
|
|
wait,
|
|
react_to_device_events: true,
|
|
react_to_user_events: true,
|
|
react_to_window_events: true,
|
|
}
|
|
}
|
|
|
|
/// Low power mode
|
|
///
|
|
/// Unlike [`Reactive`](`UpdateMode::reactive()`), this will ignore events that
|
|
/// don't come from interacting with a window, like [`MouseMotion`](winit::event::DeviceEvent::MouseMotion).
|
|
/// Use this if, for example, you only want your app to update when the mouse cursor is
|
|
/// moving over a window, not just moving in general. This can greatly reduce power consumption.
|
|
pub fn reactive_low_power(wait: Duration) -> Self {
|
|
Self::Reactive {
|
|
wait,
|
|
react_to_device_events: false,
|
|
react_to_user_events: true,
|
|
react_to_window_events: true,
|
|
}
|
|
}
|
|
}
|