Skip to content

Use objc2-* family of crates #334

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

Merged
merged 3 commits into from
May 15, 2025
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
62 changes: 55 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,14 +56,62 @@ serial_test = "3.1.0"

[target.'cfg(target_os = "macos")'.dependencies]
cgl = "0.3.2"
cocoa = "0.25"
core-foundation = "0.9"
core-graphics = "0.23"
servo-display-link = "0.2"
io-surface = "0.15"
mach2 = "0.4"
metal = "0.24"
objc = "0.2"
objc2 = "0.6.1"
objc2-app-kit = { version = "0.3", default-features = false, features = [
"std",
"objc2-quartz-core",
"objc2-core-foundation",
"NSResponder",
"NSScreen",
"NSView",
"NSGraphics",
"NSWindow",
] }
objc2-core-foundation = { version = "0.3.1", default-features = false, features = [
"std",
"CFBase",
"CFBundle",
"CFCGTypes",
"CFDictionary",
"CFNumber",
"CFString",
] }
objc2-core-video = { version = "0.3.1", default-features = false, features = [
"std",
"objc2-core-graphics",
"CVBase",
"CVDisplayLink",
"CVPixelBuffer",
"CVReturn",
] }
objc2-foundation = { version = "0.3.1", default-features = false, features = [
"std",
"objc2-core-foundation",
"NSEnumerator",
"NSGeometry",
"NSString",
"NSValue",
] }
objc2-io-surface = { version = "0.3.1", default-features = false, features = [
"std",
"libc",
"objc2",
"objc2-core-foundation",
"IOSurfaceRef",
"IOSurfaceTypes",
] }
objc2-metal = { version = "0.3.1", default-features = false, features = [
"std",
"MTLDevice",
] }
objc2-quartz-core = { version = "0.3.1", default-features = false, features = [
"std",
"objc2-core-foundation",
"CALayer",
"CATransaction",
"CATransform3D",
] }

[target.'cfg(all(unix, not(any(target_os = "macos", target_os = "android", target_env = "ohos"))))'.dependencies.wayland-sys]
version = "0.30"
Expand Down
4 changes: 0 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,6 @@ extern crate bitflags;
#[macro_use]
extern crate log;

#[cfg(target_os = "macos")]
#[macro_use]
extern crate objc;

pub mod platform;
pub use platform::default::connection::{Connection, NativeConnection};
pub use platform::default::context::{Context, ContextDescriptor, NativeContext};
Expand Down
48 changes: 32 additions & 16 deletions src/platform/macos/cgl/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,15 +125,26 @@ impl Connection {
raw_handle: rwh_05::RawWindowHandle,
_size: Size2D<i32>,
) -> Result<NativeWidget, Error> {
use crate::platform::macos::system::surface::NSView;
use cocoa::base::id;
use objc2::{MainThreadMarker, Message};
use objc2_app_kit::{NSView, NSWindow};
use rwh_05::RawWindowHandle::AppKit;

match raw_handle {
AppKit(handle) => Ok(NativeWidget {
view: NSView(unsafe { msg_send![handle.ns_view as id, retain] }),
opaque: unsafe { msg_send![handle.ns_window as id, isOpaque] },
}),
AppKit(handle) => {
assert!(
MainThreadMarker::new().is_some(),
"NSView is only usable on the main thread"
);
// SAFETY: The pointer is valid for as long as the handle is,
// and we just checked that we're on the main thread.
let ns_view = unsafe { handle.ns_view.cast::<NSView>().as_ref().unwrap() };
let ns_window = unsafe { handle.ns_window.cast::<NSWindow>().as_ref().unwrap() };

Ok(NativeWidget {
view: ns_view.retain(),
opaque: unsafe { ns_window.isOpaque() },
})
}
_ => Err(Error::IncompatibleNativeWidget),
}
}
Expand All @@ -146,21 +157,26 @@ impl Connection {
handle: rwh_06::WindowHandle,
_size: Size2D<i32>,
) -> Result<NativeWidget, Error> {
use crate::platform::macos::system::surface::NSView;
use cocoa::base::id;
use objc2::{MainThreadMarker, Message};
use objc2_app_kit::NSView;
use rwh_06::RawWindowHandle::AppKit;

match handle.as_raw() {
AppKit(handle) => {
let ns_view = handle.ns_view.as_ptr() as id;
// https://developer.apple.com/documentation/appkit/nsview/1483301-window
let ns_window: id = unsafe { msg_send![ns_view, window] };
assert!(
MainThreadMarker::new().is_some(),
"NSView is only usable on the main thread"
);
// SAFETY: The pointer is valid for as long as the handle is,
// and we just checked that we're on the main thread.
let ns_view = unsafe { handle.ns_view.cast::<NSView>().as_ref() };
let ns_window = ns_view
.window()
.expect("view must be installed in a window");
Ok(NativeWidget {
// Increment the nsview's reference count with retain. See:
// https://developer.apple.com/documentation/objectivec/1418956-nsobject/1571946-retain
view: NSView(unsafe { msg_send![ns_view, retain] }),
// https://developer.apple.com/documentation/appkit/nswindow/1419086-isopaque
opaque: unsafe { msg_send![ns_window, isOpaque] },
// Extend the lifetime of the view.
view: ns_view.retain(),
opaque: unsafe { ns_window.isOpaque() },
})
}
_ => Err(Error::IncompatibleNativeWidget),
Expand Down
26 changes: 8 additions & 18 deletions src/platform/macos/cgl/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,12 @@ use cgl::{
};
use cgl::{CGLGetCurrentContext, CGLGetPixelFormat, CGLPixelFormatAttribute, CGLPixelFormatObj};
use cgl::{CGLReleasePixelFormat, CGLRetainPixelFormat, CGLSetCurrentContext};
use core_foundation::base::TCFType;
use core_foundation::bundle::CFBundleGetBundleWithIdentifier;
use core_foundation::bundle::CFBundleGetFunctionPointerForName;
use core_foundation::bundle::CFBundleRef;
use core_foundation::string::CFString;
use glow::HasContext;
use objc2_core_foundation::{CFBundle, CFRetained, CFString};
use std::mem;
use std::os::raw::c_void;
use std::ptr;
use std::rc::Rc;
use std::str::FromStr;
use std::thread;

// No CGL error occurred.
Expand All @@ -48,15 +43,10 @@ const kCGLOGLPVersion_GL4_Core: CGLPixelFormatAttribute = 0x4100;
static OPENGL_FRAMEWORK_IDENTIFIER: &str = "com.apple.opengl";

thread_local! {
static OPENGL_FRAMEWORK: CFBundleRef = {
unsafe {
let framework_identifier: CFString =
FromStr::from_str(OPENGL_FRAMEWORK_IDENTIFIER).unwrap();
let framework =
CFBundleGetBundleWithIdentifier(framework_identifier.as_concrete_TypeRef());
assert!(!framework.is_null());
framework
}
static OPENGL_FRAMEWORK: CFRetained<CFBundle> = {
let framework_identifier = CFString::from_str(OPENGL_FRAMEWORK_IDENTIFIER);
let framework = CFBundle::bundle_with_identifier(Some(&framework_identifier));
framework.unwrap()
};
}

Expand Down Expand Up @@ -495,9 +485,9 @@ impl Device {
}

fn get_proc_address(symbol_name: &str) -> *const c_void {
OPENGL_FRAMEWORK.with(|framework| unsafe {
let symbol_name: CFString = FromStr::from_str(symbol_name).unwrap();
CFBundleGetFunctionPointerForName(*framework, symbol_name.as_concrete_TypeRef())
OPENGL_FRAMEWORK.with(|framework| {
let symbol_name = CFString::from_str(symbol_name);
framework.function_pointer_for_name(Some(&symbol_name))
})
}

Expand Down
58 changes: 49 additions & 9 deletions src/platform/macos/cgl/surface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,13 @@ use crate::gl_utils;
use crate::platform::macos::system::surface::Surface as SystemSurface;
use crate::renderbuffers::Renderbuffers;
use crate::{gl, Error, SurfaceAccess, SurfaceID, SurfaceInfo, SurfaceType, WindowingApiError};
use cgl::{kCGLNoError, CGLErrorString, CGLGetCurrentContext, CGLTexImageIOSurface2D, GLenum};
use glow::Context as Gl;

use core_foundation::base::TCFType;
use euclid::default::Size2D;
use glow::{HasContext, Texture};
use io_surface::{self, IOSurface};
use objc2_io_surface::IOSurfaceRef;
use std::ffi::CStr;
use std::fmt::{self, Debug, Formatter};
use std::marker::PhantomData;
use std::rc::Rc;
Expand Down Expand Up @@ -76,6 +77,38 @@ impl Debug for SurfaceTexture {
}
}

fn surface_bind_to_gl_texture(surface: &IOSurfaceRef, width: i32, height: i32, has_alpha: bool) {
const BGRA: GLenum = 0x80E1;
const RGBA: GLenum = 0x1908;
const RGB: GLenum = 0x1907;
const TEXTURE_RECTANGLE_ARB: GLenum = 0x84F5;
const UNSIGNED_INT_8_8_8_8_REV: GLenum = 0x8367;

unsafe {
let context = CGLGetCurrentContext();
let gl_error = CGLTexImageIOSurface2D(
context,
TEXTURE_RECTANGLE_ARB,
if has_alpha {
RGBA as GLenum
} else {
RGB as GLenum
},
width,
height,
BGRA as GLenum,
UNSIGNED_INT_8_8_8_8_REV,
surface as *const IOSurfaceRef as cgl::IOSurfaceRef,
0,
);

if gl_error != kCGLNoError {
let error_msg = CStr::from_ptr(CGLErrorString(gl_error));
panic!("{}", error_msg.to_string_lossy());
}
}
}

Comment on lines +80 to +111
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was previously provided in io_surface::IOSurface::bind_to_gl_texture, but it really mixes two domains (IOSurface and CGL), and requires that we link both of those, so I didn't want to expose it in objc2-io-surface.

impl Device {
/// Creates either a generic or a widget surface, depending on the supplied surface type.
///
Expand Down Expand Up @@ -172,12 +205,17 @@ impl Device {
})
}

fn bind_to_gl_texture(&self, gl: &Gl, io_surface: &IOSurface, size: &Size2D<i32>) -> Texture {
fn bind_to_gl_texture(
&self,
gl: &Gl,
io_surface: &IOSurfaceRef,
size: &Size2D<i32>,
) -> Texture {
unsafe {
let texture = gl.create_texture().unwrap();

gl.bind_texture(gl::TEXTURE_RECTANGLE, Some(texture));
io_surface.bind_to_gl_texture(size.width, size.height, true);
surface_bind_to_gl_texture(io_surface, size.width, size.height, true);

gl.tex_parameter_i32(
gl::TEXTURE_RECTANGLE,
Expand Down Expand Up @@ -291,10 +329,12 @@ impl Device {
unsafe {
let size = surface.system_surface.size;
gl.bind_texture(gl::TEXTURE_RECTANGLE, surface.texture_object);
surface
.system_surface
.io_surface
.bind_to_gl_texture(size.width, size.height, true);
surface_bind_to_gl_texture(
&surface.system_surface.io_surface,
size.width,
size.height,
true,
);
gl.bind_texture(gl::TEXTURE_RECTANGLE, None);
}

Expand Down Expand Up @@ -403,7 +443,7 @@ impl Device {
impl Surface {
#[inline]
fn id(&self) -> SurfaceID {
SurfaceID(self.system_surface.io_surface.as_concrete_TypeRef() as usize)
SurfaceID(&*self.system_surface.io_surface as *const IOSurfaceRef as usize)
}
}

Expand Down
Loading