diff options
Diffstat (limited to 'src/command_buffer/traits.rs')
-rw-r--r-- | src/command_buffer/traits.rs | 528 |
1 files changed, 0 insertions, 528 deletions
diff --git a/src/command_buffer/traits.rs b/src/command_buffer/traits.rs deleted file mode 100644 index 5252073..0000000 --- a/src/command_buffer/traits.rs +++ /dev/null @@ -1,528 +0,0 @@ -// Copyright (c) 2016 The vulkano developers -// Licensed under the Apache License, Version 2.0 -// <LICENSE-APACHE or -// https://www.apache.org/licenses/LICENSE-2.0> or the MIT -// license <LICENSE-MIT or https://opensource.org/licenses/MIT>, -// at your option. All files in the project carrying such -// notice may not be copied, modified, or distributed except -// according to those terms. - -use crate::buffer::BufferAccess; -use crate::command_buffer::submit::SubmitAnyBuilder; -use crate::command_buffer::submit::SubmitCommandBufferBuilder; -use crate::command_buffer::sys::UnsafeCommandBuffer; -use crate::command_buffer::CommandBufferInheritance; -use crate::command_buffer::ImageUninitializedSafe; -use crate::device::Device; -use crate::device::DeviceOwned; -use crate::device::Queue; -use crate::image::ImageAccess; -use crate::image::ImageLayout; -use crate::render_pass::FramebufferAbstract; -use crate::sync::now; -use crate::sync::AccessCheckError; -use crate::sync::AccessError; -use crate::sync::AccessFlags; -use crate::sync::FlushError; -use crate::sync::GpuFuture; -use crate::sync::NowFuture; -use crate::sync::PipelineMemoryAccess; -use crate::sync::PipelineStages; -use crate::SafeDeref; -use crate::VulkanObject; -use std::borrow::Cow; -use std::error; -use std::fmt; -use std::sync::atomic::AtomicBool; -use std::sync::atomic::Ordering; -use std::sync::Arc; -use std::sync::Mutex; - -pub unsafe trait PrimaryCommandBuffer: DeviceOwned { - /// Returns the underlying `UnsafeCommandBuffer` of this command buffer. - fn inner(&self) -> &UnsafeCommandBuffer; - - /// Checks whether this command buffer is allowed to be submitted after the `future` and on - /// the given queue, and if so locks it. - /// - /// If you call this function, then you should call `unlock` afterwards. - fn lock_submit( - &self, - future: &dyn GpuFuture, - queue: &Queue, - ) -> Result<(), CommandBufferExecError>; - - /// Unlocks the command buffer. Should be called once for each call to `lock_submit`. - /// - /// # Safety - /// - /// Must not be called if you haven't called `lock_submit` before. - unsafe fn unlock(&self); - - /// Executes this command buffer on a queue. - /// - /// This function returns an object that implements the `GpuFuture` trait. See the - /// documentation of the `sync` module for more information. - /// - /// The command buffer is not actually executed until you call `flush()` on the object. - /// You are encouraged to chain together as many futures as possible before calling `flush()`, - /// and call `.then_signal_future()` before doing so. Note however that once you called - /// `execute()` there is no way to cancel the execution, even if you didn't flush yet. - /// - /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a - /// > concrete type. - /// - /// > **Note**: This is just a shortcut for `execute_after(vulkano::sync::now(), queue)`. - /// - /// # Panic - /// - /// Panics if the device of the command buffer is not the same as the device of the future. - #[inline] - fn execute( - self, - queue: Arc<Queue>, - ) -> Result<CommandBufferExecFuture<NowFuture, Self>, CommandBufferExecError> - where - Self: Sized + 'static, - { - let device = queue.device().clone(); - self.execute_after(now(device), queue) - } - - /// Executes the command buffer after an existing future. - /// - /// This function returns an object that implements the `GpuFuture` trait. See the - /// documentation of the `sync` module for more information. - /// - /// The command buffer is not actually executed until you call `flush()` on the object. - /// You are encouraged to chain together as many futures as possible before calling `flush()`, - /// and call `.then_signal_future()` before doing so. Note however that once you called - /// `execute()` there is no way to cancel the execution, even if you didn't flush yet. - /// - /// > **Note**: In the future this function may return `-> impl GpuFuture` instead of a - /// > concrete type. - /// - /// This function requires the `'static` lifetime to be on the command buffer. This is because - /// this function returns a `CommandBufferExecFuture` whose job is to lock resources and keep - /// them alive while they are in use by the GPU. If `'static` wasn't required, you could call - /// `std::mem::forget` on that object and "unlock" these resources. For more information about - /// this problem, search the web for "rust thread scoped leakpocalypse". - /// - /// # Panic - /// - /// Panics if the device of the command buffer is not the same as the device of the future. - #[inline] - fn execute_after<F>( - self, - future: F, - queue: Arc<Queue>, - ) -> Result<CommandBufferExecFuture<F, Self>, CommandBufferExecError> - where - Self: Sized + 'static, - F: GpuFuture, - { - assert_eq!( - self.device().internal_object(), - future.device().internal_object() - ); - - if !future.queue_change_allowed() { - assert!(future.queue().unwrap().is_same(&queue)); - } - - self.lock_submit(&future, &queue)?; - - Ok(CommandBufferExecFuture { - previous: future, - command_buffer: self, - queue, - submitted: Mutex::new(false), - finished: AtomicBool::new(false), - }) - } - - fn check_buffer_access( - &self, - buffer: &dyn BufferAccess, - exclusive: bool, - queue: &Queue, - ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>; - - fn check_image_access( - &self, - image: &dyn ImageAccess, - layout: ImageLayout, - exclusive: bool, - queue: &Queue, - ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError>; -} - -unsafe impl<T> PrimaryCommandBuffer for T -where - T: SafeDeref, - T::Target: PrimaryCommandBuffer, -{ - #[inline] - fn inner(&self) -> &UnsafeCommandBuffer { - (**self).inner() - } - - #[inline] - fn lock_submit( - &self, - future: &dyn GpuFuture, - queue: &Queue, - ) -> Result<(), CommandBufferExecError> { - (**self).lock_submit(future, queue) - } - - #[inline] - unsafe fn unlock(&self) { - (**self).unlock(); - } - - #[inline] - fn check_buffer_access( - &self, - buffer: &dyn BufferAccess, - exclusive: bool, - queue: &Queue, - ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> { - (**self).check_buffer_access(buffer, exclusive, queue) - } - - #[inline] - fn check_image_access( - &self, - image: &dyn ImageAccess, - layout: ImageLayout, - exclusive: bool, - queue: &Queue, - ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> { - (**self).check_image_access(image, layout, exclusive, queue) - } -} - -pub unsafe trait SecondaryCommandBuffer: DeviceOwned { - /// Returns the underlying `UnsafeCommandBuffer` of this command buffer. - fn inner(&self) -> &UnsafeCommandBuffer; - - /// Checks whether this command buffer is allowed to be recorded to a command buffer, - /// and if so locks it. - /// - /// If you call this function, then you should call `unlock` afterwards. - fn lock_record(&self) -> Result<(), CommandBufferExecError>; - - /// Unlocks the command buffer. Should be called once for each call to `lock_record`. - /// - /// # Safety - /// - /// Must not be called if you haven't called `lock_record` before. - unsafe fn unlock(&self); - - /// Returns a `CommandBufferInheritance` value describing the properties that the command - /// buffer inherits from its parent primary command buffer. - fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract>; - - /// Returns the number of buffers accessed by this command buffer. - fn num_buffers(&self) -> usize; - - /// Returns the `index`th buffer of this command buffer, or `None` if out of range. - /// - /// The valid range is between 0 and `num_buffers()`. - fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)>; - - /// Returns the number of images accessed by this command buffer. - fn num_images(&self) -> usize; - - /// Returns the `index`th image of this command buffer, or `None` if out of range. - /// - /// The valid range is between 0 and `num_images()`. - fn image( - &self, - index: usize, - ) -> Option<( - &dyn ImageAccess, - PipelineMemoryAccess, - ImageLayout, - ImageLayout, - ImageUninitializedSafe, - )>; -} - -unsafe impl<T> SecondaryCommandBuffer for T -where - T: SafeDeref, - T::Target: SecondaryCommandBuffer, -{ - #[inline] - fn inner(&self) -> &UnsafeCommandBuffer { - (**self).inner() - } - - #[inline] - fn lock_record(&self) -> Result<(), CommandBufferExecError> { - (**self).lock_record() - } - - #[inline] - unsafe fn unlock(&self) { - (**self).unlock(); - } - - #[inline] - fn inheritance(&self) -> CommandBufferInheritance<&dyn FramebufferAbstract> { - (**self).inheritance() - } - - #[inline] - fn num_buffers(&self) -> usize { - (**self).num_buffers() - } - - #[inline] - fn buffer(&self, index: usize) -> Option<(&dyn BufferAccess, PipelineMemoryAccess)> { - (**self).buffer(index) - } - - #[inline] - fn num_images(&self) -> usize { - (**self).num_images() - } - - #[inline] - fn image( - &self, - index: usize, - ) -> Option<( - &dyn ImageAccess, - PipelineMemoryAccess, - ImageLayout, - ImageLayout, - ImageUninitializedSafe, - )> { - (**self).image(index) - } -} - -/// Represents a command buffer being executed by the GPU and the moment when the execution -/// finishes. -#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"] -pub struct CommandBufferExecFuture<F, Cb> -where - F: GpuFuture, - Cb: PrimaryCommandBuffer, -{ - previous: F, - command_buffer: Cb, - queue: Arc<Queue>, - // True if the command buffer has already been submitted. - // If flush is called multiple times, we want to block so that only one flushing is executed. - // Therefore we use a `Mutex<bool>` and not an `AtomicBool`. - submitted: Mutex<bool>, - finished: AtomicBool, -} - -unsafe impl<F, Cb> GpuFuture for CommandBufferExecFuture<F, Cb> -where - F: GpuFuture, - Cb: PrimaryCommandBuffer, -{ - #[inline] - fn cleanup_finished(&mut self) { - self.previous.cleanup_finished(); - } - - unsafe fn build_submission(&self) -> Result<SubmitAnyBuilder, FlushError> { - Ok(match self.previous.build_submission()? { - SubmitAnyBuilder::Empty => { - let mut builder = SubmitCommandBufferBuilder::new(); - builder.add_command_buffer(self.command_buffer.inner()); - SubmitAnyBuilder::CommandBuffer(builder) - } - SubmitAnyBuilder::SemaphoresWait(sem) => { - let mut builder: SubmitCommandBufferBuilder = sem.into(); - builder.add_command_buffer(self.command_buffer.inner()); - SubmitAnyBuilder::CommandBuffer(builder) - } - SubmitAnyBuilder::CommandBuffer(mut builder) => { - // FIXME: add pipeline barrier - builder.add_command_buffer(self.command_buffer.inner()); - SubmitAnyBuilder::CommandBuffer(builder) - } - SubmitAnyBuilder::QueuePresent(_) | SubmitAnyBuilder::BindSparse(_) => { - unimplemented!() // TODO: - /*present.submit(); // TODO: wrong - let mut builder = SubmitCommandBufferBuilder::new(); - builder.add_command_buffer(self.command_buffer.inner()); - SubmitAnyBuilder::CommandBuffer(builder)*/ - } - }) - } - - #[inline] - fn flush(&self) -> Result<(), FlushError> { - unsafe { - let mut submitted = self.submitted.lock().unwrap(); - if *submitted { - return Ok(()); - } - - let queue = self.queue.clone(); - - match self.build_submission()? { - SubmitAnyBuilder::Empty => {} - SubmitAnyBuilder::CommandBuffer(builder) => { - builder.submit(&queue)?; - } - _ => unreachable!(), - }; - - // Only write `true` here in order to try again next time if we failed to submit. - *submitted = true; - Ok(()) - } - } - - #[inline] - unsafe fn signal_finished(&self) { - if self.finished.swap(true, Ordering::SeqCst) == false { - self.command_buffer.unlock(); - } - - self.previous.signal_finished(); - } - - #[inline] - fn queue_change_allowed(&self) -> bool { - false - } - - #[inline] - fn queue(&self) -> Option<Arc<Queue>> { - Some(self.queue.clone()) - } - - #[inline] - fn check_buffer_access( - &self, - buffer: &dyn BufferAccess, - exclusive: bool, - queue: &Queue, - ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> { - match self - .command_buffer - .check_buffer_access(buffer, exclusive, queue) - { - Ok(v) => Ok(v), - Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)), - Err(AccessCheckError::Unknown) => { - self.previous.check_buffer_access(buffer, exclusive, queue) - } - } - } - - #[inline] - fn check_image_access( - &self, - image: &dyn ImageAccess, - layout: ImageLayout, - exclusive: bool, - queue: &Queue, - ) -> Result<Option<(PipelineStages, AccessFlags)>, AccessCheckError> { - match self - .command_buffer - .check_image_access(image, layout, exclusive, queue) - { - Ok(v) => Ok(v), - Err(AccessCheckError::Denied(err)) => Err(AccessCheckError::Denied(err)), - Err(AccessCheckError::Unknown) => self - .previous - .check_image_access(image, layout, exclusive, queue), - } - } -} - -unsafe impl<F, Cb> DeviceOwned for CommandBufferExecFuture<F, Cb> -where - F: GpuFuture, - Cb: PrimaryCommandBuffer, -{ - #[inline] - fn device(&self) -> &Arc<Device> { - self.command_buffer.device() - } -} - -impl<F, Cb> Drop for CommandBufferExecFuture<F, Cb> -where - F: GpuFuture, - Cb: PrimaryCommandBuffer, -{ - fn drop(&mut self) { - unsafe { - if !*self.finished.get_mut() { - // TODO: handle errors? - self.flush().unwrap(); - // Block until the queue finished. - self.queue.wait().unwrap(); - self.command_buffer.unlock(); - self.previous.signal_finished(); - } - } - } -} - -/// Error that can happen when attempting to execute a command buffer. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum CommandBufferExecError { - /// Access to a resource has been denied. - AccessError { - error: AccessError, - command_name: Cow<'static, str>, - command_param: Cow<'static, str>, - command_offset: usize, - }, - - /// The command buffer or one of the secondary command buffers it executes was created with the - /// "one time submit" flag, but has already been submitted it the past. - OneTimeSubmitAlreadySubmitted, - - /// The command buffer or one of the secondary command buffers it executes is already in use by - /// the GPU and was not created with the "concurrent" flag. - ExclusiveAlreadyInUse, - // TODO: missing entries (eg. wrong queue family, secondary command buffer) -} - -impl error::Error for CommandBufferExecError { - #[inline] - fn source(&self) -> Option<&(dyn error::Error + 'static)> { - match *self { - CommandBufferExecError::AccessError { ref error, .. } => Some(error), - _ => None, - } - } -} - -impl fmt::Display for CommandBufferExecError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!( - fmt, - "{}", - match *self { - CommandBufferExecError::AccessError { .. } => - "access to a resource has been denied", - CommandBufferExecError::OneTimeSubmitAlreadySubmitted => { - "the command buffer or one of the secondary command buffers it executes was \ - created with the \"one time submit\" flag, but has already been submitted in \ - the past" - } - CommandBufferExecError::ExclusiveAlreadyInUse => { - "the command buffer or one of the secondary command buffers it executes is \ - already in use was not created with the \"concurrent\" flag" - } - } - ) - } -} |