Skip to content

Commit 33c56bd

Browse files
committed
[mtl] basic error handling for the Oldest acquire method
1 parent a5a121a commit 33c56bd

File tree

2 files changed

+49
-14
lines changed

2 files changed

+49
-14
lines changed

src/backend/metal/src/command.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1785,8 +1785,9 @@ impl RawCommandQueue<Backend> for CommandQueue {
17851785

17861786
for (swapchain, index) in swapchains {
17871787
debug!("presenting frame {}", index);
1788-
let drawable = swapchain.borrow().take_drawable(index);
1789-
command_buffer.present_drawable(&drawable);
1788+
if let Ok(drawable) = swapchain.borrow().take_drawable(index) {
1789+
command_buffer.present_drawable(&drawable);
1790+
}
17901791
}
17911792

17921793
command_buffer.commit();

src/backend/metal/src/window.rs

Lines changed: 46 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ impl Drop for SurfaceInner {
4444
}
4545
}
4646

47+
#[derive(Debug)]
48+
struct FrameNotFound {
49+
drawable: metal::Drawable,
50+
texture: metal::Texture,
51+
}
52+
4753

4854
impl SurfaceInner {
4955
pub fn new(view: *mut Object, layer: CAMetalLayer) -> Self {
@@ -61,7 +67,7 @@ impl SurfaceInner {
6167
}
6268
}
6369

64-
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> {
6571
let layer_ref = self.render_layer.lock();
6672
autoreleasepool(|| { // for the drawable
6773
let (drawable, texture_temp): (&metal::DrawableRef, &metal::TextureRef) = unsafe {
@@ -79,7 +85,10 @@ impl SurfaceInner {
7985
debug!("next is frame[{}]", index);
8086
Ok((index, frame))
8187
}
82-
None => Err(()),
88+
None => Err(FrameNotFound {
89+
drawable: drawable.to_owned(),
90+
texture: texture_temp.to_owned(),
91+
}),
8392
}
8493
})
8594
}
@@ -105,6 +114,9 @@ struct FrameInner {
105114
/// If there is `None`, `available == false` means that the frame has already
106115
/// been acquired and the `drawable` will appear at some point.
107116
available: bool,
117+
/// Stays true for as long as the drawable is circulating through the
118+
/// CAMetalLayer's frame queue.
119+
linked: bool,
108120
last_frame: usize,
109121
}
110122

@@ -152,16 +164,23 @@ impl Drop for Swapchain {
152164
impl Swapchain {
153165
/// Returns the drawable for the specified swapchain image index,
154166
/// marks the index as free for future use.
155-
pub(crate) fn take_drawable(&self, index: hal::SwapImageIndex) -> metal::Drawable {
167+
pub(crate) fn take_drawable(&self, index: hal::SwapImageIndex) -> Result<metal::Drawable, ()> {
156168
let mut frame = self
157169
.frames[index as usize]
158170
.inner
159171
.lock();
160-
assert!(!frame.available);
161-
frame.available = true;
162-
frame.drawable
163-
.take()
164-
.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+
}
165184
}
166185

167186
fn signal_sync(&self, sync: hal::FrameSync<Backend>) {
@@ -199,10 +218,21 @@ impl SwapchainImage {
199218
}
200219
// wait for new frames to come until we meet the chosen one
201220
let mut count = 1;
202-
while self.surface.next_frame(&self.frames).unwrap().0 != self.index as usize {
203-
count += 1;
204-
}
205-
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+
}
206236
count
207237
}
208238
}
@@ -323,6 +353,7 @@ impl Device {
323353
inner: Mutex::new(FrameInner {
324354
drawable,
325355
available: true,
356+
linked: true,
326357
last_frame: 0,
327358
}),
328359
texture: texture.to_owned(),
@@ -413,6 +444,9 @@ impl hal::Swapchain<Backend> for Swapchain {
413444
}
414445

415446
let frame = self.frames[oldest_index].inner.lock();
447+
if !frame.linked {
448+
return Err(hal::AcquireError::OutOfDate);
449+
}
416450
(oldest_index, frame)
417451
}
418452
};

0 commit comments

Comments
 (0)