1
+ //! Softbuffer implementation using CoreGraphics.
1
2
use crate :: backend_interface:: * ;
2
3
use crate :: error:: InitError ;
3
4
use crate :: { Rect , SoftBufferError } ;
@@ -6,8 +7,7 @@ use objc2::runtime::{AnyObject, Bool};
6
7
use objc2:: { define_class, msg_send, AllocAnyThread , DefinedClass , MainThreadMarker , Message } ;
7
8
use objc2_core_foundation:: { CFRetained , CGPoint } ;
8
9
use objc2_core_graphics:: {
9
- CGBitmapInfo , CGColorRenderingIntent , CGColorSpace , CGColorSpaceCreateDeviceRGB ,
10
- CGDataProviderCreateWithData , CGImageAlphaInfo , CGImageCreate ,
10
+ CGBitmapInfo , CGColorRenderingIntent , CGColorSpace , CGDataProvider , CGImage , CGImageAlphaInfo ,
11
11
} ;
12
12
use objc2_foundation:: {
13
13
ns_string, NSDictionary , NSKeyValueChangeKey , NSKeyValueChangeNewKey ,
@@ -27,7 +27,7 @@ use std::ptr::{self, slice_from_raw_parts_mut, NonNull};
27
27
define_class ! (
28
28
#[ unsafe ( super ( NSObject ) ) ]
29
29
#[ name = "SoftbufferObserver" ]
30
- #[ ivars = Retained < CALayer > ]
30
+ #[ ivars = SendCALayer ]
31
31
struct Observer ;
32
32
33
33
/// NSKeyValueObserving
@@ -45,13 +45,9 @@ define_class!(
45
45
}
46
46
) ;
47
47
48
- // SAFETY: The `CALayer` that the observer contains is thread safe.
49
- unsafe impl Send for Observer { }
50
- unsafe impl Sync for Observer { }
51
-
52
48
impl Observer {
53
49
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 ( ) ) ) ;
55
51
unsafe { msg_send ! [ super ( this) , init] }
56
52
}
57
53
@@ -64,11 +60,9 @@ impl Observer {
64
60
65
61
let change =
66
62
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`" ) ;
72
66
73
67
// NOTE: Setting these values usually causes a quarter second animation to occur, which is
74
68
// undesirable.
@@ -106,7 +100,7 @@ pub struct CGImpl<D, W> {
106
100
/// Can also be retrieved from `layer.superlayer()`.
107
101
root_layer : SendCALayer ,
108
102
observer : Retained < Observer > ,
109
- color_space : SendCGColorSpace ,
103
+ color_space : CFRetained < CGColorSpace > ,
110
104
/// The width of the underlying buffer.
111
105
width : usize ,
112
106
/// The height of the underlying buffer.
@@ -229,7 +223,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for CGImpl<
229
223
layer. setContentsGravity ( unsafe { kCAGravityTopLeft } ) ;
230
224
231
225
// 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 ( ) ;
233
227
234
228
// Grab initial width and height from the layer (whose properties have just been initialized
235
229
// by the observer using `NSKeyValueObservingOptionInitial`).
@@ -242,7 +236,7 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> SurfaceInterface<D, W> for CGImpl<
242
236
layer : SendCALayer ( layer) ,
243
237
root_layer : SendCALayer ( root_layer) ,
244
238
observer,
245
- color_space : SendCGColorSpace ( color_space ) ,
239
+ color_space,
246
240
width,
247
241
height,
248
242
_display : PhantomData ,
@@ -310,18 +304,18 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'_,
310
304
// SAFETY: The data pointer and length are valid.
311
305
// The info pointer can safely be NULL, we don't use it in the `release` callback.
312
306
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 ( )
314
308
}
315
309
} ;
316
310
317
311
let image = unsafe {
318
- CGImageCreate (
312
+ CGImage :: new (
319
313
self . imp . width ,
320
314
self . imp . height ,
321
315
8 ,
322
316
32 ,
323
317
self . imp . width * 4 ,
324
- Some ( & self . imp . color_space . 0 ) ,
318
+ Some ( & self . imp . color_space ) ,
325
319
// TODO: This looks incorrect!
326
320
CGBitmapInfo :: ByteOrder32Little | CGBitmapInfo ( CGImageAlphaInfo :: NoneSkipFirst . 0 ) ,
327
321
Some ( & data_provider) ,
@@ -350,16 +344,17 @@ impl<D: HasDisplayHandle, W: HasWindowHandle> BufferInterface for BufferImpl<'_,
350
344
}
351
345
}
352
346
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
-
358
347
struct 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:
360
354
// https://developer.apple.com/documentation/quartzcore/catransaction/1448267-lock?language=objc
361
355
// https://stackoverflow.com/questions/76250226/how-to-render-content-of-calayer-on-a-background-thread
362
356
unsafe impl Send for SendCALayer { }
357
+ // SAFETY: Same as above.
363
358
unsafe impl Sync for SendCALayer { }
364
359
365
360
impl Deref for SendCALayer {
0 commit comments