Skip to content

Commit

Permalink
metal | vulkan-portability: extract the generic code into `get_metal_…
Browse files Browse the repository at this point in the history
…layer`
  • Loading branch information
jinleili committed Jul 1, 2022
1 parent 1ceef24 commit 9bc7143
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 58 deletions.
46 changes: 27 additions & 19 deletions wgpu-hal/src/metal/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand All @@ -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];
Expand All @@ -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 {
Expand Down
40 changes: 1 addition & 39 deletions wgpu-hal/src/vulkan/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down

0 comments on commit 9bc7143

Please sign in to comment.