diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c516648..d4ba4e4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -98,6 +98,7 @@ jobs: - name: Pin deps that break MSRV if: matrix.rust_version == '1.71.0' run: | + cargo update -p half --precise 2.4.1 cargo update -p bumpalo --precise 3.14.0 - name: Build crate diff --git a/Cargo.toml b/Cargo.toml index 2fbb87d..452623d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -81,7 +81,7 @@ features = [ ] [target.'cfg(target_vendor = "apple")'.dependencies] -objc2-core-graphics = { version = "0.3.0", default-features = false, features = [ +objc2-core-graphics = { version = "0.3.1", default-features = false, features = [ "std", "objc2", "CGColorSpace", @@ -89,11 +89,11 @@ objc2-core-graphics = { version = "0.3.0", default-features = false, features = "CGImage", ] } objc2 = "0.6.0" -objc2-core-foundation = { version = "0.3.0", default-features = false, features = [ +objc2-core-foundation = { version = "0.3.1", default-features = false, features = [ "std", "CFCGTypes", ] } -objc2-foundation = { version = "0.3.0", default-features = false, features = [ +objc2-foundation = { version = "0.3.1", default-features = false, features = [ "std", "objc2-core-foundation", "NSDictionary", @@ -103,7 +103,7 @@ objc2-foundation = { version = "0.3.0", default-features = false, features = [ "NSThread", "NSValue", ] } -objc2-quartz-core = { version = "0.3.0", default-features = false, features = [ +objc2-quartz-core = { version = "0.3.1", default-features = false, features = [ "std", "objc2-core-foundation", "CALayer", diff --git a/src/backends/cg.rs b/src/backends/cg.rs index 3e3cbe4..ba6c17a 100644 --- a/src/backends/cg.rs +++ b/src/backends/cg.rs @@ -1,3 +1,4 @@ +//! Softbuffer implementation using CoreGraphics. use crate::backend_interface::*; use crate::error::InitError; use crate::{Rect, SoftBufferError}; @@ -6,8 +7,7 @@ use objc2::runtime::{AnyObject, Bool}; use objc2::{define_class, msg_send, AllocAnyThread, DefinedClass, MainThreadMarker, Message}; use objc2_core_foundation::{CFRetained, CGPoint}; use objc2_core_graphics::{ - CGBitmapInfo, CGColorRenderingIntent, CGColorSpace, CGColorSpaceCreateDeviceRGB, - CGDataProviderCreateWithData, CGImageAlphaInfo, CGImageCreate, + CGBitmapInfo, CGColorRenderingIntent, CGColorSpace, CGDataProvider, CGImage, CGImageAlphaInfo, }; use objc2_foundation::{ ns_string, NSDictionary, NSKeyValueChangeKey, NSKeyValueChangeNewKey, @@ -27,7 +27,7 @@ use std::ptr::{self, slice_from_raw_parts_mut, NonNull}; define_class!( #[unsafe(super(NSObject))] #[name = "SoftbufferObserver"] - #[ivars = Retained] + #[ivars = SendCALayer] struct Observer; /// NSKeyValueObserving @@ -45,13 +45,9 @@ define_class!( } ); -// SAFETY: The `CALayer` that the observer contains is thread safe. -unsafe impl Send for Observer {} -unsafe impl Sync for Observer {} - impl Observer { fn new(layer: &CALayer) -> Retained { - let this = Self::alloc().set_ivars(layer.retain()); + let this = Self::alloc().set_ivars(SendCALayer(layer.retain())); unsafe { msg_send![super(this), init] } } @@ -64,11 +60,9 @@ impl Observer { let change = change.expect("requested a change dictionary in `addObserver`, but none was provided"); - let new = unsafe { - change - .objectForKey(NSKeyValueChangeNewKey) - .expect("requested change dictionary did not contain `NSKeyValueChangeNewKey`") - }; + let new = change + .objectForKey(unsafe { NSKeyValueChangeNewKey }) + .expect("requested change dictionary did not contain `NSKeyValueChangeNewKey`"); // NOTE: Setting these values usually causes a quarter second animation to occur, which is // undesirable. @@ -106,7 +100,7 @@ pub struct CGImpl { /// Can also be retrieved from `layer.superlayer()`. root_layer: SendCALayer, observer: Retained, - color_space: SendCGColorSpace, + color_space: CFRetained, /// The width of the underlying buffer. width: usize, /// The height of the underlying buffer. @@ -229,7 +223,7 @@ impl SurfaceInterface for CGImpl< layer.setContentsGravity(unsafe { kCAGravityTopLeft }); // Initialize color space here, to reduce work later on. - let color_space = unsafe { CGColorSpaceCreateDeviceRGB() }.unwrap(); + let color_space = unsafe { CGColorSpace::new_device_rgb() }.unwrap(); // Grab initial width and height from the layer (whose properties have just been initialized // by the observer using `NSKeyValueObservingOptionInitial`). @@ -242,7 +236,7 @@ impl SurfaceInterface for CGImpl< layer: SendCALayer(layer), root_layer: SendCALayer(root_layer), observer, - color_space: SendCGColorSpace(color_space), + color_space, width, height, _display: PhantomData, @@ -310,18 +304,18 @@ impl BufferInterface for BufferImpl<'_, // SAFETY: The data pointer and length are valid. // The info pointer can safely be NULL, we don't use it in the `release` callback. unsafe { - CGDataProviderCreateWithData(ptr::null_mut(), data_ptr, len, Some(release)).unwrap() + CGDataProvider::with_data(ptr::null_mut(), data_ptr, len, Some(release)).unwrap() } }; let image = unsafe { - CGImageCreate( + CGImage::new( self.imp.width, self.imp.height, 8, 32, self.imp.width * 4, - Some(&self.imp.color_space.0), + Some(&self.imp.color_space), // TODO: This looks incorrect! CGBitmapInfo::ByteOrder32Little | CGBitmapInfo(CGImageAlphaInfo::NoneSkipFirst.0), Some(&data_provider), @@ -350,16 +344,17 @@ impl BufferInterface for BufferImpl<'_, } } -struct SendCGColorSpace(CFRetained); -// SAFETY: `CGColorSpace` is immutable, and can freely be shared between threads. -unsafe impl Send for SendCGColorSpace {} -unsafe impl Sync for SendCGColorSpace {} - struct SendCALayer(Retained); -// CALayer is thread safe, like most things in Core Animation, see: + +// SAFETY: CALayer is dubiously thread safe, like most things in Core Animation. +// But since we make sure to do our changes within a CATransaction, it is +// _probably_ fine for us to use CALayer from different threads. +// +// See also: // https://developer.apple.com/documentation/quartzcore/catransaction/1448267-lock?language=objc // https://stackoverflow.com/questions/76250226/how-to-render-content-of-calayer-on-a-background-thread unsafe impl Send for SendCALayer {} +// SAFETY: Same as above. unsafe impl Sync for SendCALayer {} impl Deref for SendCALayer {