make sure windows are dropped on main thread (#13686)

# Objective

- On macOS, closing a window by respawning its entity freezes

## Solution

- `WindowWrapper` is keeping an `Arc` of the window, to be able to
access it from the rendering thread. Winit windows are closed when they
are dropped. This need to happen on the main thread on macOS
- Dropping it as soon as the window is closed means the last remaining
`Arc` will be in the rendering thread
- This PR keeps the `Arc` for one frame in the rendering thread before
actually dropping it
This commit is contained in:
François Mockers 2024-06-05 20:13:59 +02:00 committed by GitHub
parent 38d3833c83
commit 519abbca11
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -4,12 +4,12 @@ use bevy_ecs::{
prelude::{Changed, Component},
query::QueryFilter,
removal_detection::RemovedComponents,
system::{NonSendMut, Query, SystemParamItem},
system::{Local, NonSendMut, Query, SystemParamItem},
};
use bevy_utils::tracing::{error, info, warn};
use bevy_window::{
ClosingWindow, RawHandleWrapper, Window, WindowClosed, WindowClosing, WindowCreated,
WindowMode, WindowResized,
WindowMode, WindowResized, WindowWrapper,
};
use winit::dpi::{LogicalPosition, LogicalSize, PhysicalPosition, PhysicalSize};
@ -123,7 +123,10 @@ pub(crate) fn despawn_windows(
mut closing_events: EventWriter<WindowClosing>,
mut closed_events: EventWriter<WindowClosed>,
mut winit_windows: NonSendMut<WinitWindows>,
mut windows_to_drop: Local<Vec<WindowWrapper<winit::window::Window>>>,
) {
// Drop all the windows that are waiting to be closed
windows_to_drop.clear();
for window in closing.iter() {
closing_events.send(WindowClosing { window });
}
@ -133,7 +136,13 @@ pub(crate) fn despawn_windows(
// rather than having the component added
// and removed in the same frame.
if !window_entities.contains(window) {
winit_windows.remove_window(window);
if let Some(window) = winit_windows.remove_window(window) {
// Keeping WindowWrapper that are dropped for one frame
// Otherwise the last `Arc` of the window could be in the rendering thread, and dropped there
// This would hang on macOS
// Keeping the wrapper and dropping it next frame in this system ensure its dropped in the main thread
windows_to_drop.push(window);
}
closed_events.send(WindowClosed { window });
}
}