@@ -18,6 +18,9 @@ use objc::rc::autoreleasepool;
18
18
use objc:: runtime:: Object ;
19
19
20
20
21
+ //TODO: make it a weak pointer, so that we know which
22
+ // frames can be replaced if we receive an unknown
23
+ // texture pointer by an acquired drawable.
21
24
pub type CAMetalLayer = * mut Object ;
22
25
23
26
pub struct Surface {
@@ -27,9 +30,9 @@ pub struct Surface {
27
30
}
28
31
29
32
#[ derive( Debug ) ]
30
- pub ( crate ) struct SurfaceInner {
31
- pub ( crate ) view : * mut Object ,
32
- pub ( crate ) render_layer : Mutex < CAMetalLayer > ,
33
+ pub struct SurfaceInner {
34
+ view : * mut Object ,
35
+ render_layer : Mutex < CAMetalLayer > ,
33
36
}
34
37
35
38
unsafe impl Send for SurfaceInner { }
@@ -41,16 +44,30 @@ impl Drop for SurfaceInner {
41
44
}
42
45
}
43
46
47
+ #[ derive( Debug ) ]
48
+ struct FrameNotFound {
49
+ drawable : metal:: Drawable ,
50
+ texture : metal:: Texture ,
51
+ }
52
+
53
+
44
54
impl SurfaceInner {
45
- pub ( crate ) fn into_surface ( self ) -> Surface {
55
+ pub fn new ( view : * mut Object , layer : CAMetalLayer ) -> Self {
56
+ SurfaceInner {
57
+ view,
58
+ render_layer : Mutex :: new ( layer) ,
59
+ }
60
+ }
61
+
62
+ pub fn into_surface ( self ) -> Surface {
46
63
Surface {
47
64
inner : Arc :: new ( self ) ,
48
65
main_thread_id : thread:: current ( ) . id ( ) ,
49
66
has_swapchain : false ,
50
67
}
51
68
}
52
69
53
- fn next_frame < ' a > ( & self , frames : & ' a [ Frame ] ) -> Result < ( usize , MutexGuard < ' a , FrameInner > ) , ( ) > {
70
+ fn next_frame < ' a > ( & self , frames : & ' a [ Frame ] ) -> Result < ( usize , MutexGuard < ' a , FrameInner > ) , FrameNotFound > {
54
71
let layer_ref = self . render_layer . lock ( ) ;
55
72
autoreleasepool ( || { // for the drawable
56
73
let ( drawable, texture_temp) : ( & metal:: DrawableRef , & metal:: TextureRef ) = unsafe {
@@ -68,19 +85,38 @@ impl SurfaceInner {
68
85
debug ! ( "next is frame[{}]" , index) ;
69
86
Ok ( ( index, frame) )
70
87
}
71
- None => Err ( ( ) ) ,
88
+ None => Err ( FrameNotFound {
89
+ drawable : drawable. to_owned ( ) ,
90
+ texture : texture_temp. to_owned ( ) ,
91
+ } ) ,
72
92
}
73
93
} )
74
94
}
95
+
96
+ fn dimensions ( & self ) -> Extent2D {
97
+ unsafe {
98
+ // NSView/UIView bounds are measured in DIPs
99
+ let bounds: CGRect = msg_send ! [ self . view, bounds] ;
100
+ //let bounds_pixel: NSRect = msg_send![self.nsview, convertRectToBacking:bounds];
101
+ Extent2D {
102
+ width : bounds. size . width as _ ,
103
+ height : bounds. size . height as _ ,
104
+ }
105
+ }
106
+ }
75
107
}
76
108
109
+
77
110
#[ derive( Debug ) ]
78
111
struct FrameInner {
79
112
drawable : Option < metal:: Drawable > ,
80
113
/// If there is a `drawable`, availability indicates if it's free for grabs.
81
114
/// If there is `None`, `available == false` means that the frame has already
82
115
/// been acquired and the `drawable` will appear at some point.
83
116
available : bool ,
117
+ /// Stays true for as long as the drawable is circulating through the
118
+ /// CAMetalLayer's frame queue.
119
+ linked : bool ,
84
120
last_frame : usize ,
85
121
}
86
122
@@ -128,16 +164,23 @@ impl Drop for Swapchain {
128
164
impl Swapchain {
129
165
/// Returns the drawable for the specified swapchain image index,
130
166
/// marks the index as free for future use.
131
- pub ( crate ) fn take_drawable ( & self , index : hal:: SwapImageIndex ) -> metal:: Drawable {
167
+ pub ( crate ) fn take_drawable ( & self , index : hal:: SwapImageIndex ) -> Result < metal:: Drawable , ( ) > {
132
168
let mut frame = self
133
169
. frames [ index as usize ]
134
170
. inner
135
171
. lock ( ) ;
136
- assert ! ( !frame. available) ;
137
- frame. available = true ;
138
- frame. drawable
139
- . take ( )
140
- . expect ( "Drawable has not been acquired!" )
172
+ assert ! ( !frame. available && frame. linked) ;
173
+
174
+ match frame. drawable . take ( ) {
175
+ Some ( drawable) => {
176
+ frame. available = true ;
177
+ Ok ( drawable)
178
+ }
179
+ None => {
180
+ frame. linked = false ;
181
+ Err ( ( ) )
182
+ }
183
+ }
141
184
}
142
185
143
186
fn signal_sync ( & self , sync : hal:: FrameSync < Backend > ) {
@@ -175,10 +218,21 @@ impl SwapchainImage {
175
218
}
176
219
// wait for new frames to come until we meet the chosen one
177
220
let mut count = 1 ;
178
- while self . surface . next_frame ( & self . frames ) . unwrap ( ) . 0 != self . index as usize {
179
- count += 1 ;
180
- }
181
- debug ! ( "Swapchain image is ready after {} frames" , count) ;
221
+ loop {
222
+ match self . surface . next_frame ( & self . frames ) {
223
+ Ok ( ( index, _) ) if index == self . index as usize => {
224
+ debug ! ( "Swapchain image is ready after {} frames" , count) ;
225
+ break
226
+ }
227
+ Ok ( _) => {
228
+ count += 1 ;
229
+ }
230
+ Err ( _e) => {
231
+ debug ! ( "Swapchain drawables are changed" ) ;
232
+ break
233
+ }
234
+ }
235
+ }
182
236
count
183
237
}
184
238
}
@@ -234,20 +288,6 @@ impl hal::Surface<Backend> for Surface {
234
288
}
235
289
}
236
290
237
- impl SurfaceInner {
238
- fn dimensions ( & self ) -> Extent2D {
239
- unsafe {
240
- // NSView/UIView bounds are measured in DIPs
241
- let bounds: CGRect = msg_send ! [ self . view, bounds] ;
242
- //let bounds_pixel: NSRect = msg_send![self.nsview, convertRectToBacking:bounds];
243
- Extent2D {
244
- width : bounds. size . width as _ ,
245
- height : bounds. size . height as _ ,
246
- }
247
- }
248
- }
249
- }
250
-
251
291
impl Device {
252
292
pub ( crate ) fn build_swapchain (
253
293
& self ,
@@ -313,6 +353,7 @@ impl Device {
313
353
inner : Mutex :: new ( FrameInner {
314
354
drawable,
315
355
available : true ,
356
+ linked : true ,
316
357
last_frame : 0 ,
317
358
} ) ,
318
359
texture : texture. to_owned ( ) ,
@@ -340,10 +381,9 @@ impl Device {
340
381
extent : config. extent ,
341
382
last_frame : 0 ,
342
383
image_ready_callbacks : Vec :: new ( ) ,
343
- acquire_mode : AcquireMode :: Wait ,
384
+ acquire_mode : AcquireMode :: Oldest ,
344
385
} ;
345
386
346
-
347
387
( swapchain, Backbuffer :: Images ( images) )
348
388
}
349
389
}
@@ -404,6 +444,9 @@ impl hal::Swapchain<Backend> for Swapchain {
404
444
}
405
445
406
446
let frame = self . frames [ oldest_index] . inner . lock ( ) ;
447
+ if !frame. linked {
448
+ return Err ( hal:: AcquireError :: OutOfDate ) ;
449
+ }
407
450
( oldest_index, frame)
408
451
}
409
452
} ;
0 commit comments