diff --git a/vulkano/autogen/errors.rs b/vulkano/autogen/errors.rs index 920b9b3cd1..d5fe4e033d 100644 --- a/vulkano/autogen/errors.rs +++ b/vulkano/autogen/errors.rs @@ -66,8 +66,9 @@ fn errors_members(errors: &[&str]) -> Vec { let mut parts = ffi_name.split('_').collect::>(); - assert!(parts[0] == "ERROR"); - parts.remove(0); + if parts[0] == "ERROR" { + parts.remove(0); + } if ["EXT", "KHR", "NV"].contains(parts.last().unwrap()) { parts.pop(); diff --git a/vulkano/autogen/mod.rs b/vulkano/autogen/mod.rs index ff39a6f9ed..fbe387f3d9 100644 --- a/vulkano/autogen/mod.rs +++ b/vulkano/autogen/mod.rs @@ -191,7 +191,10 @@ impl<'r> VkRegistryData<'r> { }) if name == "VkResult" => Some(children.iter().filter_map(|en| { if let EnumsChild::Enum(en) = en { if let EnumSpec::Value { value, .. } = &en.spec { - if value.starts_with('-') { + // Treat NotReady and Timeout as error conditions + if value.starts_with('-') + || matches!(en.name.as_str(), "VK_NOT_READY" | "VK_TIMEOUT") + { return Some(en.name.as_str()); } } diff --git a/vulkano/src/lib.rs b/vulkano/src/lib.rs index 7aa5206312..97754dbde2 100644 --- a/vulkano/src/lib.rs +++ b/vulkano/src/lib.rs @@ -298,6 +298,8 @@ impl Error for VulkanError {} impl Display for VulkanError { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { let msg = match self { + VulkanError::NotReady => "a resource is not yet ready", + VulkanError::Timeout => "an operation has not completed in the specified time", VulkanError::OutOfHostMemory => "a host memory allocation has failed", VulkanError::OutOfDeviceMemory => "a device memory allocation has failed", VulkanError::InitializationFailed => { diff --git a/vulkano/src/swapchain/acquire_present.rs b/vulkano/src/swapchain/acquire_present.rs index a2870ca79d..146d193e06 100644 --- a/vulkano/src/swapchain/acquire_present.rs +++ b/vulkano/src/swapchain/acquire_present.rs @@ -13,9 +13,9 @@ use crate::{ device::{Device, DeviceOwned, Queue}, image::{Image, ImageLayout}, sync::{ - fence::{Fence, FenceError}, + fence::Fence, future::{AccessCheckError, AccessError, FlushError, GpuFuture, SubmitAnyBuilder}, - semaphore::{Semaphore, SemaphoreError}, + semaphore::Semaphore, }, DeviceSize, OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, VulkanError, VulkanObject, @@ -186,7 +186,7 @@ impl SwapchainAcquireFuture { /// If timeout is `None`, will potentially block forever /// /// You still need to join with this future for present to work - pub fn wait(&self, timeout: Option) -> Result<(), FenceError> { + pub fn wait(&self, timeout: Option) -> Result<(), VulkanError> { match &self.fence { Some(fence) => fence.wait(timeout), None => Ok(()), @@ -330,12 +330,6 @@ pub enum AcquireError { /// The surface has changed in a way that makes the swapchain unusable. You must query the /// surface's new properties and recreate a new swapchain if you want to continue drawing. OutOfDate, - - /// Error during fence creation. - FenceError(FenceError), - - /// Error during semaphore creation. - SemaphoreError(SemaphoreError), } impl Error for AcquireError { @@ -361,25 +355,11 @@ impl Display for AcquireError { AcquireError::FullScreenExclusiveModeLost => { "the swapchain no longer has full-screen exclusivity" } - AcquireError::FenceError(_) => "error creating fence", - AcquireError::SemaphoreError(_) => "error creating semaphore", } ) } } -impl From for AcquireError { - fn from(err: FenceError) -> Self { - AcquireError::FenceError(err) - } -} - -impl From for AcquireError { - fn from(err: SemaphoreError) -> Self { - AcquireError::SemaphoreError(err) - } -} - impl From for AcquireError { fn from(err: OomError) -> AcquireError { AcquireError::OomError(err) diff --git a/vulkano/src/sync/event.rs b/vulkano/src/sync/event.rs index 3cc3e249a7..94be34b743 100644 --- a/vulkano/src/sync/event.rs +++ b/vulkano/src/sync/event.rs @@ -27,17 +27,10 @@ use crate::{ device::{Device, DeviceOwned}, instance::InstanceOwnedDebugWrapper, - macros::impl_id_counter, - OomError, Requires, RequiresAllOf, RequiresOneOf, VulkanError, VulkanObject, -}; -use std::{ - error::Error, - fmt::{Display, Error as FmtError, Formatter}, - mem::MaybeUninit, - num::NonZeroU64, - ptr, - sync::Arc, + macros::{impl_id_counter, vulkan_bitflags}, + Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError, VulkanObject, }; +use std::{mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc}; /// Used to block the GPU execution until an event on the CPU occurs. /// @@ -51,6 +44,8 @@ pub struct Event { device: InstanceOwnedDebugWrapper>, id: NonZeroU64, must_put_in_pool: bool, + + flags: EventCreateFlags, } impl Event { @@ -61,18 +56,44 @@ impl Event { /// [`events`](crate::device::Features::events) /// feature must be enabled on the device. #[inline] - pub fn new(device: Arc, _create_info: EventCreateInfo) -> Result { - // VUID-vkCreateEvent-events-04468 + pub fn new( + device: Arc, + create_info: EventCreateInfo, + ) -> Result> { + Self::validate_new(&device, &create_info)?; + + unsafe { Ok(Self::new_unchecked(device, create_info)?) } + } + + fn validate_new( + device: &Device, + create_info: &EventCreateInfo, + ) -> Result<(), Box> { if device.enabled_extensions().khr_portability_subset && !device.enabled_features().events { - return Err(EventError::RequirementNotMet { - required_for: "this device is a portability subset device, and `Event::new` was \ - called", + return Err(Box::new(ValidationError { + problem: "this device is a portability subset device".into(), requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("events")])]), - }); + vuids: &["VUID-vkCreateEvent-events-04468"], + ..Default::default() + })); } - let create_info = ash::vk::EventCreateInfo { - flags: ash::vk::EventCreateFlags::empty(), + create_info + .validate(device) + .map_err(|err| err.add_context("create_info"))?; + + Ok(()) + } + + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + pub unsafe fn new_unchecked( + device: Arc, + create_info: EventCreateInfo, + ) -> Result { + let &EventCreateInfo { flags, _ne: _ } = &create_info; + + let create_info_vk = ash::vk::EventCreateInfo { + flags: flags.into(), ..Default::default() }; @@ -81,7 +102,7 @@ impl Event { let fns = device.fns(); (fns.v1_0.create_event)( device.handle(), - &create_info, + &create_info_vk, ptr::null(), output.as_mut_ptr(), ) @@ -90,12 +111,7 @@ impl Event { output.assume_init() }; - Ok(Event { - handle, - device: InstanceOwnedDebugWrapper(device), - id: Self::next_id(), - must_put_in_pool: false, - }) + Ok(Self::from_handle(device, handle, create_info)) } /// Takes an event from the vulkano-provided event pool. @@ -105,7 +121,7 @@ impl Event { /// For most applications, using the event pool should be preferred, /// in order to avoid creating new events every frame. #[inline] - pub fn from_pool(device: Arc) -> Result { + pub fn from_pool(device: Arc) -> Result { let handle = device.event_pool().lock().pop(); let event = match handle { Some(handle) => { @@ -121,11 +137,13 @@ impl Event { device: InstanceOwnedDebugWrapper(device), id: Self::next_id(), must_put_in_pool: true, + + flags: EventCreateFlags::empty(), } } None => { // Pool is empty, alloc new event - let mut event = Event::new(device, Default::default())?; + let mut event = unsafe { Event::new_unchecked(device, Default::default())? }; event.must_put_in_pool = true; event } @@ -144,33 +162,67 @@ impl Event { pub unsafe fn from_handle( device: Arc, handle: ash::vk::Event, - _create_info: EventCreateInfo, + create_info: EventCreateInfo, ) -> Event { + let EventCreateInfo { flags, _ne: _ } = create_info; + Event { handle, device: InstanceOwnedDebugWrapper(device), id: Self::next_id(), must_put_in_pool: false, + flags, } } + /// Returns the flags that the event was created with. + #[inline] + pub fn flags(&self) -> EventCreateFlags { + self.flags + } + /// Returns true if the event is signaled. #[inline] - pub fn signaled(&self) -> Result { + pub fn is_signaled(&self) -> Result> { + self.validate_is_signaled()?; + + unsafe { Ok(self.is_signaled_unchecked()?) } + } + + fn validate_is_signaled(&self) -> Result<(), Box> { + Ok(()) + } + + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] + #[inline] + pub unsafe fn is_signaled_unchecked(&self) -> Result { unsafe { let fns = self.device.fns(); let result = (fns.v1_0.get_event_status)(self.device.handle(), self.handle); match result { ash::vk::Result::EVENT_SET => Ok(true), ash::vk::Result::EVENT_RESET => Ok(false), - err => Err(VulkanError::from(err).into()), + err => Err(VulkanError::from(err)), } } } - /// See the docs of set(). + /// Changes the `Event` to the signaled state. + /// + /// If a command buffer is waiting on this event, it is then unblocked. + pub fn set(&mut self) -> Result<(), Validated> { + self.validate_set()?; + + unsafe { Ok(self.set_unchecked()?) } + } + + fn validate_set(&mut self) -> Result<(), Box> { + Ok(()) + } + + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] #[inline] - pub fn set_raw(&mut self) -> Result<(), OomError> { + pub unsafe fn set_unchecked(&mut self) -> Result<(), VulkanError> { unsafe { let fns = self.device.fns(); (fns.v1_0.set_event)(self.device.handle(), self.handle) @@ -180,21 +232,32 @@ impl Event { } } - /// Changes the `Event` to the signaled state. + /// Changes the `Event` to the unsignaled state. /// - /// If a command buffer is waiting on this event, it is then unblocked. + /// # Safety /// - /// # Panics + /// - There must be an execution dependency between `reset` and the execution of any \ + /// [`wait_events`] command that includes this event in its `events` parameter. /// - /// - Panics if the device or host ran out of memory. + /// [`wait_events`]: crate::command_buffer::sys::UnsafeCommandBufferBuilder::wait_events #[inline] - pub fn set(&mut self) { - self.set_raw().unwrap(); + pub unsafe fn reset(&mut self) -> Result<(), Validated> { + self.validate_reset()?; + + Ok(self.reset_unchecked()?) + } + + fn validate_reset(&mut self) -> Result<(), Box> { + // VUID-vkResetEvent-event-03821 + // VUID-vkResetEvent-event-03822 + // Unsafe + + Ok(()) } - /// See the docs of reset(). + #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] #[inline] - pub fn reset_raw(&mut self) -> Result<(), OomError> { + pub unsafe fn reset_unchecked(&mut self) -> Result<(), VulkanError> { unsafe { let fns = self.device.fns(); (fns.v1_0.reset_event)(self.device.handle(), self.handle) @@ -203,16 +266,6 @@ impl Event { Ok(()) } } - - /// Changes the `Event` to the unsignaled state. - /// - /// # Panics - /// - /// - Panics if the device or host ran out of memory. - #[inline] - pub fn reset(&mut self) { - self.reset_raw().unwrap(); - } } impl Drop for Event { @@ -251,6 +304,11 @@ impl_id_counter!(Event); /// Parameters to create a new `Event`. #[derive(Clone, Debug)] pub struct EventCreateInfo { + /// Additional properties of the event. + /// + /// The default value is empty. + pub flags: EventCreateFlags, + pub _ne: crate::NonExhaustive, } @@ -258,56 +316,39 @@ impl Default for EventCreateInfo { #[inline] fn default() -> Self { Self { + flags: EventCreateFlags::empty(), _ne: crate::NonExhaustive(()), } } } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum EventError { - /// Not enough memory available. - OomError(OomError), +impl EventCreateInfo { + pub(crate) fn validate(&self, device: &Device) -> Result<(), Box> { + let &Self { flags, _ne: _ } = self; - RequirementNotMet { - required_for: &'static str, - requires_one_of: RequiresOneOf, - }, -} + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkEventCreateInfo-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; -impl Error for EventError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - Self::OomError(err) => Some(err), - _ => None, - } + Ok(()) } } -impl Display for EventError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - Self::OomError(_) => write!(f, "not enough memory available"), - Self::RequirementNotMet { - required_for, - requires_one_of, - } => write!( - f, - "a requirement was not met for: {}; requires one of: {}", - required_for, requires_one_of, - ), - } - } -} +vulkan_bitflags! { + #[non_exhaustive] -impl From for EventError { - fn from(err: VulkanError) -> Self { - match err { - e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => { - Self::OomError(e.into()) - } - _ => panic!("unexpected error: {:?}", err), - } - } + /// Flags specifying additional properties of an event. + EventCreateFlags = EventCreateFlags(u32); + + DEVICE_ONLY = DEVICE_ONLY + RequiresOneOf([ + RequiresAllOf([APIVersion(V1_3)]), + RequiresAllOf([DeviceExtension(khr_synchronization2)]), + ]), } #[cfg(test)] @@ -318,17 +359,17 @@ mod tests { fn event_create() { let (device, _) = gfx_dev_and_queue!(); let event = Event::new(device, Default::default()).unwrap(); - assert!(!event.signaled().unwrap()); + assert!(!event.is_signaled().unwrap()); } #[test] fn event_set() { let (device, _) = gfx_dev_and_queue!(); let mut event = Event::new(device, Default::default()).unwrap(); - assert!(!event.signaled().unwrap()); + assert!(!event.is_signaled().unwrap()); - event.set(); - assert!(event.signaled().unwrap()); + event.set().unwrap(); + assert!(event.is_signaled().unwrap()); } #[test] @@ -336,11 +377,11 @@ mod tests { let (device, _) = gfx_dev_and_queue!(); let mut event = Event::new(device, Default::default()).unwrap(); - event.set(); - assert!(event.signaled().unwrap()); + event.set().unwrap(); + assert!(event.is_signaled().unwrap()); - event.reset(); - assert!(!event.signaled().unwrap()); + unsafe { event.reset().unwrap() }; + assert!(!event.is_signaled().unwrap()); } #[test] diff --git a/vulkano/src/sync/fence.rs b/vulkano/src/sync/fence.rs index 8239d011ee..1e94dcfbce 100644 --- a/vulkano/src/sync/fence.rs +++ b/vulkano/src/sync/fence.rs @@ -14,16 +14,14 @@ use crate::{ device::{physical::PhysicalDevice, Device, DeviceOwned, Queue}, instance::InstanceOwnedDebugWrapper, macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum}, - OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, - VulkanError, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError, + VulkanObject, }; use parking_lot::{Mutex, MutexGuard}; use smallvec::SmallVec; #[cfg(unix)] use std::fs::File; use std::{ - error::Error, - fmt::{Display, Error as FmtError, Formatter}, future::Future, mem::MaybeUninit, num::NonZeroU64, @@ -38,7 +36,7 @@ use std::{ /// /// # Queue-to-host synchronization /// -/// The primary use of a fence is to know when execution of a queue has reached a particular point. +/// The primary use of a fence is to know when a queue operation has completed executing. /// When adding a command to a queue, a fence can be provided with the command, to be signaled /// when the operation finishes. You can check for a fence's current status by calling /// `is_signaled`, `wait` or `await` on it. If the fence is found to be signaled, that means that @@ -54,9 +52,7 @@ use std::{ /// Because of this, it is highly recommended to call `is_signaled`, `wait` or `await` on your fences. /// Otherwise, the queue will hold onto resources indefinitely (using up memory) /// and resource locks will not be released, which may cause errors when submitting future -/// queue operations. It is not strictly necessary to wait for *every* fence, as a fence -/// that was signaled later in the queue will automatically clean up resources associated with -/// earlier fences too. +/// queue operations. #[derive(Debug)] pub struct Fence { handle: ash::vk::Fence, @@ -64,6 +60,7 @@ pub struct Fence { id: NonZeroU64, must_put_in_pool: bool, + flags: FenceCreateFlags, export_handle_types: ExternalFenceHandleTypes, state: Mutex, @@ -72,81 +69,39 @@ pub struct Fence { impl Fence { /// Creates a new `Fence`. #[inline] - pub fn new(device: Arc, create_info: FenceCreateInfo) -> Result { + pub fn new( + device: Arc, + create_info: FenceCreateInfo, + ) -> Result> { Self::validate_new(&device, &create_info)?; unsafe { Ok(Self::new_unchecked(device, create_info)?) } } - fn validate_new(device: &Device, create_info: &FenceCreateInfo) -> Result<(), FenceError> { - let &FenceCreateInfo { - signaled: _, - export_handle_types, - _ne: _, - } = create_info; - - if !export_handle_types.is_empty() { - if !(device.api_version() >= Version::V1_1 - || device.enabled_extensions().khr_external_fence) - { - return Err(FenceError::RequirementNotMet { - required_for: "`create_info.export_handle_types` is not empty", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), - RequiresAllOf(&[Requires::DeviceExtension("khr_external_fence")]), - ]), - }); - } - - // VUID-VkExportFenceCreateInfo-handleTypes-01446 - export_handle_types.validate_device(device)?; - - // VUID-VkExportFenceCreateInfo-handleTypes-01446 - for handle_type in export_handle_types.into_iter() { - let external_fence_properties = unsafe { - device - .physical_device() - .external_fence_properties_unchecked(ExternalFenceInfo::handle_type( - handle_type, - )) - }; - - if !external_fence_properties.exportable { - return Err(FenceError::HandleTypeNotExportable { handle_type }); - } - - if !external_fence_properties - .compatible_handle_types - .contains(export_handle_types) - { - return Err(FenceError::ExportHandleTypesNotCompatible); - } - } - } + fn validate_new( + device: &Device, + create_info: &FenceCreateInfo, + ) -> Result<(), Box> { + create_info + .validate(device) + .map_err(|err| err.add_context("create_info"))?; Ok(()) } #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] - #[inline] pub unsafe fn new_unchecked( device: Arc, create_info: FenceCreateInfo, ) -> Result { let FenceCreateInfo { - signaled, + flags, export_handle_types, _ne: _, } = create_info; - let mut flags = ash::vk::FenceCreateFlags::empty(); - - if signaled { - flags |= ash::vk::FenceCreateFlags::SIGNALED; - } - let mut create_info_vk = ash::vk::FenceCreateInfo { - flags, + flags: flags.into(), ..Default::default() }; let mut export_fence_create_info_vk = None; @@ -183,9 +138,12 @@ impl Fence { device: InstanceOwnedDebugWrapper(device), id: Self::next_id(), must_put_in_pool: false, + + flags, export_handle_types, + state: Mutex::new(FenceState { - is_signaled: signaled, + is_signaled: flags.intersects(FenceCreateFlags::SIGNALED), ..Default::default() }), }) @@ -198,7 +156,7 @@ impl Fence { /// For most applications, using the fence pool should be preferred, /// in order to avoid creating new fences every frame. #[inline] - pub fn from_pool(device: Arc) -> Result { + pub fn from_pool(device: Arc) -> Result { let handle = device.fence_pool().lock().pop(); let fence = match handle { Some(handle) => { @@ -215,13 +173,17 @@ impl Fence { device: InstanceOwnedDebugWrapper(device), id: Self::next_id(), must_put_in_pool: true, + + flags: FenceCreateFlags::empty(), export_handle_types: ExternalFenceHandleTypes::empty(), + state: Mutex::new(Default::default()), } } None => { // Pool is empty, alloc new fence - let mut fence = Fence::new(device, FenceCreateInfo::default())?; + let mut fence = + unsafe { Fence::new_unchecked(device, FenceCreateInfo::default())? }; fence.must_put_in_pool = true; fence } @@ -243,7 +205,7 @@ impl Fence { create_info: FenceCreateInfo, ) -> Fence { let FenceCreateInfo { - signaled, + flags, export_handle_types, _ne: _, } = create_info; @@ -253,17 +215,26 @@ impl Fence { device: InstanceOwnedDebugWrapper(device), id: Self::next_id(), must_put_in_pool: false, + + flags, export_handle_types, + state: Mutex::new(FenceState { - is_signaled: signaled, + is_signaled: flags.intersects(FenceCreateFlags::SIGNALED), ..Default::default() }), } } + /// Returns the flags that the fence was created with. + #[inline] + pub fn flags(&self) -> FenceCreateFlags { + self.flags + } + /// Returns true if the fence is signaled. #[inline] - pub fn is_signaled(&self) -> Result { + pub fn is_signaled(&self) -> Result { let queue_to_signal = { let mut state = self.state(); @@ -282,7 +253,7 @@ impl Fence { match result { ash::vk::Result::SUCCESS => unsafe { state.set_signaled() }, ash::vk::Result::NOT_READY => return Ok(false), - err => return Err(VulkanError::from(err).into()), + err => return Err(VulkanError::from(err)), } }; @@ -299,10 +270,8 @@ impl Fence { /// Waits until the fence is signaled, or at least until the timeout duration has elapsed. /// - /// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead. - /// /// If you pass a duration of 0, then the function will return without blocking. - pub fn wait(&self, timeout: Option) -> Result<(), FenceError> { + pub fn wait(&self, timeout: Option) -> Result<(), VulkanError> { let queue_to_signal = { let mut state = self.state.lock(); @@ -331,8 +300,7 @@ impl Fence { match result { ash::vk::Result::SUCCESS => unsafe { state.set_signaled() }, - ash::vk::Result::TIMEOUT => return Err(FenceError::Timeout), - err => return Err(VulkanError::from(err).into()), + err => return Err(VulkanError::from(err)), } }; @@ -355,17 +323,17 @@ impl Fence { pub fn multi_wait<'a>( fences: impl IntoIterator, timeout: Option, - ) -> Result<(), FenceError> { + ) -> Result<(), Validated> { let fences: SmallVec<[_; 8]> = fences.into_iter().collect(); Self::validate_multi_wait(&fences, timeout)?; - unsafe { Self::multi_wait_unchecked(fences, timeout) } + unsafe { Ok(Self::multi_wait_unchecked(fences, timeout)?) } } fn validate_multi_wait( fences: &[&Fence], _timeout: Option, - ) -> Result<(), FenceError> { + ) -> Result<(), Box> { if fences.is_empty() { return Ok(()); } @@ -384,7 +352,7 @@ impl Fence { pub unsafe fn multi_wait_unchecked<'a>( fences: impl IntoIterator, timeout: Option, - ) -> Result<(), FenceError> { + ) -> Result<(), VulkanError> { let queues_to_signal: SmallVec<[_; 8]> = { let iter = fences.into_iter(); let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new(); @@ -433,8 +401,7 @@ impl Fence { .zip(&mut states) .filter_map(|(fence, state)| state.set_signaled().map(|state| (state, fence))) .collect(), - ash::vk::Result::TIMEOUT => return Err(FenceError::Timeout), - err => return Err(VulkanError::from(err).into()), + err => return Err(VulkanError::from(err)), } }; @@ -451,17 +418,20 @@ impl Fence { /// /// The fence must not be in use by a queue operation. #[inline] - pub fn reset(&self) -> Result<(), FenceError> { + pub fn reset(&self) -> Result<(), Validated> { let mut state = self.state.lock(); self.validate_reset(&state)?; unsafe { Ok(self.reset_unchecked_locked(&mut state)?) } } - fn validate_reset(&self, state: &FenceState) -> Result<(), FenceError> { - // VUID-vkResetFences-pFences-01123 + fn validate_reset(&self, state: &FenceState) -> Result<(), Box> { if state.is_in_queue() { - return Err(FenceError::InQueue); + return Err(Box::new(ValidationError { + problem: "the fence is in use".into(), + vuids: &["VUID-vkResetFences-pFences-01123"], + ..Default::default() + })); } Ok(()) @@ -493,7 +463,9 @@ impl Fence { /// # Panics /// /// - Panics if not all fences belong to the same device. - pub fn multi_reset<'a>(fences: impl IntoIterator) -> Result<(), FenceError> { + pub fn multi_reset<'a>( + fences: impl IntoIterator, + ) -> Result<(), Validated> { let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences .into_iter() .map(|fence| { @@ -509,20 +481,24 @@ impl Fence { fn validate_multi_reset( fences: &[&Fence], states: &[MutexGuard<'_, FenceState>], - ) -> Result<(), FenceError> { + ) -> Result<(), Box> { if fences.is_empty() { return Ok(()); } let device = &fences[0].device; - for (fence, state) in fences.iter().zip(states) { + for (fence_index, (fence, state)) in fences.iter().zip(states).enumerate() { // VUID-vkResetFences-pFences-parent assert_eq!(device, &fence.device); - // VUID-vkResetFences-pFences-01123 if state.is_in_queue() { - return Err(FenceError::InQueue); + return Err(Box::new(ValidationError { + context: format!("fences[{}]", fence_index).into(), + problem: "the fence is in use".into(), + vuids: &["VUID-vkResetFences-pFences-01123"], + ..Default::default() + })); } } @@ -573,7 +549,10 @@ impl Fence { /// extension must be enabled on the device. #[cfg(unix)] #[inline] - pub fn export_fd(&self, handle_type: ExternalFenceHandleType) -> Result { + pub fn export_fd( + &self, + handle_type: ExternalFenceHandleType, + ) -> Result> { let mut state = self.state.lock(); self.validate_export_fd(handle_type, &state)?; @@ -585,36 +564,69 @@ impl Fence { &self, handle_type: ExternalFenceHandleType, state: &FenceState, - ) -> Result<(), FenceError> { + ) -> Result<(), Box> { if !self.device.enabled_extensions().khr_external_fence_fd { - return Err(FenceError::RequirementNotMet { - required_for: "`Fence::export_fd`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_fence_fd", )])]), - }); + ..Default::default() + })); } - // VUID-VkFenceGetFdInfoKHR-handleType-parameter - handle_type.validate_device(&self.device)?; + handle_type + .validate_device(&self.device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkFenceGetFdInfoKHR-handleType-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!( + handle_type, + ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd + ) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalFenceHandleType::OpaqueFd` or \ + `ExternalFenceHandleType::SyncFd`" + .into(), + vuids: &["VUID-VkFenceGetFdInfoKHR-handleType-01456"], + ..Default::default() + })); + } - // VUID-VkFenceGetFdInfoKHR-handleType-01453 if !self.export_handle_types.intersects(handle_type.into()) { - return Err(FenceError::HandleTypeNotEnabled); + return Err(Box::new(ValidationError { + problem: "`self.export_handle_types()` does not contain `handle_type`".into(), + vuids: &["VUID-VkFenceGetFdInfoKHR-handleType-01453"], + ..Default::default() + })); } - // VUID-VkFenceGetFdInfoKHR-handleType-01454 if handle_type.has_copy_transference() && !(state.is_signaled().unwrap_or(false) || state.is_in_queue()) { - return Err(FenceError::HandleTypeCopyNotSignaled); + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + the fence is not signaled, and \ + a signal operation on the fence is not pending" + .into(), + vuids: &["VUID-VkFenceGetFdInfoKHR-handleType-01454"], + ..Default::default() + })); } - // VUID-VkFenceGetFdInfoKHR-fence-01455 if let Some(imported_handle_type) = state.current_import { match imported_handle_type { ImportType::SwapchainAcquire => { - return Err(FenceError::ImportedForSwapchainAcquire) + return Err(Box::new(ValidationError { + problem: "the fence currently has an imported payload from a \ + swapchain acquire operation" + .into(), + vuids: &["VUID-VkFenceGetFdInfoKHR-fence-01455"], + ..Default::default() + })); } ImportType::ExternalFence(imported_handle_type) => { let external_fence_properties = unsafe { @@ -629,22 +641,19 @@ impl Fence { .export_from_imported_handle_types .intersects(imported_handle_type.into()) { - return Err(FenceError::ExportFromImportedNotSupported { - imported_handle_type, - }); + return Err(Box::new(ValidationError { + problem: "the fence currently has an imported payload, whose type \ + does not allow re-exporting as `handle_type`, as \ + returned by `PhysicalDevice::external_fence_properties`" + .into(), + vuids: &["VUID-VkFenceGetFdInfoKHR-fence-01455"], + ..Default::default() + })); } } } } - // VUID-VkFenceGetFdInfoKHR-handleType-01456 - if !matches!( - handle_type, - ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd - ) { - return Err(FenceError::HandleTypeNotFd); - } - Ok(()) } @@ -697,7 +706,7 @@ impl Fence { pub fn export_win32_handle( &self, handle_type: ExternalFenceHandleType, - ) -> Result<*mut std::ffi::c_void, FenceError> { + ) -> Result<*mut std::ffi::c_void, Validated> { let mut state = self.state.lock(); self.validate_export_win32_handle(handle_type, &state)?; @@ -709,43 +718,81 @@ impl Fence { &self, handle_type: ExternalFenceHandleType, state: &FenceState, - ) -> Result<(), FenceError> { + ) -> Result<(), Box> { if !self.device.enabled_extensions().khr_external_fence_win32 { - return Err(FenceError::RequirementNotMet { - required_for: "`Fence::export_win32_handle`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_fence_win32", )])]), - }); + ..Default::default() + })); } - // VUID-VkFenceGetWin32HandleInfoKHR-handleType-parameter - handle_type.validate_device(&self.device)?; + handle_type + .validate_device(&self.device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!( + handle_type, + ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt + ) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalFenceHandleType::OpaqueWin32` or \ + `ExternalFenceHandleType::OpaqueWin32Kmt`" + .into(), + vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01452"], + ..Default::default() + })); + } - // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01448 if !self.export_handle_types.intersects(handle_type.into()) { - return Err(FenceError::HandleTypeNotEnabled); + return Err(Box::new(ValidationError { + problem: "`self.export_handle_types()` does not contain `handle_type`".into(), + vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01448"], + ..Default::default() + })); } - // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01449 if matches!(handle_type, ExternalFenceHandleType::OpaqueWin32) && state.is_exported(handle_type) { - return Err(FenceError::AlreadyExported); + return Err(Box::new(ValidationError { + problem: "`handle_type` is `ExternalFenceHandleType::OpaqueWin32`, but \ + a handle of this type has already been exported from this fence" + .into(), + vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01449"], + ..Default::default() + })); } - // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01451 if handle_type.has_copy_transference() && !(state.is_signaled().unwrap_or(false) || state.is_in_queue()) { - return Err(FenceError::HandleTypeCopyNotSignaled); + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + the fence is not signaled, and \ + a signal operation on the fence is not pending" + .into(), + vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01451"], + ..Default::default() + })); } - // VUID-VkFenceGetWin32HandleInfoKHR-fence-01450 if let Some(imported_handle_type) = state.current_import { match imported_handle_type { ImportType::SwapchainAcquire => { - return Err(FenceError::ImportedForSwapchainAcquire) + return Err(Box::new(ValidationError { + problem: "the fence currently has an imported payload from a \ + swapchain acquire operation" + .into(), + vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-fence-01450"], + ..Default::default() + })); } ImportType::ExternalFence(imported_handle_type) => { let external_fence_properties = unsafe { @@ -760,22 +807,19 @@ impl Fence { .export_from_imported_handle_types .intersects(imported_handle_type.into()) { - return Err(FenceError::ExportFromImportedNotSupported { - imported_handle_type, - }); + return Err(Box::new(ValidationError { + problem: "the fence currently has an imported payload, whose type \ + does not allow re-exporting as `handle_type`, as \ + returned by `PhysicalDevice::external_fence_properties`" + .into(), + vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-fence-01450"], + ..Default::default() + })); } } } } - // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01452 - if !matches!( - handle_type, - ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt - ) { - return Err(FenceError::HandleTypeNotWin32); - } - Ok(()) } @@ -832,7 +876,7 @@ impl Fence { pub unsafe fn import_fd( &self, import_fence_fd_info: ImportFenceFdInfo, - ) -> Result<(), FenceError> { + ) -> Result<(), Validated> { let mut state = self.state.lock(); self.validate_import_fd(&import_fence_fd_info, &state)?; @@ -844,49 +888,27 @@ impl Fence { &self, import_fence_fd_info: &ImportFenceFdInfo, state: &FenceState, - ) -> Result<(), FenceError> { + ) -> Result<(), Box> { if !self.device.enabled_extensions().khr_external_fence_fd { - return Err(FenceError::RequirementNotMet { - required_for: "`Fence::import_fd`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_fence_fd", )])]), - }); + ..Default::default() + })); } - // VUID-vkImportFenceFdKHR-fence-01463 if state.is_in_queue() { - return Err(FenceError::InQueue); - } - - let &ImportFenceFdInfo { - flags, - handle_type, - file: _, - _ne: _, - } = import_fence_fd_info; - - // VUID-VkImportFenceFdInfoKHR-flags-parameter - flags.validate_device(&self.device)?; - - // VUID-VkImportFenceFdInfoKHR-handleType-parameter - handle_type.validate_device(&self.device)?; - - // VUID-VkImportFenceFdInfoKHR-handleType-01464 - if !matches!( - handle_type, - ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd - ) { - return Err(FenceError::HandleTypeNotFd); + return Err(Box::new(ValidationError { + problem: "the fence is in use".into(), + vuids: &["VUID-vkImportFenceFdKHR-fence-01463"], + ..Default::default() + })); } - // VUID-VkImportFenceFdInfoKHR-fd-01541 - // Can't validate, therefore unsafe - - // VUID-VkImportFenceFdInfoKHR-handleType-07306 - if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) { - return Err(FenceError::HandletypeCopyNotTemporary); - } + import_fence_fd_info + .validate(&self.device) + .map_err(|err| err.add_context("import_fence_fd_info"))?; Ok(()) } @@ -950,7 +972,7 @@ impl Fence { pub unsafe fn import_win32_handle( &self, import_fence_win32_handle_info: ImportFenceWin32HandleInfo, - ) -> Result<(), FenceError> { + ) -> Result<(), Validated> { let mut state = self.state.lock(); self.validate_import_win32_handle(&import_fence_win32_handle_info, &state)?; @@ -962,48 +984,22 @@ impl Fence { &self, import_fence_win32_handle_info: &ImportFenceWin32HandleInfo, state: &FenceState, - ) -> Result<(), FenceError> { + ) -> Result<(), Box> { if !self.device.enabled_extensions().khr_external_fence_win32 { - return Err(FenceError::RequirementNotMet { - required_for: "`Fence::import_win32_handle`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_fence_win32", )])]), - }); + ..Default::default() + })); } - // VUID-vkImportFenceWin32HandleKHR-fence-04448 if state.is_in_queue() { - return Err(FenceError::InQueue); - } - - let &ImportFenceWin32HandleInfo { - flags, - handle_type, - handle: _, - _ne: _, - } = import_fence_win32_handle_info; - - // VUID-VkImportFenceWin32HandleInfoKHR-flags-parameter - flags.validate_device(&self.device)?; - - // VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457 - handle_type.validate_device(&self.device)?; - - // VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457 - if !matches!( - handle_type, - ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt - ) { - return Err(FenceError::HandleTypeNotWin32); - } - - // VUID-VkImportFenceWin32HandleInfoKHR-handle-01539 - // Can't validate, therefore unsafe - - // VUID? - if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) { - return Err(FenceError::HandletypeCopyNotTemporary); + return Err(Box::new(ValidationError { + problem: "the fence is in use".into(), + vuids: &["VUID-vkImportFenceWin32HandleKHR-fence-04448"], + ..Default::default() + })); } Ok(()) @@ -1060,7 +1056,7 @@ impl Fence { } // Shared by Fence and FenceSignalFuture - pub(crate) fn poll_impl(&self, cx: &mut Context<'_>) -> Poll> { + pub(crate) fn poll_impl(&self, cx: &mut Context<'_>) -> Poll> { // Vulkan only allows polling of the fence status, so we have to use a spin future. // This is still better than blocking in async applications, since a smart-enough async engine // can choose to run some other tasks between probing this one. @@ -1097,7 +1093,7 @@ impl Drop for Fence { } impl Future for Fence { - type Output = Result<(), OomError>; + type Output = Result<(), VulkanError>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { self.poll_impl(cx) @@ -1122,147 +1118,125 @@ unsafe impl DeviceOwned for Fence { impl_id_counter!(Fence); -#[derive(Debug, Default)] -pub(crate) struct FenceState { - is_signaled: bool, - pending_signal: Option>, +/// Parameters to create a new `Fence`. +#[derive(Clone, Debug)] +pub struct FenceCreateInfo { + /// Additional properties of the fence. + /// + /// The default value is empty. + pub flags: FenceCreateFlags, - reference_exported: bool, - exported_handle_types: ExternalFenceHandleTypes, - current_import: Option, - permanent_import: Option, + /// The handle types that can be exported from the fence. + pub export_handle_types: ExternalFenceHandleTypes, + + pub _ne: crate::NonExhaustive, } -impl FenceState { - /// If the fence is not in a queue and has no external references, returns the current status. +impl Default for FenceCreateInfo { #[inline] - fn is_signaled(&self) -> Option { - // If either of these is true, we can't be certain of the status. - if self.is_in_queue() || self.has_external_reference() { - None - } else { - Some(self.is_signaled) + fn default() -> Self { + Self { + flags: FenceCreateFlags::empty(), + export_handle_types: ExternalFenceHandleTypes::empty(), + _ne: crate::NonExhaustive(()), } } +} - #[inline] - fn is_in_queue(&self) -> bool { - self.pending_signal.is_some() - } - - /// Returns whether there are any potential external references to the fence payload. - /// That is, the fence has been exported by reference transference, or imported. - #[inline] - fn has_external_reference(&self) -> bool { - self.reference_exported || self.current_import.is_some() - } - - #[allow(dead_code)] - #[inline] - fn is_exported(&self, handle_type: ExternalFenceHandleType) -> bool { - self.exported_handle_types.intersects(handle_type.into()) - } - - #[inline] - pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc) { - self.pending_signal = Some(Arc::downgrade(queue)); - } - - /// Called when a fence first discovers that it is signaled. - /// Returns the queue that should be informed about it. - #[inline] - unsafe fn set_signaled(&mut self) -> Option> { - self.is_signaled = true; - - // Fences with external references can't be used to determine queue completion. - if self.has_external_reference() { - self.pending_signal = None; - None - } else { - self.pending_signal.take().and_then(|queue| queue.upgrade()) - } - } +impl FenceCreateInfo { + pub(crate) fn validate(&self, device: &Device) -> Result<(), Box> { + let &Self { + flags, + export_handle_types, + _ne: _, + } = self; - /// Called when a queue is unlocking resources. - #[inline] - pub(crate) unsafe fn set_signal_finished(&mut self) { - self.is_signaled = true; - self.pending_signal = None; - } + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkFenceCreateInfo-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; - #[inline] - unsafe fn reset(&mut self) { - debug_assert!(!self.is_in_queue()); - self.current_import = self.permanent_import.map(Into::into); - self.is_signaled = false; - } + if !export_handle_types.is_empty() { + if !(device.api_version() >= Version::V1_1 + || device.enabled_extensions().khr_external_fence) + { + return Err(Box::new(ValidationError { + context: "export_handle_types".into(), + problem: "is not empty".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_external_fence")]), + ]), + ..Default::default() + })); + } - #[allow(dead_code)] - #[inline] - unsafe fn export(&mut self, handle_type: ExternalFenceHandleType) { - self.exported_handle_types |= handle_type.into(); + export_handle_types + .validate_device(device) + .map_err(|err| ValidationError { + context: "export_handle_types".into(), + vuids: &["VUID-VkExportFenceCreateInfo-handleTypes-parameter"], + ..ValidationError::from_requirement(err) + })?; - if handle_type.has_copy_transference() { - self.reset(); - } else { - self.reference_exported = true; - } - } + for handle_type in export_handle_types.into_iter() { + let external_fence_properties = unsafe { + device + .physical_device() + .external_fence_properties_unchecked(ExternalFenceInfo::handle_type( + handle_type, + )) + }; - #[allow(dead_code)] - #[inline] - unsafe fn import(&mut self, handle_type: ExternalFenceHandleType, temporary: bool) { - debug_assert!(!self.is_in_queue()); - self.current_import = Some(handle_type.into()); + if !external_fence_properties.exportable { + return Err(Box::new(ValidationError { + context: "export_handle_types".into(), + problem: format!( + "the handle type `ExternalFenceHandleTypes::{:?}` is not exportable, \ + as returned by `PhysicalDevice::external_fence_properties`", + ExternalFenceHandleTypes::from(handle_type) + ) + .into(), + vuids: &["VUID-VkExportFenceCreateInfo-handleTypes-01446"], + ..Default::default() + })); + } - if !temporary { - self.permanent_import = Some(handle_type); + if !external_fence_properties + .compatible_handle_types + .contains(export_handle_types) + { + return Err(Box::new(ValidationError { + context: "export_handle_types".into(), + problem: format!( + "the handle type `ExternalFenceHandleTypes::{:?}` is not compatible \ + with the other specified handle types, as returned by \ + `PhysicalDevice::external_fence_properties`", + ExternalFenceHandleTypes::from(handle_type) + ) + .into(), + vuids: &["VUID-VkExportFenceCreateInfo-handleTypes-01446"], + ..Default::default() + })); + } + } } - } - - #[inline] - pub(crate) unsafe fn import_swapchain_acquire(&mut self) { - debug_assert!(!self.is_in_queue()); - self.current_import = Some(ImportType::SwapchainAcquire); - } -} - -#[derive(Clone, Copy, Debug)] -enum ImportType { - SwapchainAcquire, - ExternalFence(ExternalFenceHandleType), -} -impl From for ImportType { - #[inline] - fn from(handle_type: ExternalFenceHandleType) -> Self { - Self::ExternalFence(handle_type) + Ok(()) } } -/// Parameters to create a new `Fence`. -#[derive(Clone, Debug)] -pub struct FenceCreateInfo { - /// Whether the fence should be created in the signaled state. - /// - /// The default value is `false`. - pub signaled: bool, - - /// The handle types that can be exported from the fence. - pub export_handle_types: ExternalFenceHandleTypes, +vulkan_bitflags! { + #[non_exhaustive] - pub _ne: crate::NonExhaustive, -} + /// Flags specifying additional properties of a fence. + FenceCreateFlags = FenceCreateFlags(u32); -impl Default for FenceCreateInfo { - #[inline] - fn default() -> Self { - Self { - signaled: false, - export_handle_types: ExternalFenceHandleTypes::empty(), - _ne: crate::NonExhaustive(()), - } - } + /// Creates the fence in the signaled state. + SIGNALED = SIGNALED, } vulkan_bitflags_enum! { @@ -1361,6 +1335,60 @@ impl ImportFenceFdInfo { _ne: crate::NonExhaustive(()), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), Box> { + let &Self { + flags, + handle_type, + file: _, + _ne: _, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkImportFenceFdInfoKHR-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + handle_type + .validate_device(device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkImportFenceFdInfoKHR-handleType-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!( + handle_type, + ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd + ) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalFenceHandleType::OpaqueFd` or \ + `ExternalFenceHandleType::SyncFd`" + .into(), + vuids: &["VUID-VkImportFenceFdInfoKHR-handleType-01464"], + ..Default::default() + })); + } + + // VUID-VkImportFenceFdInfoKHR-fd-01541 + // Can't validate, therefore unsafe + + if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) { + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + `flags` does not contain `FenceImportFlags::TEMPORARY`" + .into(), + vuids: &["VUID-VkImportFenceFdInfoKHR-handleType-07306"], + ..Default::default() + })); + } + + Ok(()) + } } #[cfg(windows)] @@ -1398,6 +1426,60 @@ impl ImportFenceWin32HandleInfo { _ne: crate::NonExhaustive(()), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), Box> { + let &Self { + flags, + handle_type, + handle: _, + _ne: _, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkImportFenceWin32HandleInfoKHR-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + handle_type + .validate_device(device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!( + handle_type, + ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt + ) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalFenceHandleType::OpaqueWin32` or \ + `ExternalFenceHandleType::OpaqueWin32Kmt`" + .into(), + vuids: &["VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457"], + ..Default::default() + })); + } + + // VUID-VkImportFenceWin32HandleInfoKHR-handle-01539 + // Can't validate, therefore unsafe + + if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) { + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + `flags` does not contain `FenceImportFlags::TEMPORARY`" + .into(), + // vuids? + ..Default::default() + })); + } + + Ok(()) + } } /// The fence configuration to query in @@ -1463,172 +1545,128 @@ pub struct ExternalFenceProperties { pub compatible_handle_types: ExternalFenceHandleTypes, } -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum FenceError { - /// Not enough memory available. - OomError(OomError), - - /// The device has been lost. - DeviceLost, - - /// The specified timeout wasn't long enough. - Timeout, - - RequirementNotMet { - required_for: &'static str, - requires_one_of: RequiresOneOf, - }, +#[derive(Debug, Default)] +pub(crate) struct FenceState { + is_signaled: bool, + pending_signal: Option>, - /// The provided handle type does not permit more than one export, - /// and a handle of this type was already exported previously. - AlreadyExported, + reference_exported: bool, + exported_handle_types: ExternalFenceHandleTypes, + current_import: Option, + permanent_import: Option, +} - /// The provided handle type cannot be exported from the current import handle type. - ExportFromImportedNotSupported { - imported_handle_type: ExternalFenceHandleType, - }, +impl FenceState { + /// If the fence is not in a queue and has no external references, returns the current status. + #[inline] + fn is_signaled(&self) -> Option { + // If either of these is true, we can't be certain of the status. + if self.is_in_queue() || self.has_external_reference() { + None + } else { + Some(self.is_signaled) + } + } - /// One of the export handle types is not compatible with the other provided handles. - ExportHandleTypesNotCompatible, + #[inline] + fn is_in_queue(&self) -> bool { + self.pending_signal.is_some() + } - /// A handle type with copy transference was provided, but the fence is not signaled and there - /// is no pending queue operation that will signal it. - HandleTypeCopyNotSignaled, + /// Returns whether there are any potential external references to the fence payload. + /// That is, the fence has been exported by reference transference, or imported. + #[inline] + fn has_external_reference(&self) -> bool { + self.reference_exported || self.current_import.is_some() + } - /// A handle type with copy transference was provided, - /// but the `temporary` import flag was not set. - HandletypeCopyNotTemporary, + #[allow(dead_code)] + #[inline] + fn is_exported(&self, handle_type: ExternalFenceHandleType) -> bool { + self.exported_handle_types.intersects(handle_type.into()) + } - /// The provided export handle type was not set in `export_handle_types` when creating the - /// fence. - HandleTypeNotEnabled, + #[inline] + pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc) { + self.pending_signal = Some(Arc::downgrade(queue)); + } - /// Exporting is not supported for the provided handle type. - HandleTypeNotExportable { - handle_type: ExternalFenceHandleType, - }, + /// Called when a fence first discovers that it is signaled. + /// Returns the queue that should be informed about it. + #[inline] + unsafe fn set_signaled(&mut self) -> Option> { + self.is_signaled = true; - /// The provided handle type is not a POSIX file descriptor handle. - HandleTypeNotFd, + // Fences with external references can't be used to determine queue completion. + if self.has_external_reference() { + self.pending_signal = None; + None + } else { + self.pending_signal.take().and_then(|queue| queue.upgrade()) + } + } - /// The provided handle type is not a Win32 handle. - HandleTypeNotWin32, + /// Called when a queue is unlocking resources. + #[inline] + pub(crate) unsafe fn set_signal_finished(&mut self) { + self.is_signaled = true; + self.pending_signal = None; + } - /// The fence currently has a temporary import for a swapchain acquire operation. - ImportedForSwapchainAcquire, + #[inline] + unsafe fn reset(&mut self) { + debug_assert!(!self.is_in_queue()); + self.current_import = self.permanent_import.map(Into::into); + self.is_signaled = false; + } - /// The fence is currently in use by a queue. - InQueue, -} + #[allow(dead_code)] + #[inline] + unsafe fn export(&mut self, handle_type: ExternalFenceHandleType) { + self.exported_handle_types |= handle_type.into(); -impl Error for FenceError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - Self::OomError(err) => Some(err), - _ => None, + if handle_type.has_copy_transference() { + self.reset(); + } else { + self.reference_exported = true; } } -} -impl Display for FenceError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - Self::OomError(_) => write!(f, "not enough memory available"), - Self::DeviceLost => write!(f, "the device was lost"), - Self::Timeout => write!(f, "the timeout has been reached"), - Self::RequirementNotMet { - required_for, - requires_one_of, - } => write!( - f, - "a requirement was not met for: {}; requires one of: {}", - required_for, requires_one_of, - ), - - Self::AlreadyExported => write!( - f, - "the provided handle type does not permit more than one export, and a handle of \ - this type was already exported previously", - ), - Self::ExportFromImportedNotSupported { - imported_handle_type, - } => write!( - f, - "the provided handle type cannot be exported from the current imported handle type \ - {:?}", - imported_handle_type, - ), - Self::ExportHandleTypesNotCompatible => write!( - f, - "one of the export handle types is not compatible with the other provided handles", - ), - Self::HandleTypeCopyNotSignaled => write!( - f, - "a handle type with copy transference was provided, but the fence is not signaled \ - and there is no pending queue operation that will signal it", - ), - Self::HandletypeCopyNotTemporary => write!( - f, - "a handle type with copy transference was provided, but the `temporary` \ - import flag was not set", - ), - Self::HandleTypeNotEnabled => write!( - f, - "the provided export handle type was not set in `export_handle_types` when \ - creating the fence", - ), - Self::HandleTypeNotExportable { handle_type } => write!( - f, - "exporting is not supported for handles of type {:?}", - handle_type, - ), - Self::HandleTypeNotFd => write!( - f, - "the provided handle type is not a POSIX file descriptor handle", - ), - Self::HandleTypeNotWin32 => { - write!(f, "the provided handle type is not a Win32 handle") - } - Self::ImportedForSwapchainAcquire => write!( - f, - "the fence currently has a temporary import for a swapchain acquire operation", - ), - Self::InQueue => write!(f, "the fence is currently in use by a queue"), + #[allow(dead_code)] + #[inline] + unsafe fn import(&mut self, handle_type: ExternalFenceHandleType, temporary: bool) { + debug_assert!(!self.is_in_queue()); + self.current_import = Some(handle_type.into()); + + if !temporary { + self.permanent_import = Some(handle_type); } } -} -impl From for FenceError { - fn from(err: VulkanError) -> Self { - match err { - e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => { - Self::OomError(e.into()) - } - VulkanError::DeviceLost => Self::DeviceLost, - _ => panic!("unexpected error: {:?}", err), - } + #[inline] + pub(crate) unsafe fn import_swapchain_acquire(&mut self) { + debug_assert!(!self.is_in_queue()); + self.current_import = Some(ImportType::SwapchainAcquire); } } -impl From for FenceError { - fn from(err: OomError) -> Self { - Self::OomError(err) - } +#[derive(Clone, Copy, Debug)] +enum ImportType { + SwapchainAcquire, + ExternalFence(ExternalFenceHandleType), } -impl From for FenceError { - fn from(err: RequirementNotMet) -> Self { - Self::RequirementNotMet { - required_for: err.required_for, - requires_one_of: err.requires_one_of, - } +impl From for ImportType { + #[inline] + fn from(handle_type: ExternalFenceHandleType) -> Self { + Self::ExternalFence(handle_type) } } #[cfg(test)] mod tests { use crate::{ - sync::fence::{Fence, FenceCreateInfo}, + sync::fence::{Fence, FenceCreateFlags, FenceCreateInfo}, VulkanObject, }; use std::time::Duration; @@ -1648,7 +1686,7 @@ mod tests { let fence = Fence::new( device, FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1663,7 +1701,7 @@ mod tests { let fence = Fence::new( device, FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1678,7 +1716,7 @@ mod tests { let fence = Fence::new( device, FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1696,7 +1734,7 @@ mod tests { let fence1 = Fence::new( device1.clone(), FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1704,7 +1742,7 @@ mod tests { let fence2 = Fence::new( device2.clone(), FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1726,7 +1764,7 @@ mod tests { let fence1 = Fence::new( device1.clone(), FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1734,7 +1772,7 @@ mod tests { let fence2 = Fence::new( device2.clone(), FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) diff --git a/vulkano/src/sync/future/fence_signal.rs b/vulkano/src/sync/future/fence_signal.rs index d310072289..06b1ace455 100644 --- a/vulkano/src/sync/future/fence_signal.rs +++ b/vulkano/src/sync/future/fence_signal.rs @@ -19,7 +19,7 @@ use crate::{ future::{AccessError, SubmitAnyBuilder}, PipelineStages, }, - DeviceSize, OomError, + DeviceSize, VulkanError, }; use parking_lot::{Mutex, MutexGuard}; use std::{ @@ -140,7 +140,7 @@ where F: GpuFuture, { /// Returns true if the fence is signaled by the GPU. - pub fn is_signaled(&self) -> Result { + pub fn is_signaled(&self) -> Result { let state = self.state.lock(); match &*state { @@ -190,14 +190,11 @@ where match *state { FenceSignalFutureState::Flushed(ref mut prev, ref fence) => { - match fence.wait(Some(Duration::from_secs(0))) { - Ok(()) => { - unsafe { prev.signal_finished() } - *state = FenceSignalFutureState::Cleaned; - } - Err(_) => { - prev.cleanup_finished(); - } + if fence.wait(Some(Duration::from_secs(0))).is_ok() { + unsafe { prev.signal_finished() } + *state = FenceSignalFutureState::Cleaned; + } else { + prev.cleanup_finished(); } } FenceSignalFutureState::Pending(ref mut prev, _) => { @@ -381,7 +378,7 @@ impl Future for FenceSignalFuture where F: GpuFuture, { - type Output = Result<(), OomError>; + type Output = Result<(), VulkanError>; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { // Implement through fence diff --git a/vulkano/src/sync/future/mod.rs b/vulkano/src/sync/future/mod.rs index c2613a6109..2692b3278d 100644 --- a/vulkano/src/sync/future/mod.rs +++ b/vulkano/src/sync/future/mod.rs @@ -96,10 +96,7 @@ pub use self::{ now::{now, NowFuture}, semaphore_signal::SemaphoreSignalFuture, }; -use super::{ - fence::{Fence, FenceError}, - semaphore::Semaphore, -}; +use super::{fence::Fence, semaphore::Semaphore}; use crate::{ buffer::Buffer, command_buffer::{ @@ -686,14 +683,3 @@ impl From for FlushError { } } } - -impl From for FlushError { - fn from(err: FenceError) -> FlushError { - match err { - FenceError::OomError(err) => Self::OomError(err), - FenceError::Timeout => Self::Timeout, - FenceError::DeviceLost => Self::DeviceLost, - _ => unreachable!(), - } - } -} diff --git a/vulkano/src/sync/semaphore.rs b/vulkano/src/sync/semaphore.rs index 016f0f8d97..661d1bb252 100644 --- a/vulkano/src/sync/semaphore.rs +++ b/vulkano/src/sync/semaphore.rs @@ -14,15 +14,13 @@ use crate::{ device::{physical::PhysicalDevice, Device, DeviceOwned, Queue}, instance::InstanceOwnedDebugWrapper, macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum}, - OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, - VulkanError, VulkanObject, + Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError, + VulkanObject, }; use parking_lot::{Mutex, MutexGuard}; #[cfg(unix)] use std::fs::File; use std::{ - error::Error, - fmt::{Display, Error as FmtError, Formatter}, mem::MaybeUninit, num::NonZeroU64, ptr, @@ -51,7 +49,7 @@ impl Semaphore { pub fn new( device: Arc, create_info: SemaphoreCreateInfo, - ) -> Result { + ) -> Result> { Self::validate_new(&device, &create_info)?; unsafe { Ok(Self::new_unchecked(device, create_info)?) } @@ -60,56 +58,15 @@ impl Semaphore { fn validate_new( device: &Device, create_info: &SemaphoreCreateInfo, - ) -> Result<(), SemaphoreError> { - let &SemaphoreCreateInfo { - export_handle_types, - _ne: _, - } = create_info; - - if !export_handle_types.is_empty() { - if !(device.api_version() >= Version::V1_1 - || device.enabled_extensions().khr_external_semaphore) - { - return Err(SemaphoreError::RequirementNotMet { - required_for: "`create_info.export_handle_types` is not empty", - requires_one_of: RequiresOneOf(&[ - RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), - RequiresAllOf(&[Requires::DeviceExtension("khr_external_semaphore")]), - ]), - }); - } - - // VUID-VkExportSemaphoreCreateInfo-handleTypes-parameter - export_handle_types.validate_device(device)?; - - // VUID-VkExportSemaphoreCreateInfo-handleTypes-01124 - for handle_type in export_handle_types.into_iter() { - let external_semaphore_properties = unsafe { - device - .physical_device() - .external_semaphore_properties_unchecked( - ExternalSemaphoreInfo::handle_type(handle_type), - ) - }; - - if !external_semaphore_properties.exportable { - return Err(SemaphoreError::HandleTypeNotExportable { handle_type }); - } - - if !external_semaphore_properties - .compatible_handle_types - .contains(export_handle_types) - { - return Err(SemaphoreError::ExportHandleTypesNotCompatible); - } - } - } + ) -> Result<(), Box> { + create_info + .validate(device) + .map_err(|err| err.add_context("create_info"))?; Ok(()) } #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))] - #[inline] pub unsafe fn new_unchecked( device: Arc, create_info: SemaphoreCreateInfo, @@ -151,14 +108,7 @@ impl Semaphore { output.assume_init() }; - Ok(Semaphore { - handle, - device: InstanceOwnedDebugWrapper(device), - id: Self::next_id(), - must_put_in_pool: false, - export_handle_types, - state: Mutex::new(Default::default()), - }) + Ok(Self::from_handle(device, handle, create_info)) } /// Takes a semaphore from the vulkano-provided semaphore pool. @@ -168,7 +118,7 @@ impl Semaphore { /// For most applications, using the pool should be preferred, /// in order to avoid creating new semaphores every frame. #[inline] - pub fn from_pool(device: Arc) -> Result { + pub fn from_pool(device: Arc) -> Result { let handle = device.semaphore_pool().lock().pop(); let semaphore = match handle { Some(handle) => Semaphore { @@ -181,7 +131,8 @@ impl Semaphore { }, None => { // Pool is empty, alloc new semaphore - let mut semaphore = Semaphore::new(device, Default::default())?; + let mut semaphore = + unsafe { Semaphore::new_unchecked(device, Default::default())? }; semaphore.must_put_in_pool = true; semaphore } @@ -223,7 +174,7 @@ impl Semaphore { pub fn export_fd( &self, handle_type: ExternalSemaphoreHandleType, - ) -> Result { + ) -> Result> { let mut state = self.state.lock(); self.validate_export_fd(handle_type, &state)?; @@ -235,29 +186,56 @@ impl Semaphore { &self, handle_type: ExternalSemaphoreHandleType, state: &SemaphoreState, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Box> { if !self.device.enabled_extensions().khr_external_semaphore_fd { - return Err(SemaphoreError::RequirementNotMet { - required_for: "`Semaphore::export_fd`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_semaphore_fd", )])]), - }); + ..Default::default() + })); } - // VUID-VkSemaphoreGetFdInfoKHR-handleType-parameter - handle_type.validate_device(&self.device)?; + handle_type + .validate_device(&self.device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!( + handle_type, + ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd + ) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalSemaphoreHandleType::OpaqueFd` or \ + `ExternalSemaphoreHandleType::SyncFd`" + .into(), + vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-01136"], + ..Default::default() + })); + } - // VUID-VkSemaphoreGetFdInfoKHR-handleType-01132 if !self.export_handle_types.intersects(handle_type.into()) { - return Err(SemaphoreError::HandleTypeNotEnabled); + return Err(Box::new(ValidationError { + problem: "`self.export_handle_types()` does not contain `handle_type`".into(), + vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-01132"], + ..Default::default() + })); } - // VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133 if let Some(imported_handle_type) = state.current_import { match imported_handle_type { ImportType::SwapchainAcquire => { - return Err(SemaphoreError::ImportedForSwapchainAcquire) + return Err(Box::new(ValidationError { + problem: "the semaphore currently has an imported payload from a \ + swapchain acquire operation" + .into(), + vuids: &["VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133"], + ..Default::default() + })); } ImportType::ExternalSemaphore(imported_handle_type) => { let external_semaphore_properties = unsafe { @@ -272,35 +250,45 @@ impl Semaphore { .export_from_imported_handle_types .intersects(imported_handle_type.into()) { - return Err(SemaphoreError::ExportFromImportedNotSupported { - imported_handle_type, - }); + return Err(Box::new(ValidationError { + problem: "the semaphore currently has an imported payload, whose type \ + does not allow re-exporting as `handle_type`, as \ + returned by `PhysicalDevice::external_semaphore_properties`" + .into(), + vuids: &["VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133"], + ..Default::default() + })); } } } } if handle_type.has_copy_transference() { - // VUID-VkSemaphoreGetFdInfoKHR-handleType-01134 if state.is_wait_pending() { - return Err(SemaphoreError::QueueIsWaiting); + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + a wait operation on the semaphore is pending" + .into(), + vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-01134"], + ..Default::default() + })); } - // VUID-VkSemaphoreGetFdInfoKHR-handleType-01135 - // VUID-VkSemaphoreGetFdInfoKHR-handleType-03254 if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) { - return Err(SemaphoreError::HandleTypeCopyNotSignaled); + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + the semaphore is not signaled, and \ + a signal operation on the semaphore is not pending" + .into(), + vuids: &[ + "VUID-VkSemaphoreGetFdInfoKHR-handleType-01135", + "VUID-VkSemaphoreGetFdInfoKHR-handleType-03254", + ], + ..Default::default() + })); } } - // VUID-VkSemaphoreGetFdInfoKHR-handleType-01136 - if !matches!( - handle_type, - ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd - ) { - return Err(SemaphoreError::HandleTypeNotFd); - } - Ok(()) } @@ -353,7 +341,7 @@ impl Semaphore { pub fn export_win32_handle( &self, handle_type: ExternalSemaphoreHandleType, - ) -> Result<*mut std::ffi::c_void, SemaphoreError> { + ) -> Result<*mut std::ffi::c_void, Validated> { let mut state = self.state.lock(); self.validate_export_win32_handle(handle_type, &state)?; @@ -365,42 +353,78 @@ impl Semaphore { &self, handle_type: ExternalSemaphoreHandleType, state: &SemaphoreState, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Box> { if !self .device .enabled_extensions() .khr_external_semaphore_win32 { - return Err(SemaphoreError::RequirementNotMet { - required_for: "`Semaphore::export_win32_handle`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_semaphore_win32", )])]), - }); + ..Default::default() + })); } - // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-parameter - handle_type.validate_device(&self.device)?; + handle_type + .validate_device(&self.device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!( + handle_type, + ExternalSemaphoreHandleType::OpaqueWin32 + | ExternalSemaphoreHandleType::OpaqueWin32Kmt + | ExternalSemaphoreHandleType::D3D12Fence + ) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalSemaphoreHandleType::OpaqueWin32`, \ + `ExternalSemaphoreHandleType::OpaqueWin32Kmt` or \ + `ExternalSemaphoreHandleType::D3D12Fence`" + .into(), + vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01131"], + ..Default::default() + })); + } - // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01126 if !self.export_handle_types.intersects(handle_type.into()) { - return Err(SemaphoreError::HandleTypeNotEnabled); + return Err(Box::new(ValidationError { + problem: "`self.export_handle_types()` does not contain `handle_type`".into(), + vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01126"], + ..Default::default() + })); } - // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01127 if matches!( handle_type, ExternalSemaphoreHandleType::OpaqueWin32 | ExternalSemaphoreHandleType::D3D12Fence ) && state.is_exported(handle_type) { - return Err(SemaphoreError::AlreadyExported); + return Err(Box::new(ValidationError { + problem: "`handle_type` is `ExternalSemaphoreHandleType::OpaqueWin32` or \ + `ExternalSemaphoreHandleType::D3D12Fence`, but \ + a handle of this type has already been exported from this semaphore" + .into(), + vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01127"], + ..Default::default() + })); } - // VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128 if let Some(imported_handle_type) = state.current_import { match imported_handle_type { ImportType::SwapchainAcquire => { - return Err(SemaphoreError::ImportedForSwapchainAcquire) + return Err(Box::new(ValidationError { + problem: "the semaphore currently has an imported payload from a \ + swapchain acquire operation" + .into(), + vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128"], + ..Default::default() + })); } ImportType::ExternalSemaphore(imported_handle_type) => { let external_semaphore_properties = unsafe { @@ -415,36 +439,42 @@ impl Semaphore { .export_from_imported_handle_types .intersects(imported_handle_type.into()) { - return Err(SemaphoreError::ExportFromImportedNotSupported { - imported_handle_type, - }); + return Err(Box::new(ValidationError { + problem: "the semaphore currently has an imported payload, whose type \ + does not allow re-exporting as `handle_type`, as \ + returned by `PhysicalDevice::external_semaphore_properties`" + .into(), + vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128"], + ..Default::default() + })); } } } } if handle_type.has_copy_transference() { - // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01129 if state.is_wait_pending() { - return Err(SemaphoreError::QueueIsWaiting); + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + a wait operation on the semaphore is pending" + .into(), + vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01129"], + ..Default::default() + })); } - // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01130 if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) { - return Err(SemaphoreError::HandleTypeCopyNotSignaled); + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + the semaphore is not signaled, and \ + a signal operation on the semaphore is not pending" + .into(), + vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01130"], + ..Default::default() + })); } } - // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01131 - if !matches!( - handle_type, - ExternalSemaphoreHandleType::OpaqueWin32 - | ExternalSemaphoreHandleType::OpaqueWin32Kmt - | ExternalSemaphoreHandleType::D3D12Fence - ) { - return Err(SemaphoreError::HandleTypeNotWin32); - } - Ok(()) } @@ -491,7 +521,7 @@ impl Semaphore { pub fn export_zircon_handle( &self, handle_type: ExternalSemaphoreHandleType, - ) -> Result { + ) -> Result> { let mut state = self.state.lock(); self.validate_export_zircon_handle(handle_type, &state)?; @@ -503,29 +533,51 @@ impl Semaphore { &self, handle_type: ExternalSemaphoreHandleType, state: &SemaphoreState, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Box> { if !self.device.enabled_extensions().fuchsia_external_semaphore { - return Err(SemaphoreError::RequirementNotMet { - required_for: "`Semaphore::export_zircon_handle`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "fuchsia_external_semaphore", )])]), - }); + ..Default::default() + })); } - // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-parameter - handle_type.validate_device(&self.device)?; + handle_type + .validate_device(&self.device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalSemaphoreHandleType::ZirconEvent`".into(), + vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04762"], + ..Default::default() + })); + } - // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04758 if !self.export_handle_types.intersects(&handle_type.into()) { - return Err(SemaphoreError::HandleTypeNotEnabled); + return Err(Box::new(ValidationError { + problem: "`self.export_handle_types()` does not contain `handle_type`".into(), + vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04758"], + ..Default::default() + })); } - // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759 if let Some(imported_handle_type) = state.current_import { match imported_handle_type { ImportType::SwapchainAcquire => { - return Err(SemaphoreError::ImportedForSwapchainAcquire) + return Err(Box::new(ValidationError { + problem: "the semaphore currently has an imported payload from a \ + swapchain acquire operation" + .into(), + vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759"], + ..Default::default() + })); } ImportType::ExternalSemaphore(imported_handle_type) => { let external_semaphore_properties = unsafe { @@ -540,31 +592,42 @@ impl Semaphore { .export_from_imported_handle_types .intersects(&imported_handle_type.into()) { - return Err(SemaphoreError::ExportFromImportedNotSupported { - imported_handle_type, - }); + return Err(Box::new(ValidationError { + problem: "the semaphore currently has an imported payload, whose type \ + does not allow re-exporting as `handle_type`, as \ + returned by `PhysicalDevice::external_semaphore_properties`" + .into(), + vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759"], + ..Default::default() + })); } } } } if handle_type.has_copy_transference() { - // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04760 if state.is_wait_pending() { - return Err(SemaphoreError::QueueIsWaiting); + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + a wait operation on the semaphore is pending" + .into(), + vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04760"], + ..Default::default() + })); } - // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04761 if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) { - return Err(SemaphoreError::HandleTypeCopyNotSignaled); + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + the semaphore is not signaled, and \ + a signal operation on the semaphore is not pending" + .into(), + vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04761"], + ..Default::default() + })); } } - // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04762 - if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) { - return Err(SemaphoreError::HandleTypeNotZircon); - } - Ok(()) } @@ -621,7 +684,7 @@ impl Semaphore { pub unsafe fn import_fd( &self, import_semaphore_fd_info: ImportSemaphoreFdInfo, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Validated> { let mut state = self.state.lock(); self.validate_import_fd(&import_semaphore_fd_info, &state)?; @@ -633,51 +696,27 @@ impl Semaphore { &self, import_semaphore_fd_info: &ImportSemaphoreFdInfo, state: &SemaphoreState, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Box> { if !self.device.enabled_extensions().khr_external_semaphore_fd { - return Err(SemaphoreError::RequirementNotMet { - required_for: "`Semaphore::import_fd`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_semaphore_fd", )])]), - }); + ..Default::default() + })); } - // VUID-vkImportSemaphoreFdKHR-semaphore-01142 if state.is_in_queue() { - return Err(SemaphoreError::InQueue); - } - - let &ImportSemaphoreFdInfo { - flags, - handle_type, - file: _, - _ne: _, - } = import_semaphore_fd_info; - - // VUID-VkImportSemaphoreFdInfoKHR-flags-parameter - flags.validate_device(&self.device)?; - - // VUID-VkImportSemaphoreFdInfoKHR-handleType-parameter - handle_type.validate_device(&self.device)?; - - // VUID-VkImportSemaphoreFdInfoKHR-handleType-01143 - if !matches!( - handle_type, - ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd - ) { - return Err(SemaphoreError::HandleTypeNotFd); + return Err(Box::new(ValidationError { + problem: "the semaphore is in use".into(), + vuids: &["VUID-vkImportSemaphoreFdKHR-semaphore-01142"], + ..Default::default() + })); } - // VUID-VkImportSemaphoreFdInfoKHR-fd-01544 - // VUID-VkImportSemaphoreFdInfoKHR-handleType-03263 - // Can't validate, therefore unsafe - - // VUID-VkImportSemaphoreFdInfoKHR-handleType-07307 - if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY) - { - return Err(SemaphoreError::HandletypeCopyNotTemporary); - } + import_semaphore_fd_info + .validate(&self.device) + .map_err(|err| err.add_context("import_semaphore_fd_info"))?; Ok(()) } @@ -744,7 +783,7 @@ impl Semaphore { pub unsafe fn import_win32_handle( &self, import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Validated> { let mut state = self.state.lock(); self.validate_import_win32_handle(&import_semaphore_win32_handle_info, &state)?; @@ -757,56 +796,31 @@ impl Semaphore { &self, import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo, state: &SemaphoreState, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Box> { if !self .device .enabled_extensions() .khr_external_semaphore_win32 { - return Err(SemaphoreError::RequirementNotMet { - required_for: "`Semaphore::import_win32_handle`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_semaphore_win32", )])]), - }); + ..Default::default() + })); } - // VUID? if state.is_in_queue() { - return Err(SemaphoreError::InQueue); - } - - let &ImportSemaphoreWin32HandleInfo { - flags, - handle_type, - handle: _, - _ne: _, - } = import_semaphore_win32_handle_info; - - // VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-parameter - flags.validate_device(&self.device)?; - - // VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140 - handle_type.validate_device(&self.device)?; - - // VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140 - if !matches!( - handle_type, - ExternalSemaphoreHandleType::OpaqueWin32 - | ExternalSemaphoreHandleType::OpaqueWin32Kmt - | ExternalSemaphoreHandleType::D3D12Fence - ) { - return Err(SemaphoreError::HandleTypeNotWin32); + return Err(Box::new(ValidationError { + problem: "the semaphore is in use".into(), + // vuids? + ..Default::default() + })); } - // VUID-VkImportSemaphoreWin32HandleInfoKHR-handle-01542 - // Can't validate, therefore unsafe - - // VUID? - if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY) - { - return Err(SemaphoreError::HandletypeCopyNotTemporary); - } + import_semaphore_win32_handle_info + .validate(&self.device) + .map_err(|err| err.add_context("import_semaphore_win32_handle_info"))?; Ok(()) } @@ -872,7 +886,7 @@ impl Semaphore { pub unsafe fn import_zircon_handle( &self, import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Validated> { let mut state = self.state.lock(); self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info, &state)?; @@ -887,47 +901,27 @@ impl Semaphore { &self, import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo, state: &SemaphoreState, - ) -> Result<(), SemaphoreError> { + ) -> Result<(), Box> { if !self.device.enabled_extensions().fuchsia_external_semaphore { - return Err(SemaphoreError::RequirementNotMet { - required_for: "`Semaphore::import_zircon_handle`", + return Err(Box::new(ValidationError { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "fuchsia_external_semaphore", )])]), - }); + ..Default::default() + })); } - // VUID-vkImportSemaphoreZirconHandleFUCHSIA-semaphore-04764 if state.is_in_queue() { - return Err(SemaphoreError::InQueue); - } - - let &ImportSemaphoreZirconHandleInfo { - flags, - handle_type, - zircon_handle: _, - _ne: _, - } = import_semaphore_zircon_handle_info; - - // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-flags-parameter - flags.validate_device(&self.device)?; - - // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-parameter - handle_type.validate_device(&self.device)?; - - // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-04765 - if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) { - return Err(SemaphoreError::HandleTypeNotFd); + return Err(Box::new(ValidationError { + problem: "the semaphore is in use".into(), + vuids: &["VUID-vkImportSemaphoreZirconHandleFUCHSIA-semaphore-04764"], + ..Default::default() + })); } - // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04766 - // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04767 - // Can't validate, therefore unsafe - - if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY) - { - return Err(SemaphoreError::HandletypeCopyNotTemporary); - } + import_semaphore_zircon_handle_info + .validate(&self.device) + .map_err(|err| err.add_context("import_semaphore_zircon_handle_info"))?; Ok(()) } @@ -1167,6 +1161,84 @@ impl Default for SemaphoreCreateInfo { } } +impl SemaphoreCreateInfo { + pub(crate) fn validate(&self, device: &Device) -> Result<(), Box> { + let &Self { + export_handle_types, + _ne: _, + } = self; + + if !export_handle_types.is_empty() { + if !(device.api_version() >= Version::V1_1 + || device.enabled_extensions().khr_external_semaphore) + { + return Err(Box::new(ValidationError { + context: "export_handle_types".into(), + problem: "is not empty".into(), + requires_one_of: RequiresOneOf(&[ + RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]), + RequiresAllOf(&[Requires::DeviceExtension("khr_external_semaphore")]), + ]), + ..Default::default() + })); + } + + export_handle_types + .validate_device(device) + .map_err(|err| ValidationError { + context: "export_handle_types".into(), + vuids: &["VUID-VkExportSemaphoreCreateInfo-handleTypes-parameter"], + ..ValidationError::from_requirement(err) + })?; + + for handle_type in export_handle_types.into_iter() { + let external_semaphore_properties = unsafe { + device + .physical_device() + .external_semaphore_properties_unchecked( + ExternalSemaphoreInfo::handle_type(handle_type), + ) + }; + + if !external_semaphore_properties.exportable { + return Err(Box::new(ValidationError { + context: "export_handle_types".into(), + problem: format!( + "the handle type `ExternalSemaphoreHandleTypes::{:?}` is not \ + exportable, as returned by \ + `PhysicalDevice::external_semaphore_properties`", + ExternalSemaphoreHandleTypes::from(handle_type) + ) + .into(), + vuids: &["VUID-VkExportSemaphoreCreateInfo-handleTypes-01124"], + ..Default::default() + })); + } + + if !external_semaphore_properties + .compatible_handle_types + .contains(export_handle_types) + { + return Err(Box::new(ValidationError { + context: "export_handle_types".into(), + problem: format!( + "the handle type `ExternalSemaphoreHandleTypes::{:?}` is not \ + compatible with the other specified handle types, as returned by \ + `PhysicalDevice::external_semaphore_properties`", + ExternalSemaphoreHandleTypes::from(handle_type) + ) + .into(), + vuids: &["VUID-VkExportSemaphoreCreateInfo-handleTypes-01124"], + ..Default::default() + })); + } + } + } + + Ok(()) + } +} + vulkan_bitflags_enum! { #[non_exhaustive] @@ -1282,6 +1354,62 @@ impl ImportSemaphoreFdInfo { _ne: crate::NonExhaustive(()), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), Box> { + let &Self { + flags, + handle_type, + file: _, + _ne: _, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkImportSemaphoreFdInfoKHR-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + handle_type + .validate_device(device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkImportSemaphoreFdInfoKHR-handleType-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!( + handle_type, + ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd + ) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalSemaphoreHandleType::OpaqueFd` or \ + `ExternalSemaphoreHandleType::SyncFd`" + .into(), + vuids: &["VUID-VkImportSemaphoreFdInfoKHR-handleType-01143"], + ..Default::default() + })); + } + + // VUID-VkImportSemaphoreFdInfoKHR-fd-01544 + // VUID-VkImportSemaphoreFdInfoKHR-handleType-03263 + // Can't validate, therefore unsafe + + if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY) + { + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + `flags` does not contain `SemaphoreImportFlags::TEMPORARY`" + .into(), + vuids: &["VUID-VkImportSemaphoreFdInfoKHR-handleType-07307"], + ..Default::default() + })); + } + + Ok(()) + } } #[cfg(windows)] @@ -1319,6 +1447,64 @@ impl ImportSemaphoreWin32HandleInfo { _ne: crate::NonExhaustive(()), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), Box> { + let &Self { + flags, + handle_type, + handle: _, + _ne: _, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + handle_type + .validate_device(device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!( + handle_type, + ExternalSemaphoreHandleType::OpaqueWin32 + | ExternalSemaphoreHandleType::OpaqueWin32Kmt + | ExternalSemaphoreHandleType::D3D12Fence + ) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalSemaphoreHandleType::OpaqueWin32`, \ + `ExternalSemaphoreHandleType::OpaqueWin32Kmt` or \ + `ExternalSemaphoreHandleType::D3D12Fence`" + .into(), + vuids: &["VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140"], + ..Default::default() + })); + } + + // VUID-VkImportSemaphoreWin32HandleInfoKHR-handle-01542 + // Can't validate, therefore unsafe + + if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY) + { + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + `flags` does not contain `SemaphoreImportFlags::TEMPORARY`" + .into(), + // vuids? + ..Default::default() + })); + } + + Ok(()) + } } #[cfg(target_os = "fuchsia")] @@ -1356,6 +1542,57 @@ impl ImportSemaphoreZirconHandleInfo { _ne: crate::NonExhaustive(()), } } + + pub(crate) fn validate(&self, device: &Device) -> Result<(), Box> { + let &Self { + flags, + handle_type, + zircon_handle: _, + _ne: _, + } = self; + + flags + .validate_device(device) + .map_err(|err| ValidationError { + context: "flags".into(), + vuids: &["VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-flags-parameter"], + ..ValidationError::from_requirement(err) + })?; + + handle_type + .validate_device(device) + .map_err(|err| ValidationError { + context: "handle_type".into(), + vuids: &["VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-parameter"], + ..ValidationError::from_requirement(err) + })?; + + if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) { + return Err(Box::new(ValidationError { + context: "handle_type".into(), + problem: "is not `ExternalSemaphoreHandleType::ZirconEvent`".into(), + vuids: &["VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-04765"], + ..Default::default() + })); + } + + // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04766 + // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04767 + // Can't validate, therefore unsafe + + if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY) + { + return Err(Box::new(ValidationError { + problem: "`handle_type` has copy transference, but \ + `flags` does not contain `SemaphoreImportFlags::TEMPORARY`" + .into(), + // vuids? + ..Default::default() + })); + } + + Ok(()) + } } /// The semaphore configuration to query in @@ -1421,170 +1658,6 @@ pub struct ExternalSemaphoreProperties { pub compatible_handle_types: ExternalSemaphoreHandleTypes, } -/// Error that can be returned from operations on a semaphore. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum SemaphoreError { - /// Not enough memory available. - OomError(OomError), - - RequirementNotMet { - required_for: &'static str, - requires_one_of: RequiresOneOf, - }, - - /// The provided handle type does not permit more than one export, - /// and a handle of this type was already exported previously. - AlreadyExported, - - /// The provided handle type cannot be exported from the current import handle type. - ExportFromImportedNotSupported { - imported_handle_type: ExternalSemaphoreHandleType, - }, - - /// One of the export handle types is not compatible with the other provided handles. - ExportHandleTypesNotCompatible, - - /// A handle type with copy transference was provided, but the semaphore is not signaled and - /// there is no pending queue operation that will signal it. - HandleTypeCopyNotSignaled, - - /// A handle type with copy transference was provided, - /// but the `temporary` import flag was not set. - HandletypeCopyNotTemporary, - - /// The provided export handle type was not set in `export_handle_types` when creating the - /// semaphore. - HandleTypeNotEnabled, - - /// Exporting is not supported for the provided handle type. - HandleTypeNotExportable { - handle_type: ExternalSemaphoreHandleType, - }, - - /// The provided handle type is not a POSIX file descriptor handle. - HandleTypeNotFd, - - /// The provided handle type is not a Win32 handle. - HandleTypeNotWin32, - - /// The provided handle type is not a Zircon event handle. - HandleTypeNotZircon, - - /// The semaphore currently has a temporary import for a swapchain acquire operation. - ImportedForSwapchainAcquire, - - /// The semaphore is currently in use by a queue. - InQueue, - - /// A queue is currently waiting on the semaphore. - QueueIsWaiting, -} - -impl Error for SemaphoreError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - Self::OomError(err) => Some(err), - _ => None, - } - } -} - -impl Display for SemaphoreError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - Self::OomError(_) => write!(f, "not enough memory available"), - Self::RequirementNotMet { - required_for, - requires_one_of, - } => write!( - f, - "a requirement was not met for: {}; requires one of: {}", - required_for, requires_one_of, - ), - - Self::AlreadyExported => write!( - f, - "the provided handle type does not permit more than one export, and a handle of \ - this type was already exported previously", - ), - Self::ExportFromImportedNotSupported { - imported_handle_type, - } => write!( - f, - "the provided handle type cannot be exported from the current imported handle type \ - {:?}", - imported_handle_type, - ), - Self::ExportHandleTypesNotCompatible => write!( - f, - "one of the export handle types is not compatible with the other provided handles", - ), - Self::HandleTypeCopyNotSignaled => write!( - f, - "a handle type with copy transference was provided, but the semaphore is not \ - signaled and there is no pending queue operation that will signal it", - ), - Self::HandletypeCopyNotTemporary => write!( - f, - "a handle type with copy transference was provided, but the `temporary` \ - import flag was not set", - ), - Self::HandleTypeNotEnabled => write!( - f, - "the provided export handle type was not set in `export_handle_types` when \ - creating the semaphore", - ), - Self::HandleTypeNotExportable { handle_type } => write!( - f, - "exporting is not supported for handles of type {:?}", - handle_type, - ), - Self::HandleTypeNotFd => write!( - f, - "the provided handle type is not a POSIX file descriptor handle", - ), - Self::HandleTypeNotWin32 => { - write!(f, "the provided handle type is not a Win32 handle") - } - Self::HandleTypeNotZircon => { - write!(f, "the provided handle type is not a Zircon event handle") - } - Self::ImportedForSwapchainAcquire => write!( - f, - "the semaphore currently has a temporary import for a swapchain acquire operation", - ), - Self::InQueue => write!(f, "the semaphore is currently in use by a queue"), - Self::QueueIsWaiting => write!(f, "a queue is currently waiting on the semaphore"), - } - } -} - -impl From for SemaphoreError { - fn from(err: VulkanError) -> Self { - match err { - e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => { - Self::OomError(e.into()) - } - _ => panic!("unexpected error: {:?}", err), - } - } -} - -impl From for SemaphoreError { - fn from(err: OomError) -> Self { - Self::OomError(err) - } -} - -impl From for SemaphoreError { - fn from(err: RequirementNotMet) -> Self { - Self::RequirementNotMet { - required_for: err.required_for, - requires_one_of: err.requires_one_of, - } - } -} - #[cfg(test)] mod tests { #[cfg(unix)]