Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use raw-window-metal to do layer creation #6067

Merged
merged 1 commit into from
Sep 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions internal/renderers/skia/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ bytemuck = { workspace = true }
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"] }
skia-safe = { version = "0.75.0", features = ["d3d"] }

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

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

[build-dependencies]
Expand Down
67 changes: 39 additions & 28 deletions internal/renderers/skia/metal_surface.rs
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

use cocoa::{appkit::NSView, base::id as cocoa_id};
use core_graphics_types::geometry::CGSize;
use foreign_types::ForeignTypeRef;
use foreign_types::{ForeignType, ForeignTypeRef};
use i_slint_core::api::PhysicalSize as PhysicalWindowSize;
use metal::MTLPixelFormat;
use objc::{rc::autoreleasepool, runtime::YES};
use objc::{msg_send, sel, sel_impl};
use objc::{
rc::autoreleasepool,
runtime::{Object, BOOL, NO},
};

use skia_safe::gpu::mtl;

use std::cell::RefCell;
use std::rc::Rc;

#[link(name = "QuartzCore", kind = "framework")]
extern "C" {
#[allow(non_upper_case_globals)]
static kCAGravityTopLeft: *mut Object;
#[allow(non_upper_case_globals)]
static kCAGravityBottomLeft: *mut Object;
}

/// This surface renders into the given window using Metal. The provided display argument
/// is ignored, as it has no meaning on macOS.
pub struct MetalSurface {
Expand All @@ -27,36 +38,40 @@ impl super::Surface for MetalSurface {
_display_handle: Rc<dyn raw_window_handle::HasDisplayHandle>,
size: PhysicalWindowSize,
) -> Result<Self, i_slint_core::platform::PlatformError> {
let layer = match window_handle
.window_handle()
.map_err(|e| format!("Error obtaining window handle for skia metal renderer: {e}"))?
.as_raw()
{
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("Skia Renderer: Metal surface is only supported with AppKit".into()),
};

// 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()) };

let device = metal::Device::system_default()
.ok_or_else(|| format!("Skia Renderer: No metal device found"))?;

let layer = metal::MetalLayer::new();
layer.set_device(&device);
layer.set_pixel_format(MTLPixelFormat::BGRA8Unorm);
layer.set_opaque(false);
layer.set_presents_with_transaction(false);

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

unsafe {
let view = match window_handle
.window_handle()
.map_err(|e| format!("Error obtaining window handle for skia metal renderer: {e}"))?
.as_raw()
{
raw_window_handle::RawWindowHandle::AppKit(
raw_window_handle::AppKitWindowHandle { ns_view, .. },
) => ns_view.as_ptr(),
_ => {
return Err("Skia Renderer: Metal surface is only supported with AppKit".into())
}
} as cocoa_id;
view.setWantsLayer(YES);
view.setLayer(layer.as_ref() as *const _ as _);
view.setLayerContentsPlacement(
cocoa::appkit::NSViewLayerContentsPlacement::NSViewLayerContentsPlacementTopLeft,
);
}
let flipped: BOOL = unsafe { msg_send![layer.as_ptr(), contentsAreFlipped] };
let gravity = if flipped == NO {
unsafe { kCAGravityTopLeft }
} else {
unsafe { kCAGravityBottomLeft }
};
let _: () = unsafe { msg_send![layer.as_ptr(), setContentsGravity: gravity] };

let command_queue = device.new_command_queue();

Expand Down Expand Up @@ -85,10 +100,6 @@ impl super::Surface for MetalSurface {
Ok(())
}

fn set_scale_factor(&self, scale_factor: f32) {
self.layer.set_contents_scale(scale_factor.into());
}

fn render(
&self,
_size: PhysicalWindowSize,
Expand Down
28 changes: 10 additions & 18 deletions internal/renderers/skia/vulkan_surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -395,30 +395,22 @@ impl super::Surface for VulkanSurface {
}
}

// FIXME(madsmtm): Why are we doing this instead of using `Surface::from_window`?
fn create_surface(
instance: &Arc<Instance>,
window_handle: raw_window_handle::WindowHandle<'_>,
display_handle: raw_window_handle::DisplayHandle<'_>,
) -> Result<Arc<Surface>, vulkano::Validated<vulkano::VulkanError>> {
match (window_handle.as_raw(), display_handle.as_raw()) {
#[cfg(target_os = "macos")]
(
raw_window_handle::RawWindowHandle::AppKit(raw_window_handle::AppKitWindowHandle {
ns_view,
..
}),
_,
) => unsafe {
use cocoa::{appkit::NSView, base::id as cocoa_id};
use objc::runtime::YES;

let layer = metal::MetalLayer::new();
layer.set_opaque(false);
layer.set_presents_with_transaction(false);
let view = ns_view.as_ptr() as cocoa_id;
view.setWantsLayer(YES);
view.setLayer(layer.as_ref() as *const _ as _);
Surface::from_metal(instance.clone(), layer.as_ref(), None)
#[cfg(target_vendor = "apple")]
(raw_window_handle::RawWindowHandle::AppKit(handle), _) => unsafe {
let layer = raw_window_metal::Layer::from_ns_view(handle.ns_view);
Surface::from_metal(instance.clone(), layer.as_ptr().as_ptr(), None)
},
#[cfg(target_vendor = "apple")]
(raw_window_handle::RawWindowHandle::UiKit(handle), _) => unsafe {
let layer = raw_window_metal::Layer::from_ui_view(handle.ui_view);
Surface::from_metal(instance.clone(), layer.as_ptr().as_ptr(), None)
},
(
raw_window_handle::RawWindowHandle::Xlib(raw_window_handle::XlibWindowHandle {
Expand Down
Loading