From 29361d8d9056e0f136758d4d50706352ec689991 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 22 Jul 2023 10:56:28 +0200 Subject: [PATCH 1/8] ValidationError-ify sync primitives --- vulkano/src/swapchain/acquire_present.rs | 28 +- vulkano/src/sync/event.rs | 235 ++--- vulkano/src/sync/fence.rs | 1003 +++++++++++----------- vulkano/src/sync/future/fence_signal.rs | 19 +- vulkano/src/sync/future/mod.rs | 16 +- vulkano/src/sync/semaphore.rs | 897 ++++++++++--------- 6 files changed, 1158 insertions(+), 1040 deletions(-) diff --git a/vulkano/src/swapchain/acquire_present.rs b/vulkano/src/swapchain/acquire_present.rs index a2870ca79d..acc40827b9 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,10 +186,10 @@ 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 { match &self.fence { Some(fence) => fence.wait(timeout), - None => Ok(()), + None => Ok(true), } } } @@ -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..1b88b7284a 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,16 +270,16 @@ 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. + /// Returns `true` if the fence is now signaled, `false` 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 { let queue_to_signal = { let mut state = self.state.lock(); // If the fence is already signaled, we don't need to wait. if state.is_signaled().unwrap_or(false) { - return Ok(()); + return Ok(true); } let timeout_ns = timeout.map_or(u64::MAX, |timeout| { @@ -331,8 +302,8 @@ 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()), + ash::vk::Result::TIMEOUT => return Ok(false), + err => return Err(VulkanError::from(err)), } }; @@ -344,7 +315,7 @@ impl Fence { } } - Ok(()) + Ok(true) } /// Waits for multiple fences at once. @@ -355,17 +326,17 @@ impl Fence { pub fn multi_wait<'a>( fences: impl IntoIterator, timeout: Option, - ) -> Result<(), FenceError> { + ) -> Result> { 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 +355,7 @@ impl Fence { pub unsafe fn multi_wait_unchecked<'a>( fences: impl IntoIterator, timeout: Option, - ) -> Result<(), FenceError> { + ) -> Result { let queues_to_signal: SmallVec<[_; 8]> = { let iter = fences.into_iter(); let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new(); @@ -405,7 +376,7 @@ impl Fence { // VUID-vkWaitForFences-fenceCount-arraylength // If there are no fences, or all the fences are signaled, we don't need to wait. if fences_vk.is_empty() { - return Ok(()); + return Ok(true); } let device = &fences[0].device; @@ -433,8 +404,8 @@ 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()), + ash::vk::Result::TIMEOUT => return Ok(false), + err => return Err(VulkanError::from(err)), } }; @@ -444,24 +415,27 @@ impl Fence { queue.with(|mut q| q.fence_signaled(fence)); } - Ok(()) + Ok(true) } /// Resets the 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 +467,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 +485,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 +553,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 +568,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 +645,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 +710,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 +722,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 +811,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 +880,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 +892,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 +976,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 +988,21 @@ 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", )])]), - }); + })); } - // 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 +1059,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 +1096,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 +1121,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 +1338,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 +1429,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 +1548,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 +1689,7 @@ mod tests { let fence = Fence::new( device, FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1663,7 +1704,7 @@ mod tests { let fence = Fence::new( device, FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1678,7 +1719,7 @@ mod tests { let fence = Fence::new( device, FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1696,7 +1737,7 @@ mod tests { let fence1 = Fence::new( device1.clone(), FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1704,7 +1745,7 @@ mod tests { let fence2 = Fence::new( device2.clone(), FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1726,7 +1767,7 @@ mod tests { let fence1 = Fence::new( device1.clone(), FenceCreateInfo { - signaled: true, + flags: FenceCreateFlags::SIGNALED, ..Default::default() }, ) @@ -1734,7 +1775,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..524e23e1ee 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))) == Ok(true) { + 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)] From 152868484e264bb6033a933d3e2a6e953df8b627 Mon Sep 17 00:00:00 2001 From: Rua Date: Sat, 22 Jul 2023 11:16:24 +0200 Subject: [PATCH 2/8] Fix Windows error --- vulkano/src/sync/fence.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/vulkano/src/sync/fence.rs b/vulkano/src/sync/fence.rs index 1b88b7284a..cfe27de289 100644 --- a/vulkano/src/sync/fence.rs +++ b/vulkano/src/sync/fence.rs @@ -994,6 +994,7 @@ impl Fence { requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension( "khr_external_fence_win32", )])]), + ..Default::default() })); } From 6219a0ff1bed734c05ad9503df2d077c28290c4c Mon Sep 17 00:00:00 2001 From: Rua Date: Mon, 24 Jul 2023 18:26:04 +0200 Subject: [PATCH 3/8] Return timeouts as errors instead --- vulkano/autogen/errors.rs | 5 +++-- vulkano/autogen/mod.rs | 5 ++++- vulkano/src/lib.rs | 2 ++ vulkano/src/swapchain/acquire_present.rs | 4 ++-- vulkano/src/sync/fence.rs | 20 +++++++++----------- vulkano/src/sync/future/fence_signal.rs | 2 +- 6 files changed, 21 insertions(+), 17 deletions(-) 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 acc40827b9..146d193e06 100644 --- a/vulkano/src/swapchain/acquire_present.rs +++ b/vulkano/src/swapchain/acquire_present.rs @@ -186,10 +186,10 @@ 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 { + pub fn wait(&self, timeout: Option) -> Result<(), VulkanError> { match &self.fence { Some(fence) => fence.wait(timeout), - None => Ok(true), + None => Ok(()), } } } diff --git a/vulkano/src/sync/fence.rs b/vulkano/src/sync/fence.rs index cfe27de289..82dfd8249d 100644 --- a/vulkano/src/sync/fence.rs +++ b/vulkano/src/sync/fence.rs @@ -270,16 +270,14 @@ impl Fence { /// Waits until the fence is signaled, or at least until the timeout duration has elapsed. /// - /// Returns `true` if the fence is now signaled, `false` 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 { + pub fn wait(&self, timeout: Option) -> Result<(), VulkanError> { let queue_to_signal = { let mut state = self.state.lock(); // If the fence is already signaled, we don't need to wait. if state.is_signaled().unwrap_or(false) { - return Ok(true); + return Ok(()); } let timeout_ns = timeout.map_or(u64::MAX, |timeout| { @@ -302,7 +300,7 @@ impl Fence { match result { ash::vk::Result::SUCCESS => unsafe { state.set_signaled() }, - ash::vk::Result::TIMEOUT => return Ok(false), + ash::vk::Result::TIMEOUT => return Err(VulkanError::Timeout), err => return Err(VulkanError::from(err)), } }; @@ -315,7 +313,7 @@ impl Fence { } } - Ok(true) + Ok(()) } /// Waits for multiple fences at once. @@ -326,7 +324,7 @@ impl Fence { pub fn multi_wait<'a>( fences: impl IntoIterator, timeout: Option, - ) -> Result> { + ) -> Result<(), Validated> { let fences: SmallVec<[_; 8]> = fences.into_iter().collect(); Self::validate_multi_wait(&fences, timeout)?; @@ -355,7 +353,7 @@ impl Fence { pub unsafe fn multi_wait_unchecked<'a>( fences: impl IntoIterator, timeout: Option, - ) -> Result { + ) -> Result<(), VulkanError> { let queues_to_signal: SmallVec<[_; 8]> = { let iter = fences.into_iter(); let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new(); @@ -376,7 +374,7 @@ impl Fence { // VUID-vkWaitForFences-fenceCount-arraylength // If there are no fences, or all the fences are signaled, we don't need to wait. if fences_vk.is_empty() { - return Ok(true); + return Ok(()); } let device = &fences[0].device; @@ -404,7 +402,7 @@ impl Fence { .zip(&mut states) .filter_map(|(fence, state)| state.set_signaled().map(|state| (state, fence))) .collect(), - ash::vk::Result::TIMEOUT => return Ok(false), + ash::vk::Result::TIMEOUT => return Err(VulkanError::Timeout), err => return Err(VulkanError::from(err)), } }; @@ -415,7 +413,7 @@ impl Fence { queue.with(|mut q| q.fence_signaled(fence)); } - Ok(true) + Ok(()) } /// Resets the fence. diff --git a/vulkano/src/sync/future/fence_signal.rs b/vulkano/src/sync/future/fence_signal.rs index 524e23e1ee..06b1ace455 100644 --- a/vulkano/src/sync/future/fence_signal.rs +++ b/vulkano/src/sync/future/fence_signal.rs @@ -190,7 +190,7 @@ where match *state { FenceSignalFutureState::Flushed(ref mut prev, ref fence) => { - if fence.wait(Some(Duration::from_secs(0))) == Ok(true) { + if fence.wait(Some(Duration::from_secs(0))).is_ok() { unsafe { prev.signal_finished() } *state = FenceSignalFutureState::Cleaned; } else { From 1cc4126049d55e4730401143b08d944a91573d00 Mon Sep 17 00:00:00 2001 From: Rua Date: Mon, 24 Jul 2023 18:38:50 +0200 Subject: [PATCH 4/8] Simplify a bit --- vulkano/src/sync/fence.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/vulkano/src/sync/fence.rs b/vulkano/src/sync/fence.rs index 82dfd8249d..1e94dcfbce 100644 --- a/vulkano/src/sync/fence.rs +++ b/vulkano/src/sync/fence.rs @@ -300,7 +300,6 @@ impl Fence { match result { ash::vk::Result::SUCCESS => unsafe { state.set_signaled() }, - ash::vk::Result::TIMEOUT => return Err(VulkanError::Timeout), err => return Err(VulkanError::from(err)), } }; @@ -402,7 +401,6 @@ impl Fence { .zip(&mut states) .filter_map(|(fence, state)| state.set_signaled().map(|state| (state, fence))) .collect(), - ash::vk::Result::TIMEOUT => return Err(VulkanError::Timeout), err => return Err(VulkanError::from(err)), } }; From 479c25d8bce193624aaab401f1a322a00b4855cf Mon Sep 17 00:00:00 2001 From: Rua Date: Mon, 24 Jul 2023 19:20:11 +0200 Subject: [PATCH 5/8] ValidationError-ify futures --- examples/src/bin/async-update.rs | 15 +- examples/src/bin/buffer-allocator.rs | 15 +- examples/src/bin/clear_attachments.rs | 15 +- examples/src/bin/deferred/main.rs | 15 +- examples/src/bin/gl-interop.rs | 34 ++- examples/src/bin/image-self-copy-blit/main.rs | 15 +- examples/src/bin/image/main.rs | 15 +- examples/src/bin/immutable-sampler/main.rs | 15 +- examples/src/bin/indirect.rs | 15 +- examples/src/bin/instancing.rs | 15 +- examples/src/bin/multi-window.rs | 15 +- examples/src/bin/occlusion-query.rs | 15 +- examples/src/bin/push-descriptors/main.rs | 15 +- examples/src/bin/runtime-shader/main.rs | 15 +- examples/src/bin/runtime_array/main.rs | 15 +- examples/src/bin/simple-particles.rs | 4 +- examples/src/bin/teapot/main.rs | 15 +- examples/src/bin/tessellation.rs | 15 +- examples/src/bin/texture_array/main.rs | 15 +- examples/src/bin/triangle-v1_3.rs | 15 +- examples/src/bin/triangle.rs | 15 +- vulkano-util/src/renderer.rs | 22 +- vulkano/src/command_buffer/traits.rs | 12 +- vulkano/src/device/queue.rs | 92 ++++-- vulkano/src/swapchain/acquire_present.rs | 274 +++++------------- vulkano/src/swapchain/mod.rs | 18 +- vulkano/src/sync/future/fence_signal.rs | 42 ++- vulkano/src/sync/future/join.rs | 8 +- vulkano/src/sync/future/mod.rs | 149 +--------- vulkano/src/sync/future/now.rs | 8 +- vulkano/src/sync/future/semaphore_signal.rs | 36 ++- vulkano/src/sync/mod.rs | 2 +- 32 files changed, 394 insertions(+), 592 deletions(-) diff --git a/examples/src/bin/async-update.rs b/examples/src/bin/async-update.rs index a69206a647..9a419e63e2 100644 --- a/examples/src/bin/async-update.rs +++ b/examples/src/bin/async-update.rs @@ -85,11 +85,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{ElementState, Event, KeyboardInput, VirtualKeyCode, WindowEvent}, @@ -570,9 +569,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -662,11 +661,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/buffer-allocator.rs b/examples/src/bin/buffer-allocator.rs index cc10747757..9c33873077 100644 --- a/examples/src/bin/buffer-allocator.rs +++ b/examples/src/bin/buffer-allocator.rs @@ -44,11 +44,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -318,9 +317,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -406,11 +405,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(Box::new(future) as Box<_>); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(Box::new(sync::now(device.clone())) as Box<_>); } diff --git a/examples/src/bin/clear_attachments.rs b/examples/src/bin/clear_attachments.rs index feb3a69fca..d6c1e8ee0c 100644 --- a/examples/src/bin/clear_attachments.rs +++ b/examples/src/bin/clear_attachments.rs @@ -21,11 +21,10 @@ use vulkano::{ instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -196,9 +195,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -276,11 +275,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/deferred/main.rs b/examples/src/bin/deferred/main.rs index d4d0aeb951..22e8a6c6a6 100644 --- a/examples/src/bin/deferred/main.rs +++ b/examples/src/bin/deferred/main.rs @@ -41,11 +41,10 @@ use vulkano::{ instance::{Instance, InstanceCreateFlags, InstanceCreateInfo}, memory::allocator::StandardMemoryAllocator, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -222,9 +221,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -269,11 +268,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/gl-interop.rs b/examples/src/bin/gl-interop.rs index c52af7c8f9..701cd1bd42 100644 --- a/examples/src/bin/gl-interop.rs +++ b/examples/src/bin/gl-interop.rs @@ -61,16 +61,18 @@ mod linux { PipelineShaderStageCreateInfo, }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, - swapchain::{AcquireError, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo}, + swapchain::{ + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, + }, sync::{ now, semaphore::{ ExternalSemaphoreHandleType, ExternalSemaphoreHandleTypes, Semaphore, SemaphoreCreateInfo, }, - FlushError, GpuFuture, + GpuFuture, }, - VulkanLibrary, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -350,15 +352,19 @@ mod linux { recreate_swapchain = false; } - let (image_index, suboptimal, acquire_future) = - match vulkano::swapchain::acquire_next_image(swapchain.clone(), None) { - Ok(r) => r, - Err(AcquireError::OutOfDate) => { - recreate_swapchain = true; - return; - } - Err(e) => panic!("failed to acquire next image: {e}"), - }; + let (image_index, suboptimal, acquire_future) = match acquire_next_image( + swapchain.clone(), + None, + ) + .map_err(Validated::unwrap) + { + Ok(r) => r, + Err(VulkanError::OutOfDate) => { + recreate_swapchain = true; + return; + } + Err(e) => panic!("failed to acquire next image: {e}"), + }; if suboptimal { recreate_swapchain = true; @@ -410,12 +416,12 @@ mod linux { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { future.wait(None).unwrap(); previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(vulkano::sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/image-self-copy-blit/main.rs b/examples/src/bin/image-self-copy-blit/main.rs index fad89305b4..517ffabe32 100644 --- a/examples/src/bin/image-self-copy-blit/main.rs +++ b/examples/src/bin/image-self-copy-blit/main.rs @@ -47,11 +47,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - DeviceSize, VulkanLibrary, + sync::{self, GpuFuture}, + DeviceSize, Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -444,9 +443,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -501,11 +500,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/image/main.rs b/examples/src/bin/image/main.rs index 33bc24aff0..ffb246afa7 100644 --- a/examples/src/bin/image/main.rs +++ b/examples/src/bin/image/main.rs @@ -45,11 +45,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - DeviceSize, VulkanLibrary, + sync::{self, GpuFuture}, + DeviceSize, Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -391,9 +390,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -448,11 +447,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/immutable-sampler/main.rs b/examples/src/bin/immutable-sampler/main.rs index 64f4c56fcf..01f3eeae93 100644 --- a/examples/src/bin/immutable-sampler/main.rs +++ b/examples/src/bin/immutable-sampler/main.rs @@ -54,11 +54,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - DeviceSize, VulkanLibrary, + sync::{self, GpuFuture}, + DeviceSize, Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -412,9 +411,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -469,11 +468,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/indirect.rs b/examples/src/bin/indirect.rs index 363c8fc22a..3a95874b95 100644 --- a/examples/src/bin/indirect.rs +++ b/examples/src/bin/indirect.rs @@ -61,11 +61,10 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, single_pass_renderpass, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -412,9 +411,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -515,11 +514,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/instancing.rs b/examples/src/bin/instancing.rs index 560327fcdc..bb4746875a 100644 --- a/examples/src/bin/instancing.rs +++ b/examples/src/bin/instancing.rs @@ -42,11 +42,10 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, single_pass_renderpass, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -388,9 +387,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -445,11 +444,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/multi-window.rs b/examples/src/bin/multi-window.rs index 86ba4da950..51d622c250 100644 --- a/examples/src/bin/multi-window.rs +++ b/examples/src/bin/multi-window.rs @@ -45,11 +45,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{ElementState, Event, KeyboardInput, WindowEvent}, @@ -434,9 +433,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { *recreate_swapchain = true; return; } @@ -486,11 +485,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { *previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { *recreate_swapchain = true; *previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/occlusion-query.rs b/examples/src/bin/occlusion-query.rs index d6ed354ea2..265b3dd794 100644 --- a/examples/src/bin/occlusion-query.rs +++ b/examples/src/bin/occlusion-query.rs @@ -43,11 +43,10 @@ use vulkano::{ query::{QueryControlFlags, QueryPool, QueryPoolCreateInfo, QueryResultFlags, QueryType}, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -408,9 +407,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -497,11 +496,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/push-descriptors/main.rs b/examples/src/bin/push-descriptors/main.rs index 0e7aabbd2e..515c136518 100644 --- a/examples/src/bin/push-descriptors/main.rs +++ b/examples/src/bin/push-descriptors/main.rs @@ -43,11 +43,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - DeviceSize, VulkanLibrary, + sync::{self, GpuFuture}, + DeviceSize, Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -385,9 +384,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -444,11 +443,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/runtime-shader/main.rs b/examples/src/bin/runtime-shader/main.rs index 5ca2454d29..423dcce109 100644 --- a/examples/src/bin/runtime-shader/main.rs +++ b/examples/src/bin/runtime-shader/main.rs @@ -51,11 +51,10 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, shader::ShaderModule, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -334,9 +333,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -385,11 +384,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/runtime_array/main.rs b/examples/src/bin/runtime_array/main.rs index e6e9bfa939..2f218874f2 100644 --- a/examples/src/bin/runtime_array/main.rs +++ b/examples/src/bin/runtime_array/main.rs @@ -46,11 +46,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - DeviceSize, VulkanLibrary, + sync::{self, GpuFuture}, + DeviceSize, Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -520,9 +519,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -577,11 +576,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/simple-particles.rs b/examples/src/bin/simple-particles.rs index b8b27bcb42..9923824de6 100644 --- a/examples/src/bin/simple-particles.rs +++ b/examples/src/bin/simple-particles.rs @@ -50,7 +50,7 @@ use vulkano::{ SwapchainPresentInfo, }, sync::{self, future::FenceSignalFuture, GpuFuture}, - VulkanLibrary, + Validated, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -622,7 +622,7 @@ fn main() { .then_signal_fence_and_flush(); // Update this frame's future with current fence. - fences[image_index as usize] = match future { + fences[image_index as usize] = match future.map_err(Validated::unwrap) { // Success, store result into vector. Ok(future) => Some(Arc::new(future)), diff --git a/examples/src/bin/teapot/main.rs b/examples/src/bin/teapot/main.rs index 3af3557eaf..4da2f8151e 100644 --- a/examples/src/bin/teapot/main.rs +++ b/examples/src/bin/teapot/main.rs @@ -48,11 +48,10 @@ use vulkano::{ render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, shader::EntryPoint, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -352,9 +351,9 @@ fn main() { .unwrap(); let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -412,11 +411,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/tessellation.rs b/examples/src/bin/tessellation.rs index 082782492e..4f99b2cb47 100644 --- a/examples/src/bin/tessellation.rs +++ b/examples/src/bin/tessellation.rs @@ -51,11 +51,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -446,9 +445,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -497,11 +496,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/texture_array/main.rs b/examples/src/bin/texture_array/main.rs index 77f83f75f9..01d03580d9 100644 --- a/examples/src/bin/texture_array/main.rs +++ b/examples/src/bin/texture_array/main.rs @@ -45,11 +45,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - DeviceSize, VulkanLibrary, + sync::{self, GpuFuture}, + DeviceSize, Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -402,9 +401,9 @@ fn main() { } let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -459,11 +458,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/triangle-v1_3.rs b/examples/src/bin/triangle-v1_3.rs index 5dcea99630..d738f3e23e 100644 --- a/examples/src/bin/triangle-v1_3.rs +++ b/examples/src/bin/triangle-v1_3.rs @@ -51,11 +51,10 @@ use vulkano::{ }, render_pass::{AttachmentLoadOp, AttachmentStoreOp}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - Version, VulkanLibrary, + sync::{self, GpuFuture}, + Validated, Version, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -569,9 +568,9 @@ fn main() { // This function can block if no image is available. The parameter is an optional // timeout after which the function call will return an error. let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -667,11 +666,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/examples/src/bin/triangle.rs b/examples/src/bin/triangle.rs index 25309d6a2d..a5d339ef52 100644 --- a/examples/src/bin/triangle.rs +++ b/examples/src/bin/triangle.rs @@ -45,11 +45,10 @@ use vulkano::{ }, render_pass::{Framebuffer, FramebufferCreateInfo, RenderPass, Subpass}, swapchain::{ - acquire_next_image, AcquireError, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, + acquire_next_image, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo, }, - sync::{self, FlushError, GpuFuture}, - VulkanLibrary, + sync::{self, GpuFuture}, + Validated, VulkanError, VulkanLibrary, }; use winit::{ event::{Event, WindowEvent}, @@ -569,9 +568,9 @@ fn main() { // This function can block if no image is available. The parameter is an optional // timeout after which the function call will return an error. let (image_index, suboptimal, acquire_future) = - match acquire_next_image(swapchain.clone(), None) { + match acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; return; } @@ -661,11 +660,11 @@ fn main() { ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(future) => { previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { recreate_swapchain = true; previous_frame_end = Some(sync::now(device.clone()).boxed()); } diff --git a/vulkano-util/src/renderer.rs b/vulkano-util/src/renderer.rs index ec516a5893..627ca18512 100644 --- a/vulkano-util/src/renderer.rs +++ b/vulkano-util/src/renderer.rs @@ -15,11 +15,9 @@ use vulkano::{ format::Format, image::{view::ImageView, Image, ImageCreateInfo, ImageType, ImageUsage}, memory::allocator::{AllocationCreateInfo, StandardMemoryAllocator}, - swapchain::{ - self, AcquireError, PresentMode, Surface, Swapchain, SwapchainCreateInfo, - SwapchainPresentInfo, - }, - sync::{self, FlushError, GpuFuture}, + swapchain::{self, PresentMode, Surface, Swapchain, SwapchainCreateInfo, SwapchainPresentInfo}, + sync::{self, GpuFuture}, + Validated, VulkanError, }; use winit::window::Window; @@ -261,7 +259,7 @@ impl VulkanoWindowRenderer { /// Execute your command buffers after calling this function and finish rendering by calling /// [`VulkanoWindowRenderer::present`]. #[inline] - pub fn acquire(&mut self) -> Result, AcquireError> { + pub fn acquire(&mut self) -> Result, VulkanError> { // Recreate swap chain if needed (when resizing of window occurs or swapchain is outdated) // Also resize render views if needed if self.recreate_swapchain { @@ -270,11 +268,13 @@ impl VulkanoWindowRenderer { // Acquire next image in the swapchain let (image_index, suboptimal, acquire_future) = - match swapchain::acquire_next_image(self.swapchain.clone(), None) { + match swapchain::acquire_next_image(self.swapchain.clone(), None) + .map_err(Validated::unwrap) + { Ok(r) => r, - Err(AcquireError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { self.recreate_swapchain = true; - return Err(AcquireError::OutOfDate); + return Err(VulkanError::OutOfDate); } Err(e) => panic!("failed to acquire next image: {e}"), }; @@ -306,7 +306,7 @@ impl VulkanoWindowRenderer { ), ) .then_signal_fence_and_flush(); - match future { + match future.map_err(Validated::unwrap) { Ok(mut future) => { if wait_future { match future.wait(None) { @@ -320,7 +320,7 @@ impl VulkanoWindowRenderer { self.previous_frame_end = Some(future.boxed()); } - Err(FlushError::OutOfDate) => { + Err(VulkanError::OutOfDate) => { self.recreate_swapchain = true; self.previous_frame_end = Some(sync::now(self.graphics_queue.device().clone()).boxed()); diff --git a/vulkano/src/command_buffer/traits.rs b/vulkano/src/command_buffer/traits.rs index a71fcef045..2c0b42ad8b 100644 --- a/vulkano/src/command_buffer/traits.rs +++ b/vulkano/src/command_buffer/traits.rs @@ -17,12 +17,10 @@ use crate::{ image::{Image, ImageLayout}, swapchain::Swapchain, sync::{ - future::{ - now, AccessCheckError, AccessError, FlushError, GpuFuture, NowFuture, SubmitAnyBuilder, - }, + future::{now, AccessCheckError, AccessError, GpuFuture, NowFuture, SubmitAnyBuilder}, PipelineStages, }, - DeviceSize, SafeDeref, VulkanObject, + DeviceSize, SafeDeref, Validated, VulkanError, VulkanObject, }; use parking_lot::{Mutex, MutexGuard}; use std::{ @@ -235,7 +233,7 @@ where { // Implementation of `build_submission`. Doesn't check whenever the future was already flushed. // You must make sure to not submit same command buffer multiple times. - unsafe fn build_submission_impl(&self) -> Result { + unsafe fn build_submission_impl(&self) -> Result> { Ok(match self.previous.build_submission()? { SubmitAnyBuilder::Empty => SubmitAnyBuilder::CommandBuffer( SubmitInfo { @@ -289,7 +287,7 @@ where self.previous.cleanup_finished(); } - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { if *self.submitted.lock() { return Ok(SubmitAnyBuilder::Empty); } @@ -297,7 +295,7 @@ where self.build_submission_impl() } - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { unsafe { let mut submitted = self.submitted.lock(); if *submitted { diff --git a/vulkano/src/device/queue.rs b/vulkano/src/device/queue.rs index e9677960b1..af77537a98 100644 --- a/vulkano/src/device/queue.rs +++ b/vulkano/src/device/queue.rs @@ -23,11 +23,11 @@ use crate::{ swapchain::{PresentInfo, SwapchainPresentInfo}, sync::{ fence::{Fence, FenceState}, - future::{AccessCheckError, FlushError, GpuFuture}, + future::{AccessCheckError, GpuFuture}, semaphore::SemaphoreState, }, - OomError, Requires, RequiresAllOf, RequiresOneOf, ValidationError, Version, VulkanError, - VulkanObject, + OomError, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, + VulkanError, VulkanObject, }; use ahash::HashMap; use parking_lot::{Mutex, MutexGuard}; @@ -694,7 +694,7 @@ impl<'a> QueueGuard<'a> { fence: Option>, future: &dyn GpuFuture, queue: &Queue, - ) -> Result<(), FlushError> { + ) -> Result<(), Validated> { let submit_infos: SmallVec<[_; 4]> = smallvec![submit_info]; let mut states = States::from_submit_infos(&submit_infos); @@ -707,15 +707,31 @@ impl<'a> QueueGuard<'a> { match command_buffer.usage() { CommandBufferUsage::OneTimeSubmit => { - // VUID-vkQueueSubmit2-commandBuffer-03874 if state.has_been_submitted() { - return Err(FlushError::OneTimeSubmitAlreadySubmitted); + return Err(Box::new(ValidationError { + problem: "a command buffer, or one of the secondary \ + command buffers it executes, was created with the \ + `CommandBufferUsage::OneTimeSubmit` usage, but \ + it has already been submitted in the past" + .into(), + vuids: &["VUID-vkQueueSubmit2-commandBuffer-03874"], + ..Default::default() + }) + .into()); } } CommandBufferUsage::MultipleSubmit => { - // VUID-vkQueueSubmit2-commandBuffer-03875 if state.is_submit_pending() { - return Err(FlushError::ExclusiveAlreadyInUse); + return Err(Box::new(ValidationError { + problem: "a command buffer, or one of the secondary \ + command buffers it executes, was not created with the \ + `CommandBufferUsage::SimultaneousUse` usage, but \ + it is already in use by the device" + .into(), + vuids: &["VUID-vkQueueSubmit2-commandBuffer-03875"], + ..Default::default() + }) + .into()); } } CommandBufferUsage::SimultaneousUse => (), @@ -739,10 +755,17 @@ impl<'a> QueueGuard<'a> { queue, ) { Err(AccessCheckError::Denied(error)) => { - return Err(FlushError::ResourceAccessError { - error, - use_ref: range_usage.first_use, - }); + return Err(Box::new(ValidationError { + problem: format!( + "access to a resource has been denied\n\ + resource use: {:?}\n\ + error: {}", + range_usage.first_use, error + ) + .into(), + ..Default::default() + }) + .into()); } Err(AccessCheckError::Unknown) => { let result = if range_usage.mutable { @@ -752,10 +775,17 @@ impl<'a> QueueGuard<'a> { }; if let Err(error) = result { - return Err(FlushError::ResourceAccessError { - error, - use_ref: range_usage.first_use, - }); + return Err(Box::new(ValidationError { + problem: format!( + "access to a resource has been denied\n\ + resource use: {:?}\n\ + error: {}", + range_usage.first_use, error + ) + .into(), + ..Default::default() + }) + .into()); } } _ => (), @@ -775,10 +805,17 @@ impl<'a> QueueGuard<'a> { queue, ) { Err(AccessCheckError::Denied(error)) => { - return Err(FlushError::ResourceAccessError { - error, - use_ref: range_usage.first_use, - }); + return Err(Box::new(ValidationError { + problem: format!( + "access to a resource has been denied\n\ + resource use: {:?}\n\ + error: {}", + range_usage.first_use, error + ) + .into(), + ..Default::default() + }) + .into()); } Err(AccessCheckError::Unknown) => { let result = if range_usage.mutable { @@ -789,10 +826,17 @@ impl<'a> QueueGuard<'a> { }; if let Err(error) = result { - return Err(FlushError::ResourceAccessError { - error, - use_ref: range_usage.first_use, - }); + return Err(Box::new(ValidationError { + problem: format!( + "access to a resource has been denied\n\ + resource use: {:?}\n\ + error: {}", + range_usage.first_use, error + ) + .into(), + ..Default::default() + }) + .into()); } } _ => (), diff --git a/vulkano/src/swapchain/acquire_present.rs b/vulkano/src/swapchain/acquire_present.rs index 146d193e06..7370d8ac05 100644 --- a/vulkano/src/swapchain/acquire_present.rs +++ b/vulkano/src/swapchain/acquire_present.rs @@ -14,16 +14,15 @@ use crate::{ image::{Image, ImageLayout}, sync::{ fence::Fence, - future::{AccessCheckError, AccessError, FlushError, GpuFuture, SubmitAnyBuilder}, + future::{AccessCheckError, AccessError, GpuFuture, SubmitAnyBuilder}, semaphore::Semaphore, }, - DeviceSize, OomError, RequirementNotMet, Requires, RequiresAllOf, RequiresOneOf, VulkanError, + DeviceSize, Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, VulkanError, VulkanObject, }; use smallvec::smallvec; use std::{ - error::Error, - fmt::{Debug, Display, Error as FmtError, Formatter}, + fmt::Debug, mem::MaybeUninit, num::NonZeroU64, ops::Range, @@ -50,7 +49,7 @@ use std::{ pub fn acquire_next_image( swapchain: Arc, timeout: Option, -) -> Result<(u32, bool, SwapchainAcquireFuture), AcquireError> { +) -> Result<(u32, bool, SwapchainAcquireFuture), Validated> { let semaphore = Arc::new(Semaphore::from_pool(swapchain.device.clone())?); let fence = Fence::from_pool(swapchain.device.clone())?; @@ -63,13 +62,16 @@ pub fn acquire_next_image( // > VkSwapchainCreateInfoKHR::oldSwapchain value to vkCreateSwapchainKHR let retired = swapchain.is_retired.lock(); if *retired { - return Err(AcquireError::OutOfDate); + return Err(VulkanError::OutOfDate.into()); } let acquire_result = unsafe { acquire_next_image_raw(&swapchain, timeout, Some(&semaphore), Some(&fence)) }; - if let &Err(AcquireError::FullScreenExclusiveModeLost) = &acquire_result { + if matches!( + acquire_result, + Err(Validated::Error(VulkanError::FullScreenExclusiveModeLost)) + ) { swapchain .full_screen_exclusive_held .store(false, Ordering::SeqCst); @@ -103,7 +105,7 @@ pub unsafe fn acquire_next_image_raw( timeout: Option, semaphore: Option<&Semaphore>, fence: Option<&Fence>, -) -> Result { +) -> Result> { let fns = swapchain.device.fns(); let timeout_ns = if let Some(timeout) = timeout { @@ -130,8 +132,8 @@ pub unsafe fn acquire_next_image_raw( let suboptimal = match result { ash::vk::Result::SUCCESS => false, ash::vk::Result::SUBOPTIMAL_KHR => true, - ash::vk::Result::NOT_READY => return Err(AcquireError::Timeout), - ash::vk::Result::TIMEOUT => return Err(AcquireError::Timeout), + ash::vk::Result::NOT_READY => return Err(VulkanError::NotReady.into()), + ash::vk::Result::TIMEOUT => return Err(VulkanError::Timeout.into()), err => return Err(VulkanError::from(err).into()), }; @@ -197,7 +199,7 @@ impl SwapchainAcquireFuture { unsafe impl GpuFuture for SwapchainAcquireFuture { fn cleanup_finished(&mut self) {} - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { if let Some(ref semaphore) = self.semaphore { let sem = smallvec![semaphore.clone()]; Ok(SubmitAnyBuilder::SemaphoresWait(sem)) @@ -206,7 +208,7 @@ unsafe impl GpuFuture for SwapchainAcquireFuture { } } - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { Ok(()) } @@ -307,79 +309,6 @@ unsafe impl DeviceOwned for SwapchainAcquireFuture { } } -/// Error that can happen when calling `acquire_next_image`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u32)] -pub enum AcquireError { - /// Not enough memory. - OomError(OomError), - - /// The connection to the device has been lost. - DeviceLost, - - /// The timeout of the function has been reached before an image was available. - Timeout, - - /// The surface is no longer accessible and must be recreated. - SurfaceLost, - - /// The swapchain has lost or doesn't have full-screen exclusivity possibly for - /// implementation-specific reasons outside of the application’s control. - FullScreenExclusiveModeLost, - - /// 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, -} - -impl Error for AcquireError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - AcquireError::OomError(err) => Some(err), - _ => None, - } - } -} - -impl Display for AcquireError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!( - f, - "{}", - match self { - AcquireError::OomError(_) => "not enough memory", - AcquireError::DeviceLost => "the connection to the device has been lost", - AcquireError::Timeout => "no image is available for acquiring yet", - AcquireError::SurfaceLost => "the surface of this swapchain is no longer valid", - AcquireError::OutOfDate => "the swapchain needs to be recreated", - AcquireError::FullScreenExclusiveModeLost => { - "the swapchain no longer has full-screen exclusivity" - } - } - ) - } -} - -impl From for AcquireError { - fn from(err: OomError) -> AcquireError { - AcquireError::OomError(err) - } -} - -impl From for AcquireError { - fn from(err: VulkanError) -> AcquireError { - match err { - err @ VulkanError::OutOfHostMemory => AcquireError::OomError(OomError::from(err)), - err @ VulkanError::OutOfDeviceMemory => AcquireError::OomError(OomError::from(err)), - VulkanError::DeviceLost => AcquireError::DeviceLost, - VulkanError::SurfaceLost => AcquireError::SurfaceLost, - VulkanError::OutOfDate => AcquireError::OutOfDate, - VulkanError::FullScreenExclusiveModeLost => AcquireError::FullScreenExclusiveModeLost, - _ => panic!("unexpected error: {:?}", err), - } - } -} - /// Presents an image on the screen. /// /// The actual behavior depends on the present mode that you passed when creating the swapchain. @@ -596,7 +525,7 @@ where self.previous.cleanup_finished(); } - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { if self.flushed.load(Ordering::SeqCst) { return Ok(SubmitAnyBuilder::Empty); } @@ -673,7 +602,7 @@ where }) } - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { unsafe { // If `flushed` already contains `true`, then `build_submission` will return `Empty`. @@ -693,7 +622,6 @@ where .first() .map_or(false, |first| first.present_mode.is_some()); - // VUID-VkPresentIdKHR-presentIds-04999 for swapchain_info in swapchain_infos { let &SwapchainPresentInfo { ref swapchain, @@ -707,15 +635,30 @@ where if present_id.map_or(false, |present_id| { !swapchain.try_claim_present_id(present_id) }) { - return Err(FlushError::PresentIdLessThanOrEqual); + return Err(Box::new(ValidationError { + problem: "the provided `present_id` was not greater than any \ + `present`_id passed previously for the same swapchain" + .into(), + vuids: &["VUID-VkPresentIdKHR-presentIds-04999"], + ..Default::default() + }) + .into()); } if let Some(present_mode) = present_mode { assert!(has_present_mode); - // VUID-VkSwapchainPresentModeInfoEXT-pPresentModes-07761 if !swapchain.present_modes().contains(&present_mode) { - return Err(FlushError::PresentModeNotValid); + return Err(Box::new(ValidationError { + problem: "the requested present mode is not one of the modes \ + in `swapchain.present_modes()`" + .into(), + vuids: &[ + "VUID-VkSwapchainPresentModeInfoEXT-pPresentModes-07761", + ], + ..Default::default() + }) + .into()); } } else { assert!(!has_present_mode); @@ -729,9 +672,19 @@ where ) { Ok(_) => (), Err(AccessCheckError::Unknown) => { - return Err(AccessError::SwapchainImageNotAcquired.into()) + return Err(Box::new(ValidationError { + problem: AccessError::SwapchainImageNotAcquired.to_string().into(), + ..Default::default() + }) + .into()); + } + Err(AccessCheckError::Denied(err)) => { + return Err(Box::new(ValidationError { + problem: err.to_string().into(), + ..Default::default() + }) + .into()); } - Err(AccessCheckError::Denied(e)) => return Err(e.into()), } Ok(self @@ -862,24 +815,30 @@ pub fn wait_for_present( swapchain: Arc, present_id: u64, timeout: Option, -) -> Result { - let retired = swapchain.is_retired.lock(); - - // VUID-vkWaitForPresentKHR-swapchain-04997 - if *retired { - return Err(PresentWaitError::OutOfDate); +) -> Result> { + if !swapchain.device.enabled_features().present_wait { + return Err(Box::new(ValidationError { + requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("present_wait")])]), + vuids: &["VUID-vkWaitForPresentKHR-presentWait-06234"], + ..Default::default() + }) + .into()); } if present_id == 0 { - return Err(PresentWaitError::PresentIdZero); + return Err(Box::new(ValidationError { + context: "present_id".into(), + problem: "is 0".into(), + ..Default::default() + }) + .into()); } - // VUID-vkWaitForPresentKHR-presentWait-06234 - if !swapchain.device.enabled_features().present_wait { - return Err(PresentWaitError::RequirementNotMet { - required_for: "`wait_for_present`", - requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::Feature("present_wait")])]), - }); + let retired = swapchain.is_retired.lock(); + + // VUID-vkWaitForPresentKHR-swapchain-04997 + if *retired { + return Err(VulkanError::OutOfDate.into()); } let timeout_ns = timeout.map(|dur| dur.as_nanos() as u64).unwrap_or(0); @@ -896,112 +855,17 @@ pub fn wait_for_present( match result { ash::vk::Result::SUCCESS => Ok(false), ash::vk::Result::SUBOPTIMAL_KHR => Ok(true), - ash::vk::Result::TIMEOUT => Err(PresentWaitError::Timeout), + ash::vk::Result::TIMEOUT => Err(VulkanError::Timeout.into()), err => { - let err = VulkanError::from(err).into(); + let err = VulkanError::from(err); - if let PresentWaitError::FullScreenExclusiveModeLost = &err { + if matches!(err, VulkanError::FullScreenExclusiveModeLost) { swapchain .full_screen_exclusive_held .store(false, Ordering::SeqCst); } - Err(err) - } - } -} - -/// Error that can happen when calling `acquire_next_image`. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -#[repr(u32)] -pub enum PresentWaitError { - /// Not enough memory. - OomError(OomError), - - /// The connection to the device has been lost. - DeviceLost, - - /// 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, - - /// The surface is no longer accessible and must be recreated. - SurfaceLost, - - /// The swapchain has lost or doesn't have full-screen exclusivity possibly for - /// implementation-specific reasons outside of the application’s control. - FullScreenExclusiveModeLost, - - /// The timeout of the function has been reached before the present occured. - Timeout, - - RequirementNotMet { - required_for: &'static str, - requires_one_of: RequiresOneOf, - }, - - /// Present id of zero is invalid. - PresentIdZero, -} - -impl Error for PresentWaitError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - Self::OomError(err) => Some(err), - _ => None, - } - } -} - -impl Display for PresentWaitError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - match self { - Self::OomError(e) => write!(f, "{}", e), - Self::DeviceLost => write!(f, "the connection to the device has been lost"), - Self::Timeout => write!(f, "no image is available for acquiring yet"), - Self::SurfaceLost => write!(f, "the surface of this swapchain is no longer valid"), - Self::OutOfDate => write!(f, "the swapchain needs to be recreated"), - Self::FullScreenExclusiveModeLost => { - write!(f, "the swapchain no longer has full-screen exclusivity") - } - Self::RequirementNotMet { - required_for, - requires_one_of, - } => write!( - f, - "a requirement was not met for: {}; requires one of: {}", - required_for, requires_one_of, - ), - Self::PresentIdZero => write!(f, "present id of zero is invalid"), - } - } -} - -impl From for PresentWaitError { - fn from(err: OomError) -> PresentWaitError { - Self::OomError(err) - } -} - -impl From for PresentWaitError { - fn from(err: RequirementNotMet) -> Self { - Self::RequirementNotMet { - required_for: err.required_for, - requires_one_of: err.requires_one_of, - } - } -} - -impl From for PresentWaitError { - fn from(err: VulkanError) -> PresentWaitError { - match err { - err @ VulkanError::OutOfHostMemory => Self::OomError(OomError::from(err)), - err @ VulkanError::OutOfDeviceMemory => Self::OomError(OomError::from(err)), - VulkanError::DeviceLost => Self::DeviceLost, - VulkanError::SurfaceLost => Self::SurfaceLost, - VulkanError::OutOfDate => Self::OutOfDate, - VulkanError::FullScreenExclusiveModeLost => Self::FullScreenExclusiveModeLost, - _ => panic!("unexpected error: {:?}", err), + Err(err.into()) } } } diff --git a/vulkano/src/swapchain/mod.rs b/vulkano/src/swapchain/mod.rs index 7c8a87e4e5..e78aae1ca4 100644 --- a/vulkano/src/swapchain/mod.rs +++ b/vulkano/src/swapchain/mod.rs @@ -276,9 +276,10 @@ //! as last parameter the old swapchain. //! //! ``` -//! use vulkano::swapchain; -//! use vulkano::swapchain::{AcquireError, SwapchainCreateInfo, SwapchainPresentInfo}; -//! use vulkano::sync::GpuFuture; +//! use vulkano::{ +//! swapchain::{self, SwapchainCreateInfo, SwapchainPresentInfo}, +//! sync::GpuFuture, Validated, VulkanError, +//! }; //! //! // let (swapchain, images) = Swapchain::new(...); //! # let mut swapchain: ::std::sync::Arc<::vulkano::swapchain::Swapchain> = return; @@ -298,11 +299,12 @@ //! recreate_swapchain = false; //! } //! -//! let (image_index, suboptimal, acq_future) = match swapchain::acquire_next_image(swapchain.clone(), None) { -//! Ok(r) => r, -//! Err(AcquireError::OutOfDate) => { recreate_swapchain = true; continue; }, -//! Err(err) => panic!("{:?}", err), -//! }; +//! let (image_index, suboptimal, acq_future) = +//! match swapchain::acquire_next_image(swapchain.clone(), None).map_err(Validated::unwrap) { +//! Ok(r) => r, +//! Err(VulkanError::OutOfDate) => { recreate_swapchain = true; continue; }, +//! Err(err) => panic!("{:?}", err), +//! }; //! //! // ... //! diff --git a/vulkano/src/sync/future/fence_signal.rs b/vulkano/src/sync/future/fence_signal.rs index 06b1ace455..9520516042 100644 --- a/vulkano/src/sync/future/fence_signal.rs +++ b/vulkano/src/sync/future/fence_signal.rs @@ -7,7 +7,7 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use super::{AccessCheckError, FlushError, GpuFuture}; +use super::{AccessCheckError, GpuFuture}; use crate::{ buffer::Buffer, command_buffer::{SemaphoreSubmitInfo, SubmitInfo}, @@ -19,7 +19,7 @@ use crate::{ future::{AccessError, SubmitAnyBuilder}, PipelineStages, }, - DeviceSize, VulkanError, + DeviceSize, Validated, ValidationError, VulkanError, }; use parking_lot::{Mutex, MutexGuard}; use std::{ @@ -160,7 +160,7 @@ where /// /// If the wait is successful, this function also cleans any resource locked by previous /// submissions. - pub fn wait(&self, timeout: Option) -> Result<(), FlushError> { + pub fn wait(&self, timeout: Option) -> Result<(), Validated> { let mut state = self.state.lock(); self.flush_impl(&mut state)?; @@ -211,7 +211,7 @@ where fn flush_impl( &self, state: &mut MutexGuard<'_, FenceSignalFutureState>, - ) -> Result<(), FlushError> { + ) -> Result<(), Validated> { unsafe { // In this function we temporarily replace the current state with `Poisoned` at the // beginning, and we take care to always put back a value into `state` before @@ -314,12 +314,18 @@ where }) .map_err(|err| OutcomeErr::Partial(err.into())) } else { - // VUID-VkPresentIdKHR-presentIds-04999 for swapchain_info in &present_info.swapchain_infos { if swapchain_info.present_id.map_or(false, |present_id| { !swapchain_info.swapchain.try_claim_present_id(present_id) }) { - return Err(FlushError::PresentIdLessThanOrEqual); + return Err(Box::new(ValidationError { + problem: "the provided `present_id` was not greater than any \ + `present`_id passed previously for the same swapchain" + .into(), + vuids: &["VUID-VkPresentIdKHR-presentIds-04999"], + ..Default::default() + }) + .into()); } match previous.check_swapchain_image_acquired( @@ -329,9 +335,21 @@ where ) { Ok(_) => (), Err(AccessCheckError::Unknown) => { - return Err(AccessError::SwapchainImageNotAcquired.into()) + return Err(Box::new(ValidationError { + problem: AccessError::SwapchainImageNotAcquired + .to_string() + .into(), + ..Default::default() + }) + .into()); + } + Err(AccessCheckError::Denied(err)) => { + return Err(Box::new(ValidationError { + problem: err.to_string().into(), + ..Default::default() + }) + .into()); } - Err(AccessCheckError::Denied(e)) => return Err(e.into()), } } @@ -414,7 +432,7 @@ where self.cleanup_finished_impl() } - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { let mut state = self.state.lock(); self.flush_impl(&mut state)?; @@ -433,7 +451,7 @@ where Ok(SubmitAnyBuilder::Empty) } - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { let mut state = self.state.lock(); self.flush_impl(&mut state) } @@ -569,13 +587,13 @@ where self.cleanup_finished_impl() } - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { // Note that this is sound because we always return `SubmitAnyBuilder::Empty`. See the // documentation of `build_submission`. (**self).build_submission() } - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { (**self).flush() } diff --git a/vulkano/src/sync/future/join.rs b/vulkano/src/sync/future/join.rs index 60f0ab090d..bf3d0c5383 100644 --- a/vulkano/src/sync/future/join.rs +++ b/vulkano/src/sync/future/join.rs @@ -7,13 +7,13 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder}; +use super::{AccessCheckError, GpuFuture, SubmitAnyBuilder}; use crate::{ buffer::Buffer, device::{Device, DeviceOwned, Queue}, image::{Image, ImageLayout}, swapchain::Swapchain, - DeviceSize, VulkanObject, + DeviceSize, Validated, VulkanError, VulkanObject, }; use std::{ops::Range, sync::Arc}; @@ -62,7 +62,7 @@ where self.second.cleanup_finished(); } - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { // Since each future remembers whether it has been flushed, there's no safety issue here // if we call this function multiple times. self.first.flush()?; @@ -71,7 +71,7 @@ where Ok(()) } - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { // TODO: review this function let first = self.first.build_submission()?; let second = self.second.build_submission()?; diff --git a/vulkano/src/sync/future/mod.rs b/vulkano/src/sync/future/mod.rs index 2692b3278d..64a074220a 100644 --- a/vulkano/src/sync/future/mod.rs +++ b/vulkano/src/sync/future/mod.rs @@ -100,14 +100,13 @@ use super::{fence::Fence, semaphore::Semaphore}; use crate::{ buffer::Buffer, command_buffer::{ - CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract, - ResourceUseRef, SubmitInfo, + CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract, SubmitInfo, }, device::{DeviceOwned, Queue}, image::{Image, ImageLayout}, memory::BindSparseInfo, swapchain::{self, PresentFuture, PresentInfo, Swapchain, SwapchainPresentInfo}, - DeviceSize, OomError, VulkanError, + DeviceSize, Validated, VulkanError, }; use smallvec::SmallVec; use std::{ @@ -158,14 +157,14 @@ pub unsafe trait GpuFuture: DeviceOwned { /// Once the caller has submitted the submission and has determined that the GPU has finished /// executing it, it should call `signal_finished`. Failure to do so will incur a large runtime /// overhead, as the future will have to block to make sure that it is finished. - unsafe fn build_submission(&self) -> Result; + unsafe fn build_submission(&self) -> Result>; /// Flushes the future and submits to the GPU the actions that will permit this future to /// occur. /// /// The implementation must remember that it was flushed. If the function is called multiple /// times, only the first time must result in a flush. - fn flush(&self) -> Result<(), FlushError>; + fn flush(&self) -> Result<(), Validated>; /// Sets the future to its "complete" state, meaning that it can safely be destroyed. /// @@ -297,7 +296,9 @@ pub unsafe trait GpuFuture: DeviceOwned { /// on two different queues, then you would need two submits anyway and it is always /// advantageous to submit A as soon as possible. #[inline] - fn then_signal_semaphore_and_flush(self) -> Result, FlushError> + fn then_signal_semaphore_and_flush( + self, + ) -> Result, Validated> where Self: Sized, { @@ -323,7 +324,7 @@ pub unsafe trait GpuFuture: DeviceOwned { /// /// This is a just a shortcut for `then_signal_fence()` followed with `flush()`. #[inline] - fn then_signal_fence_and_flush(self) -> Result, FlushError> + fn then_signal_fence_and_flush(self) -> Result, Validated> where Self: Sized, { @@ -405,11 +406,11 @@ where (**self).cleanup_finished() } - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { (**self).build_submission() } - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { (**self).flush() } @@ -478,9 +479,6 @@ impl SubmitAnyBuilder { /// Access to a resource was denied. #[derive(Clone, Debug, PartialEq, Eq)] pub enum AccessError { - /// Exclusive access is denied. - ExclusiveDenied, - /// The resource is already in use, and there is no tracking of concurrent usages. AlreadyInUse, @@ -496,9 +494,6 @@ pub enum AccessError { requested: ImageLayout, }, - /// Trying to use a buffer that still contains garbage data. - BufferNotInitialized, - /// Trying to use a swapchain image without depending on a corresponding acquire image future. SwapchainImageNotAcquired, } @@ -511,7 +506,6 @@ impl Display for AccessError { f, "{}", match self { - AccessError::ExclusiveDenied => "only shared access is allowed for this resource", AccessError::AlreadyInUse => { "the resource is already in use, and there is no tracking of concurrent usages" } @@ -522,9 +516,6 @@ impl Display for AccessError { "trying to use an image without transitioning it from the undefined or \ preinitialized layouts first" } - AccessError::BufferNotInitialized => { - "trying to use a buffer that still contains garbage data" - } AccessError::SwapchainImageNotAcquired => { "trying to use a swapchain image without depending on a corresponding acquire \ image future" @@ -563,123 +554,3 @@ impl From for AccessCheckError { AccessCheckError::Denied(err) } } - -/// Error that can happen when creating a graphics pipeline. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum FlushError { - /// Access to a resource has been denied. - AccessError(AccessError), - - /// Not enough memory. - OomError(OomError), - - /// The connection to the device has been lost. - DeviceLost, - - /// The surface is no longer accessible and must be recreated. - SurfaceLost, - - /// 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, - - /// The swapchain has lost or doesn't have full screen exclusivity possibly for - /// implementation-specific reasons outside of the application’s control. - FullScreenExclusiveModeLost, - - /// The flush operation needed to block, but the timeout has elapsed. - Timeout, - - /// A non-zero present_id must be greater than any non-zero present_id passed previously - /// for the same swapchain. - PresentIdLessThanOrEqual, - - /// A new present mode was provided, but this mode was not one of the valid present modes - /// that the swapchain was created with. - PresentModeNotValid, - - /// Access to a resource has been denied. - ResourceAccessError { - error: AccessError, - use_ref: Option, - }, - - /// The command buffer or one of the secondary command buffers it executes was created with the - /// "one time submit" flag, but has already been submitted it the past. - OneTimeSubmitAlreadySubmitted, - - /// The command buffer or one of the secondary command buffers it executes is already in use by - /// the GPU and was not created with the "concurrent" flag. - ExclusiveAlreadyInUse, -} - -impl Error for FlushError { - fn source(&self) -> Option<&(dyn Error + 'static)> { - match self { - Self::AccessError(err) => Some(err), - Self::OomError(err) => Some(err), - Self::ResourceAccessError { error, .. } => Some(error), - _ => None, - } - } -} - -impl Display for FlushError { - fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> { - write!( - f, - "{}", - match self { - Self::AccessError(_) => "access to a resource has been denied", - Self::OomError(_) => "not enough memory", - Self::DeviceLost => "the connection to the device has been lost", - Self::SurfaceLost => "the surface of this swapchain is no longer valid", - Self::OutOfDate => "the swapchain needs to be recreated", - Self::FullScreenExclusiveModeLost => { - "the swapchain no longer has full screen exclusivity" - } - Self::Timeout => { - "the flush operation needed to block, but the timeout has elapsed" - } - Self::PresentIdLessThanOrEqual => { - "present id is less than or equal to previous" - } - Self::PresentModeNotValid => { - "a new present mode was provided, but this mode was not one of the valid \ - present modes that the swapchain was created with" - } - Self::ResourceAccessError { .. } => "access to a resource has been denied", - Self::OneTimeSubmitAlreadySubmitted => { - "the command buffer or one of the secondary command buffers it executes was \ - created with the \"one time submit\" flag, but has already been submitted in \ - the past" - } - Self::ExclusiveAlreadyInUse => { - "the command buffer or one of the secondary command buffers it executes is \ - already in use was not created with the \"concurrent\" flag" - } - } - ) - } -} - -impl From for FlushError { - fn from(err: AccessError) -> FlushError { - Self::AccessError(err) - } -} - -impl From for FlushError { - fn from(err: VulkanError) -> Self { - match err { - VulkanError::OutOfHostMemory | VulkanError::OutOfDeviceMemory => { - Self::OomError(err.into()) - } - VulkanError::DeviceLost => Self::DeviceLost, - VulkanError::SurfaceLost => Self::SurfaceLost, - VulkanError::OutOfDate => Self::OutOfDate, - VulkanError::FullScreenExclusiveModeLost => Self::FullScreenExclusiveModeLost, - _ => panic!("unexpected error: {:?}", err), - } - } -} diff --git a/vulkano/src/sync/future/now.rs b/vulkano/src/sync/future/now.rs index 915f52a240..0cb4076c59 100644 --- a/vulkano/src/sync/future/now.rs +++ b/vulkano/src/sync/future/now.rs @@ -7,13 +7,13 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder}; +use super::{AccessCheckError, GpuFuture, SubmitAnyBuilder}; use crate::{ buffer::Buffer, device::{Device, DeviceOwned, Queue}, image::{Image, ImageLayout}, swapchain::Swapchain, - DeviceSize, + DeviceSize, Validated, VulkanError, }; use std::{ops::Range, sync::Arc}; @@ -33,12 +33,12 @@ unsafe impl GpuFuture for NowFuture { fn cleanup_finished(&mut self) {} #[inline] - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { Ok(SubmitAnyBuilder::Empty) } #[inline] - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { Ok(()) } diff --git a/vulkano/src/sync/future/semaphore_signal.rs b/vulkano/src/sync/future/semaphore_signal.rs index ee1fe4bda7..cb9a937fc9 100644 --- a/vulkano/src/sync/future/semaphore_signal.rs +++ b/vulkano/src/sync/future/semaphore_signal.rs @@ -7,7 +7,7 @@ // notice may not be copied, modified, or distributed except // according to those terms. -use super::{AccessCheckError, FlushError, GpuFuture, SubmitAnyBuilder}; +use super::{AccessCheckError, GpuFuture, SubmitAnyBuilder}; use crate::{ buffer::Buffer, command_buffer::{SemaphoreSubmitInfo, SubmitInfo}, @@ -15,7 +15,7 @@ use crate::{ image::{Image, ImageLayout}, swapchain::Swapchain, sync::{future::AccessError, semaphore::Semaphore, PipelineStages}, - DeviceSize, + DeviceSize, Validated, ValidationError, VulkanError, }; use parking_lot::Mutex; use smallvec::smallvec; @@ -69,7 +69,7 @@ where self.previous.cleanup_finished(); } - unsafe fn build_submission(&self) -> Result { + unsafe fn build_submission(&self) -> Result> { // Flushing the signaling part, since it must always be submitted before the waiting part. self.flush()?; let sem = smallvec![self.semaphore.clone()]; @@ -77,7 +77,7 @@ where Ok(SubmitAnyBuilder::SemaphoresWait(sem)) } - fn flush(&self) -> Result<(), FlushError> { + fn flush(&self) -> Result<(), Validated> { unsafe { let mut wait_submitted = self.wait_submitted.lock(); @@ -142,12 +142,18 @@ where builder.submit(&queue)?;*/ } SubmitAnyBuilder::QueuePresent(present_info) => { - // VUID-VkPresentIdKHR-presentIds-04999 for swapchain_info in &present_info.swapchain_infos { if swapchain_info.present_id.map_or(false, |present_id| { !swapchain_info.swapchain.try_claim_present_id(present_id) }) { - return Err(FlushError::PresentIdLessThanOrEqual); + return Err(Box::new(ValidationError { + problem: "the provided `present_id` was not greater than any \ + `present`_id passed previously for the same swapchain" + .into(), + vuids: &["VUID-VkPresentIdKHR-presentIds-04999"], + ..Default::default() + }) + .into()); } match self.previous.check_swapchain_image_acquired( @@ -157,9 +163,21 @@ where ) { Ok(_) => (), Err(AccessCheckError::Unknown) => { - return Err(AccessError::SwapchainImageNotAcquired.into()) + return Err(Box::new(ValidationError { + problem: AccessError::SwapchainImageNotAcquired + .to_string() + .into(), + ..Default::default() + }) + .into()); + } + Err(AccessCheckError::Denied(err)) => { + return Err(Box::new(ValidationError { + problem: err.to_string().into(), + ..Default::default() + }) + .into()); } - Err(AccessCheckError::Denied(e)) => return Err(e.into()), } } @@ -177,7 +195,7 @@ where }], None, )?; - Ok::<_, FlushError>(()) + Ok::<_, Validated>(()) })?; } }; diff --git a/vulkano/src/sync/mod.rs b/vulkano/src/sync/mod.rs index da85d29ace..102a0f5a7d 100644 --- a/vulkano/src/sync/mod.rs +++ b/vulkano/src/sync/mod.rs @@ -19,7 +19,7 @@ #[allow(unused)] pub(crate) use self::pipeline::{PipelineStageAccess, PipelineStageAccessFlags}; pub use self::{ - future::{now, FlushError, GpuFuture}, + future::{now, GpuFuture}, pipeline::{ AccessFlags, BufferMemoryBarrier, DependencyFlags, DependencyInfo, ImageMemoryBarrier, MemoryBarrier, PipelineStage, PipelineStages, QueueFamilyOwnershipTransfer, From 67a065ded3b0c5a862d6f9a46cb03d9d30f65ec2 Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 4 Aug 2023 21:20:30 +0200 Subject: [PATCH 6/8] Update vulkano/src/sync/future/semaphore_signal.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --- vulkano/src/sync/future/semaphore_signal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkano/src/sync/future/semaphore_signal.rs b/vulkano/src/sync/future/semaphore_signal.rs index cb9a937fc9..ea45232815 100644 --- a/vulkano/src/sync/future/semaphore_signal.rs +++ b/vulkano/src/sync/future/semaphore_signal.rs @@ -148,7 +148,7 @@ where }) { return Err(Box::new(ValidationError { problem: "the provided `present_id` was not greater than any \ - `present`_id passed previously for the same swapchain" + `present_id` passed previously for the same swapchain" .into(), vuids: &["VUID-VkPresentIdKHR-presentIds-04999"], ..Default::default() From 318dcec2c081010806ea02fe7d62c86960a83423 Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 4 Aug 2023 21:20:36 +0200 Subject: [PATCH 7/8] Update vulkano/src/swapchain/acquire_present.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --- vulkano/src/swapchain/acquire_present.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkano/src/swapchain/acquire_present.rs b/vulkano/src/swapchain/acquire_present.rs index 7370d8ac05..c1458c2103 100644 --- a/vulkano/src/swapchain/acquire_present.rs +++ b/vulkano/src/swapchain/acquire_present.rs @@ -637,7 +637,7 @@ where }) { return Err(Box::new(ValidationError { problem: "the provided `present_id` was not greater than any \ - `present`_id passed previously for the same swapchain" + `present_id` passed previously for the same swapchain" .into(), vuids: &["VUID-VkPresentIdKHR-presentIds-04999"], ..Default::default() From 72124b35dfa0ec4e7c60e92d71cda5a63ac5acf3 Mon Sep 17 00:00:00 2001 From: Rua Date: Fri, 4 Aug 2023 21:20:41 +0200 Subject: [PATCH 8/8] Update vulkano/src/sync/future/fence_signal.rs Co-authored-by: marc0246 <40955683+marc0246@users.noreply.github.com> --- vulkano/src/sync/future/fence_signal.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vulkano/src/sync/future/fence_signal.rs b/vulkano/src/sync/future/fence_signal.rs index 9520516042..73e4d1b46f 100644 --- a/vulkano/src/sync/future/fence_signal.rs +++ b/vulkano/src/sync/future/fence_signal.rs @@ -320,7 +320,7 @@ where }) { return Err(Box::new(ValidationError { problem: "the provided `present_id` was not greater than any \ - `present`_id passed previously for the same swapchain" + `present_id` passed previously for the same swapchain" .into(), vuids: &["VUID-VkPresentIdKHR-presentIds-04999"], ..Default::default()