1 // Copyright (c) 2016 The vulkano developers
2 // Licensed under the Apache License, Version 2.0
3 // <LICENSE-APACHE or
4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT
5 // license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
6 // at your option. All files in the project carrying such
7 // notice may not be copied, modified, or distributed except
8 // according to those terms.
9 
10 //! A fence provides synchronization between the device and the host, or between an external source
11 //! and the host.
12 
13 use crate::{
14     device::{Device, DeviceOwned, Queue},
15     macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
16     OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
17 };
18 use parking_lot::{Mutex, MutexGuard};
19 use smallvec::SmallVec;
20 #[cfg(unix)]
21 use std::fs::File;
22 use std::{
23     error::Error,
24     fmt::{Display, Error as FmtError, Formatter},
25     future::Future,
26     mem::MaybeUninit,
27     num::NonZeroU64,
28     pin::Pin,
29     ptr,
30     sync::{Arc, Weak},
31     task::{Context, Poll},
32     time::Duration,
33 };
34 
35 /// A two-state synchronization primitive that is signalled by the device and waited on by the host.
36 ///
37 /// # Queue-to-host synchronization
38 ///
39 /// The primary use of a fence is to know when execution of a queue has reached a particular point.
40 /// When adding a command to a queue, a fence can be provided with the command, to be signaled
41 /// when the operation finishes. You can check for a fence's current status by calling
42 /// `is_signaled`, `wait` or `await` on it. If the fence is found to be signaled, that means that
43 /// the queue has completed the operation that is associated with the fence, and all operations that
44 /// were submitted before it have been completed as well.
45 ///
46 /// When a queue command accesses a resource, it must be kept alive until the queue command has
47 /// finished executing, and you may not be allowed to perform certain other operations (or even any)
48 /// while the resource is in use. By calling `is_signaled`, `wait` or `await`, the queue will be
49 /// notified when the fence is signaled, so that all resources of the associated queue operation and
50 /// preceding operations can be released.
51 ///
52 /// Because of this, it is highly recommended to call `is_signaled`, `wait` or `await` on your fences.
53 /// Otherwise, the queue will hold onto resources indefinitely (using up memory)
54 /// and resource locks will not be released, which may cause errors when submitting future
55 /// queue operations. It is not strictly necessary to wait for *every* fence, as a fence
56 /// that was signaled later in the queue will automatically clean up resources associated with
57 /// earlier fences too.
58 #[derive(Debug)]
59 pub struct Fence {
60     handle: ash::vk::Fence,
61     device: Arc<Device>,
62     id: NonZeroU64,
63     must_put_in_pool: bool,
64 
65     export_handle_types: ExternalFenceHandleTypes,
66 
67     state: Mutex<FenceState>,
68 }
69 
70 impl Fence {
71     /// Creates a new `Fence`.
72     #[inline]
new(device: Arc<Device>, create_info: FenceCreateInfo) -> Result<Fence, FenceError>73     pub fn new(device: Arc<Device>, create_info: FenceCreateInfo) -> Result<Fence, FenceError> {
74         Self::validate_new(&device, &create_info)?;
75 
76         unsafe { Ok(Self::new_unchecked(device, create_info)?) }
77     }
78 
validate_new(device: &Device, create_info: &FenceCreateInfo) -> Result<(), FenceError>79     fn validate_new(device: &Device, create_info: &FenceCreateInfo) -> Result<(), FenceError> {
80         let &FenceCreateInfo {
81             signaled: _,
82             export_handle_types,
83             _ne: _,
84         } = create_info;
85 
86         if !export_handle_types.is_empty() {
87             if !(device.api_version() >= Version::V1_1
88                 || device.enabled_extensions().khr_external_fence)
89             {
90                 return Err(FenceError::RequirementNotMet {
91                     required_for: "`create_info.export_handle_types` is not empty",
92                     requires_one_of: RequiresOneOf {
93                         api_version: Some(Version::V1_1),
94                         device_extensions: &["khr_external_fence"],
95                         ..Default::default()
96                     },
97                 });
98             }
99 
100             // VUID-VkExportFenceCreateInfo-handleTypes-01446
101             export_handle_types.validate_device(device)?;
102 
103             // VUID-VkExportFenceCreateInfo-handleTypes-01446
104             for handle_type in export_handle_types.into_iter() {
105                 let external_fence_properties = unsafe {
106                     device
107                         .physical_device()
108                         .external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
109                             handle_type,
110                         ))
111                 };
112 
113                 if !external_fence_properties.exportable {
114                     return Err(FenceError::HandleTypeNotExportable { handle_type });
115                 }
116 
117                 if !external_fence_properties
118                     .compatible_handle_types
119                     .contains(export_handle_types)
120                 {
121                     return Err(FenceError::ExportHandleTypesNotCompatible);
122                 }
123             }
124         }
125 
126         Ok(())
127     }
128 
129     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
130     #[inline]
new_unchecked( device: Arc<Device>, create_info: FenceCreateInfo, ) -> Result<Fence, VulkanError>131     pub unsafe fn new_unchecked(
132         device: Arc<Device>,
133         create_info: FenceCreateInfo,
134     ) -> Result<Fence, VulkanError> {
135         let FenceCreateInfo {
136             signaled,
137             export_handle_types,
138             _ne: _,
139         } = create_info;
140 
141         let mut flags = ash::vk::FenceCreateFlags::empty();
142 
143         if signaled {
144             flags |= ash::vk::FenceCreateFlags::SIGNALED;
145         }
146 
147         let mut create_info_vk = ash::vk::FenceCreateInfo {
148             flags,
149             ..Default::default()
150         };
151         let mut export_fence_create_info_vk = None;
152 
153         if !export_handle_types.is_empty() {
154             let _ = export_fence_create_info_vk.insert(ash::vk::ExportFenceCreateInfo {
155                 handle_types: export_handle_types.into(),
156                 ..Default::default()
157             });
158         }
159 
160         if let Some(info) = export_fence_create_info_vk.as_mut() {
161             info.p_next = create_info_vk.p_next;
162             create_info_vk.p_next = info as *const _ as *const _;
163         }
164 
165         let handle = {
166             let fns = device.fns();
167             let mut output = MaybeUninit::uninit();
168             (fns.v1_0.create_fence)(
169                 device.handle(),
170                 &create_info_vk,
171                 ptr::null(),
172                 output.as_mut_ptr(),
173             )
174             .result()
175             .map_err(VulkanError::from)?;
176 
177             output.assume_init()
178         };
179 
180         Ok(Fence {
181             handle,
182             device,
183             id: Self::next_id(),
184             must_put_in_pool: false,
185             export_handle_types,
186             state: Mutex::new(FenceState {
187                 is_signaled: signaled,
188                 ..Default::default()
189             }),
190         })
191     }
192 
193     /// Takes a fence from the vulkano-provided fence pool.
194     /// If the pool is empty, a new fence will be created.
195     /// Upon `drop`, the fence is put back into the pool.
196     ///
197     /// For most applications, using the fence pool should be preferred,
198     /// in order to avoid creating new fences every frame.
199     #[inline]
from_pool(device: Arc<Device>) -> Result<Fence, FenceError>200     pub fn from_pool(device: Arc<Device>) -> Result<Fence, FenceError> {
201         let handle = device.fence_pool().lock().pop();
202         let fence = match handle {
203             Some(handle) => {
204                 unsafe {
205                     // Make sure the fence isn't signaled
206                     let fns = device.fns();
207                     (fns.v1_0.reset_fences)(device.handle(), 1, &handle)
208                         .result()
209                         .map_err(VulkanError::from)?;
210                 }
211 
212                 Fence {
213                     handle,
214                     device,
215                     id: Self::next_id(),
216                     must_put_in_pool: true,
217                     export_handle_types: ExternalFenceHandleTypes::empty(),
218                     state: Mutex::new(Default::default()),
219                 }
220             }
221             None => {
222                 // Pool is empty, alloc new fence
223                 let mut fence = Fence::new(device, FenceCreateInfo::default())?;
224                 fence.must_put_in_pool = true;
225                 fence
226             }
227         };
228 
229         Ok(fence)
230     }
231 
232     /// Creates a new `Fence` from a raw object handle.
233     ///
234     /// # Safety
235     ///
236     /// - `handle` must be a valid Vulkan object handle created from `device`.
237     /// - `create_info` must match the info used to create the object.
238     #[inline]
from_handle( device: Arc<Device>, handle: ash::vk::Fence, create_info: FenceCreateInfo, ) -> Fence239     pub unsafe fn from_handle(
240         device: Arc<Device>,
241         handle: ash::vk::Fence,
242         create_info: FenceCreateInfo,
243     ) -> Fence {
244         let FenceCreateInfo {
245             signaled,
246             export_handle_types,
247             _ne: _,
248         } = create_info;
249 
250         Fence {
251             handle,
252             device,
253             id: Self::next_id(),
254             must_put_in_pool: false,
255             export_handle_types,
256             state: Mutex::new(FenceState {
257                 is_signaled: signaled,
258                 ..Default::default()
259             }),
260         }
261     }
262 
263     /// Returns true if the fence is signaled.
264     #[inline]
is_signaled(&self) -> Result<bool, OomError>265     pub fn is_signaled(&self) -> Result<bool, OomError> {
266         let queue_to_signal = {
267             let mut state = self.state();
268 
269             // If the fence is already signaled, or it's unsignaled but there's no queue that
270             // could signal it, return the currently known value.
271             if let Some(is_signaled) = state.is_signaled() {
272                 return Ok(is_signaled);
273             }
274 
275             // We must ask Vulkan for the state.
276             let result = unsafe {
277                 let fns = self.device.fns();
278                 (fns.v1_0.get_fence_status)(self.device.handle(), self.handle)
279             };
280 
281             match result {
282                 ash::vk::Result::SUCCESS => unsafe { state.set_signaled() },
283                 ash::vk::Result::NOT_READY => return Ok(false),
284                 err => return Err(VulkanError::from(err).into()),
285             }
286         };
287 
288         // If we have a queue that we need to signal our status to,
289         // do so now after the state lock is dropped, to avoid deadlocks.
290         if let Some(queue) = queue_to_signal {
291             unsafe {
292                 queue.with(|mut q| q.fence_signaled(self));
293             }
294         }
295 
296         Ok(true)
297     }
298 
299     /// Waits until the fence is signaled, or at least until the timeout duration has elapsed.
300     ///
301     /// Returns `Ok` if the fence is now signaled. Returns `Err` if the timeout was reached instead.
302     ///
303     /// If you pass a duration of 0, then the function will return without blocking.
wait(&self, timeout: Option<Duration>) -> Result<(), FenceError>304     pub fn wait(&self, timeout: Option<Duration>) -> Result<(), FenceError> {
305         let queue_to_signal = {
306             let mut state = self.state.lock();
307 
308             // If the fence is already signaled, we don't need to wait.
309             if state.is_signaled().unwrap_or(false) {
310                 return Ok(());
311             }
312 
313             let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
314                 timeout
315                     .as_secs()
316                     .saturating_mul(1_000_000_000)
317                     .saturating_add(timeout.subsec_nanos() as u64)
318             });
319 
320             let result = unsafe {
321                 let fns = self.device.fns();
322                 (fns.v1_0.wait_for_fences)(
323                     self.device.handle(),
324                     1,
325                     &self.handle,
326                     ash::vk::TRUE,
327                     timeout_ns,
328                 )
329             };
330 
331             match result {
332                 ash::vk::Result::SUCCESS => unsafe { state.set_signaled() },
333                 ash::vk::Result::TIMEOUT => return Err(FenceError::Timeout),
334                 err => return Err(VulkanError::from(err).into()),
335             }
336         };
337 
338         // If we have a queue that we need to signal our status to,
339         // do so now after the state lock is dropped, to avoid deadlocks.
340         if let Some(queue) = queue_to_signal {
341             unsafe {
342                 queue.with(|mut q| q.fence_signaled(self));
343             }
344         }
345 
346         Ok(())
347     }
348 
349     /// Waits for multiple fences at once.
350     ///
351     /// # Panics
352     ///
353     /// - Panics if not all fences belong to the same device.
multi_wait<'a>( fences: impl IntoIterator<Item = &'a Fence>, timeout: Option<Duration>, ) -> Result<(), FenceError>354     pub fn multi_wait<'a>(
355         fences: impl IntoIterator<Item = &'a Fence>,
356         timeout: Option<Duration>,
357     ) -> Result<(), FenceError> {
358         let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
359         Self::validate_multi_wait(&fences, timeout)?;
360 
361         unsafe { Self::multi_wait_unchecked(fences, timeout) }
362     }
363 
validate_multi_wait( fences: &[&Fence], _timeout: Option<Duration>, ) -> Result<(), FenceError>364     fn validate_multi_wait(
365         fences: &[&Fence],
366         _timeout: Option<Duration>,
367     ) -> Result<(), FenceError> {
368         if fences.is_empty() {
369             return Ok(());
370         }
371 
372         let device = &fences[0].device;
373 
374         for fence in fences {
375             // VUID-vkWaitForFences-pFences-parent
376             assert_eq!(device, &fence.device);
377         }
378 
379         Ok(())
380     }
381 
382     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
multi_wait_unchecked<'a>( fences: impl IntoIterator<Item = &'a Fence>, timeout: Option<Duration>, ) -> Result<(), FenceError>383     pub unsafe fn multi_wait_unchecked<'a>(
384         fences: impl IntoIterator<Item = &'a Fence>,
385         timeout: Option<Duration>,
386     ) -> Result<(), FenceError> {
387         let queues_to_signal: SmallVec<[_; 8]> = {
388             let iter = fences.into_iter();
389             let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new();
390             let mut fences: SmallVec<[_; 8]> = SmallVec::new();
391             let mut states: SmallVec<[_; 8]> = SmallVec::new();
392 
393             for fence in iter {
394                 let state = fence.state.lock();
395 
396                 // Skip the fences that are already signaled.
397                 if !state.is_signaled().unwrap_or(false) {
398                     fences_vk.push(fence.handle);
399                     fences.push(fence);
400                     states.push(state);
401                 }
402             }
403 
404             // VUID-vkWaitForFences-fenceCount-arraylength
405             // If there are no fences, or all the fences are signaled, we don't need to wait.
406             if fences_vk.is_empty() {
407                 return Ok(());
408             }
409 
410             let device = &fences[0].device;
411             let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
412                 timeout
413                     .as_secs()
414                     .saturating_mul(1_000_000_000)
415                     .saturating_add(timeout.subsec_nanos() as u64)
416             });
417 
418             let result = {
419                 let fns = device.fns();
420                 (fns.v1_0.wait_for_fences)(
421                     device.handle(),
422                     fences_vk.len() as u32,
423                     fences_vk.as_ptr(),
424                     ash::vk::TRUE, // TODO: let the user choose false here?
425                     timeout_ns,
426                 )
427             };
428 
429             match result {
430                 ash::vk::Result::SUCCESS => fences
431                     .into_iter()
432                     .zip(&mut states)
433                     .filter_map(|(fence, state)| state.set_signaled().map(|state| (state, fence)))
434                     .collect(),
435                 ash::vk::Result::TIMEOUT => return Err(FenceError::Timeout),
436                 err => return Err(VulkanError::from(err).into()),
437             }
438         };
439 
440         // If we have queues that we need to signal our status to,
441         // do so now after the state locks are dropped, to avoid deadlocks.
442         for (queue, fence) in queues_to_signal {
443             queue.with(|mut q| q.fence_signaled(fence));
444         }
445 
446         Ok(())
447     }
448 
449     /// Resets the fence.
450     ///
451     /// The fence must not be in use by a queue operation.
452     #[inline]
reset(&self) -> Result<(), FenceError>453     pub fn reset(&self) -> Result<(), FenceError> {
454         let mut state = self.state.lock();
455         self.validate_reset(&state)?;
456 
457         unsafe { Ok(self.reset_unchecked_locked(&mut state)?) }
458     }
459 
validate_reset(&self, state: &FenceState) -> Result<(), FenceError>460     fn validate_reset(&self, state: &FenceState) -> Result<(), FenceError> {
461         // VUID-vkResetFences-pFences-01123
462         if state.is_in_queue() {
463             return Err(FenceError::InQueue);
464         }
465 
466         Ok(())
467     }
468 
469     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
470     #[inline]
reset_unchecked(&self) -> Result<(), VulkanError>471     pub unsafe fn reset_unchecked(&self) -> Result<(), VulkanError> {
472         let mut state = self.state.lock();
473 
474         self.reset_unchecked_locked(&mut state)
475     }
476 
reset_unchecked_locked(&self, state: &mut FenceState) -> Result<(), VulkanError>477     unsafe fn reset_unchecked_locked(&self, state: &mut FenceState) -> Result<(), VulkanError> {
478         let fns = self.device.fns();
479         (fns.v1_0.reset_fences)(self.device.handle(), 1, &self.handle)
480             .result()
481             .map_err(VulkanError::from)?;
482 
483         state.reset();
484 
485         Ok(())
486     }
487 
488     /// Resets multiple fences at once.
489     ///
490     /// The fences must not be in use by a queue operation.
491     ///
492     /// # Panics
493     ///
494     /// - Panics if not all fences belong to the same device.
multi_reset<'a>(fences: impl IntoIterator<Item = &'a Fence>) -> Result<(), FenceError>495     pub fn multi_reset<'a>(fences: impl IntoIterator<Item = &'a Fence>) -> Result<(), FenceError> {
496         let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences
497             .into_iter()
498             .map(|fence| {
499                 let state = fence.state.lock();
500                 (fence, state)
501             })
502             .unzip();
503         Self::validate_multi_reset(&fences, &states)?;
504 
505         unsafe { Ok(Self::multi_reset_unchecked_locked(&fences, &mut states)?) }
506     }
507 
validate_multi_reset( fences: &[&Fence], states: &[MutexGuard<'_, FenceState>], ) -> Result<(), FenceError>508     fn validate_multi_reset(
509         fences: &[&Fence],
510         states: &[MutexGuard<'_, FenceState>],
511     ) -> Result<(), FenceError> {
512         if fences.is_empty() {
513             return Ok(());
514         }
515 
516         let device = &fences[0].device;
517 
518         for (fence, state) in fences.iter().zip(states) {
519             // VUID-vkResetFences-pFences-parent
520             assert_eq!(device, &fence.device);
521 
522             // VUID-vkResetFences-pFences-01123
523             if state.is_in_queue() {
524                 return Err(FenceError::InQueue);
525             }
526         }
527 
528         Ok(())
529     }
530 
531     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
multi_reset_unchecked<'a>( fences: impl IntoIterator<Item = &'a Fence>, ) -> Result<(), VulkanError>532     pub unsafe fn multi_reset_unchecked<'a>(
533         fences: impl IntoIterator<Item = &'a Fence>,
534     ) -> Result<(), VulkanError> {
535         let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences
536             .into_iter()
537             .map(|fence| {
538                 let state = fence.state.lock();
539                 (fence, state)
540             })
541             .unzip();
542 
543         Self::multi_reset_unchecked_locked(&fences, &mut states)
544     }
545 
multi_reset_unchecked_locked( fences: &[&Fence], states: &mut [MutexGuard<'_, FenceState>], ) -> Result<(), VulkanError>546     unsafe fn multi_reset_unchecked_locked(
547         fences: &[&Fence],
548         states: &mut [MutexGuard<'_, FenceState>],
549     ) -> Result<(), VulkanError> {
550         if fences.is_empty() {
551             return Ok(());
552         }
553 
554         let device = &fences[0].device;
555         let fences_vk: SmallVec<[_; 8]> = fences.iter().map(|fence| fence.handle).collect();
556 
557         let fns = device.fns();
558         (fns.v1_0.reset_fences)(device.handle(), fences_vk.len() as u32, fences_vk.as_ptr())
559             .result()
560             .map_err(VulkanError::from)?;
561 
562         for state in states {
563             state.reset();
564         }
565 
566         Ok(())
567     }
568 
569     /// Exports the fence into a POSIX file descriptor. The caller owns the returned `File`.
570     ///
571     /// The [`khr_external_fence_fd`](crate::device::DeviceExtensions::khr_external_fence_fd)
572     /// extension must be enabled on the device.
573     #[cfg(unix)]
574     #[inline]
export_fd(&self, handle_type: ExternalFenceHandleType) -> Result<File, FenceError>575     pub fn export_fd(&self, handle_type: ExternalFenceHandleType) -> Result<File, FenceError> {
576         let mut state = self.state.lock();
577         self.validate_export_fd(handle_type, &state)?;
578 
579         unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
580     }
581 
582     #[cfg(unix)]
validate_export_fd( &self, handle_type: ExternalFenceHandleType, state: &FenceState, ) -> Result<(), FenceError>583     fn validate_export_fd(
584         &self,
585         handle_type: ExternalFenceHandleType,
586         state: &FenceState,
587     ) -> Result<(), FenceError> {
588         if !self.device.enabled_extensions().khr_external_fence_fd {
589             return Err(FenceError::RequirementNotMet {
590                 required_for: "`Fence::export_fd`",
591                 requires_one_of: RequiresOneOf {
592                     device_extensions: &["khr_external_fence_fd"],
593                     ..Default::default()
594                 },
595             });
596         }
597 
598         // VUID-VkFenceGetFdInfoKHR-handleType-parameter
599         handle_type.validate_device(&self.device)?;
600 
601         // VUID-VkFenceGetFdInfoKHR-handleType-01453
602         if !self.export_handle_types.intersects(handle_type.into()) {
603             return Err(FenceError::HandleTypeNotEnabled);
604         }
605 
606         // VUID-VkFenceGetFdInfoKHR-handleType-01454
607         if handle_type.has_copy_transference()
608             && !(state.is_signaled().unwrap_or(false) || state.is_in_queue())
609         {
610             return Err(FenceError::HandleTypeCopyNotSignaled);
611         }
612 
613         // VUID-VkFenceGetFdInfoKHR-fence-01455
614         if let Some(imported_handle_type) = state.current_import {
615             match imported_handle_type {
616                 ImportType::SwapchainAcquire => {
617                     return Err(FenceError::ImportedForSwapchainAcquire)
618                 }
619                 ImportType::ExternalFence(imported_handle_type) => {
620                     let external_fence_properties = unsafe {
621                         self.device
622                             .physical_device()
623                             .external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
624                                 handle_type,
625                             ))
626                     };
627 
628                     if !external_fence_properties
629                         .export_from_imported_handle_types
630                         .intersects(imported_handle_type.into())
631                     {
632                         return Err(FenceError::ExportFromImportedNotSupported {
633                             imported_handle_type,
634                         });
635                     }
636                 }
637             }
638         }
639 
640         // VUID-VkFenceGetFdInfoKHR-handleType-01456
641         if !matches!(
642             handle_type,
643             ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd
644         ) {
645             return Err(FenceError::HandleTypeNotFd);
646         }
647 
648         Ok(())
649     }
650 
651     #[cfg(unix)]
652     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
653     #[inline]
export_fd_unchecked( &self, handle_type: ExternalFenceHandleType, ) -> Result<File, VulkanError>654     pub unsafe fn export_fd_unchecked(
655         &self,
656         handle_type: ExternalFenceHandleType,
657     ) -> Result<File, VulkanError> {
658         let mut state = self.state.lock();
659         self.export_fd_unchecked_locked(handle_type, &mut state)
660     }
661 
662     #[cfg(unix)]
export_fd_unchecked_locked( &self, handle_type: ExternalFenceHandleType, state: &mut FenceState, ) -> Result<File, VulkanError>663     unsafe fn export_fd_unchecked_locked(
664         &self,
665         handle_type: ExternalFenceHandleType,
666         state: &mut FenceState,
667     ) -> Result<File, VulkanError> {
668         use std::os::unix::io::FromRawFd;
669 
670         let info_vk = ash::vk::FenceGetFdInfoKHR {
671             fence: self.handle,
672             handle_type: handle_type.into(),
673             ..Default::default()
674         };
675 
676         let mut output = MaybeUninit::uninit();
677         let fns = self.device.fns();
678         (fns.khr_external_fence_fd.get_fence_fd_khr)(
679             self.device.handle(),
680             &info_vk,
681             output.as_mut_ptr(),
682         )
683         .result()
684         .map_err(VulkanError::from)?;
685 
686         state.export(handle_type);
687 
688         Ok(File::from_raw_fd(output.assume_init()))
689     }
690 
691     /// Exports the fence into a Win32 handle.
692     ///
693     /// The [`khr_external_fence_win32`](crate::device::DeviceExtensions::khr_external_fence_win32)
694     /// extension must be enabled on the device.
695     #[cfg(windows)]
696     #[inline]
export_win32_handle( &self, handle_type: ExternalFenceHandleType, ) -> Result<*mut std::ffi::c_void, FenceError>697     pub fn export_win32_handle(
698         &self,
699         handle_type: ExternalFenceHandleType,
700     ) -> Result<*mut std::ffi::c_void, FenceError> {
701         let mut state = self.state.lock();
702         self.validate_export_win32_handle(handle_type, &state)?;
703 
704         unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
705     }
706 
707     #[cfg(windows)]
validate_export_win32_handle( &self, handle_type: ExternalFenceHandleType, state: &FenceState, ) -> Result<(), FenceError>708     fn validate_export_win32_handle(
709         &self,
710         handle_type: ExternalFenceHandleType,
711         state: &FenceState,
712     ) -> Result<(), FenceError> {
713         if !self.device.enabled_extensions().khr_external_fence_win32 {
714             return Err(FenceError::RequirementNotMet {
715                 required_for: "`Fence::export_win32_handle`",
716                 requires_one_of: RequiresOneOf {
717                     device_extensions: &["khr_external_fence_win32"],
718                     ..Default::default()
719                 },
720             });
721         }
722 
723         // VUID-VkFenceGetWin32HandleInfoKHR-handleType-parameter
724         handle_type.validate_device(&self.device)?;
725 
726         // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01448
727         if !self.export_handle_types.intersects(handle_type.into()) {
728             return Err(FenceError::HandleTypeNotEnabled);
729         }
730 
731         // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01449
732         if matches!(handle_type, ExternalFenceHandleType::OpaqueWin32)
733             && state.is_exported(handle_type)
734         {
735             return Err(FenceError::AlreadyExported);
736         }
737 
738         // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01451
739         if handle_type.has_copy_transference()
740             && !(state.is_signaled().unwrap_or(false) || state.is_in_queue())
741         {
742             return Err(FenceError::HandleTypeCopyNotSignaled);
743         }
744 
745         // VUID-VkFenceGetWin32HandleInfoKHR-fence-01450
746         if let Some(imported_handle_type) = state.current_import {
747             match imported_handle_type {
748                 ImportType::SwapchainAcquire => {
749                     return Err(FenceError::ImportedForSwapchainAcquire)
750                 }
751                 ImportType::ExternalFence(imported_handle_type) => {
752                     let external_fence_properties = unsafe {
753                         self.device
754                             .physical_device()
755                             .external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
756                                 handle_type,
757                             ))
758                     };
759 
760                     if !external_fence_properties
761                         .export_from_imported_handle_types
762                         .intersects(imported_handle_type.into())
763                     {
764                         return Err(FenceError::ExportFromImportedNotSupported {
765                             imported_handle_type,
766                         });
767                     }
768                 }
769             }
770         }
771 
772         // VUID-VkFenceGetWin32HandleInfoKHR-handleType-01452
773         if !matches!(
774             handle_type,
775             ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt
776         ) {
777             return Err(FenceError::HandleTypeNotWin32);
778         }
779 
780         Ok(())
781     }
782 
783     #[cfg(windows)]
784     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
785     #[inline]
export_win32_handle_unchecked( &self, handle_type: ExternalFenceHandleType, ) -> Result<*mut std::ffi::c_void, VulkanError>786     pub unsafe fn export_win32_handle_unchecked(
787         &self,
788         handle_type: ExternalFenceHandleType,
789     ) -> Result<*mut std::ffi::c_void, VulkanError> {
790         let mut state = self.state.lock();
791         self.export_win32_handle_unchecked_locked(handle_type, &mut state)
792     }
793 
794     #[cfg(windows)]
export_win32_handle_unchecked_locked( &self, handle_type: ExternalFenceHandleType, state: &mut FenceState, ) -> Result<*mut std::ffi::c_void, VulkanError>795     unsafe fn export_win32_handle_unchecked_locked(
796         &self,
797         handle_type: ExternalFenceHandleType,
798         state: &mut FenceState,
799     ) -> Result<*mut std::ffi::c_void, VulkanError> {
800         let info_vk = ash::vk::FenceGetWin32HandleInfoKHR {
801             fence: self.handle,
802             handle_type: handle_type.into(),
803             ..Default::default()
804         };
805 
806         let mut output = MaybeUninit::uninit();
807         let fns = self.device.fns();
808         (fns.khr_external_fence_win32.get_fence_win32_handle_khr)(
809             self.device.handle(),
810             &info_vk,
811             output.as_mut_ptr(),
812         )
813         .result()
814         .map_err(VulkanError::from)?;
815 
816         state.export(handle_type);
817 
818         Ok(output.assume_init())
819     }
820 
821     /// Imports a fence from a POSIX file descriptor.
822     ///
823     /// The [`khr_external_fence_fd`](crate::device::DeviceExtensions::khr_external_fence_fd)
824     /// extension must be enabled on the device.
825     ///
826     /// # Safety
827     ///
828     /// - If in `import_fence_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
829     ///   then `file` must represent a fence that was exported from Vulkan or a compatible API,
830     ///   with a driver and device UUID equal to those of the device that owns `self`.
831     #[cfg(unix)]
832     #[inline]
import_fd( &self, import_fence_fd_info: ImportFenceFdInfo, ) -> Result<(), FenceError>833     pub unsafe fn import_fd(
834         &self,
835         import_fence_fd_info: ImportFenceFdInfo,
836     ) -> Result<(), FenceError> {
837         let mut state = self.state.lock();
838         self.validate_import_fd(&import_fence_fd_info, &state)?;
839 
840         Ok(self.import_fd_unchecked_locked(import_fence_fd_info, &mut state)?)
841     }
842 
843     #[cfg(unix)]
validate_import_fd( &self, import_fence_fd_info: &ImportFenceFdInfo, state: &FenceState, ) -> Result<(), FenceError>844     fn validate_import_fd(
845         &self,
846         import_fence_fd_info: &ImportFenceFdInfo,
847         state: &FenceState,
848     ) -> Result<(), FenceError> {
849         if !self.device.enabled_extensions().khr_external_fence_fd {
850             return Err(FenceError::RequirementNotMet {
851                 required_for: "`Fence::import_fd`",
852                 requires_one_of: RequiresOneOf {
853                     device_extensions: &["khr_external_fence_fd"],
854                     ..Default::default()
855                 },
856             });
857         }
858 
859         // VUID-vkImportFenceFdKHR-fence-01463
860         if state.is_in_queue() {
861             return Err(FenceError::InQueue);
862         }
863 
864         let &ImportFenceFdInfo {
865             flags,
866             handle_type,
867             file: _,
868             _ne: _,
869         } = import_fence_fd_info;
870 
871         // VUID-VkImportFenceFdInfoKHR-flags-parameter
872         flags.validate_device(&self.device)?;
873 
874         // VUID-VkImportFenceFdInfoKHR-handleType-parameter
875         handle_type.validate_device(&self.device)?;
876 
877         // VUID-VkImportFenceFdInfoKHR-handleType-01464
878         if !matches!(
879             handle_type,
880             ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd
881         ) {
882             return Err(FenceError::HandleTypeNotFd);
883         }
884 
885         // VUID-VkImportFenceFdInfoKHR-fd-01541
886         // Can't validate, therefore unsafe
887 
888         // VUID-VkImportFenceFdInfoKHR-handleType-07306
889         if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) {
890             return Err(FenceError::HandletypeCopyNotTemporary);
891         }
892 
893         Ok(())
894     }
895 
896     #[cfg(unix)]
897     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
898     #[inline]
import_fd_unchecked( &self, import_fence_fd_info: ImportFenceFdInfo, ) -> Result<(), VulkanError>899     pub unsafe fn import_fd_unchecked(
900         &self,
901         import_fence_fd_info: ImportFenceFdInfo,
902     ) -> Result<(), VulkanError> {
903         let mut state = self.state.lock();
904         self.import_fd_unchecked_locked(import_fence_fd_info, &mut state)
905     }
906 
907     #[cfg(unix)]
import_fd_unchecked_locked( &self, import_fence_fd_info: ImportFenceFdInfo, state: &mut FenceState, ) -> Result<(), VulkanError>908     unsafe fn import_fd_unchecked_locked(
909         &self,
910         import_fence_fd_info: ImportFenceFdInfo,
911         state: &mut FenceState,
912     ) -> Result<(), VulkanError> {
913         use std::os::unix::io::IntoRawFd;
914 
915         let ImportFenceFdInfo {
916             flags,
917             handle_type,
918             file,
919             _ne: _,
920         } = import_fence_fd_info;
921 
922         let info_vk = ash::vk::ImportFenceFdInfoKHR {
923             fence: self.handle,
924             flags: flags.into(),
925             handle_type: handle_type.into(),
926             fd: file.map_or(-1, |file| file.into_raw_fd()),
927             ..Default::default()
928         };
929 
930         let fns = self.device.fns();
931         (fns.khr_external_fence_fd.import_fence_fd_khr)(self.device.handle(), &info_vk)
932             .result()
933             .map_err(VulkanError::from)?;
934 
935         state.import(handle_type, flags.intersects(FenceImportFlags::TEMPORARY));
936 
937         Ok(())
938     }
939 
940     /// Imports a fence from a Win32 handle.
941     ///
942     /// The [`khr_external_fence_win32`](crate::device::DeviceExtensions::khr_external_fence_win32)
943     /// extension must be enabled on the device.
944     ///
945     /// # Safety
946     ///
947     /// - In `import_fence_win32_handle_info`, `handle` must represent a fence that was exported
948     ///   from Vulkan or a compatible API, with a driver and device UUID equal to those of the
949     ///   device that owns `self`.
950     #[cfg(windows)]
951     #[inline]
import_win32_handle( &self, import_fence_win32_handle_info: ImportFenceWin32HandleInfo, ) -> Result<(), FenceError>952     pub unsafe fn import_win32_handle(
953         &self,
954         import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
955     ) -> Result<(), FenceError> {
956         let mut state = self.state.lock();
957         self.validate_import_win32_handle(&import_fence_win32_handle_info, &state)?;
958 
959         Ok(self.import_win32_handle_unchecked_locked(import_fence_win32_handle_info, &mut state)?)
960     }
961 
962     #[cfg(windows)]
validate_import_win32_handle( &self, import_fence_win32_handle_info: &ImportFenceWin32HandleInfo, state: &FenceState, ) -> Result<(), FenceError>963     fn validate_import_win32_handle(
964         &self,
965         import_fence_win32_handle_info: &ImportFenceWin32HandleInfo,
966         state: &FenceState,
967     ) -> Result<(), FenceError> {
968         if !self.device.enabled_extensions().khr_external_fence_win32 {
969             return Err(FenceError::RequirementNotMet {
970                 required_for: "`Fence::import_win32_handle`",
971                 requires_one_of: RequiresOneOf {
972                     device_extensions: &["khr_external_fence_win32"],
973                     ..Default::default()
974                 },
975             });
976         }
977 
978         // VUID-vkImportFenceWin32HandleKHR-fence-04448
979         if state.is_in_queue() {
980             return Err(FenceError::InQueue);
981         }
982 
983         let &ImportFenceWin32HandleInfo {
984             flags,
985             handle_type,
986             handle: _,
987             _ne: _,
988         } = import_fence_win32_handle_info;
989 
990         // VUID-VkImportFenceWin32HandleInfoKHR-flags-parameter
991         flags.validate_device(&self.device)?;
992 
993         // VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457
994         handle_type.validate_device(&self.device)?;
995 
996         // VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457
997         if !matches!(
998             handle_type,
999             ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt
1000         ) {
1001             return Err(FenceError::HandleTypeNotWin32);
1002         }
1003 
1004         // VUID-VkImportFenceWin32HandleInfoKHR-handle-01539
1005         // Can't validate, therefore unsafe
1006 
1007         // VUID?
1008         if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) {
1009             return Err(FenceError::HandletypeCopyNotTemporary);
1010         }
1011 
1012         Ok(())
1013     }
1014 
1015     #[cfg(windows)]
1016     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
1017     #[inline]
import_win32_handle_unchecked( &self, import_fence_win32_handle_info: ImportFenceWin32HandleInfo, ) -> Result<(), VulkanError>1018     pub unsafe fn import_win32_handle_unchecked(
1019         &self,
1020         import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
1021     ) -> Result<(), VulkanError> {
1022         let mut state = self.state.lock();
1023         self.import_win32_handle_unchecked_locked(import_fence_win32_handle_info, &mut state)
1024     }
1025 
1026     #[cfg(windows)]
import_win32_handle_unchecked_locked( &self, import_fence_win32_handle_info: ImportFenceWin32HandleInfo, state: &mut FenceState, ) -> Result<(), VulkanError>1027     unsafe fn import_win32_handle_unchecked_locked(
1028         &self,
1029         import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
1030         state: &mut FenceState,
1031     ) -> Result<(), VulkanError> {
1032         let ImportFenceWin32HandleInfo {
1033             flags,
1034             handle_type,
1035             handle,
1036             _ne: _,
1037         } = import_fence_win32_handle_info;
1038 
1039         let info_vk = ash::vk::ImportFenceWin32HandleInfoKHR {
1040             fence: self.handle,
1041             flags: flags.into(),
1042             handle_type: handle_type.into(),
1043             handle,
1044             name: ptr::null(), // TODO: support?
1045             ..Default::default()
1046         };
1047 
1048         let fns = self.device.fns();
1049         (fns.khr_external_fence_win32.import_fence_win32_handle_khr)(
1050             self.device.handle(),
1051             &info_vk,
1052         )
1053         .result()
1054         .map_err(VulkanError::from)?;
1055 
1056         state.import(handle_type, flags.intersects(FenceImportFlags::TEMPORARY));
1057 
1058         Ok(())
1059     }
1060 
state(&self) -> MutexGuard<'_, FenceState>1061     pub(crate) fn state(&self) -> MutexGuard<'_, FenceState> {
1062         self.state.lock()
1063     }
1064 
1065     // Shared by Fence and FenceSignalFuture
poll_impl(&self, cx: &mut Context<'_>) -> Poll<Result<(), OomError>>1066     pub(crate) fn poll_impl(&self, cx: &mut Context<'_>) -> Poll<Result<(), OomError>> {
1067         // Vulkan only allows polling of the fence status, so we have to use a spin future.
1068         // This is still better than blocking in async applications, since a smart-enough async engine
1069         // can choose to run some other tasks between probing this one.
1070 
1071         // Check if we are done without blocking
1072         match self.is_signaled() {
1073             Err(e) => return Poll::Ready(Err(e)),
1074             Ok(signalled) => {
1075                 if signalled {
1076                     return Poll::Ready(Ok(()));
1077                 }
1078             }
1079         }
1080 
1081         // Otherwise spin
1082         cx.waker().wake_by_ref();
1083         Poll::Pending
1084     }
1085 }
1086 
1087 impl Drop for Fence {
1088     #[inline]
drop(&mut self)1089     fn drop(&mut self) {
1090         unsafe {
1091             if self.must_put_in_pool {
1092                 let raw_fence = self.handle;
1093                 self.device.fence_pool().lock().push(raw_fence);
1094             } else {
1095                 let fns = self.device.fns();
1096                 (fns.v1_0.destroy_fence)(self.device.handle(), self.handle, ptr::null());
1097             }
1098         }
1099     }
1100 }
1101 
1102 impl Future for Fence {
1103     type Output = Result<(), OomError>;
1104 
poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>1105     fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
1106         self.poll_impl(cx)
1107     }
1108 }
1109 
1110 unsafe impl VulkanObject for Fence {
1111     type Handle = ash::vk::Fence;
1112 
1113     #[inline]
handle(&self) -> Self::Handle1114     fn handle(&self) -> Self::Handle {
1115         self.handle
1116     }
1117 }
1118 
1119 unsafe impl DeviceOwned for Fence {
1120     #[inline]
device(&self) -> &Arc<Device>1121     fn device(&self) -> &Arc<Device> {
1122         &self.device
1123     }
1124 }
1125 
1126 impl_id_counter!(Fence);
1127 
1128 #[derive(Debug, Default)]
1129 pub(crate) struct FenceState {
1130     is_signaled: bool,
1131     pending_signal: Option<Weak<Queue>>,
1132 
1133     reference_exported: bool,
1134     exported_handle_types: ExternalFenceHandleTypes,
1135     current_import: Option<ImportType>,
1136     permanent_import: Option<ExternalFenceHandleType>,
1137 }
1138 
1139 impl FenceState {
1140     /// If the fence is not in a queue and has no external references, returns the current status.
1141     #[inline]
is_signaled(&self) -> Option<bool>1142     fn is_signaled(&self) -> Option<bool> {
1143         // If either of these is true, we can't be certain of the status.
1144         if self.is_in_queue() || self.has_external_reference() {
1145             None
1146         } else {
1147             Some(self.is_signaled)
1148         }
1149     }
1150 
1151     #[inline]
is_in_queue(&self) -> bool1152     fn is_in_queue(&self) -> bool {
1153         self.pending_signal.is_some()
1154     }
1155 
1156     /// Returns whether there are any potential external references to the fence payload.
1157     /// That is, the fence has been exported by reference transference, or imported.
1158     #[inline]
has_external_reference(&self) -> bool1159     fn has_external_reference(&self) -> bool {
1160         self.reference_exported || self.current_import.is_some()
1161     }
1162 
1163     #[allow(dead_code)]
1164     #[inline]
is_exported(&self, handle_type: ExternalFenceHandleType) -> bool1165     fn is_exported(&self, handle_type: ExternalFenceHandleType) -> bool {
1166         self.exported_handle_types.intersects(handle_type.into())
1167     }
1168 
1169     #[inline]
add_queue_signal(&mut self, queue: &Arc<Queue>)1170     pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc<Queue>) {
1171         self.pending_signal = Some(Arc::downgrade(queue));
1172     }
1173 
1174     /// Called when a fence first discovers that it is signaled.
1175     /// Returns the queue that should be informed about it.
1176     #[inline]
set_signaled(&mut self) -> Option<Arc<Queue>>1177     unsafe fn set_signaled(&mut self) -> Option<Arc<Queue>> {
1178         self.is_signaled = true;
1179 
1180         // Fences with external references can't be used to determine queue completion.
1181         if self.has_external_reference() {
1182             self.pending_signal = None;
1183             None
1184         } else {
1185             self.pending_signal.take().and_then(|queue| queue.upgrade())
1186         }
1187     }
1188 
1189     /// Called when a queue is unlocking resources.
1190     #[inline]
set_signal_finished(&mut self)1191     pub(crate) unsafe fn set_signal_finished(&mut self) {
1192         self.is_signaled = true;
1193         self.pending_signal = None;
1194     }
1195 
1196     #[inline]
reset(&mut self)1197     unsafe fn reset(&mut self) {
1198         debug_assert!(!self.is_in_queue());
1199         self.current_import = self.permanent_import.map(Into::into);
1200         self.is_signaled = false;
1201     }
1202 
1203     #[allow(dead_code)]
1204     #[inline]
export(&mut self, handle_type: ExternalFenceHandleType)1205     unsafe fn export(&mut self, handle_type: ExternalFenceHandleType) {
1206         self.exported_handle_types |= handle_type.into();
1207 
1208         if handle_type.has_copy_transference() {
1209             self.reset();
1210         } else {
1211             self.reference_exported = true;
1212         }
1213     }
1214 
1215     #[allow(dead_code)]
1216     #[inline]
import(&mut self, handle_type: ExternalFenceHandleType, temporary: bool)1217     unsafe fn import(&mut self, handle_type: ExternalFenceHandleType, temporary: bool) {
1218         debug_assert!(!self.is_in_queue());
1219         self.current_import = Some(handle_type.into());
1220 
1221         if !temporary {
1222             self.permanent_import = Some(handle_type);
1223         }
1224     }
1225 
1226     #[inline]
import_swapchain_acquire(&mut self)1227     pub(crate) unsafe fn import_swapchain_acquire(&mut self) {
1228         debug_assert!(!self.is_in_queue());
1229         self.current_import = Some(ImportType::SwapchainAcquire);
1230     }
1231 }
1232 
1233 #[derive(Clone, Copy, Debug)]
1234 enum ImportType {
1235     SwapchainAcquire,
1236     ExternalFence(ExternalFenceHandleType),
1237 }
1238 
1239 impl From<ExternalFenceHandleType> for ImportType {
1240     #[inline]
from(handle_type: ExternalFenceHandleType) -> Self1241     fn from(handle_type: ExternalFenceHandleType) -> Self {
1242         Self::ExternalFence(handle_type)
1243     }
1244 }
1245 
1246 /// Parameters to create a new `Fence`.
1247 #[derive(Clone, Debug)]
1248 pub struct FenceCreateInfo {
1249     /// Whether the fence should be created in the signaled state.
1250     ///
1251     /// The default value is `false`.
1252     pub signaled: bool,
1253 
1254     /// The handle types that can be exported from the fence.
1255     pub export_handle_types: ExternalFenceHandleTypes,
1256 
1257     pub _ne: crate::NonExhaustive,
1258 }
1259 
1260 impl Default for FenceCreateInfo {
1261     #[inline]
default() -> Self1262     fn default() -> Self {
1263         Self {
1264             signaled: false,
1265             export_handle_types: ExternalFenceHandleTypes::empty(),
1266             _ne: crate::NonExhaustive(()),
1267         }
1268     }
1269 }
1270 
1271 vulkan_bitflags_enum! {
1272     #[non_exhaustive]
1273     /// A set of [`ExternalFenceHandleType`] values.
1274     ExternalFenceHandleTypes,
1275 
1276     /// The handle type used to export or import fences to/from an external source.
1277     ExternalFenceHandleType impl {
1278         /// Returns whether the given handle type has *copy transference* rather than *reference
1279         /// transference*.
1280         ///
1281         /// Imports of handles with copy transference must always be temporary. Exports of such
1282         /// handles must only occur if the fence is already signaled, or if there is a fence signal
1283         /// operation pending in a queue.
1284         #[inline]
1285         pub fn has_copy_transference(self) -> bool {
1286             // As defined by
1287             // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-fence-handletypes-win32
1288             // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-fence-handletypes-fd
1289             matches!(self, Self::SyncFd)
1290         }
1291     },
1292 
1293     = ExternalFenceHandleTypeFlags(u32);
1294 
1295     /// A POSIX file descriptor handle that is only usable with Vulkan and compatible APIs.
1296     ///
1297     /// This handle type has *reference transference*.
1298     OPAQUE_FD, OpaqueFd = OPAQUE_FD,
1299 
1300     /// A Windows NT handle that is only usable with Vulkan and compatible APIs.
1301     ///
1302     /// This handle type has *reference transference*.
1303     OPAQUE_WIN32, OpaqueWin32 = OPAQUE_WIN32,
1304 
1305     /// A Windows global share handle that is only usable with Vulkan and compatible APIs.
1306     ///
1307     /// This handle type has *reference transference*.
1308     OPAQUE_WIN32_KMT, OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
1309 
1310     /// A POSIX file descriptor handle to a Linux Sync File or Android Fence object.
1311     ///
1312     /// This handle type has *copy transference*.
1313     SYNC_FD, SyncFd = SYNC_FD,
1314 }
1315 
1316 vulkan_bitflags! {
1317     #[non_exhaustive]
1318 
1319     /// Additional parameters for a fence payload import.
1320     FenceImportFlags = FenceImportFlags(u32);
1321 
1322     /// The fence payload will be imported only temporarily, regardless of the permanence of the
1323     /// imported handle type.
1324     TEMPORARY = TEMPORARY,
1325 }
1326 
1327 #[cfg(unix)]
1328 #[derive(Debug)]
1329 pub struct ImportFenceFdInfo {
1330     /// Additional parameters for the import operation.
1331     ///
1332     /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
1333     ///
1334     /// The default value is [`FenceImportFlags::empty()`].
1335     pub flags: FenceImportFlags,
1336 
1337     /// The handle type of `file`.
1338     ///
1339     /// There is no default value.
1340     pub handle_type: ExternalFenceHandleType,
1341 
1342     /// The file to import the fence from.
1343     ///
1344     /// If `handle_type` is `ExternalFenceHandleType::SyncFd`, then `file` can be `None`.
1345     /// Instead of an imported file descriptor, a dummy file descriptor `-1` is used,
1346     /// which represents a fence that is always signaled.
1347     ///
1348     /// The default value is `None`, which must be overridden if `handle_type` is not
1349     /// `ExternalFenceHandleType::SyncFd`.
1350     pub file: Option<File>,
1351 
1352     pub _ne: crate::NonExhaustive,
1353 }
1354 
1355 #[cfg(unix)]
1356 impl ImportFenceFdInfo {
1357     /// Returns an `ImportFenceFdInfo` with the specified `handle_type`.
1358     #[inline]
handle_type(handle_type: ExternalFenceHandleType) -> Self1359     pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
1360         Self {
1361             flags: FenceImportFlags::empty(),
1362             handle_type,
1363             file: None,
1364             _ne: crate::NonExhaustive(()),
1365         }
1366     }
1367 }
1368 
1369 #[cfg(windows)]
1370 #[derive(Debug)]
1371 pub struct ImportFenceWin32HandleInfo {
1372     /// Additional parameters for the import operation.
1373     ///
1374     /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
1375     ///
1376     /// The default value is [`FenceImportFlags::empty()`].
1377     pub flags: FenceImportFlags,
1378 
1379     /// The handle type of `handle`.
1380     ///
1381     /// There is no default value.
1382     pub handle_type: ExternalFenceHandleType,
1383 
1384     /// The file to import the fence from.
1385     ///
1386     /// The default value is `null`, which must be overridden.
1387     pub handle: *mut std::ffi::c_void,
1388 
1389     pub _ne: crate::NonExhaustive,
1390 }
1391 
1392 #[cfg(windows)]
1393 impl ImportFenceWin32HandleInfo {
1394     /// Returns an `ImportFenceWin32HandleInfo` with the specified `handle_type`.
1395     #[inline]
handle_type(handle_type: ExternalFenceHandleType) -> Self1396     pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
1397         Self {
1398             flags: FenceImportFlags::empty(),
1399             handle_type,
1400             handle: ptr::null_mut(),
1401             _ne: crate::NonExhaustive(()),
1402         }
1403     }
1404 }
1405 
1406 /// The fence configuration to query in
1407 /// [`PhysicalDevice::external_fence_properties`](crate::device::physical::PhysicalDevice::external_fence_properties).
1408 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
1409 pub struct ExternalFenceInfo {
1410     /// The external handle type that will be used with the fence.
1411     pub handle_type: ExternalFenceHandleType,
1412 
1413     pub _ne: crate::NonExhaustive,
1414 }
1415 
1416 impl ExternalFenceInfo {
1417     /// Returns an `ExternalFenceInfo` with the specified `handle_type`.
1418     #[inline]
handle_type(handle_type: ExternalFenceHandleType) -> Self1419     pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
1420         Self {
1421             handle_type,
1422             _ne: crate::NonExhaustive(()),
1423         }
1424     }
1425 }
1426 
1427 /// The properties for exporting or importing external handles, when a fence is created
1428 /// with a specific configuration.
1429 #[derive(Clone, Debug)]
1430 #[non_exhaustive]
1431 pub struct ExternalFenceProperties {
1432     /// Whether a handle can be exported to an external source with the queried
1433     /// external handle type.
1434     pub exportable: bool,
1435 
1436     /// Whether a handle can be imported from an external source with the queried
1437     /// external handle type.
1438     pub importable: bool,
1439 
1440     /// Which external handle types can be re-exported after the queried external handle type has
1441     /// been imported.
1442     pub export_from_imported_handle_types: ExternalFenceHandleTypes,
1443 
1444     /// Which external handle types can be enabled along with the queried external handle type
1445     /// when creating the fence.
1446     pub compatible_handle_types: ExternalFenceHandleTypes,
1447 }
1448 
1449 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1450 pub enum FenceError {
1451     /// Not enough memory available.
1452     OomError(OomError),
1453 
1454     /// The device has been lost.
1455     DeviceLost,
1456 
1457     /// The specified timeout wasn't long enough.
1458     Timeout,
1459 
1460     RequirementNotMet {
1461         required_for: &'static str,
1462         requires_one_of: RequiresOneOf,
1463     },
1464 
1465     /// The provided handle type does not permit more than one export,
1466     /// and a handle of this type was already exported previously.
1467     AlreadyExported,
1468 
1469     /// The provided handle type cannot be exported from the current import handle type.
1470     ExportFromImportedNotSupported {
1471         imported_handle_type: ExternalFenceHandleType,
1472     },
1473 
1474     /// One of the export handle types is not compatible with the other provided handles.
1475     ExportHandleTypesNotCompatible,
1476 
1477     /// A handle type with copy transference was provided, but the fence is not signaled and there
1478     /// is no pending queue operation that will signal it.
1479     HandleTypeCopyNotSignaled,
1480 
1481     /// A handle type with copy transference was provided,
1482     /// but the `temporary` import flag was not set.
1483     HandletypeCopyNotTemporary,
1484 
1485     /// The provided export handle type was not set in `export_handle_types` when creating the
1486     /// fence.
1487     HandleTypeNotEnabled,
1488 
1489     /// Exporting is not supported for the provided handle type.
1490     HandleTypeNotExportable {
1491         handle_type: ExternalFenceHandleType,
1492     },
1493 
1494     /// The provided handle type is not a POSIX file descriptor handle.
1495     HandleTypeNotFd,
1496 
1497     /// The provided handle type is not a Win32 handle.
1498     HandleTypeNotWin32,
1499 
1500     /// The fence currently has a temporary import for a swapchain acquire operation.
1501     ImportedForSwapchainAcquire,
1502 
1503     /// The fence is currently in use by a queue.
1504     InQueue,
1505 }
1506 
1507 impl Error for FenceError {
source(&self) -> Option<&(dyn Error + 'static)>1508     fn source(&self) -> Option<&(dyn Error + 'static)> {
1509         match self {
1510             Self::OomError(err) => Some(err),
1511             _ => None,
1512         }
1513     }
1514 }
1515 
1516 impl Display for FenceError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1517     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1518         match self {
1519             Self::OomError(_) => write!(f, "not enough memory available"),
1520             Self::DeviceLost => write!(f, "the device was lost"),
1521             Self::Timeout => write!(f, "the timeout has been reached"),
1522             Self::RequirementNotMet {
1523                 required_for,
1524                 requires_one_of,
1525             } => write!(
1526                 f,
1527                 "a requirement was not met for: {}; requires one of: {}",
1528                 required_for, requires_one_of,
1529             ),
1530 
1531             Self::AlreadyExported => write!(
1532                 f,
1533                 "the provided handle type does not permit more than one export, and a handle of \
1534                 this type was already exported previously",
1535             ),
1536             Self::ExportFromImportedNotSupported {
1537                 imported_handle_type,
1538             } => write!(
1539                 f,
1540                 "the provided handle type cannot be exported from the current imported handle type \
1541                 {:?}",
1542                 imported_handle_type,
1543             ),
1544             Self::ExportHandleTypesNotCompatible => write!(
1545                 f,
1546                 "one of the export handle types is not compatible with the other provided handles",
1547             ),
1548             Self::HandleTypeCopyNotSignaled => write!(
1549                 f,
1550                 "a handle type with copy transference was provided, but the fence is not signaled \
1551                 and there is no pending queue operation that will signal it",
1552             ),
1553             Self::HandletypeCopyNotTemporary => write!(
1554                 f,
1555                 "a handle type with copy transference was provided, but the `temporary` \
1556                 import flag was not set",
1557             ),
1558             Self::HandleTypeNotEnabled => write!(
1559                 f,
1560                 "the provided export handle type was not set in `export_handle_types` when \
1561                 creating the fence",
1562             ),
1563             Self::HandleTypeNotExportable { handle_type } => write!(
1564                 f,
1565                 "exporting is not supported for handles of type {:?}",
1566                 handle_type,
1567             ),
1568             Self::HandleTypeNotFd => write!(
1569                 f,
1570                 "the provided handle type is not a POSIX file descriptor handle",
1571             ),
1572             Self::HandleTypeNotWin32 => {
1573                 write!(f, "the provided handle type is not a Win32 handle")
1574             }
1575             Self::ImportedForSwapchainAcquire => write!(
1576                 f,
1577                 "the fence currently has a temporary import for a swapchain acquire operation",
1578             ),
1579             Self::InQueue => write!(f, "the fence is currently in use by a queue"),
1580         }
1581     }
1582 }
1583 
1584 impl From<VulkanError> for FenceError {
from(err: VulkanError) -> Self1585     fn from(err: VulkanError) -> Self {
1586         match err {
1587             e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
1588                 Self::OomError(e.into())
1589             }
1590             VulkanError::DeviceLost => Self::DeviceLost,
1591             _ => panic!("unexpected error: {:?}", err),
1592         }
1593     }
1594 }
1595 
1596 impl From<OomError> for FenceError {
from(err: OomError) -> Self1597     fn from(err: OomError) -> Self {
1598         Self::OomError(err)
1599     }
1600 }
1601 
1602 impl From<RequirementNotMet> for FenceError {
from(err: RequirementNotMet) -> Self1603     fn from(err: RequirementNotMet) -> Self {
1604         Self::RequirementNotMet {
1605             required_for: err.required_for,
1606             requires_one_of: err.requires_one_of,
1607         }
1608     }
1609 }
1610 
1611 #[cfg(test)]
1612 mod tests {
1613     use crate::{
1614         sync::fence::{Fence, FenceCreateInfo},
1615         VulkanObject,
1616     };
1617     use std::time::Duration;
1618 
1619     #[test]
fence_create()1620     fn fence_create() {
1621         let (device, _) = gfx_dev_and_queue!();
1622 
1623         let fence = Fence::new(device, Default::default()).unwrap();
1624         assert!(!fence.is_signaled().unwrap());
1625     }
1626 
1627     #[test]
fence_create_signaled()1628     fn fence_create_signaled() {
1629         let (device, _) = gfx_dev_and_queue!();
1630 
1631         let fence = Fence::new(
1632             device,
1633             FenceCreateInfo {
1634                 signaled: true,
1635                 ..Default::default()
1636             },
1637         )
1638         .unwrap();
1639         assert!(fence.is_signaled().unwrap());
1640     }
1641 
1642     #[test]
fence_signaled_wait()1643     fn fence_signaled_wait() {
1644         let (device, _) = gfx_dev_and_queue!();
1645 
1646         let fence = Fence::new(
1647             device,
1648             FenceCreateInfo {
1649                 signaled: true,
1650                 ..Default::default()
1651             },
1652         )
1653         .unwrap();
1654         fence.wait(Some(Duration::new(0, 10))).unwrap();
1655     }
1656 
1657     #[test]
fence_reset()1658     fn fence_reset() {
1659         let (device, _) = gfx_dev_and_queue!();
1660 
1661         let fence = Fence::new(
1662             device,
1663             FenceCreateInfo {
1664                 signaled: true,
1665                 ..Default::default()
1666             },
1667         )
1668         .unwrap();
1669         fence.reset().unwrap();
1670         assert!(!fence.is_signaled().unwrap());
1671     }
1672 
1673     #[test]
multiwait_different_devices()1674     fn multiwait_different_devices() {
1675         let (device1, _) = gfx_dev_and_queue!();
1676         let (device2, _) = gfx_dev_and_queue!();
1677 
1678         assert_should_panic!({
1679             let fence1 = Fence::new(
1680                 device1.clone(),
1681                 FenceCreateInfo {
1682                     signaled: true,
1683                     ..Default::default()
1684                 },
1685             )
1686             .unwrap();
1687             let fence2 = Fence::new(
1688                 device2.clone(),
1689                 FenceCreateInfo {
1690                     signaled: true,
1691                     ..Default::default()
1692                 },
1693             )
1694             .unwrap();
1695 
1696             let _ = Fence::multi_wait(
1697                 [&fence1, &fence2].iter().cloned(),
1698                 Some(Duration::new(0, 10)),
1699             );
1700         });
1701     }
1702 
1703     #[test]
multireset_different_devices()1704     fn multireset_different_devices() {
1705         let (device1, _) = gfx_dev_and_queue!();
1706         let (device2, _) = gfx_dev_and_queue!();
1707 
1708         assert_should_panic!({
1709             let fence1 = Fence::new(
1710                 device1.clone(),
1711                 FenceCreateInfo {
1712                     signaled: true,
1713                     ..Default::default()
1714                 },
1715             )
1716             .unwrap();
1717             let fence2 = Fence::new(
1718                 device2.clone(),
1719                 FenceCreateInfo {
1720                     signaled: true,
1721                     ..Default::default()
1722                 },
1723             )
1724             .unwrap();
1725 
1726             let _ = Fence::multi_reset([&fence1, &fence2]);
1727         });
1728     }
1729 
1730     #[test]
fence_pool()1731     fn fence_pool() {
1732         let (device, _) = gfx_dev_and_queue!();
1733 
1734         assert_eq!(device.fence_pool().lock().len(), 0);
1735         let fence1_internal_obj = {
1736             let fence = Fence::from_pool(device.clone()).unwrap();
1737             assert_eq!(device.fence_pool().lock().len(), 0);
1738             fence.handle()
1739         };
1740 
1741         assert_eq!(device.fence_pool().lock().len(), 1);
1742         let fence2 = Fence::from_pool(device.clone()).unwrap();
1743         assert_eq!(device.fence_pool().lock().len(), 0);
1744         assert_eq!(fence2.handle(), fence1_internal_obj);
1745     }
1746 }
1747