diff --git a/src/backend/metal/src/device.rs b/src/backend/metal/src/device.rs index cf9facf60de..0ea3b0738d0 100644 --- a/src/backend/metal/src/device.rs +++ b/src/backend/metal/src/device.rs @@ -2024,9 +2024,12 @@ impl hal::Device for Device { &self, surface: &mut Surface, config: hal::SwapchainConfig, - _old_swapchain: Option, + old_swapchain: Option, _extent: &window::Extent2D, ) -> (Swapchain, hal::Backbuffer) { + if let Some(_swapchain) = old_swapchain { + //swapchain is dropped here + } self.build_swapchain(surface, config) } diff --git a/src/backend/metal/src/window.rs b/src/backend/metal/src/window.rs index e638df0c586..ed029f13583 100644 --- a/src/backend/metal/src/window.rs +++ b/src/backend/metal/src/window.rs @@ -44,9 +44,9 @@ impl SurfaceInner { let _ap = AutoreleasePool::new(); let layer_ref = self.render_layer.lock().unwrap(); - let (drawable, texture_temp): (metal::Drawable, &metal::TextureRef) = unsafe { - let drawable: &metal::DrawableRef = msg_send![*layer_ref, nextDrawable]; - (drawable.to_owned(), msg_send![drawable, texture]) + let (drawable, texture_temp): (&metal::DrawableRef, &metal::TextureRef) = unsafe { + let drawable = msg_send![*layer_ref, nextDrawable]; + (drawable, msg_send![drawable, texture]) }; let index = frames @@ -56,7 +56,7 @@ impl SurfaceInner { let mut frame = frames[index].inner.lock().unwrap(); assert!(frame.drawable.is_none()); - frame.drawable = Some(drawable); + frame.drawable = Some(drawable.to_owned()); debug!("Surface next frame is {}", index); (index, frame) @@ -82,11 +82,40 @@ struct Frame { unsafe impl Send for Frame {} unsafe impl Sync for Frame {} +impl Drop for Frame { + fn drop(&mut self) { + info!("dropping Frame"); + let count: u64 = unsafe { + msg_send![self.texture, retainCount] + }; + println!("\twith texture refcount {}", count); //TEMP + let mut inner = self.inner.lock().unwrap(); + if let Some(drawable) = inner.drawable.take() { + let count: u64 = unsafe { + msg_send![drawable, retainCount] + }; + println!("\twith drawable refcount {}", count); //TEMP + } + } +} + pub struct Swapchain { frames: Arc>, surface: Arc, - _size_pixels: (u64, u64), + size_pixels: (image::Size, image::Size), last_frame: usize, + image_ready_callbacks: Vec>>>, +} + +impl Drop for Swapchain { + fn drop(&mut self) { + info!("dropping Swapchain"); + for ir in self.image_ready_callbacks.drain(..) { + if ir.lock().unwrap().take().is_some() { + debug!("\twith a callback"); + } + } + } } impl Swapchain { @@ -147,7 +176,7 @@ impl SwapchainImage { impl hal::Surface for Surface { fn kind(&self) -> image::Kind { - let (width, height) = self.pixel_dimensions(); + let (width, height) = self.inner.pixel_dimensions(); image::Kind::D2(width, height, 1, 1) } @@ -182,12 +211,12 @@ impl hal::Surface for Surface { } } -impl Surface { +impl SurfaceInner { fn pixel_dimensions(&self) -> (image::Size, image::Size) { unsafe { // NSView bounds are measured in DIPs - let bounds: NSRect = msg_send![self.inner.nsview, bounds]; - let bounds_pixel: NSRect = msg_send![self.inner.nsview, convertRectToBacking:bounds]; + let bounds: NSRect = msg_send![self.nsview, bounds]; + let bounds_pixel: NSRect = msg_send![self.nsview, convertRectToBacking:bounds]; (bounds_pixel.size.width as _, bounds_pixel.size.height as _) } } @@ -200,6 +229,7 @@ impl Device { config: SwapchainConfig, ) -> (Swapchain, Backbuffer) { let _ap = AutoreleasePool::new(); // for the drawable + info!("build_swapchain {:?}", config); let mtl_format = self.private_caps .map_format(config.color_format) @@ -244,21 +274,25 @@ impl Device { (view_points_size.size, scale_factor) }; - let pixel_width = (view_size.width * scale_factor) as u64; - let pixel_height = (view_size.height * scale_factor) as u64; + let pixel_width = (view_size.width * scale_factor) as image::Size; + let pixel_height = (view_size.height * scale_factor) as image::Size; let frames = (0 .. config.image_count) .map(|_| unsafe { + //let _ap = AutoreleasePool::new(); // for the drawable //TEMP let drawable: &metal::DrawableRef = msg_send![render_layer, nextDrawable]; - let texture: metal::Texture = msg_send![drawable, texture]; - //HACK: not retaining the texture here + assert!(!drawable.as_ptr().is_null()); + let dr_count: u64 = msg_send![drawable, retainCount]; + let texture: &metal::TextureRef = msg_send![drawable, texture]; + let count: u64 = msg_send![texture, retainCount]; + println!("\tdrawable refcount {}, texture refcount {}", dr_count, count); //TEMP Frame { inner: Mutex::new(FrameInner { drawable: None, available: true, last_frame: 0, }), - texture, + texture: texture.to_owned(), } }) .collect::>(); @@ -266,10 +300,10 @@ impl Device { let images = frames .iter() .map(|frame| native::Image { - raw: frame.texture.clone(), //Note: careful! + raw: frame.texture.clone(), extent: image::Extent { - width: pixel_width as _, - height: pixel_height as _, + width: pixel_width, + height: pixel_height, depth: 1, }, num_layers: None, @@ -283,8 +317,9 @@ impl Device { let swapchain = Swapchain { frames: Arc::new(frames), surface: surface.inner.clone(), - _size_pixels: (pixel_width, pixel_height), + size_pixels: (pixel_width, pixel_height), last_frame: 0, + image_ready_callbacks: Vec::new(), }; (swapchain, Backbuffer::Images(images)) @@ -293,14 +328,21 @@ impl Device { impl hal::Swapchain for Swapchain { fn acquire_image(&mut self, sync: hal::FrameSync) -> Result { + self.last_frame += 1; + + if false && self.surface.pixel_dimensions() != self.size_pixels { + return Err(()) + } + let mut oldest_index = 0; let mut oldest_frame = self.last_frame; - self.last_frame += 1; - for (index, frame_arc) in self.frames.iter().enumerate() { let mut frame = frame_arc.inner.lock().unwrap(); - if frame.available && frame.drawable.is_some() { + if !frame.available { + continue + } + if frame.drawable.is_some() { frame.available = false; frame.last_frame = self.last_frame; self.signal_sync(sync); @@ -317,8 +359,10 @@ impl hal::Swapchain for Swapchain { let (index, mut frame) = if blocking { self.surface.next_frame(&self.frames) } else { + self.image_ready_callbacks.retain(|ir| ir.lock().unwrap().is_some()); match sync { hal::FrameSync::Semaphore(semaphore) => { + self.image_ready_callbacks.push(Arc::clone(&semaphore.image_ready)); let mut sw_image = semaphore.image_ready.lock().unwrap(); assert!(sw_image.is_none()); *sw_image = Some(SwapchainImage { @@ -337,6 +381,7 @@ impl hal::Swapchain for Swapchain { (oldest_index, frame) }; + assert!(frame.available); frame.last_frame = self.last_frame; frame.available = false;