diff options
Diffstat (limited to 'src/sync/future/join.rs')
-rw-r--r-- | src/sync/future/join.rs | 211 |
1 files changed, 116 insertions, 95 deletions
diff --git a/src/sync/future/join.rs b/src/sync/future/join.rs index c45a764..6ead696 100644 --- a/src/sync/future/join.rs +++ b/src/sync/future/join.rs @@ -7,44 +7,30 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use std::sync::Arc; - -use crate::buffer::BufferAccess; -use crate::command_buffer::submit::SubmitAnyBuilder; -use crate::device::Device; -use crate::device::DeviceOwned; -use crate::device::Queue; -use crate::image::ImageAccess; -use crate::image::ImageLayout; -use crate::sync::AccessCheckError; -use crate::sync::AccessFlags; -use crate::sync::FlushError; -use crate::sync::GpuFuture; -use crate::sync::PipelineStages; - -use crate::VulkanObject; +use super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder}; +use crate::{ + buffer::Buffer, + device::{Device, DeviceOwned, Queue}, + image::{sys::Image, ImageLayout}, + swapchain::Swapchain, + DeviceSize, VulkanObject, +}; +use std::{ops::Range, sync::Arc}; /// Joins two futures together. // TODO: handle errors -#[inline] pub fn join<F, S>(first: F, second: S) -> JoinFuture<F, S> where F: GpuFuture, S: GpuFuture, { - assert_eq!( - first.device().internal_object(), - second.device().internal_object() - ); + assert_eq!(first.device().handle(), second.device().handle()); if !first.queue_change_allowed() && !second.queue_change_allowed() { - assert!(first.queue().unwrap().is_same(&second.queue().unwrap())); + assert!(first.queue().unwrap() == second.queue().unwrap()); } - JoinFuture { - first: first, - second: second, - } + JoinFuture { first, second } } /// Two futures joined into one. @@ -59,13 +45,9 @@ where A: DeviceOwned, B: DeviceOwned, { - #[inline] fn device(&self) -> &Arc<Device> { let device = self.first.device(); - debug_assert_eq!( - self.second.device().internal_object(), - device.internal_object() - ); + debug_assert_eq!(self.second.device().handle(), device.handle()); device } } @@ -75,22 +57,20 @@ where A: GpuFuture, B: GpuFuture, { - #[inline] fn cleanup_finished(&mut self) { self.first.cleanup_finished(); self.second.cleanup_finished(); } - #[inline] fn flush(&self) -> Result<(), FlushError> { // Since each future remembers whether it has been flushed, there's no safety issue here // if we call this function multiple times. self.first.flush()?; self.second.flush()?; + Ok(()) } - #[inline] unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> { // TODO: review this function let first = self.first.build_submission()?; @@ -102,90 +82,106 @@ where (SubmitAnyBuilder::Empty, b) => b, (a, SubmitAnyBuilder::Empty) => a, (SubmitAnyBuilder::SemaphoresWait(mut a), SubmitAnyBuilder::SemaphoresWait(b)) => { - a.merge(b); + a.extend(b); SubmitAnyBuilder::SemaphoresWait(a) } - (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::CommandBuffer(b)) => { + (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::CommandBuffer(_, _)) => { self.second.flush()?; SubmitAnyBuilder::SemaphoresWait(a) } - (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::SemaphoresWait(b)) => { + (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::SemaphoresWait(b)) => { self.first.flush()?; SubmitAnyBuilder::SemaphoresWait(b) } - (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(b)) => { + (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::QueuePresent(_)) => { self.second.flush()?; SubmitAnyBuilder::SemaphoresWait(a) } - (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::SemaphoresWait(b)) => { + (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::SemaphoresWait(b)) => { self.first.flush()?; SubmitAnyBuilder::SemaphoresWait(b) } - (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::BindSparse(b)) => { + (SubmitAnyBuilder::SemaphoresWait(a), SubmitAnyBuilder::BindSparse(_, _)) => { self.second.flush()?; SubmitAnyBuilder::SemaphoresWait(a) } - (SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::SemaphoresWait(b)) => { + (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::SemaphoresWait(b)) => { self.first.flush()?; SubmitAnyBuilder::SemaphoresWait(b) } - (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::CommandBuffer(b)) => { - // TODO: we may want to add debug asserts here - let new = a.merge(b); - SubmitAnyBuilder::CommandBuffer(new) + ( + SubmitAnyBuilder::CommandBuffer(mut submit_info_a, fence_a), + SubmitAnyBuilder::CommandBuffer(submit_info_b, fence_b), + ) => { + assert!( + fence_a.is_none() || fence_b.is_none(), + "Can't merge two queue submits that both have a fence" + ); + + submit_info_a + .wait_semaphores + .extend(submit_info_b.wait_semaphores); + submit_info_a + .command_buffers + .extend(submit_info_b.command_buffers); + submit_info_a + .signal_semaphores + .extend(submit_info_b.signal_semaphores); + + SubmitAnyBuilder::CommandBuffer(submit_info_a, fence_a.or(fence_b)) } - (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::QueuePresent(b)) => { + (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::QueuePresent(_)) => { self.first.flush()?; self.second.flush()?; SubmitAnyBuilder::Empty } - (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::QueuePresent(b)) => { + (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::QueuePresent(_)) => { unimplemented!() } - (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::CommandBuffer(b)) => { + (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::CommandBuffer(_, _)) => { unimplemented!() } - (SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::QueuePresent(b)) => { + (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::QueuePresent(_)) => { unimplemented!() } - (SubmitAnyBuilder::QueuePresent(a), SubmitAnyBuilder::BindSparse(b)) => { + (SubmitAnyBuilder::QueuePresent(_), SubmitAnyBuilder::BindSparse(_, _)) => { unimplemented!() } - (SubmitAnyBuilder::BindSparse(a), SubmitAnyBuilder::CommandBuffer(b)) => { + (SubmitAnyBuilder::BindSparse(_, _), SubmitAnyBuilder::CommandBuffer(_, _)) => { unimplemented!() } - (SubmitAnyBuilder::CommandBuffer(a), SubmitAnyBuilder::BindSparse(b)) => { + (SubmitAnyBuilder::CommandBuffer(_, _), SubmitAnyBuilder::BindSparse(_, _)) => { unimplemented!() } - (SubmitAnyBuilder::BindSparse(mut a), SubmitAnyBuilder::BindSparse(b)) => { - match a.merge(b) { - Ok(()) => SubmitAnyBuilder::BindSparse(a), - Err(_) => { - // TODO: this happens if both bind sparse have been given a fence already - // annoying, but not impossible, to handle - unimplemented!() - } + ( + SubmitAnyBuilder::BindSparse(mut bind_infos_a, fence_a), + SubmitAnyBuilder::BindSparse(bind_infos_b, fence_b), + ) => { + if fence_a.is_some() && fence_b.is_some() { + // TODO: this happens if both bind sparse have been given a fence already + // annoying, but not impossible, to handle + unimplemented!() } + + bind_infos_a.extend(bind_infos_b); + SubmitAnyBuilder::BindSparse(bind_infos_a, fence_a) } }) } - #[inline] unsafe fn signal_finished(&self) { self.first.signal_finished(); self.second.signal_finished(); } - #[inline] fn queue_change_allowed(&self) -> bool { self.first.queue_change_allowed() && self.second.queue_change_allowed() } - #[inline] fn queue(&self) -> Option<Arc<Queue>> { match (self.first.queue(), self.second.queue()) { (Some(q1), Some(q2)) => { - if q1.is_same(&q2) { + if q1 == q2 { Some(q1) } else if self.first.queue_change_allowed() { Some(q2) @@ -201,68 +197,93 @@ where } } - #[inline] fn check_buffer_access( &self, - buffer: &dyn BufferAccess, + buffer: &Buffer, + range: Range<DeviceSize>, exclusive: bool, queue: &Queue, - ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> { - let first = self.first.check_buffer_access(buffer, exclusive, queue); - let second = self.second.check_buffer_access(buffer, exclusive, queue); + ) -> Result<(), AccessCheckError> { + let first = self + .first + .check_buffer_access(buffer, range.clone(), exclusive, queue); + let second = self + .second + .check_buffer_access(buffer, range, exclusive, queue); debug_assert!( - !exclusive || !(first.is_ok() && second.is_ok()), + !(exclusive && first.is_ok() && second.is_ok()), "Two futures gave exclusive access to the same resource" ); match (first, second) { (v, Err(AccessCheckError::Unknown)) => v, (Err(AccessCheckError::Unknown), v) => v, - (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(e2))) => { + (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => { Err(AccessCheckError::Denied(e1)) } // TODO: which one? - (Ok(_), Err(AccessCheckError::Denied(_))) - | (Err(AccessCheckError::Denied(_)), Ok(_)) => panic!( + (Ok(()), Err(AccessCheckError::Denied(_))) + | (Err(AccessCheckError::Denied(_)), Ok(())) => panic!( "Contradictory information \ between two futures" ), - (Ok(None), Ok(None)) => Ok(None), - (Ok(Some(a)), Ok(None)) | (Ok(None), Ok(Some(a))) => Ok(Some(a)), - (Ok(Some((a1, a2))), Ok(Some((b1, b2)))) => Ok(Some((a1 | b1, a2 | b2))), + (Ok(()), Ok(())) => Ok(()), } } - #[inline] fn check_image_access( &self, - image: &dyn ImageAccess, - layout: ImageLayout, + image: &Image, + range: Range<DeviceSize>, exclusive: bool, + expected_layout: ImageLayout, queue: &Queue, - ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> { + ) -> Result<(), AccessCheckError> { + let first = + self.first + .check_image_access(image, range.clone(), exclusive, expected_layout, queue); + let second = + self.second + .check_image_access(image, range, exclusive, expected_layout, queue); + debug_assert!( + !(exclusive && first.is_ok() && second.is_ok()), + "Two futures gave exclusive access to the same resource" + ); + match (first, second) { + (v, Err(AccessCheckError::Unknown)) => v, + (Err(AccessCheckError::Unknown), v) => v, + (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => { + Err(AccessCheckError::Denied(e1)) + } // TODO: which one? + (Ok(()), Err(AccessCheckError::Denied(_))) + | (Err(AccessCheckError::Denied(_)), Ok(())) => { + panic!("Contradictory information between two futures") + } + (Ok(()), Ok(())) => Ok(()), + } + } + + #[inline] + fn check_swapchain_image_acquired( + &self, + swapchain: &Swapchain, + image_index: u32, + _before: bool, + ) -> Result<(), AccessCheckError> { let first = self .first - .check_image_access(image, layout, exclusive, queue); + .check_swapchain_image_acquired(swapchain, image_index, false); let second = self .second - .check_image_access(image, layout, exclusive, queue); - debug_assert!( - !exclusive || !(first.is_ok() && second.is_ok()), - "Two futures gave exclusive access to the same resource" - ); + .check_swapchain_image_acquired(swapchain, image_index, false); + match (first, second) { (v, Err(AccessCheckError::Unknown)) => v, (Err(AccessCheckError::Unknown), v) => v, - (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(e2))) => { + (Err(AccessCheckError::Denied(e1)), Err(AccessCheckError::Denied(_))) => { Err(AccessCheckError::Denied(e1)) } // TODO: which one? - (Ok(_), Err(AccessCheckError::Denied(_))) - | (Err(AccessCheckError::Denied(_)), Ok(_)) => panic!( - "Contradictory information \ - between two futures" - ), - (Ok(None), Ok(None)) => Ok(None), - (Ok(Some(a)), Ok(None)) | (Ok(None), Ok(Some(a))) => Ok(Some(a)), - (Ok(Some((a1, a2))), Ok(Some((b1, b2)))) => Ok(Some((a1 | b1, a2 | b2))), + (Ok(()), Err(AccessCheckError::Denied(_))) + | (Err(AccessCheckError::Denied(_)), Ok(())) => Ok(()), + (Ok(()), Ok(())) => Ok(()), // TODO: Double Acquired? } } } |