Skip to content

Commit 945e65f

Browse files
madsmtmtronical
authored andcommitted
Use raw-window-metal to do layer creation in skia
1 parent 84fe321 commit 945e65f

File tree

3 files changed

+52
-48
lines changed

3 files changed

+52
-48
lines changed

internal/renderers/skia/Cargo.toml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ bytemuck = { workspace = true }
6060
windows = { version = "0.56.0", features = ["Win32", "Win32_System_Com", "Win32_Graphics", "Win32_Graphics_Dxgi", "Win32_Graphics_Direct3D12", "Win32_Graphics_Direct3D", "Win32_Foundation", "Win32_Graphics_Dxgi_Common", "Win32_System_Threading", "Win32_Security"] }
6161
skia-safe = { version = "0.75.0", features = ["d3d"] }
6262

63-
[target.'cfg(target_os = "macos")'.dependencies]
63+
[target.'cfg(target_vendor = "apple")'.dependencies]
6464
cocoa = { version = "0.25.0" }
6565
core-foundation = { version = "0.9.1" }
6666
metal = { version = "0.27.0" }
@@ -69,8 +69,9 @@ foreign-types = { version = "0.5.0" }
6969
objc = { version = "0.2.7" }
7070
core-graphics-types = { version = "0.1.1" }
7171
skia-safe = { version = "0.75.0", features = ["metal"] }
72+
raw-window-metal = "1.0"
7273

73-
[target.'cfg(not(any(target_os = "macos", target_family = "windows")))'.dependencies]
74+
[target.'cfg(not(any(target_vendor = "apple", target_family = "windows")))'.dependencies]
7475
skia-safe = { version = "0.75.0", features = ["gl"] }
7576

7677
[build-dependencies]

internal/renderers/skia/metal_surface.rs

Lines changed: 39 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,29 @@
11
// Copyright © SixtyFPS GmbH <info@slint.dev>
22
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0
33

4-
use cocoa::{appkit::NSView, base::id as cocoa_id};
54
use core_graphics_types::geometry::CGSize;
6-
use foreign_types::ForeignTypeRef;
5+
use foreign_types::{ForeignType, ForeignTypeRef};
76
use i_slint_core::api::PhysicalSize as PhysicalWindowSize;
87
use metal::MTLPixelFormat;
9-
use objc::{rc::autoreleasepool, runtime::YES};
8+
use objc::{msg_send, sel, sel_impl};
9+
use objc::{
10+
rc::autoreleasepool,
11+
runtime::{Object, BOOL, NO},
12+
};
1013

1114
use skia_safe::gpu::mtl;
1215

1316
use std::cell::RefCell;
1417
use std::rc::Rc;
1518

19+
#[link(name = "QuartzCore", kind = "framework")]
20+
extern "C" {
21+
#[allow(non_upper_case_globals)]
22+
static kCAGravityTopLeft: *mut Object;
23+
#[allow(non_upper_case_globals)]
24+
static kCAGravityBottomLeft: *mut Object;
25+
}
26+
1627
/// This surface renders into the given window using Metal. The provided display argument
1728
/// is ignored, as it has no meaning on macOS.
1829
pub struct MetalSurface {
@@ -27,36 +38,40 @@ impl super::Surface for MetalSurface {
2738
_display_handle: Rc<dyn raw_window_handle::HasDisplayHandle>,
2839
size: PhysicalWindowSize,
2940
) -> Result<Self, i_slint_core::platform::PlatformError> {
41+
let layer = match window_handle
42+
.window_handle()
43+
.map_err(|e| format!("Error obtaining window handle for skia metal renderer: {e}"))?
44+
.as_raw()
45+
{
46+
raw_window_handle::RawWindowHandle::AppKit(handle) => unsafe {
47+
raw_window_metal::Layer::from_ns_view(handle.ns_view)
48+
},
49+
raw_window_handle::RawWindowHandle::UiKit(handle) => unsafe {
50+
raw_window_metal::Layer::from_ui_view(handle.ui_view)
51+
},
52+
_ => return Err("Skia Renderer: Metal surface is only supported with AppKit".into()),
53+
};
54+
55+
// SAFETY: The layer is an initialized instance of `CAMetalLayer`, and
56+
// we transfer the retain count to `MetalLayer` using `into_raw`.
57+
let layer = unsafe { metal::MetalLayer::from_ptr(layer.into_raw().cast().as_ptr()) };
58+
3059
let device = metal::Device::system_default()
3160
.ok_or_else(|| format!("Skia Renderer: No metal device found"))?;
32-
33-
let layer = metal::MetalLayer::new();
3461
layer.set_device(&device);
3562
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
3663
layer.set_opaque(false);
3764
layer.set_presents_with_transaction(false);
3865

3966
layer.set_drawable_size(CGSize::new(size.width as f64, size.height as f64));
4067

41-
unsafe {
42-
let view = match window_handle
43-
.window_handle()
44-
.map_err(|e| format!("Error obtaining window handle for skia metal renderer: {e}"))?
45-
.as_raw()
46-
{
47-
raw_window_handle::RawWindowHandle::AppKit(
48-
raw_window_handle::AppKitWindowHandle { ns_view, .. },
49-
) => ns_view.as_ptr(),
50-
_ => {
51-
return Err("Skia Renderer: Metal surface is only supported with AppKit".into())
52-
}
53-
} as cocoa_id;
54-
view.setWantsLayer(YES);
55-
view.setLayer(layer.as_ref() as *const _ as _);
56-
view.setLayerContentsPlacement(
57-
cocoa::appkit::NSViewLayerContentsPlacement::NSViewLayerContentsPlacementTopLeft,
58-
);
59-
}
68+
let flipped: BOOL = unsafe { msg_send![layer.as_ptr(), contentsAreFlipped] };
69+
let gravity = if flipped == NO {
70+
unsafe { kCAGravityTopLeft }
71+
} else {
72+
unsafe { kCAGravityBottomLeft }
73+
};
74+
let _: () = unsafe { msg_send![layer.as_ptr(), setContentsGravity: gravity] };
6075

6176
let command_queue = device.new_command_queue();
6277

@@ -85,10 +100,6 @@ impl super::Surface for MetalSurface {
85100
Ok(())
86101
}
87102

88-
fn set_scale_factor(&self, scale_factor: f32) {
89-
self.layer.set_contents_scale(scale_factor.into());
90-
}
91-
92103
fn render(
93104
&self,
94105
_size: PhysicalWindowSize,

internal/renderers/skia/vulkan_surface.rs

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -395,30 +395,22 @@ impl super::Surface for VulkanSurface {
395395
}
396396
}
397397

398+
// FIXME(madsmtm): Why are we doing this instead of using `Surface::from_window`?
398399
fn create_surface(
399400
instance: &Arc<Instance>,
400401
window_handle: raw_window_handle::WindowHandle<'_>,
401402
display_handle: raw_window_handle::DisplayHandle<'_>,
402403
) -> Result<Arc<Surface>, vulkano::Validated<vulkano::VulkanError>> {
403404
match (window_handle.as_raw(), display_handle.as_raw()) {
404-
#[cfg(target_os = "macos")]
405-
(
406-
raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitWindowHandle {
407-
ns_view,
408-
..
409-
}),
410-
_,
411-
) => unsafe {
412-
use cocoa::{appkit::NSView, base::id as cocoa_id};
413-
use objc::runtime::YES;
414-
415-
let layer = metal::MetalLayer::new();
416-
layer.set_opaque(false);
417-
layer.set_presents_with_transaction(false);
418-
let view = ns_view.as_ptr() as cocoa_id;
419-
view.setWantsLayer(YES);
420-
view.setLayer(layer.as_ref() as *const _ as _);
421-
Surface::from_metal(instance.clone(), layer.as_ref(), None)
405+
#[cfg(target_vendor = "apple")]
406+
(raw_window_handle::RawWindowHandle::AppKit(handle), _) => unsafe {
407+
let layer = raw_window_metal::Layer::from_ns_view(handle.ns_view);
408+
Surface::from_metal(instance.clone(), layer.as_ptr().as_ptr(), None)
409+
},
410+
#[cfg(target_vendor = "apple")]
411+
(raw_window_handle::RawWindowHandle::UiKit(handle), _) => unsafe {
412+
let layer = raw_window_metal::Layer::from_ui_view(handle.ui_view);
413+
Surface::from_metal(instance.clone(), layer.as_ptr().as_ptr(), None)
422414
},
423415
(
424416
raw_window_handle::RawWindowHandle::Xlib(raw_window_handle::XlibWindowHandle {

0 commit comments

Comments
 (0)