Skip to content

Commit f69f132

Browse files
committed
Fix Window feedback loop between the OS and Bevy (#7517)
# Objective Fix #7377 Fix #7513 ## Solution Record the changes made to the Bevy `Window` from `winit` as 'canon' to avoid Bevy sending those changes back to `winit` again, causing a feedback loop. ## Changelog * Removed `ModifiesWindows` system label. Neither `despawn_window` nor `changed_window` actually modify the `Window` component so all the `.after(ModifiesWindows)` shouldn't be necessary. * Moved `changed_window` and `despawn_window` systems to `CoreStage::Last` to avoid systems making changes to the `Window` between `changed_window` and the end of the frame as they would be ignored. ## Migration Guide The `ModifiesWindows` system label was removed. Co-authored-by: devil-ira <justthecooldude@gmail.com>
1 parent 6314f50 commit f69f132

File tree

7 files changed

+49
-83
lines changed

7 files changed

+49
-83
lines changed

crates/bevy_pbr/src/lib.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@ mod render;
1111

1212
pub use alpha::*;
1313
use bevy_transform::TransformSystem;
14-
use bevy_window::ModifiesWindows;
1514
pub use bundle::*;
1615
pub use fog::*;
1716
pub use light::*;
@@ -199,8 +198,7 @@ impl Plugin for PbrPlugin {
199198
.in_set(SimulationLightSystems::AssignLightsToClusters)
200199
.after(TransformSystem::TransformPropagate)
201200
.after(VisibilitySystems::CheckVisibility)
202-
.after(CameraUpdateSystem)
203-
.after(ModifiesWindows),
201+
.after(CameraUpdateSystem),
204202
)
205203
.add_system(
206204
update_directional_light_cascades

crates/bevy_render/src/camera/projection.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ use bevy_reflect::{
77
std_traits::ReflectDefault, FromReflect, GetTypeRegistration, Reflect, ReflectDeserialize,
88
ReflectSerialize,
99
};
10-
use bevy_window::ModifiesWindows;
1110
use serde::{Deserialize, Serialize};
1211

1312
/// Adds [`Camera`](crate::camera::Camera) driver systems for a given projection type.
@@ -43,7 +42,6 @@ impl<T: CameraProjection + Component + GetTypeRegistration> Plugin for CameraPro
4342
.add_system(
4443
crate::camera::camera_system::<T>
4544
.in_set(CameraUpdateSystem)
46-
.after(ModifiesWindows)
4745
// We assume that each camera will only have one projection,
4846
// so we can ignore ambiguities with all other monomorphizations.
4947
// FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481.

crates/bevy_text/src/lib.rs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@ use bevy_asset::AddAsset;
2828
use bevy_ecs::prelude::*;
2929
use bevy_render::{camera::CameraUpdateSystem, ExtractSchedule, RenderApp};
3030
use bevy_sprite::SpriteSystem;
31-
use bevy_window::ModifiesWindows;
3231
use std::num::NonZeroUsize;
3332

3433
#[derive(Default)]
@@ -83,7 +82,6 @@ impl Plugin for TextPlugin {
8382
.add_system(
8483
update_text2d_layout
8584
.in_base_set(CoreSet::PostUpdate)
86-
.after(ModifiesWindows)
8785
// Potential conflict: `Assets<Image>`
8886
// In practice, they run independently since `bevy_render::camera_update_system`
8987
// will only ever observe its own render target, and `update_text2d_layout`

crates/bevy_ui/src/lib.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,6 @@ use bevy_app::prelude::*;
3434
use bevy_ecs::prelude::*;
3535
use bevy_input::InputSystem;
3636
use bevy_transform::TransformSystem;
37-
use bevy_window::ModifiesWindows;
3837
use stack::ui_stack_system;
3938
pub use stack::UiStack;
4039
use update::update_clipping_system;
@@ -110,7 +109,6 @@ impl Plugin for UiPlugin {
110109
widget::text_system
111110
.in_base_set(CoreSet::PostUpdate)
112111
.before(UiSystem::Flex)
113-
.after(ModifiesWindows)
114112
// Potential conflict: `Assets<Image>`
115113
// In practice, they run independently since `bevy_render::camera_update_system`
116114
// will only ever observe its own render target, and `widget::text_system`
@@ -135,8 +133,7 @@ impl Plugin for UiPlugin {
135133
.add_system(
136134
flex_node_system
137135
.in_set(UiSystem::Flex)
138-
.before(TransformSystem::TransformPropagate)
139-
.after(ModifiesWindows),
136+
.before(TransformSystem::TransformPropagate),
140137
)
141138
.add_system(ui_stack_system.in_set(UiSystem::Stack))
142139
.add_system(

crates/bevy_window/src/lib.rs

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,9 +137,6 @@ impl Plugin for WindowPlugin {
137137
}
138138
}
139139

140-
#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
141-
pub struct ModifiesWindows;
142-
143140
/// Defines the specific conditions the application should exit on
144141
#[derive(Clone)]
145142
pub enum ExitCondition {

crates/bevy_winit/src/lib.rs

Lines changed: 11 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod winit_config;
66
mod winit_windows;
77

88
use bevy_ecs::system::{SystemParam, SystemState};
9-
use system::{changed_window, create_window, despawn_window};
9+
use system::{changed_window, create_window, despawn_window, CachedWindow};
1010

1111
pub use winit_config::*;
1212
pub use winit_windows::*;
@@ -26,7 +26,7 @@ use bevy_utils::{
2626
};
2727
use bevy_window::{
2828
exit_on_all_closed, CursorEntered, CursorLeft, CursorMoved, FileDragAndDrop, Ime,
29-
ModifiesWindows, ReceivedCharacter, RequestRedraw, Window, WindowBackendScaleFactorChanged,
29+
ReceivedCharacter, RequestRedraw, Window, WindowBackendScaleFactorChanged,
3030
WindowCloseRequested, WindowCreated, WindowFocused, WindowMoved, WindowResized,
3131
WindowScaleFactorChanged,
3232
};
@@ -39,7 +39,6 @@ use winit::{
3939
event_loop::{ControlFlow, EventLoop, EventLoopBuilder, EventLoopWindowTarget},
4040
};
4141

42-
use crate::system::WinitWindowInfo;
4342
#[cfg(target_arch = "wasm32")]
4443
use crate::web_resize::{CanvasParentResizeEventChannel, CanvasParentResizePlugin};
4544

@@ -70,7 +69,6 @@ impl Plugin for WinitPlugin {
7069
app.init_non_send_resource::<WinitWindows>()
7170
.init_resource::<WinitSettings>()
7271
.set_runner(winit_runner)
73-
.configure_set(ModifiesWindows.in_base_set(CoreSet::PostUpdate))
7472
// exit_on_all_closed only uses the query to determine if the query is empty,
7573
// and so doesn't care about ordering relative to changed_window
7674
.add_systems(
@@ -79,7 +77,7 @@ impl Plugin for WinitPlugin {
7977
// Update the state of the window before attempting to despawn to ensure consistent event ordering
8078
despawn_window.after(changed_window),
8179
)
82-
.in_set(ModifiesWindows),
80+
.in_base_set(CoreSet::Last),
8381
);
8482

8583
#[cfg(target_arch = "wasm32")]
@@ -349,7 +347,7 @@ pub fn winit_runner(mut app: App) {
349347
// Fetch and prepare details from the world
350348
let mut system_state: SystemState<(
351349
NonSend<WinitWindows>,
352-
Query<(&mut Window, &mut WinitWindowInfo)>,
350+
Query<(&mut Window, &mut CachedWindow)>,
353351
WindowEvents,
354352
InputEvents,
355353
CursorEvents,
@@ -376,7 +374,7 @@ pub fn winit_runner(mut app: App) {
376374
return;
377375
};
378376

379-
let (mut window, mut info) =
377+
let (mut window, mut cache) =
380378
if let Ok((window, info)) = window_query.get_mut(window_entity) {
381379
(window, info)
382380
} else {
@@ -394,7 +392,6 @@ pub fn winit_runner(mut app: App) {
394392
window
395393
.resolution
396394
.set_physical_resolution(size.width, size.height);
397-
info.last_winit_size = size;
398395

399396
window_events.window_resized.send(WindowResized {
400397
window: window_entity,
@@ -421,11 +418,7 @@ pub fn winit_runner(mut app: App) {
421418
window.resolution.physical_height() as f64 - position.y,
422419
);
423420

424-
// bypassing change detection to not trigger feedback loop with system `changed_window`
425-
// this system change the cursor position in winit
426-
window
427-
.bypass_change_detection()
428-
.set_physical_cursor_position(Some(physical_position));
421+
window.set_physical_cursor_position(Some(physical_position));
429422

430423
cursor_events.cursor_moved.send(CursorMoved {
431424
window: window_entity,
@@ -439,14 +432,7 @@ pub fn winit_runner(mut app: App) {
439432
});
440433
}
441434
WindowEvent::CursorLeft { .. } => {
442-
// Component
443-
if let Ok((mut window, _)) = window_query.get_mut(window_entity) {
444-
// bypassing change detection to not trigger feedback loop with system `changed_window`
445-
// this system change the cursor position in winit
446-
window
447-
.bypass_change_detection()
448-
.set_physical_cursor_position(None);
449-
}
435+
window.set_physical_cursor_position(None);
450436

451437
cursor_events.cursor_left.send(CursorLeft {
452438
window: window_entity,
@@ -594,6 +580,10 @@ pub fn winit_runner(mut app: App) {
594580
},
595581
_ => {}
596582
}
583+
584+
if window.is_changed() {
585+
cache.window = window.clone();
586+
}
597587
}
598588
event::Event::DeviceEvent {
599589
event: DeviceEvent::MouseMotion { delta: (x, y) },

0 commit comments

Comments
 (0)