Merge pull request #626 from tomaka/swapchain-acq-fix

Remove the potential panic when destroying a SwapchainAcquireFuture
This commit is contained in:
tomaka 2017-07-08 20:22:48 +02:00 committed by GitHub
commit f886d27780

View File

@ -43,6 +43,7 @@ use swapchain::SurfaceTransform;
use sync::AccessCheckError; use sync::AccessCheckError;
use sync::AccessError; use sync::AccessError;
use sync::AccessFlagBits; use sync::AccessFlagBits;
use sync::Fence;
use sync::FlushError; use sync::FlushError;
use sync::GpuFuture; use sync::GpuFuture;
use sync::PipelineStages; use sync::PipelineStages;
@ -64,11 +65,10 @@ use vk;
/// ///
/// If you try to draw on an image without acquiring it first, the execution will block. (TODO /// If you try to draw on an image without acquiring it first, the execution will block. (TODO
/// behavior may change). /// behavior may change).
// TODO: has to make sure vkQueuePresent is called, because calling acquire_next_image many
// times in a row is an error
pub fn acquire_next_image(swapchain: Arc<Swapchain>, timeout: Option<Duration>) pub fn acquire_next_image(swapchain: Arc<Swapchain>, timeout: Option<Duration>)
-> Result<(usize, SwapchainAcquireFuture), AcquireError> { -> Result<(usize, SwapchainAcquireFuture), AcquireError> {
let semaphore = Semaphore::new(swapchain.device.clone())?; let semaphore = Semaphore::new(swapchain.device.clone())?; // TODO: take from a pool
let fence = Fence::new(swapchain.device.clone())?; // TODO: take from a pool
// TODO: propagate `suboptimal` to the user // TODO: propagate `suboptimal` to the user
let AcquiredImage { id, suboptimal } = { let AcquiredImage { id, suboptimal } = {
@ -80,13 +80,14 @@ pub fn acquire_next_image(swapchain: Arc<Swapchain>, timeout: Option<Duration>)
return Err(AcquireError::OutOfDate); return Err(AcquireError::OutOfDate);
} }
unsafe { acquire_next_image_raw(&swapchain, timeout, &semaphore) }? unsafe { acquire_next_image_raw2(&swapchain, timeout, Some(&semaphore), Some(&fence)) }?
}; };
Ok((id, Ok((id,
SwapchainAcquireFuture { SwapchainAcquireFuture {
swapchain: swapchain, swapchain: swapchain,
semaphore: semaphore, semaphore: Some(semaphore),
fence: Some(fence),
image_id: id, image_id: id,
finished: AtomicBool::new(false), finished: AtomicBool::new(false),
})) }))
@ -156,6 +157,7 @@ pub struct Swapchain {
} }
struct ImageEntry { struct ImageEntry {
// The actual image.
image: UnsafeImage, image: UnsafeImage,
// If true, then the image is still in the undefined layout and must be transitionned. // If true, then the image is still in the undefined layout and must be transitionned.
undefined_layout: AtomicBool, undefined_layout: AtomicBool,
@ -690,7 +692,12 @@ impl From<CapabilitiesError> for SwapchainCreationError {
pub struct SwapchainAcquireFuture { pub struct SwapchainAcquireFuture {
swapchain: Arc<Swapchain>, swapchain: Arc<Swapchain>,
image_id: usize, image_id: usize,
semaphore: Semaphore, // Semaphore that is signalled when the acquire is complete. Empty if the acquire has already
// happened.
semaphore: Option<Semaphore>,
// Fence that is signalled when the acquire is complete. Empty if the acquire has already
// happened.
fence: Option<Fence>,
finished: AtomicBool, finished: AtomicBool,
} }
@ -715,9 +722,13 @@ unsafe impl GpuFuture for SwapchainAcquireFuture {
#[inline] #[inline]
unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> { unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> {
if let Some(ref semaphore) = self.semaphore {
let mut sem = SubmitSemaphoresWaitBuilder::new(); let mut sem = SubmitSemaphoresWaitBuilder::new();
sem.add_wait_semaphore(&self.semaphore); sem.add_wait_semaphore(&semaphore);
Ok(SubmitAnyBuilder::SemaphoresWait(sem)) Ok(SubmitAnyBuilder::SemaphoresWait(sem))
} else {
Ok(SubmitAnyBuilder::Empty)
}
} }
#[inline] #[inline]
@ -779,23 +790,22 @@ unsafe impl GpuFuture for SwapchainAcquireFuture {
unsafe impl DeviceOwned for SwapchainAcquireFuture { unsafe impl DeviceOwned for SwapchainAcquireFuture {
#[inline] #[inline]
fn device(&self) -> &Arc<Device> { fn device(&self) -> &Arc<Device> {
self.semaphore.device() &self.swapchain.device
} }
} }
impl Drop for SwapchainAcquireFuture { impl Drop for SwapchainAcquireFuture {
fn drop(&mut self) { fn drop(&mut self) {
if !*self.finished.get_mut() { if !*self.finished.get_mut() {
panic!() // FIXME: what to do? if let Some(ref fence) = self.fence {
/*// TODO: handle errors? fence.wait(None).unwrap(); // TODO: handle error?
let fence = Fence::new(self.device().clone()).unwrap(); self.semaphore = None;
let mut builder = SubmitCommandBufferBuilder::new();
builder.add_wait_semaphore(&self.semaphore);
builder.set_signal_fence(&fence);
builder.submit(... which queue ? ...).unwrap();
fence.wait(Duration::from_secs(600)).unwrap();*/
} }
} }
// TODO: if this future is destroyed without being presented, then eventually acquiring
// a new image will block forever ; difficulty: hard
}
} }
/// Error that can happen when calling `acquire_next_image`. /// Error that can happen when calling `acquire_next_image`.
@ -1054,8 +1064,17 @@ pub struct AcquiredImage {
/// ///
/// - The semaphore must be kept alive until it is signaled. /// - The semaphore must be kept alive until it is signaled.
/// - The swapchain must not have been replaced by being passed as the old swapchain when creating a new one. /// - The swapchain must not have been replaced by being passed as the old swapchain when creating a new one.
#[inline]
pub unsafe fn acquire_next_image_raw(swapchain: &Swapchain, timeout: Option<Duration>, semaphore: &Semaphore) pub unsafe fn acquire_next_image_raw(swapchain: &Swapchain, timeout: Option<Duration>, semaphore: &Semaphore)
-> Result<AcquiredImage, AcquireError> -> Result<AcquiredImage, AcquireError>
{
acquire_next_image_raw2(swapchain, timeout, Some(semaphore), None)
}
// TODO: this should replace `acquire_next_image_raw`, but requires an API break
unsafe fn acquire_next_image_raw2(swapchain: &Swapchain, timeout: Option<Duration>,
semaphore: Option<&Semaphore>, fence: Option<&Fence>)
-> Result<AcquiredImage, AcquireError>
{ {
let vk = swapchain.device.pointers(); let vk = swapchain.device.pointers();
@ -1072,8 +1091,8 @@ pub unsafe fn acquire_next_image_raw(swapchain: &Swapchain, timeout: Option<Dura
let r = check_errors(vk.AcquireNextImageKHR(swapchain.device.internal_object(), let r = check_errors(vk.AcquireNextImageKHR(swapchain.device.internal_object(),
swapchain.swapchain, swapchain.swapchain,
timeout_ns, timeout_ns,
semaphore.internal_object(), semaphore.map(|s| s.internal_object()).unwrap_or(0),
0, fence.map(|f| f.internal_object()).unwrap_or(0),
&mut out))?; &mut out))?;
let (id, suboptimal) = match r { let (id, suboptimal) = match r {