diff --git a/crates/bevy_render/src/lib.rs b/crates/bevy_render/src/lib.rs index f8cea30fddabc..6b1e837609c8e 100644 --- a/crates/bevy_render/src/lib.rs +++ b/crates/bevy_render/src/lib.rs @@ -146,11 +146,13 @@ impl Plugin for RenderPlugin { let instance = wgpu::Instance::new(backends); let surface = { let windows = app.world.resource_mut::(); - let raw_handle = windows.get_primary().and_then(|window| unsafe { + let raw_handle = windows.get_primary().and_then(|window| { match window.window_handle() { - AbstractWindowHandle::RawWindowHandle(handle) => { + AbstractWindowHandle::RawWindowHandle(handle) => unsafe { + // SAFETY: This is only run on the main thread. Also the caller of `RawHandleWrapper::new` has + // ensured that the window was created on the main thread. Some(instance.create_surface(&handle.get_handle())) - } + }, AbstractWindowHandle::Virtual => None, } }); diff --git a/crates/bevy_window/src/raw_handle.rs b/crates/bevy_window/src/raw_handle.rs index 0e495d2c138b5..bed16c30ddcb5 100644 --- a/crates/bevy_window/src/raw_handle.rs +++ b/crates/bevy_window/src/raw_handle.rs @@ -9,11 +9,24 @@ use raw_window_handle::{ /// thread-safe. #[derive(Debug, Clone)] pub struct RawHandleWrapper { - pub window_handle: RawWindowHandle, - pub display_handle: RawDisplayHandle, + window_handle: RawWindowHandle, + display_handle: RawDisplayHandle, } impl RawHandleWrapper { + /// Create a new `RawHandleWrapper` from its components + /// + /// # Safety + /// + /// If the particular underlying handle can only be used on the same thread, the caller should ensure that the window + /// was created on the main thread. + pub unsafe fn new(window_handle: RawWindowHandle, display_handle: RawDisplayHandle) -> Self { + RawHandleWrapper { + window_handle, + display_handle, + } + } + /// Returns a [`HasRawWindowHandle`] + [`HasRawDisplayHandle`] impl, which exposes [`RawWindowHandle`] and [`RawDisplayHandle`]. /// /// # Safety @@ -23,14 +36,6 @@ impl RawHandleWrapper { pub unsafe fn get_handle(&self) -> ThreadLockedRawWindowHandleWrapper { ThreadLockedRawWindowHandleWrapper(self.clone()) } - - pub fn get_display_handle(&self) -> RawDisplayHandle { - self.display_handle - } - - pub fn get_window_handle(&self) -> RawWindowHandle { - self.window_handle - } } // SAFETY: [`RawHandleWrapper`] is just a normal "raw pointer", which doesn't impl Send/Sync. However the pointer is only @@ -58,7 +63,7 @@ pub struct ThreadLockedRawWindowHandleWrapper(RawHandleWrapper); // and so exposing a safe method to get a [`RawWindowHandle`] directly would be UB. unsafe impl HasRawWindowHandle for ThreadLockedRawWindowHandleWrapper { fn raw_window_handle(&self) -> RawWindowHandle { - self.0.get_window_handle() + self.0.window_handle } } @@ -70,6 +75,6 @@ unsafe impl HasRawWindowHandle for ThreadLockedRawWindowHandleWrapper { // and so exposing a safe method to get a [`RawDisplayHandle`] directly would be UB. unsafe impl HasRawDisplayHandle for ThreadLockedRawWindowHandleWrapper { fn raw_display_handle(&self) -> RawDisplayHandle { - self.0.get_display_handle() + self.0.display_handle } } diff --git a/crates/bevy_winit/src/lib.rs b/crates/bevy_winit/src/lib.rs index 831020323a45d..b4362a202b5d2 100644 --- a/crates/bevy_winit/src/lib.rs +++ b/crates/bevy_winit/src/lib.rs @@ -685,11 +685,14 @@ fn handle_create_window_events( #[cfg(not(any(target_os = "windows", target_feature = "x11")))] let mut window_resized_events = world.resource_mut::>(); for create_window_event in create_window_event_reader.iter(&create_window_events) { - let window = winit_windows.create_window( - event_loop, - create_window_event.id, - &create_window_event.descriptor, - ); + let window = unsafe { + // SAFETY: This is only called from the main thread + winit_windows.create_window( + event_loop, + create_window_event.id, + &create_window_event.descriptor, + ) + }; // This event is already sent on windows, x11, and xwayland. // TODO: we aren't yet sure about native wayland, so we might be able to exclude it, // but sending a duplicate event isn't problematic, as windows already does this. diff --git a/crates/bevy_winit/src/winit_windows.rs b/crates/bevy_winit/src/winit_windows.rs index 436fea00385fa..69a51a482c3c3 100644 --- a/crates/bevy_winit/src/winit_windows.rs +++ b/crates/bevy_winit/src/winit_windows.rs @@ -23,7 +23,10 @@ pub struct WinitWindows { } impl WinitWindows { - pub fn create_window( + /// # SAFETY + /// + /// This should only be called from the main thread, as it might create windows that cannot be used across threads + pub unsafe fn create_window( &mut self, event_loop: &winit::event_loop::EventLoopWindowTarget<()>, window_id: WindowId, @@ -199,9 +202,12 @@ impl WinitWindows { .map(|position| IVec2::new(position.x, position.y)); let inner_size = winit_window.inner_size(); let scale_factor = winit_window.scale_factor(); - let raw_handle = RawHandleWrapper { - window_handle: winit_window.raw_window_handle(), - display_handle: winit_window.raw_display_handle(), + let raw_handle = unsafe { + // SAFETY: Caller ensured that this is run on the main thread + RawHandleWrapper::new( + winit_window.raw_window_handle(), + winit_window.raw_display_handle(), + ) }; self.windows.insert(winit_window.id(), winit_window); Window::new(