Skip to content

Commit 122da13

Browse files
bors[bot]kvark
andcommitted
Merge #2401
2401: [mtl] Filament compatibility fixes r=grovesNL a=kvark ![gfx-filament-pbr-small](https://user-images.githubusercontent.com/107301/45447569-ea30fd80-b69d-11e8-8ffd-50aa4cd947ec.png) There are still occasional asserts on frame acquisition, so leaving #2400 open for now. PR checklist: - [ ] `make` succeeds (on *nix) - [ ] `make reftests` succeeds - [ ] tested examples with the following backends: - [ ] `rustfmt` run on changed code Co-authored-by: Dzmitry Malyshau <[email protected]>
2 parents 4d6b4da + 33c56bd commit 122da13

File tree

3 files changed

+109
-56
lines changed

3 files changed

+109
-56
lines changed

src/backend/metal/src/command.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -588,8 +588,11 @@ impl StageResources {
588588
pool_offsets.textures += 1;
589589
}
590590
if layout.content.contains(native::DescriptorContent::BUFFER) {
591-
let (buffer, offset) = data.buffers[pool_offsets.buffers as usize].unwrap();
592-
self.buffers[res_offset.buffers as usize] = Some(buffer);
591+
let (buffer, offset) = match data.buffers[pool_offsets.buffers as usize] {
592+
Some((buffer, offset)) => (Some(buffer), offset),
593+
None => (None, 0),
594+
};
595+
self.buffers[res_offset.buffers as usize] = buffer;
593596
self.buffer_offsets[res_offset.buffers as usize] = offset;
594597
res_offset.buffers += 1;
595598
pool_offsets.buffers += 1;
@@ -1782,8 +1785,9 @@ impl RawCommandQueue<Backend> for CommandQueue {
17821785

17831786
for (swapchain, index) in swapchains {
17841787
debug!("presenting frame {}", index);
1785-
let drawable = swapchain.borrow().take_drawable(index);
1786-
command_buffer.present_drawable(&drawable);
1788+
if let Ok(drawable) = swapchain.borrow().take_drawable(index) {
1789+
command_buffer.present_drawable(&drawable);
1790+
}
17871791
}
17881792

17891793
command_buffer.commit();

src/backend/metal/src/lib.rs

Lines changed: 26 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,6 @@ use core_graphics::base::CGFloat;
4848
use core_graphics::geometry::CGRect;
4949
use foreign_types::ForeignTypeRef;
5050
use objc::runtime::{Class, Object};
51-
#[cfg(target_os = "ios")]
5251
use objc::runtime::{BOOL, YES};
5352
use parking_lot::{Condvar, Mutex};
5453

@@ -194,23 +193,33 @@ impl Instance {
194193
panic!("window does not have a valid contentView");
195194
}
196195

196+
let existing: *mut Object = msg_send![view, layer];
197197
let class = Class::get("CAMetalLayer").unwrap();
198-
let render_layer: *mut Object = msg_send![class, new];
199-
msg_send![view, setLayer: render_layer];
200-
msg_send![view, retain];
201-
let bounds: CGRect = msg_send![view, bounds];
202-
msg_send![render_layer, setBounds: bounds];
203-
204-
let window: *mut Object = msg_send![view, window];
205-
if !window.is_null() {
206-
let scale_factor: CGFloat = msg_send![window, backingScaleFactor];
207-
msg_send![render_layer, setContentsScale: scale_factor];
208-
}
198+
let use_current = if existing.is_null() {
199+
false
200+
} else {
201+
let result: BOOL = msg_send![existing, isKindOfClass:class];
202+
result == YES
203+
};
204+
205+
let render_layer: *mut Object = if use_current {
206+
existing
207+
} else {
208+
let layer: *mut Object = msg_send![class, new];
209+
msg_send![view, setLayer: layer];
210+
msg_send![view, retain];
211+
let bounds: CGRect = msg_send![view, bounds];
212+
msg_send![layer, setBounds: bounds];
213+
214+
let window: *mut Object = msg_send![view, window];
215+
if !window.is_null() {
216+
let scale_factor: CGFloat = msg_send![window, backingScaleFactor];
217+
msg_send![layer, setContentsScale: scale_factor];
218+
}
219+
layer
220+
};
209221

210-
window::SurfaceInner {
211-
view,
212-
render_layer: Mutex::new(render_layer),
213-
}
222+
window::SurfaceInner::new(view, render_layer)
214223
}
215224
}
216225

@@ -259,10 +268,7 @@ impl Instance {
259268
msg_send![view, setContentScaleFactor: scale_factor];
260269

261270
msg_send![view, retain];
262-
window::SurfaceInner {
263-
view,
264-
render_layer: Mutex::new(render_layer),
265-
}
271+
window::SurfaceInner::new(view, render_layer)
266272
}
267273
}
268274

src/backend/metal/src/window.rs

Lines changed: 75 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ use objc::rc::autoreleasepool;
1818
use objc::runtime::Object;
1919

2020

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.
2124
pub type CAMetalLayer = *mut Object;
2225

2326
pub struct Surface {
@@ -27,9 +30,9 @@ pub struct Surface {
2730
}
2831

2932
#[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>,
3336
}
3437

3538
unsafe impl Send for SurfaceInner {}
@@ -41,16 +44,30 @@ impl Drop for SurfaceInner {
4144
}
4245
}
4346

47+
#[derive(Debug)]
48+
struct FrameNotFound {
49+
drawable: metal::Drawable,
50+
texture: metal::Texture,
51+
}
52+
53+
4454
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 {
4663
Surface {
4764
inner: Arc::new(self),
4865
main_thread_id: thread::current().id(),
4966
has_swapchain: false,
5067
}
5168
}
5269

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> {
5471
let layer_ref = self.render_layer.lock();
5572
autoreleasepool(|| { // for the drawable
5673
let (drawable, texture_temp): (&metal::DrawableRef, &metal::TextureRef) = unsafe {
@@ -68,19 +85,38 @@ impl SurfaceInner {
6885
debug!("next is frame[{}]", index);
6986
Ok((index, frame))
7087
}
71-
None => Err(()),
88+
None => Err(FrameNotFound {
89+
drawable: drawable.to_owned(),
90+
texture: texture_temp.to_owned(),
91+
}),
7292
}
7393
})
7494
}
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+
}
75107
}
76108

109+
77110
#[derive(Debug)]
78111
struct FrameInner {
79112
drawable: Option<metal::Drawable>,
80113
/// If there is a `drawable`, availability indicates if it's free for grabs.
81114
/// If there is `None`, `available == false` means that the frame has already
82115
/// been acquired and the `drawable` will appear at some point.
83116
available: bool,
117+
/// Stays true for as long as the drawable is circulating through the
118+
/// CAMetalLayer's frame queue.
119+
linked: bool,
84120
last_frame: usize,
85121
}
86122

@@ -128,16 +164,23 @@ impl Drop for Swapchain {
128164
impl Swapchain {
129165
/// Returns the drawable for the specified swapchain image index,
130166
/// 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, ()> {
132168
let mut frame = self
133169
.frames[index as usize]
134170
.inner
135171
.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+
}
141184
}
142185

143186
fn signal_sync(&self, sync: hal::FrameSync<Backend>) {
@@ -175,10 +218,21 @@ impl SwapchainImage {
175218
}
176219
// wait for new frames to come until we meet the chosen one
177220
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+
}
182236
count
183237
}
184238
}
@@ -234,20 +288,6 @@ impl hal::Surface<Backend> for Surface {
234288
}
235289
}
236290

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-
251291
impl Device {
252292
pub(crate) fn build_swapchain(
253293
&self,
@@ -313,6 +353,7 @@ impl Device {
313353
inner: Mutex::new(FrameInner {
314354
drawable,
315355
available: true,
356+
linked: true,
316357
last_frame: 0,
317358
}),
318359
texture: texture.to_owned(),
@@ -340,10 +381,9 @@ impl Device {
340381
extent: config.extent,
341382
last_frame: 0,
342383
image_ready_callbacks: Vec::new(),
343-
acquire_mode: AcquireMode::Wait,
384+
acquire_mode: AcquireMode::Oldest,
344385
};
345386

346-
347387
(swapchain, Backbuffer::Images(images))
348388
}
349389
}
@@ -404,6 +444,9 @@ impl hal::Swapchain<Backend> for Swapchain {
404444
}
405445

406446
let frame = self.frames[oldest_index].inner.lock();
447+
if !frame.linked {
448+
return Err(hal::AcquireError::OutOfDate);
449+
}
407450
(oldest_index, frame)
408451
}
409452
};

0 commit comments

Comments
 (0)