Make WinitWindows non send (#4027)
# Objective - Fixes #4010, as well as any similar issues in this class. - Winit functions used outside of the main thread can cause the application to unexpectedly hang. ## Solution - Make the `WinitWindows` resource `!Send`. - This ensures that any systems that use `WinitWindows` must either be exclusive (run on the main thread), or the resource is explicitly marked with the `NonSend` parameter in user systems.
This commit is contained in:
parent
81d57e129b
commit
a2d49f4a69
@ -32,7 +32,7 @@ pub struct WinitPlugin;
|
|||||||
|
|
||||||
impl Plugin for WinitPlugin {
|
impl Plugin for WinitPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.init_resource::<WinitWindows>()
|
app.init_non_send_resource::<WinitWindows>()
|
||||||
.set_runner(winit_runner)
|
.set_runner(winit_runner)
|
||||||
.add_system_to_stage(CoreStage::PostUpdate, change_window.exclusive_system());
|
.add_system_to_stage(CoreStage::PostUpdate, change_window.exclusive_system());
|
||||||
let event_loop = EventLoop::new();
|
let event_loop = EventLoop::new();
|
||||||
@ -43,7 +43,7 @@ impl Plugin for WinitPlugin {
|
|||||||
|
|
||||||
fn change_window(world: &mut World) {
|
fn change_window(world: &mut World) {
|
||||||
let world = world.cell();
|
let world = world.cell();
|
||||||
let winit_windows = world.get_resource::<WinitWindows>().unwrap();
|
let winit_windows = world.get_non_send::<WinitWindows>().unwrap();
|
||||||
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
||||||
|
|
||||||
for bevy_window in windows.iter_mut() {
|
for bevy_window in windows.iter_mut() {
|
||||||
@ -264,7 +264,7 @@ pub fn winit_runner_with(mut app: App) {
|
|||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
let world = app.world.cell();
|
let world = app.world.cell();
|
||||||
let winit_windows = world.get_resource_mut::<WinitWindows>().unwrap();
|
let winit_windows = world.get_non_send_mut::<WinitWindows>().unwrap();
|
||||||
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
||||||
let window_id =
|
let window_id =
|
||||||
if let Some(window_id) = winit_windows.get_window_id(winit_window_id) {
|
if let Some(window_id) = winit_windows.get_window_id(winit_window_id) {
|
||||||
@ -525,7 +525,7 @@ fn handle_create_window_events(
|
|||||||
create_window_event_reader: &mut ManualEventReader<CreateWindow>,
|
create_window_event_reader: &mut ManualEventReader<CreateWindow>,
|
||||||
) {
|
) {
|
||||||
let world = world.cell();
|
let world = world.cell();
|
||||||
let mut winit_windows = world.get_resource_mut::<WinitWindows>().unwrap();
|
let mut winit_windows = world.get_non_send_mut::<WinitWindows>().unwrap();
|
||||||
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
||||||
let create_window_events = world.get_resource::<Events<CreateWindow>>().unwrap();
|
let create_window_events = world.get_resource::<Events<CreateWindow>>().unwrap();
|
||||||
let mut window_created_events = world.get_resource_mut::<Events<WindowCreated>>().unwrap();
|
let mut window_created_events = world.get_resource_mut::<Events<WindowCreated>>().unwrap();
|
||||||
@ -544,7 +544,7 @@ fn handle_create_window_events(
|
|||||||
|
|
||||||
fn handle_initial_window_events(world: &mut World, event_loop: &EventLoop<()>) {
|
fn handle_initial_window_events(world: &mut World, event_loop: &EventLoop<()>) {
|
||||||
let world = world.cell();
|
let world = world.cell();
|
||||||
let mut winit_windows = world.get_resource_mut::<WinitWindows>().unwrap();
|
let mut winit_windows = world.get_non_send_mut::<WinitWindows>().unwrap();
|
||||||
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
let mut windows = world.get_resource_mut::<Windows>().unwrap();
|
||||||
let mut create_window_events = world.get_resource_mut::<Events<CreateWindow>>().unwrap();
|
let mut create_window_events = world.get_resource_mut::<Events<CreateWindow>>().unwrap();
|
||||||
let mut window_created_events = world.get_resource_mut::<Events<WindowCreated>>().unwrap();
|
let mut window_created_events = world.get_resource_mut::<Events<WindowCreated>>().unwrap();
|
||||||
|
|||||||
@ -9,6 +9,10 @@ pub struct WinitWindows {
|
|||||||
pub windows: HashMap<winit::window::WindowId, winit::window::Window>,
|
pub windows: HashMap<winit::window::WindowId, winit::window::Window>,
|
||||||
pub window_id_to_winit: HashMap<WindowId, winit::window::WindowId>,
|
pub window_id_to_winit: HashMap<WindowId, winit::window::WindowId>,
|
||||||
pub winit_to_window_id: HashMap<winit::window::WindowId, WindowId>,
|
pub winit_to_window_id: HashMap<winit::window::WindowId, WindowId>,
|
||||||
|
// Some winit functions, such as `set_window_icon` can only be used from the main thread. If
|
||||||
|
// they are used in another thread, the app will hang. This marker ensures `WinitWindows` is
|
||||||
|
// only ever accessed with bevy's non-send functions and in NonSend systems.
|
||||||
|
_not_send_sync: core::marker::PhantomData<*const ()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WinitWindows {
|
impl WinitWindows {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user