Skip to content

Commit 0d8c23f

Browse files
committed
[mtl] swapchain resize handling
1 parent 4e4cf29 commit 0d8c23f

File tree

3 files changed

+72
-28
lines changed

3 files changed

+72
-28
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-27
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+
//debug!("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)
@@ -244,32 +263,41 @@ impl Device {
244263
(view_points_size.size, scale_factor)
245264
};
246265

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

250269
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
270+
.map(|index| {
271+
let _ap = AutoreleasePool::new(); // for the drawable & texture
272+
let (drawable, texture) = unsafe {
273+
let drawable: &metal::DrawableRef = msg_send![render_layer, nextDrawable];
274+
assert!(!drawable.as_ptr().is_null());
275+
let texture: &metal::TextureRef = msg_send![drawable, texture];
276+
(drawable, texture)
277+
};
278+
if index == 0 {
279+
// when resizing, this trick frees up the currently shown frame
280+
drawable.present();
281+
}
282+
//info!("\tframe[{}] = {:?}", index, texture);
255283
Frame {
256284
inner: Mutex::new(FrameInner {
257-
drawable: None,
285+
drawable: Some(drawable.to_owned()),
258286
available: true,
259287
last_frame: 0,
260288
}),
261-
texture,
289+
texture: texture.to_owned(),
262290
}
263291
})
264292
.collect::<Vec<_>>();
265293

266294
let images = frames
267295
.iter()
268296
.map(|frame| native::Image {
269-
raw: frame.texture.clone(), //Note: careful!
297+
raw: frame.texture.clone(),
270298
extent: image::Extent {
271-
width: pixel_width as _,
272-
height: pixel_height as _,
299+
width: pixel_width,
300+
height: pixel_height,
273301
depth: 1,
274302
},
275303
num_layers: None,
@@ -283,8 +311,9 @@ impl Device {
283311
let swapchain = Swapchain {
284312
frames: Arc::new(frames),
285313
surface: surface.inner.clone(),
286-
_size_pixels: (pixel_width, pixel_height),
314+
size_pixels: (pixel_width, pixel_height),
287315
last_frame: 0,
316+
image_ready_callbacks: Vec::new(),
288317
};
289318

290319
(swapchain, Backbuffer::Images(images))
@@ -293,14 +322,22 @@ impl Device {
293322

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

299-
self.last_frame += 1;
300-
301335
for (index, frame_arc) in self.frames.iter().enumerate() {
302336
let mut frame = frame_arc.inner.lock().unwrap();
303-
if frame.available && frame.drawable.is_some() {
337+
if !frame.available {
338+
continue
339+
}
340+
if frame.drawable.is_some() {
304341
frame.available = false;
305342
frame.last_frame = self.last_frame;
306343
self.signal_sync(sync);
@@ -317,8 +354,10 @@ impl hal::Swapchain<Backend> for Swapchain {
317354
let (index, mut frame) = if blocking {
318355
self.surface.next_frame(&self.frames)
319356
} else {
357+
self.image_ready_callbacks.retain(|ir| ir.lock().unwrap().is_some());
320358
match sync {
321359
hal::FrameSync::Semaphore(semaphore) => {
360+
self.image_ready_callbacks.push(Arc::clone(&semaphore.image_ready));
322361
let mut sw_image = semaphore.image_ready.lock().unwrap();
323362
assert!(sw_image.is_none());
324363
*sw_image = Some(SwapchainImage {
@@ -337,6 +376,7 @@ impl hal::Swapchain<Backend> for Swapchain {
337376
(oldest_index, frame)
338377
};
339378

379+
assert!(frame.available);
340380
frame.last_frame = self.last_frame;
341381
frame.available = false;
342382

0 commit comments

Comments
 (0)