diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b0dd96480..0f482a350a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -45,6 +45,11 @@ Bottom level categories: #### DX12 - `DownlevelCapabilities::default()` now returns the `ANISOTROPIC_FILTERING` flag set to true so DX12 lists `ANISOTROPIC_FILTERING` as true again by @cwfitzgerald in [#2851](https://github.com/gfx-rs/wgpu/pull/2851) +### Changes + +#### Metal +- Extract the generic code into `get_metal_layer` by @jinleili in [#2826](https://github.com/gfx-rs/wgpu/pull/2826) + ## wgpu-0.13.1 (2022-07-02) ### Bug Fixes diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index 5975300442..bac3bc6871 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -81,30 +81,48 @@ impl super::Surface { delegate: Option<&HalManagedMetalLayerDelegate>, ) -> Self { let view = view as *mut Object; + let render_layer = + mem::transmute::<_, &mtl::MetalLayerRef>(Self::get_metal_layer(view, delegate)) + .to_owned(); + Self::new(NonNull::new(view), render_layer) + } + + pub unsafe fn from_layer(layer: &mtl::MetalLayerRef) -> Self { + let class = class!(CAMetalLayer); + let proper_kind: BOOL = msg_send![layer, isKindOfClass: class]; + assert_eq!(proper_kind, YES); + Self::new(None, layer.to_owned()) + } + + /// If not called on the main thread, this will panic. + pub unsafe fn get_metal_layer( + view: *mut Object, + delegate: Option<&HalManagedMetalLayerDelegate>, + ) -> *mut Object { if view.is_null() { panic!("window does not have a valid contentView"); } let is_main_thread: BOOL = msg_send![class!(NSThread), isMainThread]; if is_main_thread == NO { - panic!("create_surface cannot be called in non-ui thread."); + panic!("get_metal_layer cannot be called in non-ui thread."); } let main_layer: *mut Object = msg_send![view, layer]; let class = class!(CAMetalLayer); let is_valid_layer: BOOL = msg_send![main_layer, isKindOfClass: class]; - let render_layer = if is_valid_layer == YES { - mem::transmute::<_, &mtl::MetalLayerRef>(main_layer).to_owned() + if is_valid_layer == YES { + main_layer } else { // If the main layer is not a CAMetalLayer, we create a CAMetalLayer and use it. - let new_layer: mtl::MetalLayer = msg_send![class, new]; + let new_layer: *mut Object = msg_send![class, new]; let frame: CGRect = msg_send![main_layer, bounds]; - let () = msg_send![new_layer.as_ref(), setFrame: frame]; + let () = msg_send![new_layer, setFrame: frame]; #[cfg(target_os = "ios")] { // Unlike NSView, UIView does not allow to replace main layer. - let () = msg_send![main_layer, addSublayer: new_layer.as_ref()]; + let () = msg_send![main_layer, addSublayer: new_layer]; // On iOS, "from_view" may be called before the application initialization is complete, // `msg_send![view, window]` and `msg_send![window, screen]` will get null. let screen: *mut Object = msg_send![class!(UIScreen), mainScreen]; @@ -113,9 +131,9 @@ impl super::Surface { }; #[cfg(target_os = "macos")] { - let () = msg_send![view, setLayer: new_layer.as_ref()]; + let () = msg_send![view, setLayer: new_layer]; let () = msg_send![view, setWantsLayer: YES]; - let () = msg_send![new_layer.as_ref(), setContentsGravity: kCAGravityTopLeft]; + let () = msg_send![new_layer, setContentsGravity: kCAGravityTopLeft]; let window: *mut Object = msg_send![view, window]; if !window.is_null() { let scale_factor: CGFloat = msg_send![window, backingScaleFactor]; @@ -126,17 +144,7 @@ impl super::Surface { let () = msg_send![new_layer, setDelegate: delegate.0]; } new_layer - }; - - let _: *mut c_void = msg_send![view, retain]; - Self::new(NonNull::new(view), render_layer) - } - - pub unsafe fn from_layer(layer: &mtl::MetalLayerRef) -> Self { - let class = class!(CAMetalLayer); - let proper_kind: BOOL = msg_send![layer, isKindOfClass: class]; - assert_eq!(proper_kind, YES); - Self::new(None, layer.to_owned()) + } } pub(super) fn dimensions(&self) -> wgt::Extent3d { diff --git a/wgpu-hal/src/vulkan/instance.rs b/wgpu-hal/src/vulkan/instance.rs index 59b2130dfe..2da4288b4a 100644 --- a/wgpu-hal/src/vulkan/instance.rs +++ b/wgpu-hal/src/vulkan/instance.rs @@ -415,46 +415,8 @@ impl super::Instance { #[cfg(any(target_os = "macos", target_os = "ios"))] fn create_surface_from_view(&self, view: *mut c_void) -> super::Surface { - use core_graphics_types::{base::CGFloat, geometry::CGRect}; - use objc::{ - class, msg_send, - runtime::{Object, BOOL, YES}, - sel, sel_impl, - }; - let layer = unsafe { - let view = view as *mut Object; - let existing: *mut Object = msg_send![view, layer]; - let class = class!(CAMetalLayer); - - let use_current: BOOL = msg_send![existing, isKindOfClass: class]; - if use_current == YES { - existing - } else { - let new_layer: *mut Object = msg_send![class, new]; - let frame: CGRect = msg_send![existing, bounds]; - let () = msg_send![new_layer, setFrame: frame]; - - let scale_factor: CGFloat = if cfg!(target_os = "ios") { - let () = msg_send![existing, addSublayer: new_layer]; - // On iOS, `create_surface_from_view` may be called before the application initialization is complete, - // `msg_send![view, window]` and `msg_send![window, screen]` will get null. - let screen: *mut Object = msg_send![class!(UIScreen), mainScreen]; - msg_send![screen, nativeScale] - } else { - let () = msg_send![view, setLayer: new_layer]; - let () = msg_send![view, setWantsLayer: YES]; - let window: *mut Object = msg_send![view, window]; - if !window.is_null() { - msg_send![window, backingScaleFactor] - } else { - 1.0 - } - }; - let () = msg_send![new_layer, setContentsScale: scale_factor]; - - new_layer - } + crate::metal::Surface::get_metal_layer(view as *mut objc::runtime::Object, None) }; let surface = {