diff --git a/wgpu-native/src/device.rs b/wgpu-native/src/device.rs index ea57388e052..6a11fe82c01 100644 --- a/wgpu-native/src/device.rs +++ b/wgpu-native/src/device.rs @@ -1911,19 +1911,7 @@ pub fn device_create_swap_chain( suf.compatibility(&adapter.raw.physical_device) }; let num_frames = *caps.image_count.start(); //TODO: configure? - let usage = conv::map_texture_usage(desc.usage, hal::format::Aspects::COLOR); - let mut config = hal::SwapchainConfig::new( - desc.width, - desc.height, - conv::map_texture_format(desc.format), - num_frames, //TODO: configure? - ); - //TODO: check for supported - config.composite_alpha = hal::window::CompositeAlpha::OPAQUE; - config.present_mode = match desc.present_mode { - swap_chain::PresentMode::NoVsync => hal::PresentMode::Immediate, - swap_chain::PresentMode::Vsync => hal::PresentMode::Fifo, - }; + let config = desc.to_hal(num_frames); if let Some(formats) = formats { assert!( @@ -1960,9 +1948,9 @@ pub fn device_create_swap_chain( ); } unsafe { old.command_pool.reset(false) }; - (Some(old.raw), old.sem_available, old.command_pool) + (old.raw, old.sem_available, old.command_pool) } - _ => unsafe { + None => unsafe { let sem_available = device.raw.create_semaphore().unwrap(); let command_pool = device .raw @@ -1979,7 +1967,7 @@ pub fn device_create_swap_chain( let suf = B::get_surface_mut(surface); device .raw - .create_swapchain(suf, config.with_image_usage(usage), old_raw) + .create_swapchain(suf, config, old_raw) .unwrap() }; @@ -1988,7 +1976,11 @@ pub fn device_create_swap_chain( let mut trackers = device.trackers.lock(); let mut swap_chain = swap_chain::SwapChain { - raw: raw_swap_chain, + raw: Some(raw_swap_chain), + surface_id: Stored { + value: surface_id, + ref_count: surface.ref_count.clone(), + }, device_id: Stored { value: device_id, ref_count: device.life_guard.ref_count.clone(), diff --git a/wgpu-native/src/instance.rs b/wgpu-native/src/instance.rs index 3e106bb31c9..c3b46f17ca1 100644 --- a/wgpu-native/src/instance.rs +++ b/wgpu-native/src/instance.rs @@ -8,10 +8,11 @@ use crate::{ Backend, Device, DeviceId, + RefCount, SwapChainId, }; #[cfg(not(feature = "remote"))] -use crate::{gfx_select, SurfaceId}; +use crate::{gfx_select, LifeGuard, SurfaceId}; #[cfg(not(feature = "remote"))] use bitflags::bitflags; @@ -59,6 +60,7 @@ type GfxSurface = ::Surface; #[derive(Debug)] pub struct Surface { pub(crate) swap_chain: Option, + pub(crate) ref_count: RefCount, pub(crate) vulkan: Option>, #[cfg(any(target_os = "ios", target_os = "macos"))] pub(crate) metal: GfxSurface, @@ -158,10 +160,12 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su use raw_window_handle::RawWindowHandle as Rwh; let instance = &GLOBAL.instance; + let ref_count = LifeGuard::new().ref_count; let surface = match raw_handle { #[cfg(target_os = "ios")] Rwh::IOS(h) => Surface { swap_chain: None, + ref_count, vulkan: None, metal: instance .metal @@ -170,6 +174,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su #[cfg(target_os = "macos")] Rwh::MacOS(h) => Surface { swap_chain: None, + ref_count, vulkan: instance .vulkan .as_ref() @@ -181,6 +186,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su #[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))] Rwh::X11(h) => Surface { swap_chain: None, + ref_count, vulkan: instance .vulkan .as_ref() @@ -189,6 +195,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su #[cfg(all(unix, not(target_os = "ios"), not(target_os = "macos")))] Rwh::Wayland(h) => Surface { swap_chain: None, + ref_count, vulkan: instance .vulkan .as_ref() @@ -197,6 +204,7 @@ pub fn wgpu_create_surface(raw_handle: raw_window_handle::RawWindowHandle) -> Su #[cfg(windows)] Rwh::Windows(h) => Surface { swap_chain: None, + ref_count, vulkan: instance .vulkan .as_ref() @@ -235,6 +243,7 @@ pub extern "C" fn wgpu_create_surface_from_xlib( pub extern "C" fn wgpu_create_surface_from_metal_layer(layer: *mut std::ffi::c_void) -> SurfaceId { let surface = Surface { swap_chain: None, + ref_count: LifeGuard::new().ref_count, vulkan: None, //TODO: currently requires `NSView` metal: GLOBAL .instance diff --git a/wgpu-native/src/swap_chain.rs b/wgpu-native/src/swap_chain.rs index 8bae0179c0c..adc6c100921 100644 --- a/wgpu-native/src/swap_chain.rs +++ b/wgpu-native/src/swap_chain.rs @@ -8,9 +8,12 @@ use crate::{ Extent3d, Stored, SwapChainId, + SurfaceId, TextureId, TextureViewId, }; +#[cfg(not(feature = "remote"))] +use crate::hub::GLOBAL; use hal::{self, Device as _, Swapchain as _}; use log::{trace, warn}; @@ -56,13 +59,16 @@ pub(crate) struct Frame { //TODO: does it need a ref-counted lifetime? #[derive(Debug)] pub struct SwapChain { - pub(crate) raw: B::Swapchain, + //Note: it's only an option because we may need to move it out + // and then put a new swapchain back in. + pub(crate) raw: Option, + pub(crate) surface_id: Stored, pub(crate) device_id: Stored, pub(crate) desc: SwapChainDescriptor, pub(crate) frames: Vec>, pub(crate) acquired: Vec, pub(crate) sem_available: B::Semaphore, - #[cfg_attr(not(not(feature = "remote")), allow(dead_code))] //TODO: remove + #[cfg_attr(feature = "remote", allow(dead_code))] //TODO: remove pub(crate) command_pool: hal::CommandPool, } @@ -84,6 +90,23 @@ pub struct SwapChainDescriptor { } impl SwapChainDescriptor { + pub(crate) fn to_hal(&self, num_frames: u32) -> hal::window::SwapchainConfig { + let mut config = hal::SwapchainConfig::new( + self.width, + self.height, + conv::map_texture_format(self.format), + num_frames, + ); + //TODO: check for supported + config.image_usage = conv::map_texture_usage(self.usage, hal::format::Aspects::COLOR); + config.composite_alpha = hal::window::CompositeAlpha::OPAQUE; + config.present_mode = match self.present_mode { + PresentMode::NoVsync => hal::PresentMode::Immediate, + PresentMode::Vsync => hal::PresentMode::Fifo, + }; + config + } + pub fn to_texture_desc(&self) -> resource::TextureDescriptor { resource::TextureDescriptor { size: Extent3d { @@ -108,10 +131,14 @@ pub struct SwapChainOutput { pub view_id: TextureViewId, } -pub fn swap_chain_get_next_texture(swap_chain_id: SwapChainId) -> SwapChainOutput { +pub fn swap_chain_get_next_texture( + swap_chain_id: SwapChainId +) -> SwapChainOutput { let hub = B::hub(); let mut token = Token::root(); + #[cfg(not(feature = "remote"))] + let (mut surface_guard, mut token) = GLOBAL.surfaces.write(&mut token); let (device_guard, mut token) = hub.devices.read(&mut token); let (mut swap_chain_guard, _) = hub.swap_chains.write(&mut token); let swap_chain = &mut swap_chain_guard[swap_chain_id]; @@ -120,31 +147,73 @@ pub fn swap_chain_get_next_texture(swap_chain_id: SwapChainId) -> let image_index = unsafe { swap_chain .raw + .as_mut() + .unwrap() .acquire_image(!0, Some(&swap_chain.sem_available), None) - } - .ok(); + }; #[cfg(not(feature = "remote"))] { - //use crate::device::device_create_swap_chain_textures} - if image_index.is_none() { + if image_index.is_err() { warn!("acquire_image failed, re-creating"); - unimplemented!() - //let textures = device_create_swap_chain(device_id, swap_chain_id, &descriptor, &mut token); - //swap_chain_populate_textures(swap_chain_id, textures, &mut token); //TODO? + //TODO: remove this once gfx-rs stops destroying the old swapchain + device.raw.wait_idle().unwrap(); + let (mut texture_guard, mut token) = hub.textures.write(&mut token); + let (mut texture_view_guard, _) = hub.texture_views.write(&mut token); + let mut trackers = device.trackers.lock(); + + let old_raw = swap_chain.raw.take(); + let config = swap_chain.desc.to_hal(swap_chain.frames.len() as u32); + let surface = &mut surface_guard[swap_chain.surface_id.value]; + + let (raw, images) = unsafe { + let suf = B::get_surface_mut(surface); + device + .raw + .create_swapchain(suf, config, old_raw) + .unwrap() + }; + swap_chain.raw = Some(raw); + for (frame, image) in swap_chain.frames.iter_mut().zip(images) { + let texture = &mut texture_guard[frame.texture_id.value]; + let view_raw = unsafe { + device + .raw + .create_image_view( + &image, + hal::image::ViewKind::D2, + conv::map_texture_format(texture.format), + hal::format::Swizzle::NO, + texture.full_range.clone(), + ) + .unwrap() + }; + texture.raw = image; + trackers.textures.reset( + frame.texture_id.value, + texture.full_range.clone(), + resource::TextureUsage::UNINITIALIZED, + ); + let old_view = mem::replace(&mut texture_view_guard[frame.view_id.value].raw, view_raw); + unsafe { + device.raw.destroy_image_view(old_view); + } + } } } let image_index = match image_index { - Some((index, suboptimal)) => { + Ok((index, suboptimal)) => { if suboptimal.is_some() { warn!("acquire_image: sub-optimal"); } index } - None => unsafe { + Err(_) => unsafe { swap_chain .raw + .as_mut() + .unwrap() .acquire_image(!0, Some(&swap_chain.sem_available), None) .unwrap() .0 @@ -266,7 +335,7 @@ pub fn swap_chain_present(swap_chain_id: SwapChainId) { let queue = &mut device.queue_group.queues[0]; queue.submit(submission, Some(&frame.fence)); queue.present( - iter::once((&swap_chain.raw, image_index)), + iter::once((swap_chain.raw.as_ref().unwrap(), image_index)), iter::once(&frame.sem_present), ) }; diff --git a/wgpu-native/src/track/mod.rs b/wgpu-native/src/track/mod.rs index 03d26dd97f9..03707687b67 100644 --- a/wgpu-native/src/track/mod.rs +++ b/wgpu-native/src/track/mod.rs @@ -223,6 +223,27 @@ impl ResourceTracker { .is_none() } + /// Resets a resource to the specified usage. + #[cfg(not(feature = "remote"))] + pub fn reset( + &mut self, + id: S::Id, + selector: S::Selector, + default: S::Usage, + ) { + let mut state = S::default(); + match state.change(id, selector, default, None) { + Ok(()) => (), + Err(_) => unreachable!(), + } + + let (index, epoch, backend) = id.unzip(); + debug_assert_eq!(backend, self.backend); + let res = self.map.get_mut(&index).unwrap(); + assert_eq!(res.epoch, epoch); + res.state = state; + } + /// Query the usage of a resource selector. /// /// Returns `Some(Usage)` only if this usage is consistent