Handle frame acquisition failure internally

This commit is contained in:
Dzmitry Malyshau 2019-08-29 22:27:21 -04:00
parent 175e992149
commit d37ecdf248
4 changed files with 122 additions and 31 deletions

View File

@ -1911,19 +1911,7 @@ pub fn device_create_swap_chain<B: GfxBackend>(
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<B: GfxBackend>(
);
}
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<B: GfxBackend>(
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<B: GfxBackend>(
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(),

View File

@ -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<B> = <B as hal::Backend>::Surface;
#[derive(Debug)]
pub struct Surface {
pub(crate) swap_chain: Option<SwapChainId>,
pub(crate) ref_count: RefCount,
pub(crate) vulkan: Option<GfxSurface<backend::Vulkan>>,
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub(crate) metal: GfxSurface<backend::Metal>,
@ -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

View File

@ -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<B: hal::Backend> {
//TODO: does it need a ref-counted lifetime?
#[derive(Debug)]
pub struct SwapChain<B: hal::Backend> {
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<B::Swapchain>,
pub(crate) surface_id: Stored<SurfaceId>,
pub(crate) device_id: Stored<DeviceId>,
pub(crate) desc: SwapChainDescriptor,
pub(crate) frames: Vec<Frame<B>>,
pub(crate) acquired: Vec<hal::SwapImageIndex>,
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<B, hal::General>,
}
@ -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<B: GfxBackend>(swap_chain_id: SwapChainId) -> SwapChainOutput {
pub fn swap_chain_get_next_texture<B: GfxBackend>(
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<B: GfxBackend>(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<B: GfxBackend>(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),
)
};

View File

@ -223,6 +223,27 @@ impl<S: ResourceState> ResourceTracker<S> {
.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