diff --git a/.deny.toml b/.deny.toml index d5c2534f64..a547102a82 100644 --- a/.deny.toml +++ b/.deny.toml @@ -7,6 +7,9 @@ skip-tree = [ # introduced by Deno, to be investigated { name = "petgraph", version = "0.6.5" }, + + # Winit 0.30 uses an older objc2 + { name = "objc2-foundation", version = "0.2" }, ] skip = [ # Flume uses an old version diff --git a/Cargo.lock b/Cargo.lock index 5ac6df3d5d..44b0e001d5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1253,6 +1253,16 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", +] + [[package]] name = "displaydoc" version = "0.2.5" @@ -2808,6 +2818,15 @@ dependencies = [ "objc2-encode 4.1.0", ] +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode 4.1.0", +] + [[package]] name = "objc2-app-kit" version = "0.2.2" @@ -2820,8 +2839,8 @@ dependencies = [ "objc2 0.5.2", "objc2-core-data", "objc2-core-image", - "objc2-foundation", - "objc2-quartz-core", + "objc2-foundation 0.2.2", + "objc2-quartz-core 0.2.2", ] [[package]] @@ -2834,7 +2853,7 @@ dependencies = [ "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -2845,7 +2864,7 @@ checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" dependencies = [ "block2 0.5.1", "objc2 0.5.2", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -2857,7 +2876,18 @@ dependencies = [ "bitflags 2.9.4", "block2 0.5.1", "objc2 0.5.2", - "objc2-foundation", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.9.4", + "dispatch2", + "objc2 0.6.3", ] [[package]] @@ -2868,8 +2898,8 @@ checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" dependencies = [ "block2 0.5.1", "objc2 0.5.2", - "objc2-foundation", - "objc2-metal", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", ] [[package]] @@ -2881,7 +2911,7 @@ dependencies = [ "block2 0.5.1", "objc2 0.5.2", "objc2-contacts", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -2909,6 +2939,17 @@ dependencies = [ "objc2 0.5.2", ] +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", + "objc2-core-foundation", +] + [[package]] name = "objc2-link-presentation" version = "0.2.2" @@ -2918,7 +2959,7 @@ dependencies = [ "block2 0.5.1", "objc2 0.5.2", "objc2-app-kit", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -2930,7 +2971,18 @@ dependencies = [ "bitflags 2.9.4", "block2 0.5.1", "objc2 0.5.2", - "objc2-foundation", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-metal" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", + "objc2-foundation 0.3.2", ] [[package]] @@ -2942,8 +2994,21 @@ dependencies = [ "bitflags 2.9.4", "block2 0.5.1", "objc2 0.5.2", - "objc2-foundation", - "objc2-metal", + "objc2-foundation 0.2.2", + "objc2-metal 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" +dependencies = [ + "bitflags 2.9.4", + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-metal 0.3.2", ] [[package]] @@ -2953,7 +3018,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" dependencies = [ "objc2 0.5.2", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -2969,9 +3034,9 @@ dependencies = [ "objc2-core-data", "objc2-core-image", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-link-presentation", - "objc2-quartz-core", + "objc2-quartz-core 0.2.2", "objc2-symbols", "objc2-uniform-type-identifiers", "objc2-user-notifications", @@ -2985,7 +3050,7 @@ checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" dependencies = [ "block2 0.5.1", "objc2 0.5.2", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -2998,7 +3063,7 @@ dependencies = [ "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", - "objc2-foundation", + "objc2-foundation 0.2.2", ] [[package]] @@ -3437,6 +3502,18 @@ version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" +[[package]] +name = "raw-window-metal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40d213455a5f1dc59214213c7330e074ddf8114c9a42411eb890c767357ce135" +dependencies = [ + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "objc2-quartz-core 0.3.2", +] + [[package]] name = "rayon" version = "1.11.0" @@ -4991,6 +5068,7 @@ dependencies = [ "range-alloc", "raw-window-handle 0.5.2", "raw-window-handle 0.6.2", + "raw-window-metal", "renderdoc-sys", "rustc-hash 1.1.0", "smallvec", @@ -5699,7 +5777,7 @@ dependencies = [ "ndk 0.9.0", "objc2 0.5.2", "objc2-app-kit", - "objc2-foundation", + "objc2-foundation 0.2.2", "objc2-ui-kit", "orbclient", "percent-encoding", diff --git a/Cargo.toml b/Cargo.toml index d78e742c29..69733523f4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -202,6 +202,7 @@ metal = "0.32" block = "0.1.6" core-graphics-types = "0.2" objc = "0.2.5" +raw-window-metal = "1.0" # Vulkan dependencies android_system_properties = "0.1.1" diff --git a/wgpu-hal/Cargo.toml b/wgpu-hal/Cargo.toml index 3b8c37c861..edf110c511 100644 --- a/wgpu-hal/Cargo.toml +++ b/wgpu-hal/Cargo.toml @@ -59,7 +59,7 @@ unexpected_cfgs = { level = "warn", check-cfg = [ # exclude the Vulkan backend on MacOS unless a separate feature `vulkan-portability` is enabled. In response # to these features, it enables features of platform specific crates. For example, the `vulkan` feature in wgpu-core # enables the `vulkan` feature in `wgpu-core-deps-windows-linux-android` which in turn enables the -# `vulkan` feature in `wgpu-hal` _only_ on those platforms. If you enable the `vulkan-portability` feature, it +# `vulkan` feature in `wgpu-hal` _only_ on those platforms. If you enable the `vulkan-portability` feature, it # will enable the `vulkan` feature in `wgpu-core-deps-apple`. The only way to do this is unfortunately to have # a separate crate for each platform category that participates in the feature unification. # @@ -83,6 +83,7 @@ metal = [ "dep:objc", "dep:parking_lot", "dep:profiling", + "dep:raw-window-metal", ] vulkan = [ "naga/spv-out", @@ -99,6 +100,7 @@ vulkan = [ "dep:ordered-float", "dep:parking_lot", "dep:profiling", + "dep:raw-window-metal", "dep:smallvec", "dep:windows", "windows/Win32", @@ -281,6 +283,9 @@ core-graphics-types = { workspace = true, optional = true } metal = { workspace = true, optional = true } objc = { workspace = true, optional = true } +# backend: Metal + Vulkan +raw-window-metal = { workspace = true, optional = true } + ######################### ### Platform: Android ### ######################### diff --git a/wgpu-hal/src/metal/layer_observer.rs b/wgpu-hal/src/metal/layer_observer.rs deleted file mode 100644 index 8acd83b531..0000000000 --- a/wgpu-hal/src/metal/layer_observer.rs +++ /dev/null @@ -1,190 +0,0 @@ -//! A rewrite of `raw-window-metal` using `objc` instead of `objc2`. -//! -//! See that for details: -//! -//! This should be temporary, see . - -use core::ffi::{c_void, CStr}; -use core_graphics_types::base::CGFloat; -use core_graphics_types::geometry::CGRect; -use objc::declare::ClassDecl; -use objc::rc::StrongPtr; -use objc::runtime::{Class, Object, Sel, BOOL, NO}; -use objc::{class, msg_send, sel, sel_impl}; -use std::sync::OnceLock; - -#[link(name = "Foundation", kind = "framework")] -extern "C" { - static NSKeyValueChangeNewKey: &'static Object; -} - -#[allow(non_upper_case_globals)] -const NSKeyValueObservingOptionNew: usize = 0x01; -#[allow(non_upper_case_globals)] -const NSKeyValueObservingOptionInitial: usize = 0x04; - -const CONTENTS_SCALE: &CStr = c"contentsScale"; -const BOUNDS: &CStr = c"bounds"; - -/// Create a new custom layer that tracks parameters from the given super layer. -/// -/// Same as . -pub unsafe fn new_observer_layer(root_layer: *mut Object) -> StrongPtr { - let this: *mut Object = unsafe { msg_send![class(), new] }; - - // Add the layer as a sublayer of the root layer. - let _: () = unsafe { msg_send![root_layer, addSublayer: this] }; - - // Register for key-value observing. - let key_path: *const Object = - unsafe { msg_send![class!(NSString), stringWithUTF8String: CONTENTS_SCALE.as_ptr()] }; - let _: () = unsafe { - msg_send![ - root_layer, - addObserver: this - forKeyPath: key_path - options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial - context: context_ptr() - ] - }; - - let key_path: *const Object = - unsafe { msg_send![class!(NSString), stringWithUTF8String: BOUNDS.as_ptr()] }; - let _: () = unsafe { - msg_send![ - root_layer, - addObserver: this - forKeyPath: key_path - options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial - context: context_ptr() - ] - }; - - // Uncomment when debugging resize issues. - // extern "C" { - // static kCAGravityTopLeft: *mut Object; - // } - // let _: () = unsafe { msg_send![this, setContentsGravity: kCAGravityTopLeft] }; - - unsafe { StrongPtr::new(this) } -} - -/// Same as . -fn class() -> &'static Class { - static CLASS: OnceLock<&'static Class> = OnceLock::new(); - - CLASS.get_or_init(|| { - let superclass = class!(CAMetalLayer); - let class_name = format!("WgpuObserverLayer@{:p}", &CLASS); - let mut decl = ClassDecl::new(&class_name, superclass).unwrap(); - - // From NSKeyValueObserving. - let sel = sel!(observeValueForKeyPath:ofObject:change:context:); - let method: extern "C" fn( - &Object, - Sel, - *mut Object, - *mut Object, - *mut Object, - *mut c_void, - ) = observe_value; - unsafe { decl.add_method(sel, method) }; - - let sel = sel!(dealloc); - let method: extern "C" fn(&Object, Sel) = dealloc; - unsafe { decl.add_method(sel, method) }; - - decl.register() - }) -} - -/// The unique context pointer for this class. -fn context_ptr() -> *mut c_void { - let ptr: *const Class = class(); - ptr.cast_mut().cast() -} - -/// Same as . -extern "C" fn observe_value( - this: &Object, - _cmd: Sel, - key_path: *mut Object, - object: *mut Object, - change: *mut Object, - context: *mut c_void, -) { - // An unrecognized context must belong to the super class. - if context != context_ptr() { - // SAFETY: The signature is correct, and it's safe to forward to - // the superclass' method when we're overriding the method. - return unsafe { - msg_send![ - super(this, class!(CAMetalLayer)), - observeValueForKeyPath: key_path - ofObject: object - change: change - context: context - ] - }; - } - - assert!(!change.is_null()); - - let key = unsafe { NSKeyValueChangeNewKey }; - let new: *mut Object = unsafe { msg_send![change, objectForKey: key] }; - assert!(!new.is_null()); - - let to_compare: *const Object = - unsafe { msg_send![class!(NSString), stringWithUTF8String: CONTENTS_SCALE.as_ptr()] }; - let is_equal: BOOL = unsafe { msg_send![key_path, isEqual: to_compare] }; - if is_equal != NO { - // `contentsScale` is a CGFloat, and so the observed value is always a NSNumber. - let scale_factor: CGFloat = if cfg!(target_pointer_width = "64") { - unsafe { msg_send![new, doubleValue] } - } else { - unsafe { msg_send![new, floatValue] } - }; - - // Set the scale factor of the layer to match the root layer. - let _: () = unsafe { msg_send![this, setContentsScale: scale_factor] }; - return; - } - - let to_compare: *const Object = - unsafe { msg_send![class!(NSString), stringWithUTF8String: BOUNDS.as_ptr()] }; - let is_equal: BOOL = unsafe { msg_send![key_path, isEqual: to_compare] }; - if is_equal != NO { - // `bounds` is a CGRect, and so the observed value is always a NSNumber. - let bounds: CGRect = unsafe { msg_send![new, rectValue] }; - - // Set `bounds` and `position` to match the root layer. - // - // This differs from just setting the `bounds`, as it also takes into account any - // translation that the superlayer may have that we'd want to preserve. - let _: () = unsafe { msg_send![this, setFrame: bounds] }; - return; - } - - panic!("unknown observed keypath {key_path:?}"); -} - -extern "C" fn dealloc(this: &Object, _cmd: Sel) { - // Load the root layer if it still exists, and deregister the observer. - // - // This is not entirely sound, as the ObserverLayer _could_ have been - // moved to another layer; but Wgpu doesn't do that, so it should be fine. - // - // `raw-window-metal` uses a weak instance variable to do it correctly: - // https://docs.rs/raw-window-metal/1.1.0/src/raw_window_metal/observer.rs.html#74-132 - // (but that's difficult to do with `objc`). - let root_layer: *mut Object = unsafe { msg_send![this, superlayer] }; - if !root_layer.is_null() { - let key_path: *const Object = - unsafe { msg_send![class!(NSString), stringWithUTF8String: CONTENTS_SCALE.as_ptr()] }; - let _: () = unsafe { msg_send![root_layer, removeObserver: this forKeyPath: key_path] }; - - let key_path: *const Object = - unsafe { msg_send![class!(NSString), stringWithUTF8String: BOUNDS.as_ptr()] }; - let _: () = unsafe { msg_send![root_layer, removeObserver: this forKeyPath: key_path] }; - } -} diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 00223b2f77..1cbac13c58 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -22,7 +22,6 @@ mod adapter; mod command; mod conv; mod device; -mod layer_observer; mod surface; mod time; @@ -33,10 +32,11 @@ use arrayvec::ArrayVec; use bitflags::bitflags; use hashbrown::HashMap; use metal::{ - foreign_types::ForeignTypeRef as _, MTLArgumentBuffersTier, MTLBuffer, MTLCommandBufferStatus, - MTLCullMode, MTLDepthClipMode, MTLIndexType, MTLLanguageVersion, MTLPrimitiveType, - MTLReadWriteTextureTier, MTLRenderStages, MTLResource, MTLResourceUsage, MTLSamplerState, - MTLSize, MTLTexture, MTLTextureType, MTLTriangleFillMode, MTLWinding, + foreign_types::{ForeignType as _, ForeignTypeRef as _}, + MTLArgumentBuffersTier, MTLBuffer, MTLCommandBufferStatus, MTLCullMode, MTLDepthClipMode, + MTLIndexType, MTLLanguageVersion, MTLPrimitiveType, MTLReadWriteTextureTier, MTLRenderStages, + MTLResource, MTLResourceUsage, MTLSamplerState, MTLSize, MTLTexture, MTLTextureType, + MTLTriangleFillMode, MTLWinding, }; use naga::FastHashMap; use parking_lot::{Mutex, RwLock}; @@ -106,7 +106,7 @@ pub struct Instance {} impl Instance { pub fn create_surface_from_layer(&self, layer: &metal::MetalLayerRef) -> Surface { - unsafe { Surface::from_layer(layer) } + Surface::from_layer(layer) } } @@ -125,19 +125,25 @@ impl crate::Instance for Instance { _display_handle: raw_window_handle::RawDisplayHandle, window_handle: raw_window_handle::RawWindowHandle, ) -> Result { - match window_handle { - #[cfg(any(target_os = "ios", target_os = "visionos"))] - raw_window_handle::RawWindowHandle::UiKit(handle) => { - Ok(unsafe { Surface::from_view(handle.ui_view.cast()) }) + let layer = match window_handle { + raw_window_handle::RawWindowHandle::AppKit(handle) => unsafe { + raw_window_metal::Layer::from_ns_view(handle.ns_view) + }, + raw_window_handle::RawWindowHandle::UiKit(handle) => unsafe { + raw_window_metal::Layer::from_ui_view(handle.ui_view) + }, + _ => { + return Err(crate::InstanceError::new(format!( + "window handle {window_handle:?} is not a Metal-compatible handle" + ))) } - #[cfg(target_os = "macos")] - raw_window_handle::RawWindowHandle::AppKit(handle) => { - Ok(unsafe { Surface::from_view(handle.ns_view.cast()) }) - } - _ => Err(crate::InstanceError::new(format!( - "window handle {window_handle:?} is not a Metal-compatible handle" - ))), - } + }; + + // SAFETY: The layer is an initialized instance of `CAMetalLayer`, and + // we transfer the retain count to `MetalLayer` using `into_raw`. + let layer = unsafe { metal::MetalLayer::from_ptr(layer.into_raw().cast().as_ptr()) }; + + Ok(Surface::new(layer)) } unsafe fn enumerate_adapters( diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index 2a705cd790..04a328894d 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -1,29 +1,22 @@ #![allow(clippy::let_unit_value)] // `let () =` being used to constrain result type use alloc::borrow::ToOwned as _; -use core::mem::ManuallyDrop; -use core::ptr::NonNull; use core_graphics_types::{ base::CGFloat, geometry::{CGRect, CGSize}, }; -use metal::{foreign_types::ForeignType, MTLTextureType}; +use metal::MTLTextureType; use objc::{ class, msg_send, - rc::{autoreleasepool, StrongPtr}, - runtime::{Object, BOOL, NO, YES}, + rc::autoreleasepool, + runtime::{BOOL, YES}, sel, sel_impl, }; use parking_lot::{Mutex, RwLock}; -use crate::metal::layer_observer::new_observer_layer; - -#[link(name = "QuartzCore", kind = "framework")] -extern "C" {} - impl super::Surface { - fn new(layer: metal::MetalLayer) -> Self { + pub fn new(layer: metal::MetalLayer) -> Self { Self { render_layer: Mutex::new(layer), swapchain_format: RwLock::new(None), @@ -32,81 +25,13 @@ impl super::Surface { } } - /// If not called on the main thread, this will panic. - #[allow(clippy::transmute_ptr_to_ref)] - pub unsafe fn from_view(view: NonNull) -> Self { - let layer = unsafe { Self::get_metal_layer(view) }; - let layer = ManuallyDrop::new(layer); - // SAFETY: The layer is an initialized instance of `CAMetalLayer`, and - // we transfer the retain count to `MetalLayer` using `ManuallyDrop`. - let layer = unsafe { metal::MetalLayer::from_ptr(layer.cast()) }; - Self::new(layer) - } - - pub unsafe fn from_layer(layer: &metal::MetalLayerRef) -> Self { + pub fn from_layer(layer: &metal::MetalLayerRef) -> Self { let class = class!(CAMetalLayer); - let proper_kind: BOOL = msg_send![layer, isKindOfClass: class]; + let proper_kind: BOOL = unsafe { msg_send![layer, isKindOfClass: class] }; assert_eq!(proper_kind, YES); Self::new(layer.to_owned()) } - /// Get or create a new `CAMetalLayer` associated with the given `NSView` - /// or `UIView`. - /// - /// # Panics - /// - /// If called from a thread that is not the main thread, this will panic. - /// - /// # Safety - /// - /// The `view` must be a valid instance of `NSView` or `UIView`. - pub(crate) unsafe fn get_metal_layer(view: NonNull) -> StrongPtr { - let is_main_thread: BOOL = msg_send![class!(NSThread), isMainThread]; - if is_main_thread == NO { - panic!("get_metal_layer cannot be called in non-ui thread."); - } - - // Ensure that the view is layer-backed. - // Views are always layer-backed in UIKit. - #[cfg(target_os = "macos")] - let () = msg_send![view.as_ptr(), setWantsLayer: YES]; - - let root_layer: *mut Object = msg_send![view.as_ptr(), layer]; - // `-[NSView layer]` can return `NULL`, while `-[UIView layer]` should - // always be available. - assert!(!root_layer.is_null(), "failed making the view layer-backed"); - - // NOTE: We explicitly do not touch properties such as - // `layerContentsPlacement`, `needsDisplayOnBoundsChange` and - // `contentsGravity` etc. on the root layer, both since we would like - // to give the user full control over them, and because the default - // values suit us pretty well (especially the contents placement being - // `NSViewLayerContentsRedrawDuringViewResize`, which allows the view - // to receive `drawRect:`/`updateLayer` calls). - - let is_metal_layer: BOOL = msg_send![root_layer, isKindOfClass: class!(CAMetalLayer)]; - if is_metal_layer == YES { - // The view has a `CAMetalLayer` as the root layer, which can - // happen for example if user overwrote `-[NSView layerClass]` or - // the view is `MTKView`. - // - // This is easily handled: We take "ownership" over the layer, and - // render directly into that; after all, the user passed a view - // with an explicit Metal layer to us, so this is very likely what - // they expect us to do. - unsafe { StrongPtr::retain(root_layer) } - } else { - // The view does not have a `CAMetalLayer` as the root layer (this - // is the default for most views). - // - // This case is trickier! We cannot use the existing layer with - // Metal, so we must do something else. There are a few options, - // we do the same as outlined in: - // https://docs.rs/raw-window-metal/1.1.0/raw_window_metal/#reasoning-behind-creating-a-sublayer - unsafe { new_observer_layer(root_layer) } - } - } - /// Gets the current dimensions of the `Surface`. /// /// This function is safe to call off of the main thread. However, note that diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 572ffcd3f0..9a8812de24 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -554,10 +554,10 @@ impl super::Instance { Ok(self.create_surface_from_vk_surface_khr(surface)) } - #[cfg(metal)] - fn create_surface_from_view( + #[cfg(target_vendor = "apple")] + fn create_surface_from_layer( &self, - view: core::ptr::NonNull, + layer: raw_window_metal::Layer, ) -> Result { if !self.shared.extensions.contains(&ext::metal_surface::NAME) { return Err(crate::InstanceError::new(String::from( @@ -565,17 +565,14 @@ impl super::Instance { ))); } - let layer = unsafe { crate::metal::Surface::get_metal_layer(view.cast()) }; // NOTE: The layer is retained by Vulkan's `vkCreateMetalSurfaceEXT`, // so no need to retain it beyond the scope of this function. - let layer_ptr = (*layer).cast(); - let surface = { let metal_loader = ext::metal_surface::Instance::new(&self.shared.entry, &self.shared.raw); let vk_info = vk::MetalSurfaceCreateInfoEXT::default() .flags(vk::MetalSurfaceCreateFlagsEXT::empty()) - .layer(layer_ptr); + .layer(layer.as_ptr().as_ptr()); unsafe { metal_loader.create_metal_surface(&vk_info, None).unwrap() } }; @@ -944,17 +941,19 @@ impl crate::Instance for super::Instance { })?; self.create_surface_from_hwnd(hinstance.get(), handle.hwnd.get()) } - #[cfg(all(target_os = "macos", feature = "metal"))] + #[cfg(target_vendor = "apple")] (Rwh::AppKit(handle), _) if self.shared.extensions.contains(&ext::metal_surface::NAME) => { - self.create_surface_from_view(handle.ns_view) + let layer = unsafe { raw_window_metal::Layer::from_ns_view(handle.ns_view) }; + self.create_surface_from_layer(layer) } - #[cfg(all(any(target_os = "ios", target_os = "visionos"), feature = "metal"))] + #[cfg(target_vendor = "apple")] (Rwh::UiKit(handle), _) if self.shared.extensions.contains(&ext::metal_surface::NAME) => { - self.create_surface_from_view(handle.ui_view) + let layer = unsafe { raw_window_metal::Layer::from_ui_view(handle.ui_view) }; + self.create_surface_from_layer(layer) } (_, _) => Err(crate::InstanceError::new(format!( "window handle {window_handle:?} is not a Vulkan-compatible handle"