Skip to content

Commit 1ffe038

Browse files
committed
[hal] Do not expose dependency on metal and objc crates
1 parent 9fccdf5 commit 1ffe038

File tree

3 files changed

+57
-32
lines changed

3 files changed

+57
-32
lines changed

wgpu-core/src/instance.rs

Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -303,34 +303,28 @@ impl Instance {
303303
}
304304
}
305305

306+
/// Construct a surface from a pointer to a `CAMetalLayer`.
307+
///
306308
/// # Safety
307309
///
308-
/// `layer` must be a valid pointer.
310+
/// The given layer pointer must point to a valid, non-NULL, initialized
311+
/// instance of `CAMetalLayer`.
309312
#[cfg(metal)]
310313
pub unsafe fn create_surface_metal(
311314
&self,
312315
layer: *mut core::ffi::c_void,
313316
) -> Result<Surface, CreateSurfaceError> {
317+
use core::ptr::NonNull;
318+
314319
profiling::scope!("Instance::create_surface_metal");
315320

316-
let instance = unsafe { self.as_hal::<hal::api::Metal>() }
321+
let _instance = unsafe { self.as_hal::<hal::api::Metal>() }
317322
.ok_or(CreateSurfaceError::BackendNotEnabled(Backend::Metal))?;
318323

319-
let layer = layer.cast();
320-
// SAFETY: We do this cast and deref. (rather than using `metal` to get the
321-
// object we want) to avoid direct coupling on the `metal` crate.
322-
//
323-
// To wit, this pointer…
324-
//
325-
// - …is properly aligned.
326-
// - …is dereferenceable to a `MetalLayerRef` as an invariant of the `metal`
327-
// field.
328-
// - …points to an _initialized_ `MetalLayerRef`.
329-
// - …is only ever aliased via an immutable reference that lives within this
330-
// lexical scope.
331-
let layer = unsafe { &*layer };
332-
let raw_surface: Box<dyn hal::DynSurface> =
333-
Box::new(instance.create_surface_from_layer(layer));
324+
let layer = NonNull::new(layer).expect("layer pointer must not be NULL");
325+
// SAFETY: Upheld by caller.
326+
let raw_surface = unsafe { hal::metal::Surface::from_layer(layer) };
327+
let raw_surface: Box<dyn hal::DynSurface> = Box::new(raw_surface);
334328

335329
let surface = Surface {
336330
presentation: Mutex::new(rank::SURFACE_PRESENTATION, None),

wgpu-hal/src/metal/mod.rs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -103,12 +103,6 @@ crate::impl_dyn_resource!(
103103

104104
pub struct Instance {}
105105

106-
impl Instance {
107-
pub fn create_surface_from_layer(&self, layer: &metal::MetalLayerRef) -> Surface {
108-
unsafe { Surface::from_layer(layer) }
109-
}
110-
}
111-
112106
impl crate::Instance for Instance {
113107
type A = Api;
114108

@@ -127,11 +121,11 @@ impl crate::Instance for Instance {
127121
match window_handle {
128122
#[cfg(any(target_os = "ios", target_os = "visionos"))]
129123
raw_window_handle::RawWindowHandle::UiKit(handle) => {
130-
Ok(unsafe { Surface::from_view(handle.ui_view.cast()) })
124+
Ok(unsafe { Surface::from_ui_view(handle.ui_view) })
131125
}
132126
#[cfg(target_os = "macos")]
133127
raw_window_handle::RawWindowHandle::AppKit(handle) => {
134-
Ok(unsafe { Surface::from_view(handle.ns_view.cast()) })
128+
Ok(unsafe { Surface::from_ns_view(handle.ns_view) })
135129
}
136130
_ => Err(crate::InstanceError::new(format!(
137131
"window handle {window_handle:?} is not a Metal-compatible handle"

wgpu-hal/src/metal/surface.rs

Lines changed: 44 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#![allow(clippy::let_unit_value)] // `let () =` being used to constrain result type
22

33
use alloc::borrow::ToOwned as _;
4-
use core::mem::ManuallyDrop;
54
use core::ptr::NonNull;
5+
use core::{ffi::c_void, mem::ManuallyDrop};
66
use std::thread;
77

88
use core_graphics_types::{
@@ -34,20 +34,57 @@ impl super::Surface {
3434
}
3535
}
3636

37-
/// If not called on the main thread, this will panic.
38-
#[allow(clippy::transmute_ptr_to_ref)]
39-
pub unsafe fn from_view(view: NonNull<Object>) -> Self {
40-
let layer = unsafe { Self::get_metal_layer(view) };
37+
/// Construct a surface from a pointer to a `NSView`.
38+
///
39+
/// # Panics
40+
///
41+
/// Panics if called from a thread that is not the main thread.
42+
///
43+
/// # Safety
44+
///
45+
/// The given view pointer must be a valid instance of `NSView`.
46+
pub unsafe fn from_ns_view(view: NonNull<c_void>) -> Self {
47+
// SAFETY: Upheld by caller.
48+
let layer = unsafe { Self::get_metal_layer(view.cast()) };
4149
let layer = ManuallyDrop::new(layer);
4250
// SAFETY: The layer is an initialized instance of `CAMetalLayer`, and
4351
// we transfer the retain count to `MetalLayer` using `ManuallyDrop`.
4452
let layer = unsafe { metal::MetalLayer::from_ptr(layer.cast()) };
4553
Self::new(layer)
4654
}
4755

48-
pub unsafe fn from_layer(layer: &metal::MetalLayerRef) -> Self {
56+
/// Construct a surface from a pointer to a `UIView`.
57+
///
58+
/// # Panics
59+
///
60+
/// Panics if called from a thread that is not the main thread.
61+
///
62+
/// # Safety
63+
///
64+
/// The given view pointer must be a valid instance of `UIView`.
65+
pub unsafe fn from_ui_view(view: NonNull<c_void>) -> Self {
66+
// SAFETY: Upheld by caller.
67+
let layer = unsafe { Self::get_metal_layer(view.cast()) };
68+
let layer = ManuallyDrop::new(layer);
69+
// SAFETY: The layer is an initialized instance of `CAMetalLayer`, and
70+
// we transfer the retain count to `MetalLayer` using `ManuallyDrop`.
71+
let layer = unsafe { metal::MetalLayer::from_ptr(layer.cast()) };
72+
Self::new(layer)
73+
}
74+
75+
/// Construct a surface from a pointer to a `CAMetalLayer`.
76+
///
77+
/// # Safety
78+
///
79+
/// The given view pointer must be a valid instance of `CAMetalLayer`.
80+
pub unsafe fn from_layer(layer: NonNull<c_void>) -> Self {
81+
// SAFETY: Validity of the pointer is upheld by the caller.
82+
//
83+
// We extend the lifetime of the layer with `to_owned` below.
84+
let layer = unsafe { layer.cast::<metal::MetalLayerRef>().as_ref() };
85+
4986
let class = class!(CAMetalLayer);
50-
let proper_kind: BOOL = msg_send![layer, isKindOfClass: class];
87+
let proper_kind: BOOL = unsafe { msg_send![layer, isKindOfClass: class] };
5188
assert_eq!(proper_kind, YES);
5289
Self::new(layer.to_owned())
5390
}

0 commit comments

Comments
 (0)