2024-03-23 02:22:52 +00:00
|
|
|
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
|
2024-03-27 03:30:08 +00:00
|
|
|
#![forbid(unsafe_code)]
|
2024-03-25 18:52:50 +00:00
|
|
|
#![doc(
|
|
|
|
html_logo_url = "https://bevyengine.org/assets/icon.png",
|
|
|
|
html_favicon_url = "https://bevyengine.org/assets/icon.png"
|
|
|
|
)]
|
2024-03-23 02:22:52 +00:00
|
|
|
|
2023-03-21 19:59:30 +00:00
|
|
|
//! `bevy_winit` provides utilities to handle window creation and the eventloop through [`winit`]
|
|
|
|
//!
|
|
|
|
//! Most commonly, the [`WinitPlugin`] is used as part of
|
|
|
|
//! [`DefaultPlugins`](https://docs.rs/bevy/latest/bevy/struct.DefaultPlugins.html).
|
2023-10-06 00:31:10 +00:00
|
|
|
//! The app's [runner](bevy_app::App::runner) is set by `WinitPlugin` and handles the `winit` [`EventLoop`].
|
2023-03-21 19:59:30 +00:00
|
|
|
//! See `winit_runner` for details.
|
|
|
|
|
2023-03-01 22:45:04 +00:00
|
|
|
pub mod accessibility;
|
2020-04-04 21:59:49 +00:00
|
|
|
mod converters;
|
2023-01-19 00:38:28 +00:00
|
|
|
mod system;
|
2020-08-21 05:37:19 +00:00
|
|
|
mod winit_config;
|
2024-03-03 23:51:53 +00:00
|
|
|
pub mod winit_event;
|
2020-03-30 21:53:32 +00:00
|
|
|
mod winit_windows;
|
2021-01-01 21:31:22 +00:00
|
|
|
|
2024-04-22 16:48:18 +00:00
|
|
|
use std::sync::{Arc, Mutex};
|
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
use approx::relative_eq;
|
2023-03-01 22:45:04 +00:00
|
|
|
use bevy_a11y::AccessibilityRequested;
|
2024-03-04 19:15:05 +00:00
|
|
|
use bevy_utils::Instant;
|
2024-03-12 14:54:06 +00:00
|
|
|
pub use system::create_windows;
|
|
|
|
use system::{changed_windows, despawn_windows, CachedWindow};
|
2024-01-28 21:09:23 +00:00
|
|
|
use winit::dpi::{LogicalSize, PhysicalSize};
|
2020-08-21 05:37:19 +00:00
|
|
|
pub use winit_config::*;
|
2024-03-03 23:51:53 +00:00
|
|
|
pub use winit_event::*;
|
2020-08-21 05:37:19 +00:00
|
|
|
pub use winit_windows::*;
|
2020-03-28 00:43:03 +00:00
|
|
|
|
fix run-once runners (#10195)
# Objective
- After #9826, there are issues on "run once runners"
- example `without_winit` crashes:
```
2023-10-19T22:06:01.810019Z INFO bevy_render::renderer: AdapterInfo { name: "llvmpipe (LLVM 15.0.7, 256 bits)", vendor: 65541, device: 0, device_type: Cpu, driver: "llvmpipe", driver_info: "Mesa 23.2.1 - kisak-mesa PPA (LLVM 15.0.7)", backend: Vulkan }
2023-10-19T22:06:02.860331Z WARN bevy_audio::audio_output: No audio device found.
2023-10-19T22:06:03.215154Z INFO bevy_diagnostic::system_information_diagnostics_plugin::internal: SystemInfo { os: "Linux 22.04 Ubuntu", kernel: "6.2.0-1014-azure", cpu: "Intel(R) Xeon(R) CPU E5-2673 v3 @ 2.40GHz", core_count: "2", memory: "6.8 GiB" }
thread 'main' panicked at crates/bevy_render/src/pipelined_rendering.rs:91:14:
Unable to get RenderApp. Another plugin may have removed the RenderApp before PipelinedRenderingPlugin
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
```
- example `headless` runs the app twice with the `run_once` schedule
## Solution
- Expose a more complex state of an app than just "ready"
- Also block adding plugins to an app after it has finished or cleaned
up its plugins as that wouldn't work anyway
## Migration Guide
* `app.ready()` has been replaced by `app.plugins_state()` which will
return more details on the current state of plugins in the app
2023-10-23 12:25:02 +00:00
|
|
|
use bevy_app::{App, AppExit, Last, Plugin, PluginsState};
|
2024-02-25 15:19:27 +00:00
|
|
|
use bevy_ecs::event::ManualEventReader;
|
2022-05-05 13:35:43 +00:00
|
|
|
use bevy_ecs::prelude::*;
|
2024-01-28 21:09:23 +00:00
|
|
|
use bevy_ecs::system::SystemState;
|
2023-01-19 00:38:28 +00:00
|
|
|
use bevy_input::{
|
|
|
|
mouse::{MouseButtonInput, MouseMotion, MouseScrollUnit, MouseWheel},
|
2023-06-08 20:31:43 +00:00
|
|
|
touchpad::{TouchpadMagnify, TouchpadRotate},
|
2022-03-01 19:33:56 +00:00
|
|
|
};
|
2023-01-19 00:38:28 +00:00
|
|
|
use bevy_math::{ivec2, DVec2, Vec2};
|
2023-07-31 21:41:59 +00:00
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
use bevy_tasks::tick_global_task_pools_on_main_thread;
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
use bevy_utils::tracing::{error, trace, warn};
|
2024-04-30 00:49:41 +00:00
|
|
|
#[allow(deprecated)]
|
2020-04-19 19:13:04 +00:00
|
|
|
use bevy_window::{
|
2023-10-23 20:47:55 +00:00
|
|
|
exit_on_all_closed, ApplicationLifetime, CursorEntered, CursorLeft, CursorMoved,
|
|
|
|
FileDragAndDrop, Ime, ReceivedCharacter, RequestRedraw, Window,
|
|
|
|
WindowBackendScaleFactorChanged, WindowCloseRequested, WindowCreated, WindowDestroyed,
|
2023-11-26 21:58:54 +00:00
|
|
|
WindowFocused, WindowMoved, WindowOccluded, WindowResized, WindowScaleFactorChanged,
|
|
|
|
WindowThemeChanged,
|
2020-04-19 19:13:04 +00:00
|
|
|
};
|
2023-10-02 13:06:13 +00:00
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
use bevy_window::{PrimaryWindow, RawHandleWrapper};
|
2022-05-05 13:35:43 +00:00
|
|
|
|
2023-02-03 16:41:39 +00:00
|
|
|
#[cfg(target_os = "android")]
|
2023-12-19 20:15:03 +00:00
|
|
|
pub use winit::platform::android::activity as android_activity;
|
2023-02-03 16:41:39 +00:00
|
|
|
|
2024-03-04 19:15:05 +00:00
|
|
|
use winit::event::StartCause;
|
2020-03-28 00:43:03 +00:00
|
|
|
use winit::{
|
2024-01-09 15:41:46 +00:00
|
|
|
event::{self, DeviceEvent, Event, WindowEvent},
|
2023-02-03 16:41:39 +00:00
|
|
|
event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopWindowTarget},
|
2020-03-28 00:43:03 +00:00
|
|
|
};
|
|
|
|
|
2023-12-09 14:22:33 +00:00
|
|
|
use crate::accessibility::{AccessKitAdapters, AccessKitPlugin, WinitActionHandlers};
|
2023-03-01 22:45:04 +00:00
|
|
|
|
2023-06-05 21:04:22 +00:00
|
|
|
use crate::converters::convert_winit_theme;
|
2023-01-19 00:38:28 +00:00
|
|
|
|
2023-07-31 21:41:59 +00:00
|
|
|
/// [`AndroidApp`] provides an interface to query the application state as well as monitor events
|
|
|
|
/// (for example lifecycle and input events).
|
2023-02-03 16:41:39 +00:00
|
|
|
#[cfg(target_os = "android")]
|
2023-12-19 20:15:03 +00:00
|
|
|
pub static ANDROID_APP: std::sync::OnceLock<android_activity::AndroidApp> =
|
|
|
|
std::sync::OnceLock::new();
|
2023-02-03 16:41:39 +00:00
|
|
|
|
2023-08-31 19:05:49 +00:00
|
|
|
/// A [`Plugin`] that uses `winit` to create and manage windows, and receive window and input
|
2023-07-31 21:41:59 +00:00
|
|
|
/// events.
|
|
|
|
///
|
2023-08-31 19:05:49 +00:00
|
|
|
/// This plugin will add systems and resources that sync with the `winit` backend and also
|
2023-09-25 18:35:46 +00:00
|
|
|
/// replace the existing [`App`] runner with one that constructs an [event loop](EventLoop) to
|
2023-07-31 21:41:59 +00:00
|
|
|
/// receive window and input events from the OS.
|
2020-03-29 07:53:47 +00:00
|
|
|
#[derive(Default)]
|
2023-10-06 13:26:06 +00:00
|
|
|
pub struct WinitPlugin {
|
|
|
|
/// Allows the window (and the event loop) to be created on any thread
|
|
|
|
/// instead of only the main thread.
|
|
|
|
///
|
|
|
|
/// See [`EventLoopBuilder::build`] for more information on this.
|
|
|
|
///
|
|
|
|
/// # Supported platforms
|
|
|
|
///
|
|
|
|
/// Only works on Linux (X11/Wayland) and Windows.
|
|
|
|
/// This field is ignored on other platforms.
|
|
|
|
pub run_on_any_thread: bool,
|
|
|
|
}
|
2020-03-29 07:53:47 +00:00
|
|
|
|
2020-08-08 03:22:17 +00:00
|
|
|
impl Plugin for WinitPlugin {
|
2021-07-27 20:21:06 +00:00
|
|
|
fn build(&self, app: &mut App) {
|
2024-03-04 17:17:17 +00:00
|
|
|
let mut event_loop_builder = EventLoopBuilder::<UserEvent>::with_user_event();
|
2023-10-06 13:26:06 +00:00
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
// linux check is needed because x11 might be enabled on other platforms.
|
|
|
|
#[cfg(all(target_os = "linux", feature = "x11"))]
|
2023-10-06 13:26:06 +00:00
|
|
|
{
|
2024-01-28 21:09:23 +00:00
|
|
|
use winit::platform::x11::EventLoopBuilderExtX11;
|
2023-10-06 13:26:06 +00:00
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
// This allows a Bevy app to be started and ran outside of the main thread.
|
|
|
|
// A use case for this is to allow external applications to spawn a thread
|
|
|
|
// which runs a Bevy app without requiring the Bevy app to need to reside on
|
|
|
|
// the main thread, which can be problematic.
|
|
|
|
event_loop_builder.with_any_thread(self.run_on_any_thread);
|
|
|
|
}
|
2023-10-06 13:26:06 +00:00
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
// linux check is needed because wayland might be enabled on other platforms.
|
|
|
|
#[cfg(all(target_os = "linux", feature = "wayland"))]
|
|
|
|
{
|
|
|
|
use winit::platform::wayland::EventLoopBuilderExtWayland;
|
|
|
|
event_loop_builder.with_any_thread(self.run_on_any_thread);
|
2023-10-06 13:26:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(target_os = "windows")]
|
|
|
|
{
|
|
|
|
use winit::platform::windows::EventLoopBuilderExtWindows;
|
|
|
|
event_loop_builder.with_any_thread(self.run_on_any_thread);
|
|
|
|
}
|
|
|
|
|
2023-02-03 16:41:39 +00:00
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
{
|
|
|
|
use winit::platform::android::EventLoopBuilderExtAndroid;
|
2024-01-28 21:09:23 +00:00
|
|
|
let msg = "Bevy must be setup with the #[bevy_main] macro on Android";
|
|
|
|
event_loop_builder.with_android_app(ANDROID_APP.get().expect(msg).clone());
|
2023-02-03 16:41:39 +00:00
|
|
|
}
|
|
|
|
|
2022-02-24 01:40:02 +00:00
|
|
|
app.init_non_send_resource::<WinitWindows>()
|
Reduce power usage with configurable event loop (#3974)
# Objective
- Reduce power usage for games when not focused.
- Reduce power usage to ~0 when a desktop application is minimized (opt-in).
- Reduce power usage when focused, only updating on a `winit` event, or the user sends a redraw request. (opt-in)
https://user-images.githubusercontent.com/2632925/156904387-ec47d7de-7f06-4c6f-8aaf-1e952c1153a2.mp4
Note resource usage in the Task Manager in the above video.
## Solution
- Added a type `UpdateMode` that allows users to specify how the winit event loop is updated, without exposing winit types.
- Added two fields to `WinitConfig`, both with the `UpdateMode` type. One configures how the application updates when focused, and the other configures how the application behaves when it is not focused. Users can modify this resource manually to set the type of event loop control flow they want.
- For convenience, two functions were added to `WinitConfig`, that provide reasonable presets: `game()` (default) and `desktop_app()`.
- The `game()` preset, which is used by default, is unchanged from current behavior with one exception: when the app is out of focus the app updates at a minimum of 10fps, or every time a winit event is received. This has a huge positive impact on power use and responsiveness on my machine, which will otherwise continue running the app at many hundreds of fps when out of focus or minimized.
- The `desktop_app()` preset is fully reactive, only updating when user input (winit event) is supplied or a `RedrawRequest` event is sent. When the app is out of focus, it only updates on `Window` events - i.e. any winit event that directly interacts with the window. What this means in practice is that the app uses *zero* resources when minimized or not interacted with, but still updates fluidly when the app is out of focus and the user mouses over the application.
- Added a `RedrawRequest` event so users can force an update even if there are no events. This is useful in an application when you want to, say, run an animation even when the user isn't providing input.
- Added an example `low_power` to demonstrate these changes
## Usage
Configuring the event loop:
```rs
use bevy::winit::{WinitConfig};
// ...
.insert_resource(WinitConfig::desktop_app()) // preset
// or
.insert_resource(WinitConfig::game()) // preset
// or
.insert_resource(WinitConfig{ .. }) // manual
```
Requesting a redraw:
```rs
use bevy::window::RequestRedraw;
// ...
fn request_redraw(mut event: EventWriter<RequestRedraw>) {
event.send(RequestRedraw);
}
```
## Other details
- Because we have a single event loop for multiple windows, every time I've mentioned "focused" above, I more precisely mean, "if at least one bevy window is focused".
- Due to a platform bug in winit (https://github.com/rust-windowing/winit/issues/1619), we can't simply use `Window::request_redraw()`. As a workaround, this PR will temporarily set the window mode to `Poll` when a redraw is requested. This is then reset to the user's `WinitConfig` setting on the next frame.
2022-03-07 23:32:05 +00:00
|
|
|
.init_resource::<WinitSettings>()
|
2024-03-03 23:51:53 +00:00
|
|
|
.add_event::<WinitEvent>()
|
2020-10-15 18:42:19 +00:00
|
|
|
.set_runner(winit_runner)
|
Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.
# Objective
- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45
## Solution
- [x] Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests
## Changelog
### Added
- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`
### Removed
- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.
### Changed
- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
- `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied.
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.
## Migration Guide
- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage` enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
- Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
- Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
- For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with
- `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`
## TODO
- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
- [x] unbreak directional lights
- [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
- [x] game menu example shows loading screen and menu simultaneously
- [x] display settings menu is a blank screen
- [x] `without_winit` example panics
- [x] ensure all tests pass
- [x] SubApp doc test fails
- [x] runs_spawn_local tasks fails
- [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)
## Points of Difficulty and Controversy
**Reviewers, please give feedback on these and look closely**
1. Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.
## Future Work (ideally before 0.10)
- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
|
|
|
.add_systems(
|
2023-03-18 01:45:34 +00:00
|
|
|
Last,
|
Migrate engine to Schedule v3 (#7267)
Huge thanks to @maniwani, @devil-ira, @hymm, @cart, @superdump and @jakobhellermann for the help with this PR.
# Objective
- Followup #6587.
- Minimal integration for the Stageless Scheduling RFC: https://github.com/bevyengine/rfcs/pull/45
## Solution
- [x] Remove old scheduling module
- [x] Migrate new methods to no longer use extension methods
- [x] Fix compiler errors
- [x] Fix benchmarks
- [x] Fix examples
- [x] Fix docs
- [x] Fix tests
## Changelog
### Added
- a large number of methods on `App` to work with schedules ergonomically
- the `CoreSchedule` enum
- `App::add_extract_system` via the `RenderingAppExtension` trait extension method
- the private `prepare_view_uniforms` system now has a public system set for scheduling purposes, called `ViewSet::PrepareUniforms`
### Removed
- stages, and all code that mentions stages
- states have been dramatically simplified, and no longer use a stack
- `RunCriteriaLabel`
- `AsSystemLabel` trait
- `on_hierarchy_reports_enabled` run criteria (now just uses an ad hoc resource checking run condition)
- systems in `RenderSet/Stage::Extract` no longer warn when they do not read data from the main world
- `RunCriteriaLabel`
- `transform_propagate_system_set`: this was a nonstandard pattern that didn't actually provide enough control. The systems are already `pub`: the docs have been updated to ensure that the third-party usage is clear.
### Changed
- `System::default_labels` is now `System::default_system_sets`.
- `App::add_default_labels` is now `App::add_default_sets`
- `CoreStage` and `StartupStage` enums are now `CoreSet` and `StartupSet`
- `App::add_system_set` was renamed to `App::add_systems`
- The `StartupSchedule` label is now defined as part of the `CoreSchedules` enum
- `.label(SystemLabel)` is now referred to as `.in_set(SystemSet)`
- `SystemLabel` trait was replaced by `SystemSet`
- `SystemTypeIdLabel<T>` was replaced by `SystemSetType<T>`
- The `ReportHierarchyIssue` resource now has a public constructor (`new`), and implements `PartialEq`
- Fixed time steps now use a schedule (`CoreSchedule::FixedTimeStep`) rather than a run criteria.
- Adding rendering extraction systems now panics rather than silently failing if no subapp with the `RenderApp` label is found.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied.
- `SceneSpawnerSystem` now runs under `CoreSet::Update`, rather than `CoreStage::PreUpdate.at_end()`.
- `bevy_pbr::add_clusters` is no longer an exclusive system
- the top level `bevy_ecs::schedule` module was replaced with `bevy_ecs::scheduling`
- `tick_global_task_pools_on_main_thread` is no longer run as an exclusive system. Instead, it has been replaced by `tick_global_task_pools`, which uses a `NonSend` resource to force running on the main thread.
## Migration Guide
- Calls to `.label(MyLabel)` should be replaced with `.in_set(MySet)`
- Stages have been removed. Replace these with system sets, and then add command flushes using the `apply_system_buffers` exclusive system where needed.
- The `CoreStage`, `StartupStage, `RenderStage` and `AssetStage` enums have been replaced with `CoreSet`, `StartupSet, `RenderSet` and `AssetSet`. The same scheduling guarantees have been preserved.
- Systems are no longer added to `CoreSet::Update` by default. Add systems manually if this behavior is needed, although you should consider adding your game logic systems to `CoreSchedule::FixedTimestep` instead for more reliable framerate-independent behavior.
- Similarly, startup systems are no longer part of `StartupSet::Startup` by default. In most cases, this won't matter to you.
- For example, `add_system_to_stage(CoreStage::PostUpdate, my_system)` should be replaced with
- `add_system(my_system.in_set(CoreSet::PostUpdate)`
- When testing systems or otherwise running them in a headless fashion, simply construct and run a schedule using `Schedule::new()` and `World::run_schedule` rather than constructing stages
- Run criteria have been renamed to run conditions. These can now be combined with each other and with states.
- Looping run criteria and state stacks have been removed. Use an exclusive system that runs a schedule if you need this level of control over system control flow.
- For app-level control flow over which schedules get run when (such as for rollback networking), create your own schedule and insert it under the `CoreSchedule::Outer` label.
- Fixed timesteps are now evaluated in a schedule, rather than controlled via run criteria. The `run_fixed_timestep` system runs this schedule between `CoreSet::First` and `CoreSet::PreUpdate` by default.
- Command flush points introduced by `AssetStage` have been removed. If you were relying on these, add them back manually.
- Adding extract systems is now typically done directly on the main app. Make sure the `RenderingAppExtension` trait is in scope, then call `app.add_extract_system(my_system)`.
- the `calculate_bounds` system, with the `CalculateBounds` label, is now in `CoreSet::Update`, rather than in `CoreSet::PostUpdate` before commands are applied. You may need to order your movement systems to occur before this system in order to avoid system order ambiguities in culling behavior.
- the `RenderLabel` `AppLabel` was renamed to `RenderApp` for clarity
- `App::add_state` now takes 0 arguments: the starting state is set based on the `Default` impl.
- Instead of creating `SystemSet` containers for systems that run in stages, simply use `.on_enter::<State::Variant>()` or its `on_exit` or `on_update` siblings.
- `SystemLabel` derives should be replaced with `SystemSet`. You will also need to add the `Debug`, `PartialEq`, `Eq`, and `Hash` traits to satisfy the new trait bounds.
- `with_run_criteria` has been renamed to `run_if`. Run criteria have been renamed to run conditions for clarity, and should now simply return a bool.
- States have been dramatically simplified: there is no longer a "state stack". To queue a transition to the next state, call `NextState::set`
## TODO
- [x] remove dead methods on App and World
- [x] add `App::add_system_to_schedule` and `App::add_systems_to_schedule`
- [x] avoid adding the default system set at inappropriate times
- [x] remove any accidental cycles in the default plugins schedule
- [x] migrate benchmarks
- [x] expose explicit labels for the built-in command flush points
- [x] migrate engine code
- [x] remove all mentions of stages from the docs
- [x] verify docs for States
- [x] fix uses of exclusive systems that use .end / .at_start / .before_commands
- [x] migrate RenderStage and AssetStage
- [x] migrate examples
- [x] ensure that transform propagation is exported in a sufficiently public way (the systems are already pub)
- [x] ensure that on_enter schedules are run at least once before the main app
- [x] re-enable opt-in to execution order ambiguities
- [x] revert change to `update_bounds` to ensure it runs in `PostUpdate`
- [x] test all examples
- [x] unbreak directional lights
- [x] unbreak shadows (see 3d_scene, 3d_shape, lighting, transparaency_3d examples)
- [x] game menu example shows loading screen and menu simultaneously
- [x] display settings menu is a blank screen
- [x] `without_winit` example panics
- [x] ensure all tests pass
- [x] SubApp doc test fails
- [x] runs_spawn_local tasks fails
- [x] [Fix panic_when_hierachy_cycle test hanging](https://github.com/alice-i-cecile/bevy/pull/120)
## Points of Difficulty and Controversy
**Reviewers, please give feedback on these and look closely**
1. Default sets, from the RFC, have been removed. These added a tremendous amount of implicit complexity and result in hard to debug scheduling errors. They're going to be tackled in the form of "base sets" by @cart in a followup.
2. The outer schedule controls which schedule is run when `App::update` is called.
3. I implemented `Label for `Box<dyn Label>` for our label types. This enables us to store schedule labels in concrete form, and then later run them. I ran into the same set of problems when working with one-shot systems. We've previously investigated this pattern in depth, and it does not appear to lead to extra indirection with nested boxes.
4. `SubApp::update` simply runs the default schedule once. This sucks, but this whole API is incomplete and this was the minimal changeset.
5. `time_system` and `tick_global_task_pools_on_main_thread` no longer use exclusive systems to attempt to force scheduling order
6. Implemetnation strategy for fixed timesteps
7. `AssetStage` was migrated to `AssetSet` without reintroducing command flush points. These did not appear to be used, and it's nice to remove these bottlenecks.
8. Migration of `bevy_render/lib.rs` and pipelined rendering. The logic here is unusually tricky, as we have complex scheduling requirements.
## Future Work (ideally before 0.10)
- Rename schedule_v3 module to schedule or scheduling
- Add a derive macro to states, and likely a `EnumIter` trait of some form
- Figure out what exactly to do with the "systems added should basically work by default" problem
- Improve ergonomics for working with fixed timesteps and states
- Polish FixedTime API to match Time
- Rebase and merge #7415
- Resolve all internal ambiguities (blocked on better tools, especially #7442)
- Add "base sets" to replace the removed default sets.
2023-02-06 02:04:50 +00:00
|
|
|
(
|
2023-07-31 21:41:59 +00:00
|
|
|
// `exit_on_all_closed` only checks if windows exist but doesn't access data,
|
|
|
|
// so we don't need to care about its ordering relative to `changed_windows`
|
|
|
|
changed_windows.ambiguous_with(exit_on_all_closed),
|
|
|
|
despawn_windows,
|
|
|
|
)
|
|
|
|
.chain(),
|
2023-01-19 00:38:28 +00:00
|
|
|
);
|
2022-09-06 14:45:44 +00:00
|
|
|
|
2023-12-09 14:22:33 +00:00
|
|
|
app.add_plugins(AccessKitPlugin);
|
2023-03-01 22:45:04 +00:00
|
|
|
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
let event_loop = event_loop_builder
|
|
|
|
.build()
|
|
|
|
.expect("Failed to build event loop");
|
2022-07-04 13:04:14 +00:00
|
|
|
|
2023-07-31 21:41:59 +00:00
|
|
|
// iOS, macOS, and Android don't like it if you create windows before the event loop is
|
|
|
|
// initialized.
|
|
|
|
//
|
|
|
|
// See:
|
|
|
|
// - https://github.com/rust-windowing/winit/blob/master/README.md#macos
|
|
|
|
// - https://github.com/rust-windowing/winit/blob/master/README.md#ios
|
2023-01-19 00:38:28 +00:00
|
|
|
#[cfg(not(any(target_os = "android", target_os = "ios", target_os = "macos")))]
|
|
|
|
{
|
2023-07-31 21:41:59 +00:00
|
|
|
// Otherwise, we want to create a window before `bevy_render` initializes the renderer
|
|
|
|
// so that we have a surface to use as a hint. This improves compatibility with `wgpu`
|
|
|
|
// backends, especially WASM/WebGL2.
|
2024-03-31 03:16:10 +00:00
|
|
|
let mut create_window = SystemState::<CreateWindowParams>::from_world(app.world_mut());
|
|
|
|
create_windows(&event_loop, create_window.get_mut(app.world_mut()));
|
|
|
|
create_window.apply(app.world_mut());
|
2022-05-05 13:35:43 +00:00
|
|
|
}
|
2023-01-19 00:38:28 +00:00
|
|
|
|
2023-07-31 21:41:59 +00:00
|
|
|
// `winit`'s windows are bound to the event loop that created them, so the event loop must
|
|
|
|
// be inserted as a resource here to pass it onto the runner.
|
|
|
|
app.insert_non_send_resource(event_loop);
|
2022-05-05 13:35:43 +00:00
|
|
|
}
|
2020-03-29 07:53:47 +00:00
|
|
|
}
|
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
trait AppSendEvent {
|
2024-03-03 23:51:53 +00:00
|
|
|
fn send(&mut self, event: impl Into<WinitEvent>);
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
2024-03-03 23:51:53 +00:00
|
|
|
impl AppSendEvent for Vec<WinitEvent> {
|
|
|
|
fn send(&mut self, event: impl Into<WinitEvent>) {
|
|
|
|
self.push(Into::<WinitEvent>::into(event));
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
2020-12-24 18:43:30 +00:00
|
|
|
}
|
|
|
|
|
2023-07-31 21:41:59 +00:00
|
|
|
/// Persistent state that is used to run the [`App`] according to the current
|
|
|
|
/// [`UpdateMode`].
|
|
|
|
struct WinitAppRunnerState {
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
/// Current activity state of the app.
|
|
|
|
activity_state: UpdateState,
|
|
|
|
/// Current update mode of the app.
|
|
|
|
update_mode: UpdateMode,
|
2023-07-31 21:41:59 +00:00
|
|
|
/// Is `true` if a new [`WindowEvent`] has been received since the last update.
|
|
|
|
window_event_received: bool,
|
2024-01-15 15:46:11 +00:00
|
|
|
/// Is `true` if a new [`DeviceEvent`] has been received since the last update.
|
|
|
|
device_event_received: bool,
|
2023-07-31 21:41:59 +00:00
|
|
|
/// 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.
|
|
|
|
wait_elapsed: bool,
|
2024-01-15 15:46:11 +00:00
|
|
|
/// Number of "forced" updates to trigger on application start
|
|
|
|
startup_forced_updates: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl WinitAppRunnerState {
|
|
|
|
fn reset_on_update(&mut self) {
|
|
|
|
self.window_event_received = false;
|
|
|
|
self.device_event_received = false;
|
2023-10-23 20:47:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-07-31 21:41:59 +00:00
|
|
|
impl Default for WinitAppRunnerState {
|
Reduce power usage with configurable event loop (#3974)
# Objective
- Reduce power usage for games when not focused.
- Reduce power usage to ~0 when a desktop application is minimized (opt-in).
- Reduce power usage when focused, only updating on a `winit` event, or the user sends a redraw request. (opt-in)
https://user-images.githubusercontent.com/2632925/156904387-ec47d7de-7f06-4c6f-8aaf-1e952c1153a2.mp4
Note resource usage in the Task Manager in the above video.
## Solution
- Added a type `UpdateMode` that allows users to specify how the winit event loop is updated, without exposing winit types.
- Added two fields to `WinitConfig`, both with the `UpdateMode` type. One configures how the application updates when focused, and the other configures how the application behaves when it is not focused. Users can modify this resource manually to set the type of event loop control flow they want.
- For convenience, two functions were added to `WinitConfig`, that provide reasonable presets: `game()` (default) and `desktop_app()`.
- The `game()` preset, which is used by default, is unchanged from current behavior with one exception: when the app is out of focus the app updates at a minimum of 10fps, or every time a winit event is received. This has a huge positive impact on power use and responsiveness on my machine, which will otherwise continue running the app at many hundreds of fps when out of focus or minimized.
- The `desktop_app()` preset is fully reactive, only updating when user input (winit event) is supplied or a `RedrawRequest` event is sent. When the app is out of focus, it only updates on `Window` events - i.e. any winit event that directly interacts with the window. What this means in practice is that the app uses *zero* resources when minimized or not interacted with, but still updates fluidly when the app is out of focus and the user mouses over the application.
- Added a `RedrawRequest` event so users can force an update even if there are no events. This is useful in an application when you want to, say, run an animation even when the user isn't providing input.
- Added an example `low_power` to demonstrate these changes
## Usage
Configuring the event loop:
```rs
use bevy::winit::{WinitConfig};
// ...
.insert_resource(WinitConfig::desktop_app()) // preset
// or
.insert_resource(WinitConfig::game()) // preset
// or
.insert_resource(WinitConfig{ .. }) // manual
```
Requesting a redraw:
```rs
use bevy::window::RequestRedraw;
// ...
fn request_redraw(mut event: EventWriter<RequestRedraw>) {
event.send(RequestRedraw);
}
```
## Other details
- Because we have a single event loop for multiple windows, every time I've mentioned "focused" above, I more precisely mean, "if at least one bevy window is focused".
- Due to a platform bug in winit (https://github.com/rust-windowing/winit/issues/1619), we can't simply use `Window::request_redraw()`. As a workaround, this PR will temporarily set the window mode to `Poll` when a redraw is requested. This is then reset to the user's `WinitConfig` setting on the next frame.
2022-03-07 23:32:05 +00:00
|
|
|
fn default() -> Self {
|
|
|
|
Self {
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
activity_state: UpdateState::NotYetStarted,
|
|
|
|
update_mode: UpdateMode::Continuous,
|
2023-07-31 21:41:59 +00:00
|
|
|
window_event_received: false,
|
2024-01-15 15:46:11 +00:00
|
|
|
device_event_received: false,
|
2023-07-31 21:41:59 +00:00
|
|
|
redraw_requested: false,
|
|
|
|
wait_elapsed: false,
|
2024-01-15 15:46:11 +00:00
|
|
|
// 3 seems to be enough, 5 is a safe margin
|
|
|
|
startup_forced_updates: 5,
|
Reduce power usage with configurable event loop (#3974)
# Objective
- Reduce power usage for games when not focused.
- Reduce power usage to ~0 when a desktop application is minimized (opt-in).
- Reduce power usage when focused, only updating on a `winit` event, or the user sends a redraw request. (opt-in)
https://user-images.githubusercontent.com/2632925/156904387-ec47d7de-7f06-4c6f-8aaf-1e952c1153a2.mp4
Note resource usage in the Task Manager in the above video.
## Solution
- Added a type `UpdateMode` that allows users to specify how the winit event loop is updated, without exposing winit types.
- Added two fields to `WinitConfig`, both with the `UpdateMode` type. One configures how the application updates when focused, and the other configures how the application behaves when it is not focused. Users can modify this resource manually to set the type of event loop control flow they want.
- For convenience, two functions were added to `WinitConfig`, that provide reasonable presets: `game()` (default) and `desktop_app()`.
- The `game()` preset, which is used by default, is unchanged from current behavior with one exception: when the app is out of focus the app updates at a minimum of 10fps, or every time a winit event is received. This has a huge positive impact on power use and responsiveness on my machine, which will otherwise continue running the app at many hundreds of fps when out of focus or minimized.
- The `desktop_app()` preset is fully reactive, only updating when user input (winit event) is supplied or a `RedrawRequest` event is sent. When the app is out of focus, it only updates on `Window` events - i.e. any winit event that directly interacts with the window. What this means in practice is that the app uses *zero* resources when minimized or not interacted with, but still updates fluidly when the app is out of focus and the user mouses over the application.
- Added a `RedrawRequest` event so users can force an update even if there are no events. This is useful in an application when you want to, say, run an animation even when the user isn't providing input.
- Added an example `low_power` to demonstrate these changes
## Usage
Configuring the event loop:
```rs
use bevy::winit::{WinitConfig};
// ...
.insert_resource(WinitConfig::desktop_app()) // preset
// or
.insert_resource(WinitConfig::game()) // preset
// or
.insert_resource(WinitConfig{ .. }) // manual
```
Requesting a redraw:
```rs
use bevy::window::RequestRedraw;
// ...
fn request_redraw(mut event: EventWriter<RequestRedraw>) {
event.send(RequestRedraw);
}
```
## Other details
- Because we have a single event loop for multiple windows, every time I've mentioned "focused" above, I more precisely mean, "if at least one bevy window is focused".
- Due to a platform bug in winit (https://github.com/rust-windowing/winit/issues/1619), we can't simply use `Window::request_redraw()`. As a workaround, this PR will temporarily set the window mode to `Poll` when a redraw is requested. This is then reset to the user's `WinitConfig` setting on the next frame.
2022-03-07 23:32:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
#[derive(PartialEq, Eq, Debug)]
|
|
|
|
enum UpdateState {
|
|
|
|
NotYetStarted,
|
|
|
|
Active,
|
|
|
|
Suspended,
|
|
|
|
WillSuspend,
|
|
|
|
WillResume,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl UpdateState {
|
|
|
|
#[inline]
|
|
|
|
fn is_active(&self) -> bool {
|
|
|
|
match self {
|
|
|
|
Self::NotYetStarted | Self::Suspended => false,
|
|
|
|
Self::Active | Self::WillSuspend | Self::WillResume => true,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-03-12 14:54:06 +00:00
|
|
|
/// The parameters of the [`create_windows`] system.
|
|
|
|
pub type CreateWindowParams<'w, 's, F = ()> = (
|
2024-01-28 21:09:23 +00:00
|
|
|
Commands<'w, 's>,
|
|
|
|
Query<'w, 's, (Entity, &'static mut Window), F>,
|
|
|
|
EventWriter<'w, WindowCreated>,
|
|
|
|
NonSendMut<'w, WinitWindows>,
|
|
|
|
NonSendMut<'w, AccessKitAdapters>,
|
|
|
|
ResMut<'w, WinitActionHandlers>,
|
|
|
|
Res<'w, AccessibilityRequested>,
|
|
|
|
);
|
|
|
|
|
2024-03-04 17:17:17 +00:00
|
|
|
/// The [`winit::event_loop::EventLoopProxy`] with the specific [`winit::event::Event::UserEvent`] used in the [`winit_runner`].
|
|
|
|
///
|
|
|
|
/// The `EventLoopProxy` can be used to request a redraw from outside bevy.
|
|
|
|
///
|
|
|
|
/// Use `NonSend<EventLoopProxy>` to receive this resource.
|
|
|
|
pub type EventLoopProxy = winit::event_loop::EventLoopProxy<UserEvent>;
|
|
|
|
|
|
|
|
type UserEvent = RequestRedraw;
|
|
|
|
|
2023-03-21 19:59:30 +00:00
|
|
|
/// The default [`App::runner`] for the [`WinitPlugin`] plugin.
|
|
|
|
///
|
2023-07-31 21:41:59 +00:00
|
|
|
/// Overriding the app's [runner](bevy_app::App::runner) while using `WinitPlugin` will bypass the
|
|
|
|
/// `EventLoop`.
|
2024-04-22 16:48:18 +00:00
|
|
|
pub fn winit_runner(mut app: App) -> AppExit {
|
2023-11-16 21:50:17 +00:00
|
|
|
if app.plugins_state() == PluginsState::Ready {
|
|
|
|
app.finish();
|
|
|
|
app.cleanup();
|
|
|
|
}
|
|
|
|
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
let event_loop = app
|
2024-03-31 03:16:10 +00:00
|
|
|
.world_mut()
|
2024-03-04 17:17:17 +00:00
|
|
|
.remove_non_send_resource::<EventLoop<UserEvent>>()
|
2022-02-08 23:04:19 +00:00
|
|
|
.unwrap();
|
2023-01-19 00:38:28 +00:00
|
|
|
|
2024-03-31 03:16:10 +00:00
|
|
|
app.world_mut()
|
2022-02-08 23:04:19 +00:00
|
|
|
.insert_non_send_resource(event_loop.create_proxy());
|
2020-03-28 00:43:03 +00:00
|
|
|
|
2023-07-31 21:41:59 +00:00
|
|
|
let mut runner_state = WinitAppRunnerState::default();
|
|
|
|
|
2024-04-22 16:48:18 +00:00
|
|
|
// TODO: AppExit is effectively a u8 we could use a AtomicU8 here instead of a mutex.
|
|
|
|
let mut exit_status = Arc::new(Mutex::new(AppExit::Success));
|
|
|
|
let handle_exit_status = exit_status.clone();
|
|
|
|
|
2023-07-31 21:41:59 +00:00
|
|
|
// prepare structures to access data in the world
|
|
|
|
let mut redraw_event_reader = ManualEventReader::<RequestRedraw>::default();
|
Optionally resize Window canvas element to fit parent element (#4726)
Currently Bevy's web canvases are "fixed size". They are manually set to specific dimensions. This might be fine for some games and website layouts, but for sites with flexible layouts, or games that want to "fill" the browser window, Bevy doesn't provide the tools needed to make this easy out of the box.
There are third party plugins like [bevy-web-resizer](https://github.com/frewsxcv/bevy-web-resizer/) that listen for window resizes, take the new dimensions, and resize the winit window accordingly. However this only covers a subset of cases and this is common enough functionality that it should be baked into Bevy.
A significant motivating use case here is the [Bevy WASM Examples page](https://bevyengine.org/examples/). This scales the canvas to fit smaller windows (such as mobile). But this approach both breaks winit's mouse events and removes pixel-perfect rendering (which means we might be rendering too many or too few pixels). https://github.com/bevyengine/bevy-website/issues/371
In an ideal world, winit would support this behavior out of the box. But unfortunately that seems blocked for now: https://github.com/rust-windowing/winit/pull/2074. And it builds on the ResizeObserver api, which isn't supported in all browsers yet (and is only supported in very new versions of the popular browsers).
While we wait for a complete winit solution, I've added a `fit_canvas_to_parent` option to WindowDescriptor / Window, which when enabled will listen for window resizes and resize the Bevy canvas/window to fit its parent element. This enables users to scale bevy canvases using arbitrary CSS, by "inheriting" their parents' size. Note that the wrapper element _is_ required because winit overrides the canvas sizing with absolute values on each resize.
There is one limitation worth calling out here: while the majority of canvas resizes will be triggered by window resizes, modifying element layout at runtime (css animations, javascript-driven element changes, dev-tool-injected changes, etc) will not be detected here. I'm not aware of a good / efficient event-driven way to do this outside of the ResizeObserver api. In practice, window-resize-driven canvas resizing should cover the majority of use cases. Users that want to actively poll for element resizes can just do that (or we can build another feature and let people choose based on their specific needs).
I also took the chance to make a couple of minor tweaks:
* Made the `canvas` window setting available on all platforms. Users shouldn't need to deal with cargo feature selection to support web scenarios. We can just ignore the value on non-web platforms. I added documentation that explains this.
* Removed the redundant "initial create windows" handler. With the addition of the code in this pr, the code duplication was untenable.
This enables a number of patterns:
## Easy "fullscreen window" mode for the default canvas
The "parent element" defaults to the `<body>` element.
```rust
app
.insert_resource(WindowDescriptor {
fit_canvas_to_parent: true,
..default()
})
```
And CSS:
```css
html, body {
margin: 0;
height: 100%;
}
```
## Fit custom canvas to "wrapper" parent element
```rust
app
.insert_resource(WindowDescriptor {
fit_canvas_to_parent: true,
canvas: Some("#bevy".to_string()),
..default()
})
```
And the HTML:
```html
<div style="width: 50%; height: 100%">
<canvas id="bevy"></canvas>
</div>
```
2022-05-20 23:13:48 +00:00
|
|
|
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
let mut focused_windows_state: SystemState<(Res<WinitSettings>, Query<(Entity, &Window)>)> =
|
2024-03-31 03:16:10 +00:00
|
|
|
SystemState::new(app.world_mut());
|
2020-08-21 05:37:19 +00:00
|
|
|
|
2023-07-31 21:41:59 +00:00
|
|
|
let mut event_writer_system_state: SystemState<(
|
2024-01-28 21:09:23 +00:00
|
|
|
EventWriter<WindowResized>,
|
2023-07-31 21:41:59 +00:00
|
|
|
NonSend<WinitWindows>,
|
|
|
|
Query<(&mut Window, &mut CachedWindow)>,
|
2023-11-03 21:37:25 +00:00
|
|
|
NonSend<AccessKitAdapters>,
|
2024-03-31 03:16:10 +00:00
|
|
|
)> = SystemState::new(app.world_mut());
|
2023-01-19 00:38:28 +00:00
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
let mut create_window =
|
2024-03-31 03:16:10 +00:00
|
|
|
SystemState::<CreateWindowParams<Added<Window>>>::from_world(app.world_mut());
|
2024-03-03 23:51:53 +00:00
|
|
|
let mut winit_events = Vec::default();
|
2024-01-28 21:09:23 +00:00
|
|
|
// set up the event loop
|
2024-03-04 17:17:17 +00:00
|
|
|
let event_handler = move |event, event_loop: &EventLoopWindowTarget<UserEvent>| {
|
2024-04-22 16:48:18 +00:00
|
|
|
let mut exit_status = handle_exit_status.lock().unwrap();
|
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
handle_winit_event(
|
|
|
|
&mut app,
|
|
|
|
&mut runner_state,
|
|
|
|
&mut create_window,
|
|
|
|
&mut event_writer_system_state,
|
|
|
|
&mut focused_windows_state,
|
|
|
|
&mut redraw_event_reader,
|
2024-03-03 23:51:53 +00:00
|
|
|
&mut winit_events,
|
2024-04-22 16:48:18 +00:00
|
|
|
&mut exit_status,
|
2024-01-28 21:09:23 +00:00
|
|
|
event,
|
|
|
|
event_loop,
|
|
|
|
);
|
|
|
|
};
|
Webgpu support (#8336)
# Objective
- Support WebGPU
- alternative to #5027 that doesn't need any async / await
- fixes #8315
- Surprise fix #7318
## Solution
### For async renderer initialisation
- Update the plugin lifecycle:
- app builds the plugin
- calls `plugin.build`
- registers the plugin
- app starts the event loop
- event loop waits for `ready` of all registered plugins in the same
order
- returns `true` by default
- then call all `finish` then all `cleanup` in the same order as
registered
- then execute the schedule
In the case of the renderer, to avoid anything async:
- building the renderer plugin creates a detached task that will send
back the initialised renderer through a mutex in a resource
- `ready` will wait for the renderer to be present in the resource
- `finish` will take that renderer and place it in the expected
resources by other plugins
- other plugins (that expect the renderer to be available) `finish` are
called and they are able to set up their pipelines
- `cleanup` is called, only custom one is still for pipeline rendering
### For WebGPU support
- update the `build-wasm-example` script to support passing `--api
webgpu` that will build the example with WebGPU support
- feature for webgl2 was always enabled when building for wasm. it's now
in the default feature list and enabled on all platforms, so check for
this feature must also check that the target_arch is `wasm32`
---
## Migration Guide
- `Plugin::setup` has been renamed `Plugin::cleanup`
- `Plugin::finish` has been added, and plugins adding pipelines should
do it in this function instead of `Plugin::build`
```rust
// Before
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app.insert_resource::<MyResource>
.add_systems(Update, my_system);
let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Err(_) => return,
};
render_app
.init_resource::<RenderResourceNeedingDevice>()
.init_resource::<OtherRenderResource>();
}
}
// After
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app.insert_resource::<MyResource>
.add_systems(Update, my_system);
let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Err(_) => return,
};
render_app
.init_resource::<OtherRenderResource>();
}
fn finish(&self, app: &mut App) {
let render_app = match app.get_sub_app_mut(RenderApp) {
Ok(render_app) => render_app,
Err(_) => return,
};
render_app
.init_resource::<RenderResourceNeedingDevice>();
}
}
```
2023-05-04 22:07:57 +00:00
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
trace!("starting winit event loop");
|
|
|
|
// TODO(clean): the winit docs mention using `spawn` instead of `run` on WASM.
|
|
|
|
if let Err(err) = event_loop.run(event_handler) {
|
|
|
|
error!("winit event loop returned an error: {err}");
|
|
|
|
}
|
2024-04-22 16:48:18 +00:00
|
|
|
|
|
|
|
// We should be the only ones holding this `Arc` since the event loop exiting cleanly
|
|
|
|
// should drop the event handler. if this is not the case something funky is happening.
|
|
|
|
Arc::get_mut(&mut exit_status)
|
|
|
|
.map(|mutex| mutex.get_mut().unwrap().clone())
|
|
|
|
.unwrap_or(AppExit::error())
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
#[allow(clippy::too_many_arguments /* TODO: probs can reduce # of args */)]
|
|
|
|
fn handle_winit_event(
|
|
|
|
app: &mut App,
|
|
|
|
runner_state: &mut WinitAppRunnerState,
|
|
|
|
create_window: &mut SystemState<CreateWindowParams<Added<Window>>>,
|
|
|
|
event_writer_system_state: &mut SystemState<(
|
|
|
|
EventWriter<WindowResized>,
|
|
|
|
NonSend<WinitWindows>,
|
|
|
|
Query<(&mut Window, &mut CachedWindow)>,
|
|
|
|
NonSend<AccessKitAdapters>,
|
|
|
|
)>,
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
focused_windows_state: &mut SystemState<(Res<WinitSettings>, Query<(Entity, &Window)>)>,
|
2024-01-28 21:09:23 +00:00
|
|
|
redraw_event_reader: &mut ManualEventReader<RequestRedraw>,
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events: &mut Vec<WinitEvent>,
|
2024-04-22 16:48:18 +00:00
|
|
|
exit_status: &mut AppExit,
|
2024-03-04 17:17:17 +00:00
|
|
|
event: Event<UserEvent>,
|
|
|
|
event_loop: &EventLoopWindowTarget<UserEvent>,
|
2024-01-28 21:09:23 +00:00
|
|
|
) {
|
|
|
|
#[cfg(feature = "trace")]
|
|
|
|
let _span = bevy_utils::tracing::info_span!("winit event_handler").entered();
|
|
|
|
|
|
|
|
if app.plugins_state() != PluginsState::Cleaned {
|
|
|
|
if app.plugins_state() != PluginsState::Ready {
|
|
|
|
#[cfg(not(target_arch = "wasm32"))]
|
|
|
|
tick_global_task_pools_on_main_thread();
|
|
|
|
} else {
|
|
|
|
app.finish();
|
|
|
|
app.cleanup();
|
2023-01-19 00:38:28 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
runner_state.redraw_requested = true;
|
|
|
|
}
|
2024-01-15 15:46:11 +00:00
|
|
|
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
// create any new windows
|
|
|
|
// (even if app did not update, some may have been created by plugin setup)
|
|
|
|
create_windows(event_loop, create_window.get_mut(app.world_mut()));
|
|
|
|
create_window.apply(app.world_mut());
|
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
match event {
|
|
|
|
Event::AboutToWait => {
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
if let Some(app_redraw_events) = app.world().get_resource::<Events<RequestRedraw>>() {
|
|
|
|
if redraw_event_reader.read(app_redraw_events).last().is_some() {
|
|
|
|
runner_state.redraw_requested = true;
|
2023-07-31 21:41:59 +00:00
|
|
|
}
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
let (config, windows) = focused_windows_state.get(app.world());
|
|
|
|
let focused = windows.iter().any(|(_, window)| window.focused);
|
|
|
|
|
|
|
|
let mut update_mode = config.update_mode(focused);
|
|
|
|
let mut should_update = should_update(runner_state, update_mode);
|
2024-01-28 21:09:23 +00:00
|
|
|
|
|
|
|
if runner_state.startup_forced_updates > 0 {
|
|
|
|
runner_state.startup_forced_updates -= 1;
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
// Ensure that an update is triggered on the first iterations for app initialization
|
|
|
|
should_update = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if runner_state.activity_state == UpdateState::WillSuspend {
|
|
|
|
runner_state.activity_state = UpdateState::Suspended;
|
|
|
|
// Trigger one last update to enter the suspended state
|
2024-01-28 21:09:23 +00:00
|
|
|
should_update = true;
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
|
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
{
|
|
|
|
// Remove the `RawHandleWrapper` from the primary window.
|
|
|
|
// This will trigger the surface destruction.
|
|
|
|
let mut query = app
|
|
|
|
.world_mut()
|
|
|
|
.query_filtered::<Entity, With<PrimaryWindow>>();
|
|
|
|
let entity = query.single(&app.world());
|
|
|
|
app.world_mut()
|
|
|
|
.entity_mut(entity)
|
|
|
|
.remove::<RawHandleWrapper>();
|
|
|
|
}
|
2024-01-09 15:41:46 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
if runner_state.activity_state == UpdateState::WillResume {
|
|
|
|
runner_state.activity_state = UpdateState::Active;
|
|
|
|
// Trigger the update to enter the active state
|
2024-01-28 21:09:23 +00:00
|
|
|
should_update = true;
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
// Trigger the next redraw ro refresh the screen immediately
|
|
|
|
runner_state.redraw_requested = true;
|
|
|
|
|
|
|
|
#[cfg(target_os = "android")]
|
|
|
|
{
|
|
|
|
// Get windows that are cached but without raw handles. Those window were already created, but got their
|
|
|
|
// handle wrapper removed when the app was suspended.
|
|
|
|
let mut query = app
|
|
|
|
.world_mut()
|
|
|
|
.query_filtered::<(Entity, &Window), (With<CachedWindow>, Without<bevy_window::RawHandleWrapper>)>();
|
|
|
|
if let Ok((entity, window)) = query.get_single(&app.world()) {
|
|
|
|
let window = window.clone();
|
|
|
|
|
|
|
|
let (
|
|
|
|
..,
|
|
|
|
mut winit_windows,
|
|
|
|
mut adapters,
|
|
|
|
mut handlers,
|
|
|
|
accessibility_requested,
|
|
|
|
) = create_window.get_mut(app.world_mut());
|
|
|
|
|
|
|
|
let winit_window = winit_windows.create_window(
|
|
|
|
event_loop,
|
|
|
|
entity,
|
|
|
|
&window,
|
|
|
|
&mut adapters,
|
|
|
|
&mut handlers,
|
|
|
|
&accessibility_requested,
|
|
|
|
);
|
|
|
|
|
|
|
|
let wrapper = RawHandleWrapper::new(winit_window).unwrap();
|
|
|
|
|
|
|
|
app.world_mut().entity_mut(entity).insert(wrapper);
|
|
|
|
}
|
|
|
|
}
|
2024-01-09 15:41:46 +00:00
|
|
|
}
|
2023-01-19 00:38:28 +00:00
|
|
|
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
// This is recorded before running app.update(), to run the next cycle after a correct timeout.
|
|
|
|
// If the cycle takes more than the wait timeout, it will be re-executed immediately.
|
|
|
|
let begin_frame_time = Instant::now();
|
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
if should_update {
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
// Not redrawing, but the timeout elapsed.
|
|
|
|
run_app_update(runner_state, app, winit_events);
|
|
|
|
|
|
|
|
// Running the app may have changed the WinitSettings resource, so we have to re-extract it.
|
|
|
|
let (config, windows) = focused_windows_state.get(app.world());
|
|
|
|
let focused = windows.iter().any(|(_, window)| window.focused);
|
|
|
|
|
|
|
|
update_mode = config.update_mode(focused);
|
|
|
|
}
|
|
|
|
|
|
|
|
match update_mode {
|
|
|
|
UpdateMode::Continuous => {
|
|
|
|
// per winit's docs on [Window::is_visible](https://docs.rs/winit/latest/winit/window/struct.Window.html#method.is_visible),
|
|
|
|
// we cannot use the visibility to drive rendering on these platforms
|
|
|
|
// so we cannot discern whether to beneficially use `Poll` or not?
|
|
|
|
cfg_if::cfg_if! {
|
|
|
|
if #[cfg(not(any(
|
|
|
|
target_arch = "wasm32",
|
|
|
|
target_os = "android",
|
|
|
|
target_os = "ios",
|
|
|
|
all(target_os = "linux", any(feature = "x11", feature = "wayland"))
|
|
|
|
)))]
|
|
|
|
{
|
|
|
|
let winit_windows = app.world().non_send_resource::<WinitWindows>();
|
|
|
|
let visible = winit_windows.windows.iter().any(|(_, w)| {
|
|
|
|
w.is_visible().unwrap_or(false)
|
|
|
|
});
|
|
|
|
|
|
|
|
event_loop.set_control_flow(if visible {
|
|
|
|
ControlFlow::Wait
|
|
|
|
} else {
|
|
|
|
ControlFlow::Poll
|
|
|
|
});
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
event_loop.set_control_flow(ControlFlow::Wait);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Trigger the next redraw to refresh the screen immediately if waiting
|
|
|
|
if let ControlFlow::Wait = event_loop.control_flow() {
|
|
|
|
runner_state.redraw_requested = true;
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
}
|
|
|
|
UpdateMode::Reactive { wait } | UpdateMode::ReactiveLowPower { wait } => {
|
|
|
|
// Set the next timeout, starting from the instant before running app.update() to avoid frame delays
|
|
|
|
if let Some(next) = begin_frame_time.checked_add(wait) {
|
|
|
|
if runner_state.wait_elapsed {
|
|
|
|
event_loop.set_control_flow(ControlFlow::WaitUntil(next));
|
|
|
|
}
|
2023-11-03 21:37:25 +00:00
|
|
|
}
|
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
|
|
|
|
if update_mode != runner_state.update_mode {
|
|
|
|
// Trigger the next redraw since we're changing the update mode
|
|
|
|
runner_state.redraw_requested = true;
|
|
|
|
runner_state.update_mode = update_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
if runner_state.redraw_requested
|
|
|
|
&& runner_state.activity_state != UpdateState::Suspended
|
|
|
|
{
|
|
|
|
let winit_windows = app.world().non_send_resource::<WinitWindows>();
|
|
|
|
for window in winit_windows.windows.values() {
|
|
|
|
window.request_redraw();
|
|
|
|
}
|
|
|
|
runner_state.redraw_requested = false;
|
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
2024-03-04 19:15:05 +00:00
|
|
|
Event::NewEvents(cause) => {
|
|
|
|
runner_state.wait_elapsed = match cause {
|
|
|
|
StartCause::WaitCancelled {
|
|
|
|
requested_resume: Some(resume),
|
|
|
|
..
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
} => {
|
|
|
|
// If the resume time is not after now, it means that at least the wait timeout
|
|
|
|
// has elapsed.
|
|
|
|
resume <= Instant::now()
|
|
|
|
}
|
2024-03-04 19:15:05 +00:00
|
|
|
_ => true,
|
|
|
|
};
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
Event::WindowEvent {
|
|
|
|
event, window_id, ..
|
|
|
|
} => {
|
|
|
|
let (mut window_resized, winit_windows, mut windows, access_kit_adapters) =
|
2024-03-31 03:16:10 +00:00
|
|
|
event_writer_system_state.get_mut(app.world_mut());
|
2024-01-28 21:09:23 +00:00
|
|
|
|
|
|
|
let Some(window) = winit_windows.get_window_entity(window_id) else {
|
|
|
|
warn!("Skipped event {event:?} for unknown winit Window Id {window_id:?}");
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
let Ok((mut win, _)) = windows.get_mut(window) else {
|
|
|
|
warn!("Window {window:?} is missing `Window` component, skipping event {event:?}");
|
|
|
|
return;
|
|
|
|
};
|
|
|
|
|
|
|
|
// Allow AccessKit to respond to `WindowEvent`s before they reach
|
|
|
|
// the engine.
|
|
|
|
if let Some(adapter) = access_kit_adapters.get(&window) {
|
|
|
|
if let Some(winit_window) = winit_windows.get_window(window) {
|
|
|
|
adapter.process_event(winit_window, &event);
|
|
|
|
}
|
|
|
|
}
|
2023-11-03 21:37:25 +00:00
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
runner_state.window_event_received = true;
|
2020-12-27 19:24:31 +00:00
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
match event {
|
|
|
|
WindowEvent::Resized(size) => {
|
|
|
|
react_to_resize(&mut win, size, &mut window_resized, window);
|
|
|
|
}
|
2024-03-03 23:51:53 +00:00
|
|
|
WindowEvent::CloseRequested => winit_events.send(WindowCloseRequested { window }),
|
2024-01-28 21:09:23 +00:00
|
|
|
WindowEvent::KeyboardInput { ref event, .. } => {
|
|
|
|
if event.state.is_pressed() {
|
|
|
|
if let Some(char) = &event.text {
|
|
|
|
let char = char.clone();
|
2024-04-30 00:49:41 +00:00
|
|
|
#[allow(deprecated)]
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(ReceivedCharacter { window, char });
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
}
|
2020-12-27 19:24:31 +00:00
|
|
|
}
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(converters::convert_keyboard_input(event, window));
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::CursorMoved { position, .. } => {
|
|
|
|
let physical_position = DVec2::new(position.x, position.y);
|
2024-02-12 18:14:22 +00:00
|
|
|
|
|
|
|
let last_position = win.physical_cursor_position();
|
|
|
|
let delta = last_position.map(|last_pos| {
|
|
|
|
(physical_position.as_vec2() - last_pos) / win.resolution.scale_factor()
|
|
|
|
});
|
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
win.set_physical_cursor_position(Some(physical_position));
|
|
|
|
let position =
|
|
|
|
(physical_position / win.resolution.scale_factor() as f64).as_vec2();
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(CursorMoved {
|
2024-02-12 18:14:22 +00:00
|
|
|
window,
|
|
|
|
position,
|
|
|
|
delta,
|
|
|
|
});
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::CursorEntered { .. } => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(CursorEntered { window });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::CursorLeft { .. } => {
|
|
|
|
win.set_physical_cursor_position(None);
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(CursorLeft { window });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::MouseInput { state, button, .. } => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(MouseButtonInput {
|
2024-01-28 21:09:23 +00:00
|
|
|
button: converters::convert_mouse_button(button),
|
|
|
|
state: converters::convert_element_state(state),
|
|
|
|
window,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
WindowEvent::TouchpadMagnify { delta, .. } => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(TouchpadMagnify(delta as f32));
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::TouchpadRotate { delta, .. } => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(TouchpadRotate(delta));
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::MouseWheel { delta, .. } => match delta {
|
|
|
|
event::MouseScrollDelta::LineDelta(x, y) => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(MouseWheel {
|
2024-01-28 21:09:23 +00:00
|
|
|
unit: MouseScrollUnit::Line,
|
|
|
|
x,
|
|
|
|
y,
|
|
|
|
window,
|
2023-01-19 00:38:28 +00:00
|
|
|
});
|
2020-12-27 19:24:31 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
event::MouseScrollDelta::PixelDelta(p) => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(MouseWheel {
|
2024-01-28 21:09:23 +00:00
|
|
|
unit: MouseScrollUnit::Pixel,
|
|
|
|
x: p.x as f32,
|
|
|
|
y: p.y as f32,
|
|
|
|
window,
|
2020-08-21 00:04:01 +00:00
|
|
|
});
|
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
},
|
|
|
|
WindowEvent::Touch(touch) => {
|
|
|
|
let location = touch
|
|
|
|
.location
|
|
|
|
.to_logical(win.resolution.scale_factor() as f64);
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(converters::convert_touch_input(touch, location, window));
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::ScaleFactorChanged {
|
|
|
|
scale_factor,
|
|
|
|
mut inner_size_writer,
|
|
|
|
} => {
|
|
|
|
let prior_factor = win.resolution.scale_factor();
|
|
|
|
win.resolution.set_scale_factor(scale_factor as f32);
|
|
|
|
// Note: this may be different from new_scale_factor if
|
|
|
|
// `scale_factor_override` is set to Some(thing)
|
|
|
|
let new_factor = win.resolution.scale_factor();
|
|
|
|
|
|
|
|
let mut new_inner_size =
|
|
|
|
PhysicalSize::new(win.physical_width(), win.physical_height());
|
|
|
|
let scale_factor_override = win.resolution.scale_factor_override();
|
|
|
|
if let Some(forced_factor) = scale_factor_override {
|
|
|
|
// This window is overriding the OS-suggested DPI, so its physical size
|
|
|
|
// should be set based on the overriding value. Its logical size already
|
|
|
|
// incorporates any resize constraints.
|
|
|
|
let maybe_new_inner_size = LogicalSize::new(win.width(), win.height())
|
|
|
|
.to_physical::<u32>(forced_factor as f64);
|
|
|
|
if let Err(err) = inner_size_writer.request_inner_size(new_inner_size) {
|
|
|
|
warn!("Winit Failed to resize the window: {err}");
|
|
|
|
} else {
|
|
|
|
new_inner_size = maybe_new_inner_size;
|
2020-12-27 19:24:31 +00:00
|
|
|
}
|
2020-11-03 19:32:48 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
let new_logical_width = new_inner_size.width as f32 / new_factor;
|
|
|
|
let new_logical_height = new_inner_size.height as f32 / new_factor;
|
|
|
|
|
|
|
|
let width_equal = relative_eq!(win.width(), new_logical_width);
|
|
|
|
let height_equal = relative_eq!(win.height(), new_logical_height);
|
|
|
|
win.resolution
|
|
|
|
.set_physical_resolution(new_inner_size.width, new_inner_size.height);
|
|
|
|
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(WindowBackendScaleFactorChanged {
|
2024-01-28 21:09:23 +00:00
|
|
|
window,
|
2020-12-27 19:24:31 +00:00
|
|
|
scale_factor,
|
2024-01-28 21:09:23 +00:00
|
|
|
});
|
|
|
|
if scale_factor_override.is_none() && !relative_eq!(new_factor, prior_factor) {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(WindowScaleFactorChanged {
|
2024-01-28 21:09:23 +00:00
|
|
|
window,
|
|
|
|
scale_factor,
|
2020-12-27 19:24:31 +00:00
|
|
|
});
|
2020-12-18 21:08:26 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
|
|
|
|
if !width_equal || !height_equal {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(WindowResized {
|
2024-01-28 21:09:23 +00:00
|
|
|
window,
|
|
|
|
width: new_logical_width,
|
|
|
|
height: new_logical_height,
|
2023-11-26 21:58:54 +00:00
|
|
|
});
|
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::Focused(focused) => {
|
|
|
|
win.focused = focused;
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(WindowFocused { window, focused });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::Occluded(occluded) => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(WindowOccluded { window, occluded });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::DroppedFile(path_buf) => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(FileDragAndDrop::DroppedFile { window, path_buf });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::HoveredFile(path_buf) => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(FileDragAndDrop::HoveredFile { window, path_buf });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::HoveredFileCancelled => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(FileDragAndDrop::HoveredFileCanceled { window });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::Moved(position) => {
|
|
|
|
let position = ivec2(position.x, position.y);
|
|
|
|
win.position.set(position);
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(WindowMoved { window, position });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::Ime(event) => match event {
|
|
|
|
event::Ime::Preedit(value, cursor) => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(Ime::Preedit {
|
2024-01-28 21:09:23 +00:00
|
|
|
window,
|
|
|
|
value,
|
|
|
|
cursor,
|
2021-01-25 04:06:06 +00:00
|
|
|
});
|
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
event::Ime::Commit(value) => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(Ime::Commit { window, value });
|
2023-06-05 21:04:22 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
event::Ime::Enabled => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(Ime::Enabled { window });
|
2023-07-04 21:50:53 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
event::Ime::Disabled => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(Ime::Disabled { window });
|
Fix perf degradation on web builds (#11227)
# Objective
- Since #10702, the way bevy updates the window leads to major slowdowns
as seen in
- #11122
- #11220
- Slow is bad, furthermore, _very_ slow is _very_ bad. We should fix
this issue.
## Solution
- Move the app update code into the `Event::WindowEvent { event:
WindowEvent::RedrawRequested }` branch of the event loop.
- Run `window.request_redraw()` When `runner_state.redraw_requested`
- Instead of swapping `ControlFlow` between `Poll` and `Wait`, we always
keep it at `Wait`, and use `window.request_redraw()` to schedule an
immediate call to the event loop.
- `runner_state.redraw_requested` is set to `true` when
`UpdateMode::Continuous` and when a `RequestRedraw` event is received.
- Extract the redraw code into a separate function, because otherwise
I'd go crazy with the indentation level.
- Fix #11122.
## Testing
I tested the WASM builds as follow:
```sh
cargo run -p build-wasm-example -- --api webgl2 bevymark
python -m http.server --directory examples/wasm/ 8080
# Open browser at http://localhost:8080
```
On main, even spawning a couple sprites is super choppy. Even if it says
"300 FPS". While on this branch, it is smooth as butter.
I also found that it fixes all choppiness on window resize (tested on
Linux/X11). This was another issue from #10702 IIRC.
So here is what I tested:
- On `wasm`: `many_foxes` and `bevymark`, with `argh::from_env()`
commented out, otherwise we get a cryptic error.
- Both with `PresentMode::AutoVsync` and `PresentMode::AutoNoVsync`
- On main, it is consistently choppy.
- With this PR, the visible frame rate is consistent with the diagnostic
numbers
- On native (linux/x11) I ran similar tests, making sure that
`AutoVsync` limits to monitor framerate, and `AutoNoVsync` doesn't.
## Future work
Code could be improved, I wanted a quick solution easy to review, but we
really need to make the code more accessible.
- #9768
- ~~**`WinitSettings::desktop_app()` is completely borked.**~~ actually
broken on main as well
### Review guide
Consider enable the non-whitespace diff to see the _real_ change set.
2024-01-06 19:40:13 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
},
|
|
|
|
WindowEvent::ThemeChanged(theme) => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(WindowThemeChanged {
|
2024-01-28 21:09:23 +00:00
|
|
|
window,
|
|
|
|
theme: convert_winit_theme(theme),
|
|
|
|
});
|
2020-12-07 21:24:25 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
WindowEvent::Destroyed => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(WindowDestroyed { window });
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
WindowEvent::RedrawRequested => {
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
run_app_update(runner_state, app, winit_events);
|
2023-02-07 14:18:13 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
_ => {}
|
2020-12-27 19:24:31 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
|
2024-03-31 03:16:10 +00:00
|
|
|
let mut windows = app.world_mut().query::<(&mut Window, &mut CachedWindow)>();
|
|
|
|
if let Ok((window_component, mut cache)) = windows.get_mut(app.world_mut(), window) {
|
2024-01-28 21:09:23 +00:00
|
|
|
if window_component.is_changed() {
|
|
|
|
cache.window = window_component.clone();
|
2024-01-15 15:46:11 +00:00
|
|
|
}
|
2020-08-16 07:30:04 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
Event::DeviceEvent { event, .. } => {
|
|
|
|
runner_state.device_event_received = true;
|
|
|
|
if let DeviceEvent::MouseMotion { delta: (x, y) } = event {
|
|
|
|
let delta = Vec2::new(x as f32, y as f32);
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(MouseMotion { delta });
|
2021-07-16 00:50:39 +00:00
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
Event::Suspended => {
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events.send(ApplicationLifetime::Suspended);
|
2024-01-28 21:09:23 +00:00
|
|
|
// Mark the state as `WillSuspend`. This will let the schedule run one last time
|
|
|
|
// before actually suspending to let the application react
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
runner_state.activity_state = UpdateState::WillSuspend;
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
|
|
|
Event::Resumed => {
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
match runner_state.activity_state {
|
|
|
|
UpdateState::NotYetStarted => winit_events.send(ApplicationLifetime::Started),
|
2024-03-03 23:51:53 +00:00
|
|
|
_ => winit_events.send(ApplicationLifetime::Resumed),
|
2024-01-28 21:09:23 +00:00
|
|
|
}
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
runner_state.activity_state = UpdateState::WillResume;
|
Fix perf degradation on web builds (#11227)
# Objective
- Since #10702, the way bevy updates the window leads to major slowdowns
as seen in
- #11122
- #11220
- Slow is bad, furthermore, _very_ slow is _very_ bad. We should fix
this issue.
## Solution
- Move the app update code into the `Event::WindowEvent { event:
WindowEvent::RedrawRequested }` branch of the event loop.
- Run `window.request_redraw()` When `runner_state.redraw_requested`
- Instead of swapping `ControlFlow` between `Poll` and `Wait`, we always
keep it at `Wait`, and use `window.request_redraw()` to schedule an
immediate call to the event loop.
- `runner_state.redraw_requested` is set to `true` when
`UpdateMode::Continuous` and when a `RequestRedraw` event is received.
- Extract the redraw code into a separate function, because otherwise
I'd go crazy with the indentation level.
- Fix #11122.
## Testing
I tested the WASM builds as follow:
```sh
cargo run -p build-wasm-example -- --api webgl2 bevymark
python -m http.server --directory examples/wasm/ 8080
# Open browser at http://localhost:8080
```
On main, even spawning a couple sprites is super choppy. Even if it says
"300 FPS". While on this branch, it is smooth as butter.
I also found that it fixes all choppiness on window resize (tested on
Linux/X11). This was another issue from #10702 IIRC.
So here is what I tested:
- On `wasm`: `many_foxes` and `bevymark`, with `argh::from_env()`
commented out, otherwise we get a cryptic error.
- Both with `PresentMode::AutoVsync` and `PresentMode::AutoNoVsync`
- On main, it is consistently choppy.
- With this PR, the visible frame rate is consistent with the diagnostic
numbers
- On native (linux/x11) I ran similar tests, making sure that
`AutoVsync` limits to monitor framerate, and `AutoNoVsync` doesn't.
## Future work
Code could be improved, I wanted a quick solution easy to review, but we
really need to make the code more accessible.
- #9768
- ~~**`WinitSettings::desktop_app()` is completely borked.**~~ actually
broken on main as well
### Review guide
Consider enable the non-whitespace diff to see the _real_ change set.
2024-01-06 19:40:13 +00:00
|
|
|
}
|
2024-03-04 17:17:17 +00:00
|
|
|
Event::UserEvent(RequestRedraw) => {
|
|
|
|
runner_state.redraw_requested = true;
|
|
|
|
}
|
2024-01-28 21:09:23 +00:00
|
|
|
_ => (),
|
Fix perf degradation on web builds (#11227)
# Objective
- Since #10702, the way bevy updates the window leads to major slowdowns
as seen in
- #11122
- #11220
- Slow is bad, furthermore, _very_ slow is _very_ bad. We should fix
this issue.
## Solution
- Move the app update code into the `Event::WindowEvent { event:
WindowEvent::RedrawRequested }` branch of the event loop.
- Run `window.request_redraw()` When `runner_state.redraw_requested`
- Instead of swapping `ControlFlow` between `Poll` and `Wait`, we always
keep it at `Wait`, and use `window.request_redraw()` to schedule an
immediate call to the event loop.
- `runner_state.redraw_requested` is set to `true` when
`UpdateMode::Continuous` and when a `RequestRedraw` event is received.
- Extract the redraw code into a separate function, because otherwise
I'd go crazy with the indentation level.
- Fix #11122.
## Testing
I tested the WASM builds as follow:
```sh
cargo run -p build-wasm-example -- --api webgl2 bevymark
python -m http.server --directory examples/wasm/ 8080
# Open browser at http://localhost:8080
```
On main, even spawning a couple sprites is super choppy. Even if it says
"300 FPS". While on this branch, it is smooth as butter.
I also found that it fixes all choppiness on window resize (tested on
Linux/X11). This was another issue from #10702 IIRC.
So here is what I tested:
- On `wasm`: `many_foxes` and `bevymark`, with `argh::from_env()`
commented out, otherwise we get a cryptic error.
- Both with `PresentMode::AutoVsync` and `PresentMode::AutoNoVsync`
- On main, it is consistently choppy.
- With this PR, the visible frame rate is consistent with the diagnostic
numbers
- On native (linux/x11) I ran similar tests, making sure that
`AutoVsync` limits to monitor framerate, and `AutoNoVsync` doesn't.
## Future work
Code could be improved, I wanted a quick solution easy to review, but we
really need to make the code more accessible.
- #9768
- ~~**`WinitSettings::desktop_app()` is completely borked.**~~ actually
broken on main as well
### Review guide
Consider enable the non-whitespace diff to see the _real_ change set.
2024-01-06 19:40:13 +00:00
|
|
|
}
|
2024-03-03 23:51:53 +00:00
|
|
|
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
if let Some(app_exit) = app.should_exit() {
|
|
|
|
*exit_status = app_exit;
|
|
|
|
event_loop.exit();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-03-03 23:51:53 +00:00
|
|
|
// We drain events after every received winit event in addition to on app update to ensure
|
|
|
|
// the work of pushing events into event queues is spread out over time in case the app becomes
|
|
|
|
// dormant for a long stretch.
|
|
|
|
forward_winit_events(winit_events, app);
|
Fix perf degradation on web builds (#11227)
# Objective
- Since #10702, the way bevy updates the window leads to major slowdowns
as seen in
- #11122
- #11220
- Slow is bad, furthermore, _very_ slow is _very_ bad. We should fix
this issue.
## Solution
- Move the app update code into the `Event::WindowEvent { event:
WindowEvent::RedrawRequested }` branch of the event loop.
- Run `window.request_redraw()` When `runner_state.redraw_requested`
- Instead of swapping `ControlFlow` between `Poll` and `Wait`, we always
keep it at `Wait`, and use `window.request_redraw()` to schedule an
immediate call to the event loop.
- `runner_state.redraw_requested` is set to `true` when
`UpdateMode::Continuous` and when a `RequestRedraw` event is received.
- Extract the redraw code into a separate function, because otherwise
I'd go crazy with the indentation level.
- Fix #11122.
## Testing
I tested the WASM builds as follow:
```sh
cargo run -p build-wasm-example -- --api webgl2 bevymark
python -m http.server --directory examples/wasm/ 8080
# Open browser at http://localhost:8080
```
On main, even spawning a couple sprites is super choppy. Even if it says
"300 FPS". While on this branch, it is smooth as butter.
I also found that it fixes all choppiness on window resize (tested on
Linux/X11). This was another issue from #10702 IIRC.
So here is what I tested:
- On `wasm`: `many_foxes` and `bevymark`, with `argh::from_env()`
commented out, otherwise we get a cryptic error.
- Both with `PresentMode::AutoVsync` and `PresentMode::AutoNoVsync`
- On main, it is consistently choppy.
- With this PR, the visible frame rate is consistent with the diagnostic
numbers
- On native (linux/x11) I ran similar tests, making sure that
`AutoVsync` limits to monitor framerate, and `AutoNoVsync` doesn't.
## Future work
Code could be improved, I wanted a quick solution easy to review, but we
really need to make the code more accessible.
- #9768
- ~~**`WinitSettings::desktop_app()` is completely borked.**~~ actually
broken on main as well
### Review guide
Consider enable the non-whitespace diff to see the _real_ change set.
2024-01-06 19:40:13 +00:00
|
|
|
}
|
2023-07-31 21:41:59 +00:00
|
|
|
|
fix: rewrite winit loop (#12669)
# Objective
- Simplifies/clarifies the winit loop.
- Fixes #12612.
## Solution
The Winit loop runs following this flow:
* NewEvents
* Any number of other events, that can be 0, including RequestRedraw
* AboutToWait
Bevy also uses the UpdateMode, to define how the next loop has to run.
It can be essentially:
* Continuous, using ControlFlow::Wait for windowed apps, and
ControlFlow::Poll for windowless apps
* Reactive/ReactiveLowPower, using ControlFlow::WaitUntil with a
specific wait delay
The changes are made to follow this pattern, so that
* NewEvents define if the WaitUntil has been canceled because we
received a Winit event.
* AboutToWait:
* checks if the window has to be redrawn
* otherwise calls app.update() if the WaitUntil timeout has elapsed
* updates the ControlFlow accordingly
To make the code more logical:
* AboutToWait checks if any Bevy's RequestRedraw event has been emitted
* create_windows is run every cycle, at the beginning of the loop
* the ActiveState (that could be renamed ActivityState) is updated in
AboutToWait, symmetrically for WillSuspend/WillResume
* the AppExit events are checked every loop cycle, to exit the app early
## Platform-specific testing
- [x] Windows
- [x] MacOs
- [x] Linux (x11)
- [x] Linux (Wayland)
- [x] Android
- [x] iOS
- [x] WASM/WebGL2 (Chrome)
- [x] WASM/WebGL2 (Firefox)
- [x] WASM/WebGL2 (Safari)
- [x] WASM/WebGpu (Chrome)
---------
Co-authored-by: François <francois.mockers@vleue.com>
2024-05-02 19:57:19 +00:00
|
|
|
fn should_update(runner_state: &WinitAppRunnerState, update_mode: UpdateMode) -> bool {
|
|
|
|
let handle_event = match update_mode {
|
|
|
|
UpdateMode::Continuous | UpdateMode::Reactive { .. } => {
|
|
|
|
runner_state.wait_elapsed
|
|
|
|
|| runner_state.window_event_received
|
|
|
|
|| runner_state.device_event_received
|
|
|
|
}
|
|
|
|
UpdateMode::ReactiveLowPower { .. } => {
|
|
|
|
runner_state.wait_elapsed || runner_state.window_event_received
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
handle_event && runner_state.activity_state.is_active()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn run_app_update(
|
Fix perf degradation on web builds (#11227)
# Objective
- Since #10702, the way bevy updates the window leads to major slowdowns
as seen in
- #11122
- #11220
- Slow is bad, furthermore, _very_ slow is _very_ bad. We should fix
this issue.
## Solution
- Move the app update code into the `Event::WindowEvent { event:
WindowEvent::RedrawRequested }` branch of the event loop.
- Run `window.request_redraw()` When `runner_state.redraw_requested`
- Instead of swapping `ControlFlow` between `Poll` and `Wait`, we always
keep it at `Wait`, and use `window.request_redraw()` to schedule an
immediate call to the event loop.
- `runner_state.redraw_requested` is set to `true` when
`UpdateMode::Continuous` and when a `RequestRedraw` event is received.
- Extract the redraw code into a separate function, because otherwise
I'd go crazy with the indentation level.
- Fix #11122.
## Testing
I tested the WASM builds as follow:
```sh
cargo run -p build-wasm-example -- --api webgl2 bevymark
python -m http.server --directory examples/wasm/ 8080
# Open browser at http://localhost:8080
```
On main, even spawning a couple sprites is super choppy. Even if it says
"300 FPS". While on this branch, it is smooth as butter.
I also found that it fixes all choppiness on window resize (tested on
Linux/X11). This was another issue from #10702 IIRC.
So here is what I tested:
- On `wasm`: `many_foxes` and `bevymark`, with `argh::from_env()`
commented out, otherwise we get a cryptic error.
- Both with `PresentMode::AutoVsync` and `PresentMode::AutoNoVsync`
- On main, it is consistently choppy.
- With this PR, the visible frame rate is consistent with the diagnostic
numbers
- On native (linux/x11) I ran similar tests, making sure that
`AutoVsync` limits to monitor framerate, and `AutoNoVsync` doesn't.
## Future work
Code could be improved, I wanted a quick solution easy to review, but we
really need to make the code more accessible.
- #9768
- ~~**`WinitSettings::desktop_app()` is completely borked.**~~ actually
broken on main as well
### Review guide
Consider enable the non-whitespace diff to see the _real_ change set.
2024-01-06 19:40:13 +00:00
|
|
|
runner_state: &mut WinitAppRunnerState,
|
|
|
|
app: &mut App,
|
2024-03-03 23:51:53 +00:00
|
|
|
winit_events: &mut Vec<WinitEvent>,
|
Fix perf degradation on web builds (#11227)
# Objective
- Since #10702, the way bevy updates the window leads to major slowdowns
as seen in
- #11122
- #11220
- Slow is bad, furthermore, _very_ slow is _very_ bad. We should fix
this issue.
## Solution
- Move the app update code into the `Event::WindowEvent { event:
WindowEvent::RedrawRequested }` branch of the event loop.
- Run `window.request_redraw()` When `runner_state.redraw_requested`
- Instead of swapping `ControlFlow` between `Poll` and `Wait`, we always
keep it at `Wait`, and use `window.request_redraw()` to schedule an
immediate call to the event loop.
- `runner_state.redraw_requested` is set to `true` when
`UpdateMode::Continuous` and when a `RequestRedraw` event is received.
- Extract the redraw code into a separate function, because otherwise
I'd go crazy with the indentation level.
- Fix #11122.
## Testing
I tested the WASM builds as follow:
```sh
cargo run -p build-wasm-example -- --api webgl2 bevymark
python -m http.server --directory examples/wasm/ 8080
# Open browser at http://localhost:8080
```
On main, even spawning a couple sprites is super choppy. Even if it says
"300 FPS". While on this branch, it is smooth as butter.
I also found that it fixes all choppiness on window resize (tested on
Linux/X11). This was another issue from #10702 IIRC.
So here is what I tested:
- On `wasm`: `many_foxes` and `bevymark`, with `argh::from_env()`
commented out, otherwise we get a cryptic error.
- Both with `PresentMode::AutoVsync` and `PresentMode::AutoNoVsync`
- On main, it is consistently choppy.
- With this PR, the visible frame rate is consistent with the diagnostic
numbers
- On native (linux/x11) I ran similar tests, making sure that
`AutoVsync` limits to monitor framerate, and `AutoNoVsync` doesn't.
## Future work
Code could be improved, I wanted a quick solution easy to review, but we
really need to make the code more accessible.
- #9768
- ~~**`WinitSettings::desktop_app()` is completely borked.**~~ actually
broken on main as well
### Review guide
Consider enable the non-whitespace diff to see the _real_ change set.
2024-01-06 19:40:13 +00:00
|
|
|
) {
|
2024-01-15 15:46:11 +00:00
|
|
|
runner_state.reset_on_update();
|
|
|
|
|
2024-03-03 23:51:53 +00:00
|
|
|
forward_winit_events(winit_events, app);
|
|
|
|
|
2024-01-15 15:46:11 +00:00
|
|
|
if app.plugins_state() == PluginsState::Cleaned {
|
Fix perf degradation on web builds (#11227)
# Objective
- Since #10702, the way bevy updates the window leads to major slowdowns
as seen in
- #11122
- #11220
- Slow is bad, furthermore, _very_ slow is _very_ bad. We should fix
this issue.
## Solution
- Move the app update code into the `Event::WindowEvent { event:
WindowEvent::RedrawRequested }` branch of the event loop.
- Run `window.request_redraw()` When `runner_state.redraw_requested`
- Instead of swapping `ControlFlow` between `Poll` and `Wait`, we always
keep it at `Wait`, and use `window.request_redraw()` to schedule an
immediate call to the event loop.
- `runner_state.redraw_requested` is set to `true` when
`UpdateMode::Continuous` and when a `RequestRedraw` event is received.
- Extract the redraw code into a separate function, because otherwise
I'd go crazy with the indentation level.
- Fix #11122.
## Testing
I tested the WASM builds as follow:
```sh
cargo run -p build-wasm-example -- --api webgl2 bevymark
python -m http.server --directory examples/wasm/ 8080
# Open browser at http://localhost:8080
```
On main, even spawning a couple sprites is super choppy. Even if it says
"300 FPS". While on this branch, it is smooth as butter.
I also found that it fixes all choppiness on window resize (tested on
Linux/X11). This was another issue from #10702 IIRC.
So here is what I tested:
- On `wasm`: `many_foxes` and `bevymark`, with `argh::from_env()`
commented out, otherwise we get a cryptic error.
- Both with `PresentMode::AutoVsync` and `PresentMode::AutoNoVsync`
- On main, it is consistently choppy.
- With this PR, the visible frame rate is consistent with the diagnostic
numbers
- On native (linux/x11) I ran similar tests, making sure that
`AutoVsync` limits to monitor framerate, and `AutoNoVsync` doesn't.
## Future work
Code could be improved, I wanted a quick solution easy to review, but we
really need to make the code more accessible.
- #9768
- ~~**`WinitSettings::desktop_app()` is completely borked.**~~ actually
broken on main as well
### Review guide
Consider enable the non-whitespace diff to see the _real_ change set.
2024-01-06 19:40:13 +00:00
|
|
|
app.update();
|
2020-08-21 05:37:19 +00:00
|
|
|
}
|
2020-03-29 07:53:47 +00:00
|
|
|
}
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
|
|
|
|
fn react_to_resize(
|
2024-01-28 21:09:23 +00:00
|
|
|
win: &mut Mut<'_, Window>,
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
size: winit::dpi::PhysicalSize<u32>,
|
2024-01-28 21:09:23 +00:00
|
|
|
window_resized: &mut EventWriter<WindowResized>,
|
|
|
|
window: Entity,
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
) {
|
2024-01-28 21:09:23 +00:00
|
|
|
win.resolution
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
.set_physical_resolution(size.width, size.height);
|
|
|
|
|
2024-01-28 21:09:23 +00:00
|
|
|
window_resized.send(WindowResized {
|
|
|
|
window,
|
|
|
|
width: win.width(),
|
|
|
|
height: win.height(),
|
Update winit dependency to 0.29 (#10702)
# Objective
- Update winit dependency to 0.29
## Changelog
### KeyCode changes
- Removed `ScanCode`, as it was [replaced by
KeyCode](https://github.com/rust-windowing/winit/blob/master/CHANGELOG.md#0292).
- `ReceivedCharacter.char` is now a `SmolStr`, [relevant
doc](https://docs.rs/winit/latest/winit/event/struct.KeyEvent.html#structfield.text).
- Changed most `KeyCode` values, and added more.
KeyCode has changed meaning. With this PR, it refers to physical
position on keyboard rather than the printed letter on keyboard keys.
In practice this means:
- On QWERTY keyboard layouts, nothing changes
- On any other keyboard layout, `KeyCode` no longer reflects the label
on key.
- This is "good". In bevy 0.12, when you used WASD for movement, users
with non-QWERTY keyboards couldn't play your game! This was especially
bad for non-latin keyboards. Now, WASD represents the physical keys. A
French player will press the ZQSD keys, which are near each other,
Kyrgyz players will use "Цфыв".
- This is "bad" as well. You can't know in advance what the label of the
key for input is. Your UI says "press WASD to move", even if in reality,
they should be pressing "ZQSD" or "Цфыв". You also no longer can use
`KeyCode` for text inputs. In any case, it was a pretty bad API for text
input. You should use `ReceivedCharacter` now instead.
### Other changes
- Use `web-time` rather than `instant` crate.
(https://github.com/rust-windowing/winit/pull/2836)
- winit did split `run_return` in `run_onDemand` and `pump_events`, I
did the same change in bevy_winit and used `pump_events`.
- Removed `return_from_run` from `WinitSettings` as `winit::run` now
returns on supported platforms.
- I left the example "return_after_run" as I think it's still useful.
- This winit change is done partly to allow to create a new window after
quitting all windows: https://github.com/emilk/egui/issues/1918 ; this
PR doesn't address.
- added `width` and `height` properties in the `canvas` from wasm
example
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1420567168)
## Known regressions (important follow ups?)
- Provide an API for reacting when a specific key from current layout
was released.
- possible solutions: use winit::Key from winit::KeyEvent ; mapping
between KeyCode and Key ; or .
- We don't receive characters through alt+numpad (e.g. alt + 151 = "ù")
anymore ; reproduced on winit example "ime". maybe related to
https://github.com/rust-windowing/winit/issues/2945
- (windows) Window content doesn't refresh at all when resizing. By
reading https://github.com/rust-windowing/winit/issues/2900 ; I suspect
we should just fire a `window.request_redraw();` from `AboutToWait`, and
handle actual redrawing within `RedrawRequested`. I'm not sure how to
move all that code so I'd appreciate it to be a follow up.
- (windows) unreleased winit fix for using set_control_flow in
AboutToWait https://github.com/rust-windowing/winit/issues/3215 ; ⚠️ I'm
not sure what the implications are, but that feels bad 🤔
## Follow up
I'd like to avoid bloating this PR, here are a few follow up tasks
worthy of a separate PR, or new issue to track them once this PR is
closed, as they would either complicate reviews, or at risk of being
controversial:
- remove CanvasParentResizePlugin
(https://github.com/bevyengine/bevy/pull/10702#discussion_r1417068856)
- avoid mentionning explicitly winit in docs from bevy_window ?
- NamedKey integration on bevy_input:
https://github.com/rust-windowing/winit/pull/3143 introduced a new
NamedKey variant. I implemented it only on the converters but we'd
benefit making the same changes to bevy_input.
- Add more info in KeyboardInput
https://github.com/bevyengine/bevy/pull/10702#pullrequestreview-1748336313
- https://github.com/bevyengine/bevy/pull/9905 added a workaround on a
bug allegedly fixed by winit 0.29. We should check if it's still
necessary.
- update to raw_window_handle 0.6
- blocked by wgpu
- Rename `KeyCode` to `PhysicalKeyCode`
https://github.com/bevyengine/bevy/pull/10702#discussion_r1404595015
- remove `instant` dependency, [replaced
by](https://github.com/rust-windowing/winit/pull/2836) `web_time`), we'd
need to update to :
- fastrand >= 2.0
- [`async-executor`](https://github.com/smol-rs/async-executor) >= 1.7
- [`futures-lite`](https://github.com/smol-rs/futures-lite) >= 2.0
- Verify license, see
[discussion](https://github.com/bevyengine/bevy/pull/8745#discussion_r1402439800)
- we might be missing a short notice or description of changes made
- Consider using https://github.com/rust-windowing/cursor-icon directly
rather than vendoring it in bevy.
- investigate [this
unwrap](https://github.com/bevyengine/bevy/pull/8745#discussion_r1387044986)
(`winit_window.canvas().unwrap();`)
- Use more good things about winit's update
- https://github.com/bevyengine/bevy/pull/10689#issuecomment-1823560428
## Migration Guide
This PR should have one.
2023-12-21 07:40:47 +00:00
|
|
|
});
|
|
|
|
}
|