From c3de161dd2a0144bef1fa740b9ef25166415247a Mon Sep 17 00:00:00 2001 From: Dzmitry Malyshau Date: Fri, 27 Aug 2021 12:49:48 -0400 Subject: [PATCH] hal/metal: inherit scaling from NSView --- wgpu-hal/src/metal/mod.rs | 16 ++++++++---- wgpu-hal/src/metal/surface.rs | 49 +++++++++++++++++++++++++++++++---- 2 files changed, 55 insertions(+), 10 deletions(-) diff --git a/wgpu-hal/src/metal/mod.rs b/wgpu-hal/src/metal/mod.rs index 4ebbacce5a..7b95588f46 100644 --- a/wgpu-hal/src/metal/mod.rs +++ b/wgpu-hal/src/metal/mod.rs @@ -61,7 +61,9 @@ impl crate::Api for Api { type ComputePipeline = ComputePipeline; } -pub struct Instance {} +pub struct Instance { + managed_metal_layer_delegate: surface::HalManagedMetalLayerDelegate, +} impl Instance { pub fn create_surface_from_layer(&self, layer: &mtl::MetalLayerRef) -> Surface { @@ -72,7 +74,9 @@ impl Instance { impl crate::Instance for Instance { unsafe fn init(_desc: &crate::InstanceDescriptor) -> Result { //TODO: enable `METAL_DEVICE_WRAPPER_TYPE` environment based on the flags? - Ok(Instance {}) + Ok(Instance { + managed_metal_layer_delegate: surface::HalManagedMetalLayerDelegate::new(), + }) } unsafe fn create_surface( @@ -82,12 +86,14 @@ impl crate::Instance for Instance { match has_handle.raw_window_handle() { #[cfg(target_os = "ios")] raw_window_handle::RawWindowHandle::IOS(handle) => { + let _ = &self.managed_metal_layer_delegate; Ok(Surface::from_uiview(handle.ui_view)) } #[cfg(target_os = "macos")] - raw_window_handle::RawWindowHandle::MacOS(handle) => { - Ok(Surface::from_nsview(handle.ns_view)) - } + raw_window_handle::RawWindowHandle::MacOS(handle) => Ok(Surface::from_nsview( + handle.ns_view, + &self.managed_metal_layer_delegate, + )), _ => Err(crate::InstanceError), } } diff --git a/wgpu-hal/src/metal/surface.rs b/wgpu-hal/src/metal/surface.rs index e66a536907..a223d52e4d 100644 --- a/wgpu-hal/src/metal/surface.rs +++ b/wgpu-hal/src/metal/surface.rs @@ -1,13 +1,15 @@ -use std::{mem, os::raw::c_void, ptr::NonNull, thread}; +use std::{mem, os::raw::c_void, ptr::NonNull, sync::Once, thread}; use core_graphics_types::{ base::CGFloat, geometry::{CGRect, CGSize}, }; use objc::{ - class, msg_send, + class, + declare::ClassDecl, + msg_send, rc::autoreleasepool, - runtime::{Object, BOOL, YES}, + runtime::{Class, Object, Sel, BOOL, YES}, sel, sel_impl, }; use parking_lot::Mutex; @@ -19,6 +21,40 @@ extern "C" { static kCAGravityTopLeft: *mut Object; } +extern "C" fn layer_should_inherit_contents_scale_from_window( + _: &Class, + _: Sel, + _layer: *mut Object, + _new_scale: CGFloat, + _from_window: *mut Object, +) -> BOOL { + YES +} + +const CAML_DELEGATE_CLASS: &str = "HalManagedMetalLayerDelegate"; +static CAML_DELEGATE_REGISTER: Once = Once::new(); + +#[derive(Debug)] +pub struct HalManagedMetalLayerDelegate(&'static Class); + +impl HalManagedMetalLayerDelegate { + pub fn new() -> Self { + CAML_DELEGATE_REGISTER.call_once(|| { + type Fun = extern "C" fn(&Class, Sel, *mut Object, CGFloat, *mut Object) -> BOOL; + let mut decl = ClassDecl::new(CAML_DELEGATE_CLASS, class!(NSObject)).unwrap(); + #[allow(trivial_casts)] // false positive + unsafe { + decl.add_class_method( + sel!(layer:shouldInheritContentsScale:fromWindow:), + layer_should_inherit_contents_scale_from_window as Fun, + ); + } + decl.register(); + }); + Self(Class::get(CAML_DELEGATE_CLASS).unwrap()) + } +} + impl super::Surface { fn new(view: Option>, layer: mtl::MetalLayer) -> Self { Self { @@ -74,7 +110,10 @@ impl super::Surface { #[cfg(target_os = "macos")] #[allow(clippy::transmute_ptr_to_ref)] - pub unsafe fn from_nsview(nsview: *mut c_void) -> Self { + pub unsafe fn from_nsview( + nsview: *mut c_void, + delegate: &HalManagedMetalLayerDelegate, + ) -> Self { let view = nsview as *mut Object; if view.is_null() { panic!("window does not have a valid contentView"); @@ -109,7 +148,7 @@ impl super::Surface { let scale_factor: CGFloat = msg_send![window, backingScaleFactor]; let () = msg_send![layer, setContentsScale: scale_factor]; } - //let () = msg_send![layer, setDelegate: self.gfx_managed_metal_layer_delegate.0]; + let () = msg_send![layer, setDelegate: delegate.0]; layer };