1+ //! Softbuffer implementation using CoreGraphics.
12use crate :: backend_interface:: * ;
23use crate :: error:: InitError ;
34use crate :: { Rect , SoftBufferError } ;
@@ -6,8 +7,7 @@ use objc2::runtime::{AnyObject, Bool};
67use objc2:: { define_class, msg_send, AllocAnyThread , DefinedClass , MainThreadMarker , Message } ;
78use objc2_core_foundation:: { CFRetained , CGPoint } ;
89use objc2_core_graphics:: {
9- CGBitmapInfo , CGColorRenderingIntent , CGColorSpace , CGColorSpaceCreateDeviceRGB ,
10- CGDataProviderCreateWithData , CGImageAlphaInfo , CGImageCreate ,
10+ CGBitmapInfo , CGColorRenderingIntent , CGColorSpace , CGDataProvider , CGImage , CGImageAlphaInfo ,
1111} ;
1212use objc2_foundation:: {
1313 ns_string, NSDictionary , NSKeyValueChangeKey , NSKeyValueChangeNewKey ,
@@ -27,7 +27,7 @@ use std::ptr::{self, slice_from_raw_parts_mut, NonNull};
2727define_class ! (
2828 #[ unsafe ( super ( NSObject ) ) ]
2929 #[ name = "SoftbufferObserver" ]
30- #[ ivars = Retained < CALayer > ]
30+ #[ ivars = SendCALayer ]
3131 struct Observer ;
3232
3333 /// NSKeyValueObserving
@@ -45,13 +45,9 @@ define_class!(
4545 }
4646) ;
4747
48- // SAFETY: The `CALayer` that the observer contains is thread safe.
49- unsafe impl Send for Observer { }
50- unsafe impl Sync for Observer { }
51-
5248impl Observer {
5349 fn new ( layer : & CALayer ) -> Retained < Self > {
54- let this = Self :: alloc ( ) . set_ivars ( layer. retain ( ) ) ;
50+ let this = Self :: alloc ( ) . set_ivars ( SendCALayer ( layer. retain ( ) ) ) ;
5551 unsafe { msg_send ! [ super ( this) , init] }
5652 }
5753
@@ -64,11 +60,9 @@ impl Observer {
6460
6561 let change =
6662 change. expect ( "requested a change dictionary in `addObserver`, but none was provided" ) ;
67- let new = unsafe {
68- change
69- . objectForKey ( NSKeyValueChangeNewKey )
70- . expect ( "requested change dictionary did not contain `NSKeyValueChangeNewKey`" )
71- } ;
63+ let new = change
64+ . objectForKey ( unsafe { NSKeyValueChangeNewKey } )
65+ . expect ( "requested change dictionary did not contain `NSKeyValueChangeNewKey`" ) ;
7266
7367 // NOTE: Setting these values usually causes a quarter second animation to occur, which is
7468 // undesirable.
@@ -106,7 +100,7 @@ pub struct CGImpl<D, W> {
106100 /// Can also be retrieved from `layer.superlayer()`.
107101 root_layer : SendCALayer ,
108102 observer : Retained < Observer > ,
109- color_space : SendCGColorSpace ,
103+ color_space : CFRetained < CGColorSpace > ,
110104 /// The width of the underlying buffer.
111105 width : usize ,
112106 /// The height of the underlying buffer.
@@ -229,7 +223,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for CGImpl<
229223 layer. setContentsGravity ( unsafe { kCAGravityTopLeft } ) ;
230224
231225 // Initialize color space here, to reduce work later on.
232- let color_space = unsafe { CGColorSpaceCreateDeviceRGB ( ) } . unwrap ( ) ;
226+ let color_space = unsafe { CGColorSpace :: new_device_rgb ( ) } . unwrap ( ) ;
233227
234228 // Grab initial width and height from the layer (whose properties have just been initialized
235229 // by the observer using `NSKeyValueObservingOptionInitial`).
@@ -242,7 +236,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for CGImpl<
242236 layer : SendCALayer ( layer) ,
243237 root_layer : SendCALayer ( root_layer) ,
244238 observer,
245- color_space : SendCGColorSpace ( color_space ) ,
239+ color_space,
246240 width,
247241 height,
248242 _display : PhantomData ,
@@ -310,18 +304,18 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'_,
310304 // SAFETY: The data pointer and length are valid.
311305 // The info pointer can safely be NULL, we don't use it in the `release` callback.
312306 unsafe {
313- CGDataProviderCreateWithData ( ptr:: null_mut ( ) , data_ptr, len, Some ( release) ) . unwrap ( )
307+ CGDataProvider :: with_data ( ptr:: null_mut ( ) , data_ptr, len, Some ( release) ) . unwrap ( )
314308 }
315309 } ;
316310
317311 let image = unsafe {
318- CGImageCreate (
312+ CGImage :: new (
319313 self . imp . width ,
320314 self . imp . height ,
321315 8 ,
322316 32 ,
323317 self . imp . width * 4 ,
324- Some ( & self . imp . color_space . 0 ) ,
318+ Some ( & self . imp . color_space ) ,
325319 // TODO: This looks incorrect!
326320 CGBitmapInfo :: ByteOrder32Little | CGBitmapInfo ( CGImageAlphaInfo :: NoneSkipFirst . 0 ) ,
327321 Some ( & data_provider) ,
@@ -350,16 +344,17 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'_,
350344 }
351345}
352346
353- struct SendCGColorSpace ( CFRetained < CGColorSpace > ) ;
354- // SAFETY: `CGColorSpace` is immutable, and can freely be shared between threads.
355- unsafe impl Send for SendCGColorSpace { }
356- unsafe impl Sync for SendCGColorSpace { }
357-
358347struct SendCALayer ( Retained < CALayer > ) ;
359- // CALayer is thread safe, like most things in Core Animation, see:
348+
349+ // SAFETY: CALayer is dubiously thread safe, like most things in Core Animation.
350+ // But since we make sure to do our changes within a CATransaction, it is
351+ // _probably_ fine for us to use CALayer from different threads.
352+ //
353+ // See also:
360354// https://developer.apple.com/documentation/quartzcore/catransaction/1448267-lock?language=objc
361355// https://stackoverflow.com/questions/76250226/how-to-render-content-of-calayer-on-a-background-thread
362356unsafe impl Send for SendCALayer { }
357+ // SAFETY: Same as above.
363358unsafe impl Sync for SendCALayer { }
364359
365360impl Deref for SendCALayer {
0 commit comments