diff options
Diffstat (limited to 'src/command_buffer/pool/sys.rs')
-rw-r--r-- | src/command_buffer/pool/sys.rs | 421 |
1 files changed, 0 insertions, 421 deletions
diff --git a/src/command_buffer/pool/sys.rs b/src/command_buffer/pool/sys.rs deleted file mode 100644 index 8432182..0000000 --- a/src/command_buffer/pool/sys.rs +++ /dev/null @@ -1,421 +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::check_errors; -use crate::device::physical::QueueFamily; -use crate::device::Device; -use crate::device::DeviceOwned; -use crate::Error; -use crate::OomError; -use crate::Version; -use crate::VulkanObject; -use smallvec::SmallVec; -use std::error; -use std::fmt; -use std::marker::PhantomData; -use std::mem::MaybeUninit; -use std::ptr; -use std::sync::Arc; -use std::vec::IntoIter as VecIntoIter; - -/// Low-level implementation of a command pool. -/// -/// A command pool is always tied to a specific queue family. Command buffers allocated from a pool -/// can only be executed on the corresponding queue family. -/// -/// This struct doesn't implement the `Sync` trait because Vulkan command pools are not thread -/// safe. In other words, you can only use a pool from one thread at a time. -#[derive(Debug)] -pub struct UnsafeCommandPool { - pool: ash::vk::CommandPool, - device: Arc<Device>, - - // Index of the associated queue family in the physical device. - queue_family_index: u32, - - // We don't want `UnsafeCommandPool` to implement Sync. - // This marker unimplements both Send and Sync, but we reimplement Send manually right under. - dummy_avoid_sync: PhantomData<*const u8>, -} - -unsafe impl Send for UnsafeCommandPool {} - -impl UnsafeCommandPool { - /// Creates a new pool. - /// - /// The command buffers created with this pool can only be executed on queues of the given - /// family. - /// - /// Setting `transient` to true is a hint to the implementation that the command buffers will - /// be short-lived. - /// Setting `reset_cb` to true means that command buffers can be reset individually. - /// - /// # Panic - /// - /// - Panics if the queue family doesn't belong to the same physical device as `device`. - /// - pub fn new( - device: Arc<Device>, - queue_family: QueueFamily, - transient: bool, - reset_cb: bool, - ) -> Result<UnsafeCommandPool, OomError> { - assert_eq!( - device.physical_device().internal_object(), - queue_family.physical_device().internal_object(), - "Device doesn't match physical device when creating a command pool" - ); - - let fns = device.fns(); - - let flags = { - let flag1 = if transient { - ash::vk::CommandPoolCreateFlags::TRANSIENT - } else { - ash::vk::CommandPoolCreateFlags::empty() - }; - let flag2 = if reset_cb { - ash::vk::CommandPoolCreateFlags::RESET_COMMAND_BUFFER - } else { - ash::vk::CommandPoolCreateFlags::empty() - }; - flag1 | flag2 - }; - - let pool = unsafe { - let infos = ash::vk::CommandPoolCreateInfo { - flags: flags, - queue_family_index: queue_family.id(), - ..Default::default() - }; - - let mut output = MaybeUninit::uninit(); - check_errors(fns.v1_0.create_command_pool( - device.internal_object(), - &infos, - ptr::null(), - output.as_mut_ptr(), - ))?; - output.assume_init() - }; - - Ok(UnsafeCommandPool { - pool: pool, - device: device.clone(), - queue_family_index: queue_family.id(), - dummy_avoid_sync: PhantomData, - }) - } - - /// Resets the pool, which resets all the command buffers that were allocated from it. - /// - /// If `release_resources` is true, it is a hint to the implementation that it should free all - /// the memory internally allocated for this pool. - /// - /// # Safety - /// - /// The command buffers allocated from this pool jump to the initial state. - /// - pub unsafe fn reset(&self, release_resources: bool) -> Result<(), OomError> { - let flags = if release_resources { - ash::vk::CommandPoolResetFlags::RELEASE_RESOURCES - } else { - ash::vk::CommandPoolResetFlags::empty() - }; - - let fns = self.device.fns(); - check_errors( - fns.v1_0 - .reset_command_pool(self.device.internal_object(), self.pool, flags), - )?; - Ok(()) - } - - /// Trims a command pool, which recycles unused internal memory from the command pool back to - /// the system. - /// - /// Command buffers allocated from the pool are not affected by trimming. - /// - /// This function is supported only if the `VK_KHR_maintenance1` extension was enabled at - /// device creation. Otherwise an error is returned. - /// Since this operation is purely an optimization it is legitimate to call this function and - /// simply ignore any possible error. - pub fn trim(&self) -> Result<(), CommandPoolTrimError> { - unsafe { - if !(self.device.api_version() >= Version::V1_1 - || self.device.enabled_extensions().khr_maintenance1) - { - return Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled); - } - - let fns = self.device.fns(); - - if self.device.api_version() >= Version::V1_1 { - fns.v1_1.trim_command_pool( - self.device.internal_object(), - self.pool, - ash::vk::CommandPoolTrimFlags::empty(), - ); - } else { - fns.khr_maintenance1.trim_command_pool_khr( - self.device.internal_object(), - self.pool, - ash::vk::CommandPoolTrimFlagsKHR::empty(), - ); - } - - Ok(()) - } - } - - /// Allocates `count` command buffers. - /// - /// If `secondary` is true, allocates secondary command buffers. Otherwise, allocates primary - /// command buffers. - pub fn alloc_command_buffers( - &self, - secondary: bool, - count: u32, - ) -> Result<UnsafeCommandPoolAllocIter, OomError> { - if count == 0 { - return Ok(UnsafeCommandPoolAllocIter { - device: self.device.clone(), - list: vec![].into_iter(), - }); - } - - let infos = ash::vk::CommandBufferAllocateInfo { - command_pool: self.pool, - level: if secondary { - ash::vk::CommandBufferLevel::SECONDARY - } else { - ash::vk::CommandBufferLevel::PRIMARY - }, - command_buffer_count: count, - ..Default::default() - }; - - unsafe { - let fns = self.device.fns(); - let mut out = Vec::with_capacity(count as usize); - check_errors(fns.v1_0.allocate_command_buffers( - self.device.internal_object(), - &infos, - out.as_mut_ptr(), - ))?; - - out.set_len(count as usize); - - Ok(UnsafeCommandPoolAllocIter { - device: self.device.clone(), - list: out.into_iter(), - }) - } - } - - /// Frees individual command buffers. - /// - /// # Safety - /// - /// The command buffers must have been allocated from this pool. They must not be in use. - /// - pub unsafe fn free_command_buffers<I>(&self, command_buffers: I) - where - I: Iterator<Item = UnsafeCommandPoolAlloc>, - { - let command_buffers: SmallVec<[_; 4]> = - command_buffers.map(|cb| cb.command_buffer).collect(); - let fns = self.device.fns(); - fns.v1_0.free_command_buffers( - self.device.internal_object(), - self.pool, - command_buffers.len() as u32, - command_buffers.as_ptr(), - ) - } - - /// Returns the queue family on which command buffers of this pool can be executed. - #[inline] - pub fn queue_family(&self) -> QueueFamily { - self.device - .physical_device() - .queue_family_by_id(self.queue_family_index) - .unwrap() - } -} - -unsafe impl DeviceOwned for UnsafeCommandPool { - #[inline] - fn device(&self) -> &Arc<Device> { - &self.device - } -} - -unsafe impl VulkanObject for UnsafeCommandPool { - type Object = ash::vk::CommandPool; - - #[inline] - fn internal_object(&self) -> ash::vk::CommandPool { - self.pool - } -} - -impl Drop for UnsafeCommandPool { - #[inline] - fn drop(&mut self) { - unsafe { - let fns = self.device.fns(); - fns.v1_0 - .destroy_command_pool(self.device.internal_object(), self.pool, ptr::null()); - } - } -} - -/// Opaque type that represents a command buffer allocated from a pool. -pub struct UnsafeCommandPoolAlloc { - command_buffer: ash::vk::CommandBuffer, - device: Arc<Device>, -} - -unsafe impl DeviceOwned for UnsafeCommandPoolAlloc { - #[inline] - fn device(&self) -> &Arc<Device> { - &self.device - } -} - -unsafe impl VulkanObject for UnsafeCommandPoolAlloc { - type Object = ash::vk::CommandBuffer; - - #[inline] - fn internal_object(&self) -> ash::vk::CommandBuffer { - self.command_buffer - } -} - -/// Iterator for newly-allocated command buffers. -#[derive(Debug)] -pub struct UnsafeCommandPoolAllocIter { - device: Arc<Device>, - list: VecIntoIter<ash::vk::CommandBuffer>, -} - -impl Iterator for UnsafeCommandPoolAllocIter { - type Item = UnsafeCommandPoolAlloc; - - #[inline] - fn next(&mut self) -> Option<UnsafeCommandPoolAlloc> { - self.list - .next() - .map(|command_buffer| UnsafeCommandPoolAlloc { - command_buffer, - device: self.device.clone(), - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option<usize>) { - self.list.size_hint() - } -} - -impl ExactSizeIterator for UnsafeCommandPoolAllocIter {} - -/// Error that can happen when trimming command pools. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum CommandPoolTrimError { - /// The `KHR_maintenance1` extension was not enabled. - Maintenance1ExtensionNotEnabled, -} - -impl error::Error for CommandPoolTrimError {} - -impl fmt::Display for CommandPoolTrimError { - #[inline] - fn fmt(&self, fmt: &mut fmt::Formatter) -> Result<(), fmt::Error> { - write!( - fmt, - "{}", - match *self { - CommandPoolTrimError::Maintenance1ExtensionNotEnabled => { - "the `KHR_maintenance1` extension was not enabled" - } - } - ) - } -} - -impl From<Error> for CommandPoolTrimError { - #[inline] - fn from(err: Error) -> CommandPoolTrimError { - panic!("unexpected error: {:?}", err) - } -} - -#[cfg(test)] -mod tests { - use crate::command_buffer::pool::CommandPoolTrimError; - use crate::command_buffer::pool::UnsafeCommandPool; - use crate::Version; - - #[test] - fn basic_create() { - let (device, queue) = gfx_dev_and_queue!(); - let _ = UnsafeCommandPool::new(device, queue.family(), false, false).unwrap(); - } - - #[test] - fn queue_family_getter() { - let (device, queue) = gfx_dev_and_queue!(); - let pool = UnsafeCommandPool::new(device, queue.family(), false, false).unwrap(); - assert_eq!(pool.queue_family().id(), queue.family().id()); - } - - #[test] - fn panic_if_not_match_family() { - let (device, _) = gfx_dev_and_queue!(); - let (_, queue) = gfx_dev_and_queue!(); - - assert_should_panic!( - "Device doesn't match physical device when creating a command pool", - { - let _ = UnsafeCommandPool::new(device, queue.family(), false, false); - } - ); - } - - #[test] - fn check_maintenance_when_trim() { - let (device, queue) = gfx_dev_and_queue!(); - let pool = UnsafeCommandPool::new(device.clone(), queue.family(), false, false).unwrap(); - - if device.api_version() >= Version::V1_1 { - match pool.trim() { - Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled) => panic!(), - _ => (), - } - } else { - match pool.trim() { - Err(CommandPoolTrimError::Maintenance1ExtensionNotEnabled) => (), - _ => panic!(), - } - } - } - - // TODO: test that trim works if VK_KHR_maintenance1 if enabled ; the test macro doesn't - // support enabling extensions yet - - #[test] - fn basic_alloc() { - let (device, queue) = gfx_dev_and_queue!(); - let pool = UnsafeCommandPool::new(device, queue.family(), false, false).unwrap(); - let iter = pool.alloc_command_buffers(false, 12).unwrap(); - assert_eq!(iter.count(), 12); - } -} |