Refactor the swap chain frame tracking

This commit is contained in:
Dzmitry Malyshau 2020-01-21 14:24:45 -05:00
parent ec54038e7c
commit 8a5de68aab
6 changed files with 42 additions and 55 deletions

View File

@ -136,7 +136,7 @@ pub struct CommandBuffer<B: hal::Backend> {
pub(crate) device_id: Stored<id::DeviceId>, pub(crate) device_id: Stored<id::DeviceId>,
pub(crate) life_guard: LifeGuard, pub(crate) life_guard: LifeGuard,
pub(crate) trackers: TrackerSet, pub(crate) trackers: TrackerSet,
pub(crate) used_swap_chain: Option<(Stored<id::TextureViewId>, B::Framebuffer)>, pub(crate) used_swap_chain: Option<(Stored<id::SwapChainId>, B::Framebuffer)>,
pub(crate) features: Features, pub(crate) features: Features,
} }
@ -263,13 +263,17 @@ impl<F> Global<F> {
) -> id::CommandBufferId { ) -> id::CommandBufferId {
let hub = B::hub(self); let hub = B::hub(self);
let mut token = Token::root(); let mut token = Token::root();
let (swap_chain_guard, mut token) = hub.swap_chains.read(&mut token);
//TODO: actually close the last recorded command buffer //TODO: actually close the last recorded command buffer
let (mut comb_guard, _) = hub.command_buffers.write(&mut token); let (mut comb_guard, _) = hub.command_buffers.write(&mut token);
let comb = &mut comb_guard[encoder_id]; let comb = &mut comb_guard[encoder_id];
assert!(comb.is_recording); assert!(comb.is_recording);
comb.is_recording = false; comb.is_recording = false;
// stop tracking the swapchain image, if used // stop tracking the swapchain image, if used
if let Some((ref view_id, _)) = comb.used_swap_chain { if let Some((ref sc_id, _)) = comb.used_swap_chain {
let view_id = swap_chain_guard[sc_id.value].acquired_view_id
.as_ref()
.expect("Used swap chain frame has already presented");
comb.trackers.views.remove(view_id.value); comb.trackers.views.remove(view_id.value);
} }
log::debug!("Command buffer {:?} {:#?}", encoder_id, comb.trackers); log::debug!("Command buffer {:?} {:#?}", encoder_id, comb.trackers);

View File

@ -325,7 +325,7 @@ impl<F> Global<F> {
let base_trackers = &cmb.trackers; let base_trackers = &cmb.trackers;
let mut extent = None; let mut extent = None;
let mut used_swap_chain_image = None::<Stored<id::TextureViewId>>; let mut used_swap_chain = None::<Stored<id::SwapChainId>>;
let sample_count = color_attachments let sample_count = color_attachments
.get(0) .get(0)
@ -430,15 +430,12 @@ impl<F> Global<F> {
}; };
old_layout .. hal::image::Layout::ColorAttachmentOptimal old_layout .. hal::image::Layout::ColorAttachmentOptimal
} }
TextureViewInner::SwapChain { .. } => { TextureViewInner::SwapChain { ref source_id, .. } => {
if let Some((ref view_id, _)) = cmb.used_swap_chain { if let Some((ref sc_id, _)) = cmb.used_swap_chain {
assert_eq!(view_id.value, at.attachment); assert_eq!(source_id.value, sc_id.value);
} else { } else {
assert!(used_swap_chain_image.is_none()); assert!(used_swap_chain.is_none());
used_swap_chain_image = Some(Stored { used_swap_chain = Some(source_id.clone());
value: at.attachment,
ref_count: view.life_guard.add_ref(),
});
} }
let end = hal::image::Layout::Present; let end = hal::image::Layout::Present;
@ -490,15 +487,12 @@ impl<F> Global<F> {
}; };
old_layout .. hal::image::Layout::ColorAttachmentOptimal old_layout .. hal::image::Layout::ColorAttachmentOptimal
} }
TextureViewInner::SwapChain { .. } => { TextureViewInner::SwapChain { ref source_id, .. } => {
if let Some((ref view_id, _)) = cmb.used_swap_chain { if let Some((ref sc_id, _)) = cmb.used_swap_chain {
assert_eq!(view_id.value, resolve_target); assert_eq!(source_id.value, sc_id.value);
} else { } else {
assert!(used_swap_chain_image.is_none()); assert!(used_swap_chain.is_none());
used_swap_chain_image = Some(Stored { used_swap_chain = Some(source_id.clone());
value: resolve_target,
ref_count: view.life_guard.add_ref(),
});
} }
let end = hal::image::Layout::Present; let end = hal::image::Layout::Present;
@ -624,8 +618,8 @@ impl<F> Global<F> {
depth_stencil: depth_stencil_attachment.map(|at| at.attachment), depth_stencil: depth_stencil_attachment.map(|at| at.attachment),
}; };
let framebuffer = match used_swap_chain_image.take() { let framebuffer = match used_swap_chain.take() {
Some(view_id) => { Some(sc_id) => {
assert!(cmb.used_swap_chain.is_none()); assert!(cmb.used_swap_chain.is_none());
// Always create a new framebuffer and delete it after presentation. // Always create a new framebuffer and delete it after presentation.
let attachments = fb_key.all().map(|&id| match view_guard[id].inner { let attachments = fb_key.all().map(|&id| match view_guard[id].inner {
@ -638,7 +632,7 @@ impl<F> Global<F> {
.create_framebuffer(&render_pass, attachments, extent.unwrap()) .create_framebuffer(&render_pass, attachments, extent.unwrap())
.unwrap() .unwrap()
}; };
cmb.used_swap_chain = Some((view_id, framebuffer)); cmb.used_swap_chain = Some((sc_id, framebuffer));
&mut cmb.used_swap_chain.as_mut().unwrap().1 &mut cmb.used_swap_chain.as_mut().unwrap().1
} }
None => { None => {

View File

@ -31,6 +31,7 @@ use hal::{
use parking_lot::{Mutex, MutexGuard}; use parking_lot::{Mutex, MutexGuard};
use rendy_descriptor::{DescriptorAllocator, DescriptorRanges}; use rendy_descriptor::{DescriptorAllocator, DescriptorRanges};
use rendy_memory::{Block, Heaps}; use rendy_memory::{Block, Heaps};
use smallvec::SmallVec;
use std::{ use std::{
collections::hash_map::Entry, collections::hash_map::Entry,
@ -668,7 +669,7 @@ impl<F: IdentityFilter<id::TextureId>> Global<F> {
texture.life_guard.ref_count.take(); texture.life_guard.ref_count.take();
texture.device_id.value texture.device_id.value
}; };
let (device_guard, mut token) = hub.devices.read(&mut token); let (device_guard, mut token) = hub.devices.read(&mut token);
device_guard[device_id] device_guard[device_id]
.lock_life(&mut token) .lock_life(&mut token)
@ -1309,16 +1310,16 @@ impl<F: AllIdentityFilter + IdentityFilter<id::CommandBufferId>> Global<F> {
.submission_index .submission_index
.fetch_add(1, Ordering::Relaxed); .fetch_add(1, Ordering::Relaxed);
let (swap_chain_guard, mut token) = hub.swap_chains.read(&mut token); let (mut swap_chain_guard, mut token) = hub.swap_chains.write(&mut token);
let (mut command_buffer_guard, mut token) = hub.command_buffers.write(&mut token); let (mut command_buffer_guard, mut token) = hub.command_buffers.write(&mut token);
let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token); let (bind_group_guard, mut token) = hub.bind_groups.read(&mut token);
let (buffer_guard, mut token) = hub.buffers.read(&mut token); let (buffer_guard, mut token) = hub.buffers.read(&mut token);
let (texture_guard, mut token) = hub.textures.read(&mut token); let (texture_guard, mut token) = hub.textures.read(&mut token);
let (mut texture_view_guard, mut token) = hub.texture_views.write(&mut token); let (texture_view_guard, mut token) = hub.texture_views.read(&mut token);
let (sampler_guard, _) = hub.samplers.read(&mut token); let (sampler_guard, _) = hub.samplers.read(&mut token);
//Note: locking the trackers has to be done after the storages //Note: locking the trackers has to be done after the storages
let mut signal_semaphores = Vec::new(); let mut signal_swapchain_semaphores = SmallVec::<[_; 1]>::new();
let mut trackers = device.trackers.lock(); let mut trackers = device.trackers.lock();
//TODO: if multiple command buffers are submitted, we can re-use the last //TODO: if multiple command buffers are submitted, we can re-use the last
@ -1329,21 +1330,12 @@ impl<F: AllIdentityFilter + IdentityFilter<id::CommandBufferId>> Global<F> {
for &cmb_id in command_buffer_ids { for &cmb_id in command_buffer_ids {
let comb = &mut command_buffer_guard[cmb_id]; let comb = &mut command_buffer_guard[cmb_id];
if let Some((view_id, fbo)) = comb.used_swap_chain.take() { if let Some((sc_id, fbo)) = comb.used_swap_chain.take() {
match texture_view_guard[view_id.value].inner { let sc = &mut swap_chain_guard[sc_id.value];
resource::TextureViewInner::Native { .. } => unreachable!(), if sc.acquired_framebuffers.is_empty() {
resource::TextureViewInner::SwapChain { signal_swapchain_semaphores.push(sc_id.value);
ref source_id, }
ref mut framebuffers, sc.acquired_framebuffers.push(fbo);
..
} => {
if framebuffers.is_empty() {
let sem = &swap_chain_guard[source_id.value].semaphore;
signal_semaphores.push(sem);
}
framebuffers.push(fbo);
}
};
} }
// optimize the tracked states // optimize the tracked states
@ -1405,12 +1397,15 @@ impl<F: AllIdentityFilter + IdentityFilter<id::CommandBufferId>> Global<F> {
// now prepare the GPU submission // now prepare the GPU submission
let fence = device.raw.create_fence(false).unwrap(); let fence = device.raw.create_fence(false).unwrap();
let submission = hal::queue::Submission::<_, _, Vec<&B::Semaphore>> { let submission = hal::queue::Submission {
command_buffers: command_buffer_ids command_buffers: command_buffer_ids
.iter() .iter()
.flat_map(|&cmb_id| &command_buffer_guard[cmb_id].raw), .flat_map(|&cmb_id| &command_buffer_guard[cmb_id].raw),
wait_semaphores: Vec::new(), wait_semaphores: Vec::new(),
signal_semaphores, signal_semaphores: signal_swapchain_semaphores
.into_iter()
.map(|sc_id| &swap_chain_guard[sc_id].semaphore),
}; };
unsafe { unsafe {
@ -1853,6 +1848,7 @@ impl<F: IdentityFilter<id::SwapChainId>> Global<F> {
num_frames, num_frames,
semaphore: device.raw.create_semaphore().unwrap(), semaphore: device.raw.create_semaphore().unwrap(),
acquired_view_id: None, acquired_view_id: None,
acquired_framebuffers: Vec::new(),
}; };
swap_chain_guard.insert(sc_id, swap_chain); swap_chain_guard.insert(sc_id, swap_chain);
sc_id sc_id

View File

@ -165,6 +165,7 @@ impl<B: hal::Backend> Access<Adapter<B>> for Surface {}
impl<B: hal::Backend> Access<Device<B>> for Root {} impl<B: hal::Backend> Access<Device<B>> for Root {}
impl<B: hal::Backend> Access<Device<B>> for Surface {} impl<B: hal::Backend> Access<Device<B>> for Surface {}
impl<B: hal::Backend> Access<Device<B>> for Adapter<B> {} impl<B: hal::Backend> Access<Device<B>> for Adapter<B> {}
impl<B: hal::Backend> Access<SwapChain<B>> for Root {}
impl<B: hal::Backend> Access<SwapChain<B>> for Device<B> {} impl<B: hal::Backend> Access<SwapChain<B>> for Device<B> {}
impl<B: hal::Backend> Access<PipelineLayout<B>> for Root {} impl<B: hal::Backend> Access<PipelineLayout<B>> for Root {}
impl<B: hal::Backend> Access<PipelineLayout<B>> for Device<B> {} impl<B: hal::Backend> Access<PipelineLayout<B>> for Device<B> {}

View File

@ -14,7 +14,6 @@ use crate::{
use hal; use hal;
use rendy_memory::MemoryBlock; use rendy_memory::MemoryBlock;
use smallvec::SmallVec;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -307,7 +306,6 @@ pub(crate) enum TextureViewInner<B: hal::Backend> {
SwapChain { SwapChain {
image: <B::Surface as hal::window::PresentationSurface<B>>::SwapchainImage, image: <B::Surface as hal::window::PresentationSurface<B>>::SwapchainImage,
source_id: Stored<SwapChainId>, source_id: Stored<SwapChainId>,
framebuffers: SmallVec<[B::Framebuffer; 1]>,
}, },
} }

View File

@ -45,8 +45,6 @@ use crate::{
use hal::{self, device::Device as _, queue::CommandQueue as _, window::PresentationSurface as _}; use hal::{self, device::Device as _, queue::CommandQueue as _, window::PresentationSurface as _};
use smallvec::SmallVec;
const FRAME_TIMEOUT_MS: u64 = 1000; const FRAME_TIMEOUT_MS: u64 = 1000;
pub const DESIRED_NUM_FRAMES: u32 = 3; pub const DESIRED_NUM_FRAMES: u32 = 3;
@ -59,6 +57,7 @@ pub struct SwapChain<B: hal::Backend> {
pub(crate) num_frames: hal::window::SwapImageIndex, pub(crate) num_frames: hal::window::SwapImageIndex,
pub(crate) semaphore: B::Semaphore, pub(crate) semaphore: B::Semaphore,
pub(crate) acquired_view_id: Option<Stored<TextureViewId>>, pub(crate) acquired_view_id: Option<Stored<TextureViewId>>,
pub(crate) acquired_framebuffers: Vec<B::Framebuffer>,
} }
#[repr(C)] #[repr(C)]
@ -169,7 +168,6 @@ impl<F: IdentityFilter<TextureViewId>> Global<F> {
value: swap_chain_id, value: swap_chain_id,
ref_count: sc.life_guard.add_ref(), ref_count: sc.life_guard.add_ref(),
}, },
framebuffers: SmallVec::new(),
}, },
format: sc.desc.format, format: sc.desc.format,
extent: hal::image::Extent { extent: hal::image::Extent {
@ -218,13 +216,9 @@ impl<F: IdentityFilter<TextureViewId>> Global<F> {
.take() .take()
.expect("Swap chain image is not acquired"); .expect("Swap chain image is not acquired");
let (view, _) = hub.texture_views.unregister(view_id.value, &mut token); let (view, _) = hub.texture_views.unregister(view_id.value, &mut token);
let (image, framebuffers) = match view.inner { let image = match view.inner {
resource::TextureViewInner::Native { .. } => unreachable!(), resource::TextureViewInner::Native { .. } => unreachable!(),
resource::TextureViewInner::SwapChain { resource::TextureViewInner::SwapChain { image, .. } => image,
image,
framebuffers,
..
} => (image, framebuffers),
}; };
let err = unsafe { let err = unsafe {
@ -235,7 +229,7 @@ impl<F: IdentityFilter<TextureViewId>> Global<F> {
log::warn!("present failed: {:?}", e); log::warn!("present failed: {:?}", e);
} }
for fbo in framebuffers { for fbo in sc.acquired_framebuffers.drain(..) {
unsafe { unsafe {
device.raw.destroy_framebuffer(fbo); device.raw.destroy_framebuffer(fbo);
} }