Skip to content

Commit 061bee7

Browse files
fix: upgrade to winit v0.30 (#13366)
# Objective - Upgrade winit to v0.30 - Fixes #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 #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>
1 parent 44c8cc6 commit 061bee7

File tree

25 files changed

+1349
-1021
lines changed

25 files changed

+1349
-1021
lines changed

Cargo.toml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,6 +359,10 @@ argh = "0.1.12"
359359
thiserror = "1.0"
360360
event-listener = "5.3.0"
361361

362+
[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
363+
wasm-bindgen = { version = "0.2" }
364+
web-sys = { version = "0.3", features = ["Window"] }
365+
362366
[[example]]
363367
name = "hello_world"
364368
path = "examples/hello_world.rs"
@@ -2836,6 +2840,17 @@ description = "Creates a solid color window"
28362840
category = "Window"
28372841
wasm = true
28382842

2843+
[[example]]
2844+
name = "custom_user_event"
2845+
path = "examples/window/custom_user_event.rs"
2846+
doc-scrape-examples = true
2847+
2848+
[package.metadata.example.custom_user_event]
2849+
name = "Custom User Event"
2850+
description = "Handles custom user events within the event loop"
2851+
category = "Window"
2852+
wasm = true
2853+
28392854
[[example]]
28402855
name = "low_power"
28412856
path = "examples/window/low_power.rs"

crates/bevy_a11y/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ bevy_app = { path = "../bevy_app", version = "0.14.0-dev" }
1414
bevy_derive = { path = "../bevy_derive", version = "0.14.0-dev" }
1515
bevy_ecs = { path = "../bevy_ecs", version = "0.14.0-dev" }
1616

17-
accesskit = "0.12"
17+
accesskit = "0.14"
1818

1919
[lints]
2020
workspace = true

crates/bevy_internal/src/default_plugins.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl PluginGroup for DefaultPlugins {
6969

7070
#[cfg(feature = "bevy_winit")]
7171
{
72-
group = group.add(bevy_winit::WinitPlugin::default());
72+
group = group.add::<bevy_winit::WinitPlugin>(bevy_winit::WinitPlugin::default());
7373
}
7474

7575
#[cfg(feature = "bevy_render")]

crates/bevy_render/src/lib.rs

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ use bevy_utils::prelude::default;
5858
pub use extract_param::Extract;
5959

6060
use bevy_hierarchy::ValidParentCheckPlugin;
61-
use bevy_window::{PrimaryWindow, RawHandleWrapper};
61+
use bevy_window::{PrimaryWindow, RawHandleWrapperHolder};
6262
use extract_resource::ExtractResourcePlugin;
6363
use globals::GlobalsPlugin;
6464
use render_asset::RenderAssetBytesPerFrame;
@@ -268,10 +268,9 @@ impl Plugin for RenderPlugin {
268268
));
269269

270270
let mut system_state: SystemState<
271-
Query<&RawHandleWrapper, With<PrimaryWindow>>,
271+
Query<&RawHandleWrapperHolder, With<PrimaryWindow>>,
272272
> = SystemState::new(app.world_mut());
273273
let primary_window = system_state.get(app.world()).get_single().ok().cloned();
274-
275274
let settings = render_creation.clone();
276275
let async_renderer = async move {
277276
let instance = wgpu::Instance::new(wgpu::InstanceDescriptor {
@@ -282,11 +281,20 @@ impl Plugin for RenderPlugin {
282281
});
283282

284283
// SAFETY: Plugins should be set up on the main thread.
285-
let surface = primary_window.map(|wrapper| unsafe {
286-
let handle = wrapper.get_handle();
287-
instance
288-
.create_surface(handle)
289-
.expect("Failed to create wgpu surface")
284+
let surface = primary_window.and_then(|wrapper| unsafe {
285+
let maybe_handle = wrapper.0.lock().expect(
286+
"Couldn't get the window handle in time for renderer initialization",
287+
);
288+
if let Some(wrapper) = maybe_handle.as_ref() {
289+
let handle = wrapper.get_handle();
290+
Some(
291+
instance
292+
.create_surface(handle)
293+
.expect("Failed to create wgpu surface"),
294+
)
295+
} else {
296+
None
297+
}
290298
});
291299

292300
let request_adapter_options = wgpu::RequestAdapterOptions {

crates/bevy_tasks/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ concurrent-queue = { version = "2.0.0", optional = true }
2222
wasm-bindgen-futures = "0.4"
2323

2424
[dev-dependencies]
25-
web-time = { version = "0.2" }
25+
web-time = { version = "1.1" }
2626

2727
[lints]
2828
workspace = true

crates/bevy_utils/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ detailed_trace = []
1414
[dependencies]
1515
ahash = "0.8.7"
1616
tracing = { version = "0.1", default-features = false, features = ["std"] }
17-
web-time = { version = "0.2" }
17+
web-time = { version = "1.1" }
1818
hashbrown = { version = "0.14", features = ["serde"] }
1919
bevy_utils_proc_macros = { version = "0.14.0-dev", path = "macros" }
2020
thread_local = "1.0"

crates/bevy_window/src/event.rs

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -388,13 +388,28 @@ pub struct WindowThemeChanged {
388388
derive(serde::Serialize, serde::Deserialize),
389389
reflect(Serialize, Deserialize)
390390
)]
391-
pub enum ApplicationLifetime {
392-
/// The application just started.
393-
Started,
391+
pub enum AppLifecycle {
392+
/// The application is not started yet.
393+
Idle,
394+
/// The application is running.
395+
Running,
396+
/// The application is going to be suspended.
397+
/// Applications have one frame to react to this event before being paused in the background.
398+
WillSuspend,
394399
/// The application was suspended.
395-
///
396-
/// On Android, applications have one frame to react to this event before being paused in the background.
397400
Suspended,
398-
/// The application was resumed.
399-
Resumed,
401+
/// The application is going to be resumed.
402+
/// Applications have one extra frame to react to this event before being fully resumed.
403+
WillResume,
404+
}
405+
406+
impl AppLifecycle {
407+
/// Return `true` if the app can be updated.
408+
#[inline]
409+
pub fn is_active(&self) -> bool {
410+
match self {
411+
Self::Idle | Self::Suspended => false,
412+
Self::Running | Self::WillSuspend | Self::WillResume => true,
413+
}
414+
}
400415
}

crates/bevy_window/src/lib.rs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
//! The [`WindowPlugin`] sets up some global window-related parameters and
1212
//! is part of the [`DefaultPlugins`](https://docs.rs/bevy/latest/bevy/struct.DefaultPlugins.html).
1313
14+
use std::sync::{Arc, Mutex};
15+
1416
use bevy_a11y::Focus;
1517

1618
mod cursor;
@@ -106,13 +108,16 @@ impl Plugin for WindowPlugin {
106108
.add_event::<FileDragAndDrop>()
107109
.add_event::<WindowMoved>()
108110
.add_event::<WindowThemeChanged>()
109-
.add_event::<ApplicationLifetime>();
111+
.add_event::<AppLifecycle>();
110112

111113
if let Some(primary_window) = &self.primary_window {
112114
let initial_focus = app
113115
.world_mut()
114116
.spawn(primary_window.clone())
115-
.insert(PrimaryWindow)
117+
.insert((
118+
PrimaryWindow,
119+
RawHandleWrapperHolder(Arc::new(Mutex::new(None))),
120+
))
116121
.id();
117122
if let Some(mut focus) = app.world_mut().get_resource_mut::<Focus>() {
118123
**focus = Some(initial_focus);
@@ -153,7 +158,7 @@ impl Plugin for WindowPlugin {
153158
.register_type::<FileDragAndDrop>()
154159
.register_type::<WindowMoved>()
155160
.register_type::<WindowThemeChanged>()
156-
.register_type::<ApplicationLifetime>();
161+
.register_type::<AppLifecycle>();
157162

158163
// Register window descriptor and related types
159164
app.register_type::<Window>()

crates/bevy_window/src/raw_handle.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,12 @@ use raw_window_handle::{
55
DisplayHandle, HandleError, HasDisplayHandle, HasWindowHandle, RawDisplayHandle,
66
RawWindowHandle, WindowHandle,
77
};
8-
use std::{any::Any, marker::PhantomData, ops::Deref, sync::Arc};
8+
use std::{
9+
any::Any,
10+
marker::PhantomData,
11+
ops::Deref,
12+
sync::{Arc, Mutex},
13+
};
914

1015
/// A wrapper over a window.
1116
///
@@ -116,3 +121,7 @@ impl HasDisplayHandle for ThreadLockedRawWindowHandleWrapper {
116121
Ok(unsafe { DisplayHandle::borrow_raw(self.0.display_handle) })
117122
}
118123
}
124+
125+
/// Holder of the [`RawHandleWrapper`] with wrappers, to allow use in asynchronous context
126+
#[derive(Debug, Clone, Component)]
127+
pub struct RawHandleWrapperHolder(pub Arc<Mutex<Option<RawHandleWrapper>>>);

crates/bevy_window/src/window.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -687,10 +687,10 @@ impl Default for WindowResolution {
687687

688688
impl WindowResolution {
689689
/// Creates a new [`WindowResolution`].
690-
pub fn new(logical_width: f32, logical_height: f32) -> Self {
690+
pub fn new(physical_width: f32, physical_height: f32) -> Self {
691691
Self {
692-
physical_width: logical_width as u32,
693-
physical_height: logical_height as u32,
692+
physical_width: physical_width as u32,
693+
physical_height: physical_height as u32,
694694
..Default::default()
695695
}
696696
}
@@ -783,9 +783,7 @@ impl WindowResolution {
783783
/// Set the window's scale factor, this may get overridden by the backend.
784784
#[inline]
785785
pub fn set_scale_factor(&mut self, scale_factor: f32) {
786-
let (width, height) = (self.width(), self.height());
787786
self.scale_factor = scale_factor;
788-
self.set(width, height);
789787
}
790788

791789
/// Set the window's scale factor, this will be used over what the backend decides.
@@ -794,9 +792,7 @@ impl WindowResolution {
794792
/// size is not within the limits.
795793
#[inline]
796794
pub fn set_scale_factor_override(&mut self, scale_factor_override: Option<f32>) {
797-
let (width, height) = (self.width(), self.height());
798795
self.scale_factor_override = scale_factor_override;
799-
self.set(width, height);
800796
}
801797
}
802798

0 commit comments

Comments
 (0)