Skip to content

Commit 1f4cbc4

Browse files
committed
[mtl] swapchain resize handling
1 parent 3d7d45c commit 1f4cbc4

File tree

3 files changed

+72
-29
lines changed

3 files changed

+72
-29
lines changed

examples/quad/main.rs

+1
Original file line numberDiff line numberDiff line change
@@ -599,6 +599,7 @@ fn swapchain_stuff(
599599
println!("Surface format: {:?}", format);
600600
let swap_config = SwapchainConfig::new()
601601
.with_color(format)
602+
.with_image_count(caps.image_count.start)
602603
.with_image_usage(i::Usage::COLOR_ATTACHMENT);
603604
let (swap_chain, backbuffer) = device.create_swapchain(surface, swap_config, None, &extent);
604605

src/backend/metal/src/device.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -2024,9 +2024,12 @@ impl hal::Device<Backend> for Device {
20242024
&self,
20252025
surface: &mut Surface,
20262026
config: hal::SwapchainConfig,
2027-
_old_swapchain: Option<Swapchain>,
2027+
old_swapchain: Option<Swapchain>,
20282028
_extent: &window::Extent2D,
20292029
) -> (Swapchain, hal::Backbuffer<Backend>) {
2030+
if let Some(_swapchain) = old_swapchain {
2031+
//swapchain is dropped here
2032+
}
20302033
self.build_swapchain(surface, config)
20312034
}
20322035

src/backend/metal/src/window.rs

+67-28
Original file line numberDiff line numberDiff line change
@@ -44,21 +44,22 @@ impl SurfaceInner {
4444
let _ap = AutoreleasePool::new();
4545
let layer_ref = self.render_layer.lock().unwrap();
4646

47-
let (drawable, texture_temp): (metal::Drawable, &metal::TextureRef) = unsafe {
48-
let drawable: &metal::DrawableRef = msg_send![*layer_ref, nextDrawable];
49-
(drawable.to_owned(), msg_send![drawable, texture])
47+
let (drawable, texture_temp): (&metal::DrawableRef, &metal::TextureRef) = unsafe {
48+
let drawable = msg_send![*layer_ref, nextDrawable];
49+
(drawable, msg_send![drawable, texture])
5050
};
5151

52+
trace!("looking for {:?}", texture_temp);
5253
let index = frames
5354
.iter()
5455
.position(|f| f.texture.as_ptr() == texture_temp.as_ptr())
5556
.expect("Surface lost?");
5657

5758
let mut frame = frames[index].inner.lock().unwrap();
5859
assert!(frame.drawable.is_none());
59-
frame.drawable = Some(drawable);
60+
frame.drawable = Some(drawable.to_owned());
6061

61-
debug!("Surface next frame is {}", index);
62+
debug!("next is frame[{}]", index);
6263
(index, frame)
6364
}
6465
}
@@ -82,11 +83,29 @@ struct Frame {
8283
unsafe impl Send for Frame {}
8384
unsafe impl Sync for Frame {}
8485

86+
impl Drop for Frame {
87+
fn drop(&mut self) {
88+
info!("dropping Frame");
89+
}
90+
}
91+
8592
pub struct Swapchain {
8693
frames: Arc<Vec<Frame>>,
8794
surface: Arc<SurfaceInner>,
88-
_size_pixels: (u64, u64),
95+
size_pixels: (image::Size, image::Size),
8996
last_frame: usize,
97+
image_ready_callbacks: Vec<Arc<Mutex<Option<SwapchainImage>>>>,
98+
}
99+
100+
impl Drop for Swapchain {
101+
fn drop(&mut self) {
102+
info!("dropping Swapchain");
103+
for ir in self.image_ready_callbacks.drain(..) {
104+
if ir.lock().unwrap().take().is_some() {
105+
debug!("\twith a callback");
106+
}
107+
}
108+
}
90109
}
91110

92111
impl Swapchain {
@@ -147,7 +166,7 @@ impl SwapchainImage {
147166

148167
impl hal::Surface<Backend> for Surface {
149168
fn kind(&self) -> image::Kind {
150-
let (width, height) = self.pixel_dimensions();
169+
let (width, height) = self.inner.pixel_dimensions();
151170

152171
image::Kind::D2(width, height, 1, 1)
153172
}
@@ -157,7 +176,7 @@ impl hal::Surface<Backend> for Surface {
157176
) -> (hal::SurfaceCapabilities, Option<Vec<format::Format>>, Vec<hal::PresentMode>) {
158177
let caps = hal::SurfaceCapabilities {
159178
//Note: this is hardcoded in `CAMetalLayer` documentation
160-
image_count: 2 .. 3,
179+
image_count: 2 .. 4,
161180
current_extent: None,
162181
extents: Extent2D { width: 4, height: 4} .. Extent2D { width: 4096, height: 4096 },
163182
max_image_layers: 1,
@@ -182,12 +201,12 @@ impl hal::Surface<Backend> for Surface {
182201
}
183202
}
184203

185-
impl Surface {
204+
impl SurfaceInner {
186205
fn pixel_dimensions(&self) -> (image::Size, image::Size) {
187206
unsafe {
188207
// NSView bounds are measured in DIPs
189-
let bounds: NSRect = msg_send![self.inner.nsview, bounds];
190-
let bounds_pixel: NSRect = msg_send![self.inner.nsview, convertRectToBacking:bounds];
208+
let bounds: NSRect = msg_send![self.nsview, bounds];
209+
let bounds_pixel: NSRect = msg_send![self.nsview, convertRectToBacking:bounds];
191210
(bounds_pixel.size.width as _, bounds_pixel.size.height as _)
192211
}
193212
}
@@ -199,7 +218,7 @@ impl Device {
199218
surface: &mut Surface,
200219
config: SwapchainConfig,
201220
) -> (Swapchain, Backbuffer<Backend>) {
202-
let _ap = AutoreleasePool::new(); // for the drawable
221+
info!("build_swapchain {:?}", config);
203222

204223
let mtl_format = self.private_caps
205224
.map_format(config.color_format)
@@ -224,7 +243,6 @@ impl Device {
224243
msg_send![render_layer, setMaximumDrawableCount: config.image_count as u64];
225244
//TODO: only set it where supported
226245
msg_send![render_layer, setDisplaySyncEnabled: display_sync];
227-
//msg_send![render_layer, setPresentsWithTransaction: true];
228246

229247
// Update render layer size
230248
let view_points_size: CGRect = msg_send![nsview, bounds];
@@ -244,32 +262,41 @@ impl Device {
244262
(view_points_size.size, scale_factor)
245263
};
246264

247-
let pixel_width = (view_size.width * scale_factor) as u64;
248-
let pixel_height = (view_size.height * scale_factor) as u64;
265+
let pixel_width = (view_size.width * scale_factor) as image::Size;
266+
let pixel_height = (view_size.height * scale_factor) as image::Size;
249267

250268
let frames = (0 .. config.image_count)
251-
.map(|_| unsafe {
252-
let drawable: &metal::DrawableRef = msg_send![render_layer, nextDrawable];
253-
let texture: metal::Texture = msg_send![drawable, texture];
254-
//HACK: not retaining the texture here
269+
.map(|index| {
270+
let _ap = AutoreleasePool::new(); // for the drawable & texture
271+
let (drawable, texture) = unsafe {
272+
let drawable: &metal::DrawableRef = msg_send![render_layer, nextDrawable];
273+
assert!(!drawable.as_ptr().is_null());
274+
let texture: &metal::TextureRef = msg_send![drawable, texture];
275+
(drawable, texture)
276+
};
277+
if index == 0 {
278+
// when resizing, this trick frees up the currently shown frame
279+
drawable.present();
280+
}
281+
trace!("\tframe[{}] = {:?}", index, texture);
255282
Frame {
256283
inner: Mutex::new(FrameInner {
257-
drawable: None,
284+
drawable: Some(drawable.to_owned()),
258285
available: true,
259286
last_frame: 0,
260287
}),
261-
texture,
288+
texture: texture.to_owned(),
262289
}
263290
})
264291
.collect::<Vec<_>>();
265292

266293
let images = frames
267294
.iter()
268295
.map(|frame| native::Image {
269-
raw: frame.texture.clone(), //Note: careful!
296+
raw: frame.texture.clone(),
270297
extent: image::Extent {
271-
width: pixel_width as _,
272-
height: pixel_height as _,
298+
width: pixel_width,
299+
height: pixel_height,
273300
depth: 1,
274301
},
275302
num_layers: None,
@@ -283,8 +310,9 @@ impl Device {
283310
let swapchain = Swapchain {
284311
frames: Arc::new(frames),
285312
surface: surface.inner.clone(),
286-
_size_pixels: (pixel_width, pixel_height),
313+
size_pixels: (pixel_width, pixel_height),
287314
last_frame: 0,
315+
image_ready_callbacks: Vec::new(),
288316
};
289317

290318
(swapchain, Backbuffer::Images(images))
@@ -293,14 +321,22 @@ impl Device {
293321

294322
impl hal::Swapchain<Backend> for Swapchain {
295323
fn acquire_image(&mut self, sync: hal::FrameSync<Backend>) -> Result<hal::SwapImageIndex, ()> {
324+
self.last_frame += 1;
325+
326+
//TODO: figure out a proper story of HiDPI
327+
if false && self.surface.pixel_dimensions() != self.size_pixels {
328+
return Err(())
329+
}
330+
296331
let mut oldest_index = 0;
297332
let mut oldest_frame = self.last_frame;
298333

299-
self.last_frame += 1;
300-
301334
for (index, frame_arc) in self.frames.iter().enumerate() {
302335
let mut frame = frame_arc.inner.lock().unwrap();
303-
if frame.available && frame.drawable.is_some() {
336+
if !frame.available {
337+
continue
338+
}
339+
if frame.drawable.is_some() {
304340
frame.available = false;
305341
frame.last_frame = self.last_frame;
306342
self.signal_sync(sync);
@@ -317,8 +353,10 @@ impl hal::Swapchain<Backend> for Swapchain {
317353
let (index, mut frame) = if blocking {
318354
self.surface.next_frame(&self.frames)
319355
} else {
356+
self.image_ready_callbacks.retain(|ir| ir.lock().unwrap().is_some());
320357
match sync {
321358
hal::FrameSync::Semaphore(semaphore) => {
359+
self.image_ready_callbacks.push(Arc::clone(&semaphore.image_ready));
322360
let mut sw_image = semaphore.image_ready.lock().unwrap();
323361
assert!(sw_image.is_none());
324362
*sw_image = Some(SwapchainImage {
@@ -337,6 +375,7 @@ impl hal::Swapchain<Backend> for Swapchain {
337375
(oldest_index, frame)
338376
};
339377

378+
assert!(frame.available);
340379
frame.last_frame = self.last_frame;
341380
frame.available = false;
342381

0 commit comments

Comments
 (0)