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 semaphore provides synchronization between multiple queues, with non-command buffer
11 //! commands on the same queue, or between the device and an external source.
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 #[cfg(unix)]
20 use std::fs::File;
21 use std::{
22     error::Error,
23     fmt::{Display, Error as FmtError, Formatter},
24     mem::MaybeUninit,
25     num::NonZeroU64,
26     ptr,
27     sync::{Arc, Weak},
28 };
29 
30 /// Used to provide synchronization between command buffers during their execution.
31 ///
32 /// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
33 /// semaphore's status or wait for it to be signaled.
34 #[derive(Debug)]
35 pub struct Semaphore {
36     handle: ash::vk::Semaphore,
37     device: Arc<Device>,
38     id: NonZeroU64,
39     must_put_in_pool: bool,
40 
41     export_handle_types: ExternalSemaphoreHandleTypes,
42 
43     state: Mutex<SemaphoreState>,
44 }
45 
46 impl Semaphore {
47     /// Creates a new `Semaphore`.
48     #[inline]
new( device: Arc<Device>, create_info: SemaphoreCreateInfo, ) -> Result<Semaphore, SemaphoreError>49     pub fn new(
50         device: Arc<Device>,
51         create_info: SemaphoreCreateInfo,
52     ) -> Result<Semaphore, SemaphoreError> {
53         Self::validate_new(&device, &create_info)?;
54 
55         unsafe { Ok(Self::new_unchecked(device, create_info)?) }
56     }
57 
validate_new( device: &Device, create_info: &SemaphoreCreateInfo, ) -> Result<(), SemaphoreError>58     fn validate_new(
59         device: &Device,
60         create_info: &SemaphoreCreateInfo,
61     ) -> Result<(), SemaphoreError> {
62         let &SemaphoreCreateInfo {
63             export_handle_types,
64             _ne: _,
65         } = create_info;
66 
67         if !export_handle_types.is_empty() {
68             if !(device.api_version() >= Version::V1_1
69                 || device.enabled_extensions().khr_external_semaphore)
70             {
71                 return Err(SemaphoreError::RequirementNotMet {
72                     required_for: "`create_info.export_handle_types` is not empty",
73                     requires_one_of: RequiresOneOf {
74                         api_version: Some(Version::V1_1),
75                         device_extensions: &["khr_external_semaphore"],
76                         ..Default::default()
77                     },
78                 });
79             }
80 
81             // VUID-VkExportSemaphoreCreateInfo-handleTypes-parameter
82             export_handle_types.validate_device(device)?;
83 
84             // VUID-VkExportSemaphoreCreateInfo-handleTypes-01124
85             for handle_type in export_handle_types.into_iter() {
86                 let external_semaphore_properties = unsafe {
87                     device
88                         .physical_device()
89                         .external_semaphore_properties_unchecked(
90                             ExternalSemaphoreInfo::handle_type(handle_type),
91                         )
92                 };
93 
94                 if !external_semaphore_properties.exportable {
95                     return Err(SemaphoreError::HandleTypeNotExportable { handle_type });
96                 }
97 
98                 if !external_semaphore_properties
99                     .compatible_handle_types
100                     .contains(export_handle_types)
101                 {
102                     return Err(SemaphoreError::ExportHandleTypesNotCompatible);
103                 }
104             }
105         }
106 
107         Ok(())
108     }
109 
110     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
111     #[inline]
new_unchecked( device: Arc<Device>, create_info: SemaphoreCreateInfo, ) -> Result<Semaphore, VulkanError>112     pub unsafe fn new_unchecked(
113         device: Arc<Device>,
114         create_info: SemaphoreCreateInfo,
115     ) -> Result<Semaphore, VulkanError> {
116         let SemaphoreCreateInfo {
117             export_handle_types,
118             _ne: _,
119         } = create_info;
120 
121         let mut create_info_vk = ash::vk::SemaphoreCreateInfo {
122             flags: ash::vk::SemaphoreCreateFlags::empty(),
123             ..Default::default()
124         };
125         let mut export_semaphore_create_info_vk = None;
126 
127         if !export_handle_types.is_empty() {
128             let _ = export_semaphore_create_info_vk.insert(ash::vk::ExportSemaphoreCreateInfo {
129                 handle_types: export_handle_types.into(),
130                 ..Default::default()
131             });
132         };
133 
134         if let Some(info) = export_semaphore_create_info_vk.as_mut() {
135             info.p_next = create_info_vk.p_next;
136             create_info_vk.p_next = info as *const _ as *const _;
137         }
138 
139         let handle = {
140             let fns = device.fns();
141             let mut output = MaybeUninit::uninit();
142             (fns.v1_0.create_semaphore)(
143                 device.handle(),
144                 &create_info_vk,
145                 ptr::null(),
146                 output.as_mut_ptr(),
147             )
148             .result()
149             .map_err(VulkanError::from)?;
150             output.assume_init()
151         };
152 
153         Ok(Semaphore {
154             handle,
155             device,
156             id: Self::next_id(),
157             must_put_in_pool: false,
158             export_handle_types,
159             state: Mutex::new(Default::default()),
160         })
161     }
162 
163     /// Takes a semaphore from the vulkano-provided semaphore pool.
164     /// If the pool is empty, a new semaphore will be allocated.
165     /// Upon `drop`, the semaphore is put back into the pool.
166     ///
167     /// For most applications, using the pool should be preferred,
168     /// in order to avoid creating new semaphores every frame.
169     #[inline]
from_pool(device: Arc<Device>) -> Result<Semaphore, SemaphoreError>170     pub fn from_pool(device: Arc<Device>) -> Result<Semaphore, SemaphoreError> {
171         let handle = device.semaphore_pool().lock().pop();
172         let semaphore = match handle {
173             Some(handle) => Semaphore {
174                 handle,
175                 device,
176                 id: Self::next_id(),
177                 must_put_in_pool: true,
178                 export_handle_types: ExternalSemaphoreHandleTypes::empty(),
179                 state: Mutex::new(Default::default()),
180             },
181             None => {
182                 // Pool is empty, alloc new semaphore
183                 let mut semaphore = Semaphore::new(device, Default::default())?;
184                 semaphore.must_put_in_pool = true;
185                 semaphore
186             }
187         };
188 
189         Ok(semaphore)
190     }
191 
192     /// Creates a new `Semaphore` from a raw object handle.
193     ///
194     /// # Safety
195     ///
196     /// - `handle` must be a valid Vulkan object handle created from `device`.
197     /// - `create_info` must match the info used to create the object.
198     #[inline]
from_handle( device: Arc<Device>, handle: ash::vk::Semaphore, create_info: SemaphoreCreateInfo, ) -> Semaphore199     pub unsafe fn from_handle(
200         device: Arc<Device>,
201         handle: ash::vk::Semaphore,
202         create_info: SemaphoreCreateInfo,
203     ) -> Semaphore {
204         let SemaphoreCreateInfo {
205             export_handle_types,
206             _ne: _,
207         } = create_info;
208 
209         Semaphore {
210             handle,
211             device,
212             id: Self::next_id(),
213             must_put_in_pool: false,
214             export_handle_types,
215             state: Mutex::new(Default::default()),
216         }
217     }
218 
219     /// Exports the semaphore into a POSIX file descriptor. The caller owns the returned `File`.
220     #[cfg(unix)]
221     #[inline]
export_fd( &self, handle_type: ExternalSemaphoreHandleType, ) -> Result<File, SemaphoreError>222     pub fn export_fd(
223         &self,
224         handle_type: ExternalSemaphoreHandleType,
225     ) -> Result<File, SemaphoreError> {
226         let mut state = self.state.lock();
227         self.validate_export_fd(handle_type, &state)?;
228 
229         unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
230     }
231 
232     #[cfg(unix)]
validate_export_fd( &self, handle_type: ExternalSemaphoreHandleType, state: &SemaphoreState, ) -> Result<(), SemaphoreError>233     fn validate_export_fd(
234         &self,
235         handle_type: ExternalSemaphoreHandleType,
236         state: &SemaphoreState,
237     ) -> Result<(), SemaphoreError> {
238         if !self.device.enabled_extensions().khr_external_semaphore_fd {
239             return Err(SemaphoreError::RequirementNotMet {
240                 required_for: "`Semaphore::export_fd`",
241                 requires_one_of: RequiresOneOf {
242                     device_extensions: &["khr_external_semaphore_fd"],
243                     ..Default::default()
244                 },
245             });
246         }
247 
248         // VUID-VkSemaphoreGetFdInfoKHR-handleType-parameter
249         handle_type.validate_device(&self.device)?;
250 
251         // VUID-VkSemaphoreGetFdInfoKHR-handleType-01132
252         if !self.export_handle_types.intersects(handle_type.into()) {
253             return Err(SemaphoreError::HandleTypeNotEnabled);
254         }
255 
256         // VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133
257         if let Some(imported_handle_type) = state.current_import {
258             match imported_handle_type {
259                 ImportType::SwapchainAcquire => {
260                     return Err(SemaphoreError::ImportedForSwapchainAcquire)
261                 }
262                 ImportType::ExternalSemaphore(imported_handle_type) => {
263                     let external_semaphore_properties = unsafe {
264                         self.device
265                             .physical_device()
266                             .external_semaphore_properties_unchecked(
267                                 ExternalSemaphoreInfo::handle_type(handle_type),
268                             )
269                     };
270 
271                     if !external_semaphore_properties
272                         .export_from_imported_handle_types
273                         .intersects(imported_handle_type.into())
274                     {
275                         return Err(SemaphoreError::ExportFromImportedNotSupported {
276                             imported_handle_type,
277                         });
278                     }
279                 }
280             }
281         }
282 
283         if handle_type.has_copy_transference() {
284             // VUID-VkSemaphoreGetFdInfoKHR-handleType-01134
285             if state.is_wait_pending() {
286                 return Err(SemaphoreError::QueueIsWaiting);
287             }
288 
289             // VUID-VkSemaphoreGetFdInfoKHR-handleType-01135
290             // VUID-VkSemaphoreGetFdInfoKHR-handleType-03254
291             if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
292                 return Err(SemaphoreError::HandleTypeCopyNotSignaled);
293             }
294         }
295 
296         // VUID-VkSemaphoreGetFdInfoKHR-handleType-01136
297         if !matches!(
298             handle_type,
299             ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd
300         ) {
301             return Err(SemaphoreError::HandleTypeNotFd);
302         }
303 
304         Ok(())
305     }
306 
307     #[cfg(unix)]
308     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
309     #[inline]
export_fd_unchecked( &self, handle_type: ExternalSemaphoreHandleType, ) -> Result<File, VulkanError>310     pub unsafe fn export_fd_unchecked(
311         &self,
312         handle_type: ExternalSemaphoreHandleType,
313     ) -> Result<File, VulkanError> {
314         let mut state = self.state.lock();
315         self.export_fd_unchecked_locked(handle_type, &mut state)
316     }
317 
318     #[cfg(unix)]
export_fd_unchecked_locked( &self, handle_type: ExternalSemaphoreHandleType, state: &mut SemaphoreState, ) -> Result<File, VulkanError>319     unsafe fn export_fd_unchecked_locked(
320         &self,
321         handle_type: ExternalSemaphoreHandleType,
322         state: &mut SemaphoreState,
323     ) -> Result<File, VulkanError> {
324         use std::os::unix::io::FromRawFd;
325 
326         let info = ash::vk::SemaphoreGetFdInfoKHR {
327             semaphore: self.handle,
328             handle_type: handle_type.into(),
329             ..Default::default()
330         };
331 
332         let mut output = MaybeUninit::uninit();
333         let fns = self.device.fns();
334         (fns.khr_external_semaphore_fd.get_semaphore_fd_khr)(
335             self.device.handle(),
336             &info,
337             output.as_mut_ptr(),
338         )
339         .result()
340         .map_err(VulkanError::from)?;
341 
342         state.export(handle_type);
343 
344         Ok(File::from_raw_fd(output.assume_init()))
345     }
346 
347     /// Exports the semaphore into a Win32 handle.
348     ///
349     /// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
350     /// extension must be enabled on the device.
351     #[cfg(windows)]
352     #[inline]
export_win32_handle( &self, handle_type: ExternalSemaphoreHandleType, ) -> Result<*mut std::ffi::c_void, SemaphoreError>353     pub fn export_win32_handle(
354         &self,
355         handle_type: ExternalSemaphoreHandleType,
356     ) -> Result<*mut std::ffi::c_void, SemaphoreError> {
357         let mut state = self.state.lock();
358         self.validate_export_win32_handle(handle_type, &state)?;
359 
360         unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
361     }
362 
363     #[cfg(windows)]
validate_export_win32_handle( &self, handle_type: ExternalSemaphoreHandleType, state: &SemaphoreState, ) -> Result<(), SemaphoreError>364     fn validate_export_win32_handle(
365         &self,
366         handle_type: ExternalSemaphoreHandleType,
367         state: &SemaphoreState,
368     ) -> Result<(), SemaphoreError> {
369         if !self
370             .device
371             .enabled_extensions()
372             .khr_external_semaphore_win32
373         {
374             return Err(SemaphoreError::RequirementNotMet {
375                 required_for: "`Semaphore::export_win32_handle`",
376                 requires_one_of: RequiresOneOf {
377                     device_extensions: &["khr_external_semaphore_win32"],
378                     ..Default::default()
379                 },
380             });
381         }
382 
383         // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-parameter
384         handle_type.validate_device(&self.device)?;
385 
386         // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01126
387         if !self.export_handle_types.intersects(handle_type.into()) {
388             return Err(SemaphoreError::HandleTypeNotEnabled);
389         }
390 
391         // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01127
392         if matches!(
393             handle_type,
394             ExternalSemaphoreHandleType::OpaqueWin32 | ExternalSemaphoreHandleType::D3D12Fence
395         ) && state.is_exported(handle_type)
396         {
397             return Err(SemaphoreError::AlreadyExported);
398         }
399 
400         // VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128
401         if let Some(imported_handle_type) = state.current_import {
402             match imported_handle_type {
403                 ImportType::SwapchainAcquire => {
404                     return Err(SemaphoreError::ImportedForSwapchainAcquire)
405                 }
406                 ImportType::ExternalSemaphore(imported_handle_type) => {
407                     let external_semaphore_properties = unsafe {
408                         self.device
409                             .physical_device()
410                             .external_semaphore_properties_unchecked(
411                                 ExternalSemaphoreInfo::handle_type(handle_type),
412                             )
413                     };
414 
415                     if !external_semaphore_properties
416                         .export_from_imported_handle_types
417                         .intersects(imported_handle_type.into())
418                     {
419                         return Err(SemaphoreError::ExportFromImportedNotSupported {
420                             imported_handle_type,
421                         });
422                     }
423                 }
424             }
425         }
426 
427         if handle_type.has_copy_transference() {
428             // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01129
429             if state.is_wait_pending() {
430                 return Err(SemaphoreError::QueueIsWaiting);
431             }
432 
433             // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01130
434             if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
435                 return Err(SemaphoreError::HandleTypeCopyNotSignaled);
436             }
437         }
438 
439         // VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01131
440         if !matches!(
441             handle_type,
442             ExternalSemaphoreHandleType::OpaqueWin32
443                 | ExternalSemaphoreHandleType::OpaqueWin32Kmt
444                 | ExternalSemaphoreHandleType::D3D12Fence
445         ) {
446             return Err(SemaphoreError::HandleTypeNotWin32);
447         }
448 
449         Ok(())
450     }
451 
452     #[cfg(windows)]
453     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
454     #[inline]
export_win32_handle_unchecked( &self, handle_type: ExternalSemaphoreHandleType, ) -> Result<*mut std::ffi::c_void, VulkanError>455     pub unsafe fn export_win32_handle_unchecked(
456         &self,
457         handle_type: ExternalSemaphoreHandleType,
458     ) -> Result<*mut std::ffi::c_void, VulkanError> {
459         let mut state = self.state.lock();
460         self.export_win32_handle_unchecked_locked(handle_type, &mut state)
461     }
462 
463     #[cfg(windows)]
export_win32_handle_unchecked_locked( &self, handle_type: ExternalSemaphoreHandleType, state: &mut SemaphoreState, ) -> Result<*mut std::ffi::c_void, VulkanError>464     unsafe fn export_win32_handle_unchecked_locked(
465         &self,
466         handle_type: ExternalSemaphoreHandleType,
467         state: &mut SemaphoreState,
468     ) -> Result<*mut std::ffi::c_void, VulkanError> {
469         let info_vk = ash::vk::SemaphoreGetWin32HandleInfoKHR {
470             semaphore: self.handle,
471             handle_type: handle_type.into(),
472             ..Default::default()
473         };
474 
475         let mut output = MaybeUninit::uninit();
476         let fns = self.device.fns();
477         (fns.khr_external_semaphore_win32
478             .get_semaphore_win32_handle_khr)(
479             self.device.handle(), &info_vk, output.as_mut_ptr()
480         )
481         .result()
482         .map_err(VulkanError::from)?;
483 
484         state.export(handle_type);
485 
486         Ok(output.assume_init())
487     }
488 
489     /// Exports the semaphore into a Zircon event handle.
490     #[cfg(target_os = "fuchsia")]
491     #[inline]
export_zircon_handle( &self, handle_type: ExternalSemaphoreHandleType, ) -> Result<ash::vk::zx_handle_t, SemaphoreError>492     pub fn export_zircon_handle(
493         &self,
494         handle_type: ExternalSemaphoreHandleType,
495     ) -> Result<ash::vk::zx_handle_t, SemaphoreError> {
496         let mut state = self.state.lock();
497         self.validate_export_zircon_handle(handle_type, &state)?;
498 
499         unsafe { Ok(self.export_zircon_handle_unchecked_locked(handle_type, &mut state)?) }
500     }
501 
502     #[cfg(target_os = "fuchsia")]
validate_export_zircon_handle( &self, handle_type: ExternalSemaphoreHandleType, state: &SemaphoreState, ) -> Result<(), SemaphoreError>503     fn validate_export_zircon_handle(
504         &self,
505         handle_type: ExternalSemaphoreHandleType,
506         state: &SemaphoreState,
507     ) -> Result<(), SemaphoreError> {
508         if !self.device.enabled_extensions().fuchsia_external_semaphore {
509             return Err(SemaphoreError::RequirementNotMet {
510                 required_for: "`Semaphore::export_zircon_handle`",
511                 requires_one_of: RequiresOneOf {
512                     device_extensions: &["fuchsia_external_semaphore"],
513                     ..Default::default()
514                 },
515             });
516         }
517 
518         // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-parameter
519         handle_type.validate_device(&self.device)?;
520 
521         // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04758
522         if !self.export_handle_types.intersects(&handle_type.into()) {
523             return Err(SemaphoreError::HandleTypeNotEnabled);
524         }
525 
526         // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759
527         if let Some(imported_handle_type) = state.current_import {
528             match imported_handle_type {
529                 ImportType::SwapchainAcquire => {
530                     return Err(SemaphoreError::ImportedForSwapchainAcquire)
531                 }
532                 ImportType::ExternalSemaphore(imported_handle_type) => {
533                     let external_semaphore_properties = unsafe {
534                         self.device
535                             .physical_device()
536                             .external_semaphore_properties_unchecked(
537                                 ExternalSemaphoreInfo::handle_type(handle_type),
538                             )
539                     };
540 
541                     if !external_semaphore_properties
542                         .export_from_imported_handle_types
543                         .intersects(&imported_handle_type.into())
544                     {
545                         return Err(SemaphoreError::ExportFromImportedNotSupported {
546                             imported_handle_type,
547                         });
548                     }
549                 }
550             }
551         }
552 
553         if handle_type.has_copy_transference() {
554             // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04760
555             if state.is_wait_pending() {
556                 return Err(SemaphoreError::QueueIsWaiting);
557             }
558 
559             // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04761
560             if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
561                 return Err(SemaphoreError::HandleTypeCopyNotSignaled);
562             }
563         }
564 
565         // VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04762
566         if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
567             return Err(SemaphoreError::HandleTypeNotZircon);
568         }
569 
570         Ok(())
571     }
572 
573     #[cfg(target_os = "fuchsia")]
574     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
575     #[inline]
export_zircon_handle_unchecked( &self, handle_type: ExternalSemaphoreHandleType, ) -> Result<ash::vk::zx_handle_t, VulkanError>576     pub unsafe fn export_zircon_handle_unchecked(
577         &self,
578         handle_type: ExternalSemaphoreHandleType,
579     ) -> Result<ash::vk::zx_handle_t, VulkanError> {
580         let mut state = self.state.lock();
581         self.export_zircon_handle_unchecked_locked(handle_type, &mut state)
582     }
583 
584     #[cfg(target_os = "fuchsia")]
export_zircon_handle_unchecked_locked( &self, handle_type: ExternalSemaphoreHandleType, state: &mut SemaphoreState, ) -> Result<ash::vk::zx_handle_t, VulkanError>585     unsafe fn export_zircon_handle_unchecked_locked(
586         &self,
587         handle_type: ExternalSemaphoreHandleType,
588         state: &mut SemaphoreState,
589     ) -> Result<ash::vk::zx_handle_t, VulkanError> {
590         let info = ash::vk::SemaphoreGetZirconHandleInfoFUCHSIA {
591             semaphore: self.handle,
592             handle_type: handle_type.into(),
593             ..Default::default()
594         };
595 
596         let mut output = MaybeUninit::uninit();
597         let fns = self.device.fns();
598         (fns.fuchsia_external_semaphore
599             .get_semaphore_zircon_handle_fuchsia)(
600             self.device.handle(), &info, output.as_mut_ptr()
601         )
602         .result()
603         .map_err(VulkanError::from)?;
604 
605         state.export(handle_type);
606 
607         Ok(output.assume_init())
608     }
609 
610     /// Imports a semaphore from a POSIX file descriptor.
611     ///
612     /// The [`khr_external_semaphore_fd`](crate::device::DeviceExtensions::khr_external_semaphore_fd)
613     /// extension must be enabled on the device.
614     ///
615     /// # Safety
616     ///
617     /// - If in `import_semaphore_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
618     ///   then `file` must represent a binary semaphore that was exported from Vulkan or a
619     ///   compatible API, with a driver and device UUID equal to those of the device that owns
620     ///   `self`.
621     #[cfg(unix)]
622     #[inline]
import_fd( &self, import_semaphore_fd_info: ImportSemaphoreFdInfo, ) -> Result<(), SemaphoreError>623     pub unsafe fn import_fd(
624         &self,
625         import_semaphore_fd_info: ImportSemaphoreFdInfo,
626     ) -> Result<(), SemaphoreError> {
627         let mut state = self.state.lock();
628         self.validate_import_fd(&import_semaphore_fd_info, &state)?;
629 
630         Ok(self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)?)
631     }
632 
633     #[cfg(unix)]
validate_import_fd( &self, import_semaphore_fd_info: &ImportSemaphoreFdInfo, state: &SemaphoreState, ) -> Result<(), SemaphoreError>634     fn validate_import_fd(
635         &self,
636         import_semaphore_fd_info: &ImportSemaphoreFdInfo,
637         state: &SemaphoreState,
638     ) -> Result<(), SemaphoreError> {
639         if !self.device.enabled_extensions().khr_external_semaphore_fd {
640             return Err(SemaphoreError::RequirementNotMet {
641                 required_for: "`Semaphore::import_fd`",
642                 requires_one_of: RequiresOneOf {
643                     device_extensions: &["khr_external_semaphore_fd"],
644                     ..Default::default()
645                 },
646             });
647         }
648 
649         // VUID-vkImportSemaphoreFdKHR-semaphore-01142
650         if state.is_in_queue() {
651             return Err(SemaphoreError::InQueue);
652         }
653 
654         let &ImportSemaphoreFdInfo {
655             flags,
656             handle_type,
657             file: _,
658             _ne: _,
659         } = import_semaphore_fd_info;
660 
661         // VUID-VkImportSemaphoreFdInfoKHR-flags-parameter
662         flags.validate_device(&self.device)?;
663 
664         // VUID-VkImportSemaphoreFdInfoKHR-handleType-parameter
665         handle_type.validate_device(&self.device)?;
666 
667         // VUID-VkImportSemaphoreFdInfoKHR-handleType-01143
668         if !matches!(
669             handle_type,
670             ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd
671         ) {
672             return Err(SemaphoreError::HandleTypeNotFd);
673         }
674 
675         // VUID-VkImportSemaphoreFdInfoKHR-fd-01544
676         // VUID-VkImportSemaphoreFdInfoKHR-handleType-03263
677         // Can't validate, therefore unsafe
678 
679         // VUID-VkImportSemaphoreFdInfoKHR-handleType-07307
680         if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
681         {
682             return Err(SemaphoreError::HandletypeCopyNotTemporary);
683         }
684 
685         Ok(())
686     }
687 
688     #[cfg(unix)]
689     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
690     #[inline]
import_fd_unchecked( &self, import_semaphore_fd_info: ImportSemaphoreFdInfo, ) -> Result<(), VulkanError>691     pub unsafe fn import_fd_unchecked(
692         &self,
693         import_semaphore_fd_info: ImportSemaphoreFdInfo,
694     ) -> Result<(), VulkanError> {
695         let mut state = self.state.lock();
696         self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)
697     }
698 
699     #[cfg(unix)]
import_fd_unchecked_locked( &self, import_semaphore_fd_info: ImportSemaphoreFdInfo, state: &mut SemaphoreState, ) -> Result<(), VulkanError>700     unsafe fn import_fd_unchecked_locked(
701         &self,
702         import_semaphore_fd_info: ImportSemaphoreFdInfo,
703         state: &mut SemaphoreState,
704     ) -> Result<(), VulkanError> {
705         use std::os::unix::io::IntoRawFd;
706 
707         let ImportSemaphoreFdInfo {
708             flags,
709             handle_type,
710             file,
711             _ne: _,
712         } = import_semaphore_fd_info;
713 
714         let info_vk = ash::vk::ImportSemaphoreFdInfoKHR {
715             semaphore: self.handle,
716             flags: flags.into(),
717             handle_type: handle_type.into(),
718             fd: file.map_or(-1, |file| file.into_raw_fd()),
719             ..Default::default()
720         };
721 
722         let fns = self.device.fns();
723         (fns.khr_external_semaphore_fd.import_semaphore_fd_khr)(self.device.handle(), &info_vk)
724             .result()
725             .map_err(VulkanError::from)?;
726 
727         state.import(
728             handle_type,
729             flags.intersects(SemaphoreImportFlags::TEMPORARY),
730         );
731 
732         Ok(())
733     }
734 
735     /// Imports a semaphore from a Win32 handle.
736     ///
737     /// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
738     /// extension must be enabled on the device.
739     ///
740     /// # Safety
741     ///
742     /// - In `import_semaphore_win32_handle_info`, `handle` must represent a binary semaphore that
743     ///   was exported from Vulkan or a compatible API, with a driver and device UUID equal to
744     ///   those of the device that owns `self`.
745     #[cfg(windows)]
746     #[inline]
import_win32_handle( &self, import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo, ) -> Result<(), SemaphoreError>747     pub unsafe fn import_win32_handle(
748         &self,
749         import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
750     ) -> Result<(), SemaphoreError> {
751         let mut state = self.state.lock();
752         self.validate_import_win32_handle(&import_semaphore_win32_handle_info, &state)?;
753 
754         Ok(self
755             .import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)?)
756     }
757 
758     #[cfg(windows)]
validate_import_win32_handle( &self, import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo, state: &SemaphoreState, ) -> Result<(), SemaphoreError>759     fn validate_import_win32_handle(
760         &self,
761         import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo,
762         state: &SemaphoreState,
763     ) -> Result<(), SemaphoreError> {
764         if !self
765             .device
766             .enabled_extensions()
767             .khr_external_semaphore_win32
768         {
769             return Err(SemaphoreError::RequirementNotMet {
770                 required_for: "`Semaphore::import_win32_handle`",
771                 requires_one_of: RequiresOneOf {
772                     device_extensions: &["khr_external_semaphore_win32"],
773                     ..Default::default()
774                 },
775             });
776         }
777 
778         // VUID?
779         if state.is_in_queue() {
780             return Err(SemaphoreError::InQueue);
781         }
782 
783         let &ImportSemaphoreWin32HandleInfo {
784             flags,
785             handle_type,
786             handle: _,
787             _ne: _,
788         } = import_semaphore_win32_handle_info;
789 
790         // VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-parameter
791         flags.validate_device(&self.device)?;
792 
793         // VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140
794         handle_type.validate_device(&self.device)?;
795 
796         // VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140
797         if !matches!(
798             handle_type,
799             ExternalSemaphoreHandleType::OpaqueWin32
800                 | ExternalSemaphoreHandleType::OpaqueWin32Kmt
801                 | ExternalSemaphoreHandleType::D3D12Fence
802         ) {
803             return Err(SemaphoreError::HandleTypeNotWin32);
804         }
805 
806         // VUID-VkImportSemaphoreWin32HandleInfoKHR-handle-01542
807         // Can't validate, therefore unsafe
808 
809         // VUID?
810         if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
811         {
812             return Err(SemaphoreError::HandletypeCopyNotTemporary);
813         }
814 
815         Ok(())
816     }
817 
818     #[cfg(windows)]
819     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
820     #[inline]
import_win32_handle_unchecked( &self, import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo, ) -> Result<(), VulkanError>821     pub unsafe fn import_win32_handle_unchecked(
822         &self,
823         import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
824     ) -> Result<(), VulkanError> {
825         let mut state = self.state.lock();
826         self.import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)
827     }
828 
829     #[cfg(windows)]
import_win32_handle_unchecked_locked( &self, import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo, state: &mut SemaphoreState, ) -> Result<(), VulkanError>830     unsafe fn import_win32_handle_unchecked_locked(
831         &self,
832         import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
833         state: &mut SemaphoreState,
834     ) -> Result<(), VulkanError> {
835         let ImportSemaphoreWin32HandleInfo {
836             flags,
837             handle_type,
838             handle,
839             _ne: _,
840         } = import_semaphore_win32_handle_info;
841 
842         let info_vk = ash::vk::ImportSemaphoreWin32HandleInfoKHR {
843             semaphore: self.handle,
844             flags: flags.into(),
845             handle_type: handle_type.into(),
846             handle,
847             name: ptr::null(), // TODO: support?
848             ..Default::default()
849         };
850 
851         let fns = self.device.fns();
852         (fns.khr_external_semaphore_win32
853             .import_semaphore_win32_handle_khr)(self.device.handle(), &info_vk)
854         .result()
855         .map_err(VulkanError::from)?;
856 
857         state.import(
858             handle_type,
859             flags.intersects(SemaphoreImportFlags::TEMPORARY),
860         );
861 
862         Ok(())
863     }
864 
865     /// Imports a semaphore from a Zircon event handle.
866     ///
867     /// The [`fuchsia_external_semaphore`](crate::device::DeviceExtensions::fuchsia_external_semaphore)
868     /// extension must be enabled on the device.
869     ///
870     /// # Safety
871     ///
872     /// - In `import_semaphore_zircon_handle_info`, `zircon_handle` must have `ZX_RIGHTS_BASIC` and
873     ///   `ZX_RIGHTS_SIGNAL`.
874     #[cfg(target_os = "fuchsia")]
875     #[inline]
import_zircon_handle( &self, import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo, ) -> Result<(), SemaphoreError>876     pub unsafe fn import_zircon_handle(
877         &self,
878         import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
879     ) -> Result<(), SemaphoreError> {
880         let mut state = self.state.lock();
881         self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info, &state)?;
882 
883         Ok(self.import_zircon_handle_unchecked_locked(
884             import_semaphore_zircon_handle_info,
885             &mut state,
886         )?)
887     }
888 
889     #[cfg(target_os = "fuchsia")]
validate_import_zircon_handle( &self, import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo, state: &SemaphoreState, ) -> Result<(), SemaphoreError>890     fn validate_import_zircon_handle(
891         &self,
892         import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo,
893         state: &SemaphoreState,
894     ) -> Result<(), SemaphoreError> {
895         if !self.device.enabled_extensions().fuchsia_external_semaphore {
896             return Err(SemaphoreError::RequirementNotMet {
897                 required_for: "`Semaphore::import_zircon_handle`",
898                 requires_one_of: RequiresOneOf {
899                     device_extensions: &["fuchsia_external_semaphore"],
900                     ..Default::default()
901                 },
902             });
903         }
904 
905         // VUID-vkImportSemaphoreZirconHandleFUCHSIA-semaphore-04764
906         if state.is_in_queue() {
907             return Err(SemaphoreError::InQueue);
908         }
909 
910         let &ImportSemaphoreZirconHandleInfo {
911             flags,
912             handle_type,
913             zircon_handle: _,
914             _ne: _,
915         } = import_semaphore_zircon_handle_info;
916 
917         // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-flags-parameter
918         flags.validate_device(&self.device)?;
919 
920         // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-parameter
921         handle_type.validate_device(&self.device)?;
922 
923         // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-04765
924         if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
925             return Err(SemaphoreError::HandleTypeNotFd);
926         }
927 
928         // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04766
929         // VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04767
930         // Can't validate, therefore unsafe
931 
932         if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
933         {
934             return Err(SemaphoreError::HandletypeCopyNotTemporary);
935         }
936 
937         Ok(())
938     }
939 
940     #[cfg(target_os = "fuchsia")]
941     #[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
942     #[inline]
import_zircon_handle_unchecked( &self, import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo, ) -> Result<(), VulkanError>943     pub unsafe fn import_zircon_handle_unchecked(
944         &self,
945         import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
946     ) -> Result<(), VulkanError> {
947         let mut state = self.state.lock();
948         self.import_zircon_handle_unchecked_locked(import_semaphore_zircon_handle_info, &mut state)
949     }
950 
951     #[cfg(target_os = "fuchsia")]
import_zircon_handle_unchecked_locked( &self, import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo, state: &mut SemaphoreState, ) -> Result<(), VulkanError>952     unsafe fn import_zircon_handle_unchecked_locked(
953         &self,
954         import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
955         state: &mut SemaphoreState,
956     ) -> Result<(), VulkanError> {
957         let ImportSemaphoreZirconHandleInfo {
958             flags,
959             handle_type,
960             zircon_handle,
961             _ne: _,
962         } = import_semaphore_zircon_handle_info;
963 
964         let info_vk = ash::vk::ImportSemaphoreZirconHandleInfoFUCHSIA {
965             semaphore: self.handle,
966             flags: flags.into(),
967             handle_type: handle_type.into(),
968             zircon_handle,
969             ..Default::default()
970         };
971 
972         let fns = self.device.fns();
973         (fns.fuchsia_external_semaphore
974             .import_semaphore_zircon_handle_fuchsia)(self.device.handle(), &info_vk)
975         .result()
976         .map_err(VulkanError::from)?;
977 
978         state.import(
979             handle_type,
980             flags.intersects(SemaphoreImportFlags::TEMPORARY),
981         );
982 
983         Ok(())
984     }
985 
state(&self) -> MutexGuard<'_, SemaphoreState>986     pub(crate) fn state(&self) -> MutexGuard<'_, SemaphoreState> {
987         self.state.lock()
988     }
989 }
990 
991 impl Drop for Semaphore {
992     #[inline]
drop(&mut self)993     fn drop(&mut self) {
994         unsafe {
995             if self.must_put_in_pool {
996                 let raw_sem = self.handle;
997                 self.device.semaphore_pool().lock().push(raw_sem);
998             } else {
999                 let fns = self.device.fns();
1000                 (fns.v1_0.destroy_semaphore)(self.device.handle(), self.handle, ptr::null());
1001             }
1002         }
1003     }
1004 }
1005 
1006 unsafe impl VulkanObject for Semaphore {
1007     type Handle = ash::vk::Semaphore;
1008 
1009     #[inline]
handle(&self) -> Self::Handle1010     fn handle(&self) -> Self::Handle {
1011         self.handle
1012     }
1013 }
1014 
1015 unsafe impl DeviceOwned for Semaphore {
1016     #[inline]
device(&self) -> &Arc<Device>1017     fn device(&self) -> &Arc<Device> {
1018         &self.device
1019     }
1020 }
1021 
1022 impl_id_counter!(Semaphore);
1023 
1024 #[derive(Debug, Default)]
1025 pub(crate) struct SemaphoreState {
1026     is_signaled: bool,
1027     pending_signal: Option<SignalType>,
1028     pending_wait: Option<Weak<Queue>>,
1029 
1030     reference_exported: bool,
1031     exported_handle_types: ExternalSemaphoreHandleTypes,
1032     current_import: Option<ImportType>,
1033     permanent_import: Option<ExternalSemaphoreHandleType>,
1034 }
1035 
1036 impl SemaphoreState {
1037     /// If the semaphore does not have a pending operation and has no external references,
1038     /// returns the current status.
1039     #[inline]
is_signaled(&self) -> Option<bool>1040     fn is_signaled(&self) -> Option<bool> {
1041         // If any of these is true, we can't be certain of the status.
1042         if self.pending_signal.is_some()
1043             || self.pending_wait.is_some()
1044             || self.has_external_reference()
1045         {
1046             None
1047         } else {
1048             Some(self.is_signaled)
1049         }
1050     }
1051 
1052     #[inline]
is_signal_pending(&self) -> bool1053     fn is_signal_pending(&self) -> bool {
1054         self.pending_signal.is_some()
1055     }
1056 
1057     #[inline]
is_wait_pending(&self) -> bool1058     fn is_wait_pending(&self) -> bool {
1059         self.pending_wait.is_some()
1060     }
1061 
1062     #[inline]
is_in_queue(&self) -> bool1063     fn is_in_queue(&self) -> bool {
1064         matches!(self.pending_signal, Some(SignalType::Queue(_))) || self.pending_wait.is_some()
1065     }
1066 
1067     /// Returns whether there are any potential external references to the semaphore payload.
1068     /// That is, the semaphore has been exported by reference transference, or imported.
1069     #[inline]
has_external_reference(&self) -> bool1070     fn has_external_reference(&self) -> bool {
1071         self.reference_exported || self.current_import.is_some()
1072     }
1073 
1074     #[allow(dead_code)]
1075     #[inline]
is_exported(&self, handle_type: ExternalSemaphoreHandleType) -> bool1076     fn is_exported(&self, handle_type: ExternalSemaphoreHandleType) -> bool {
1077         self.exported_handle_types.intersects(handle_type.into())
1078     }
1079 
1080     #[inline]
add_queue_signal(&mut self, queue: &Arc<Queue>)1081     pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc<Queue>) {
1082         self.pending_signal = Some(SignalType::Queue(Arc::downgrade(queue)));
1083     }
1084 
1085     #[inline]
add_queue_wait(&mut self, queue: &Arc<Queue>)1086     pub(crate) unsafe fn add_queue_wait(&mut self, queue: &Arc<Queue>) {
1087         self.pending_wait = Some(Arc::downgrade(queue));
1088     }
1089 
1090     /// Called when a queue is unlocking resources.
1091     #[inline]
set_signal_finished(&mut self)1092     pub(crate) unsafe fn set_signal_finished(&mut self) {
1093         self.pending_signal = None;
1094         self.is_signaled = true;
1095     }
1096 
1097     /// Called when a queue is unlocking resources.
1098     #[inline]
set_wait_finished(&mut self)1099     pub(crate) unsafe fn set_wait_finished(&mut self) {
1100         self.pending_wait = None;
1101         self.current_import = self.permanent_import.map(Into::into);
1102         self.is_signaled = false;
1103     }
1104 
1105     #[allow(dead_code)]
1106     #[inline]
export(&mut self, handle_type: ExternalSemaphoreHandleType)1107     unsafe fn export(&mut self, handle_type: ExternalSemaphoreHandleType) {
1108         self.exported_handle_types |= handle_type.into();
1109 
1110         if handle_type.has_copy_transference() {
1111             self.current_import = self.permanent_import.map(Into::into);
1112             self.is_signaled = false;
1113         } else {
1114             self.reference_exported = true;
1115         }
1116     }
1117 
1118     #[allow(dead_code)]
1119     #[inline]
import(&mut self, handle_type: ExternalSemaphoreHandleType, temporary: bool)1120     unsafe fn import(&mut self, handle_type: ExternalSemaphoreHandleType, temporary: bool) {
1121         self.current_import = Some(handle_type.into());
1122 
1123         if !temporary {
1124             self.permanent_import = Some(handle_type);
1125         }
1126     }
1127 
1128     #[inline]
swapchain_acquire(&mut self)1129     pub(crate) unsafe fn swapchain_acquire(&mut self) {
1130         self.pending_signal = Some(SignalType::SwapchainAcquire);
1131         self.current_import = Some(ImportType::SwapchainAcquire);
1132     }
1133 }
1134 
1135 #[derive(Clone, Debug)]
1136 enum SignalType {
1137     Queue(Weak<Queue>),
1138     SwapchainAcquire,
1139 }
1140 
1141 #[derive(Clone, Copy, Debug)]
1142 enum ImportType {
1143     SwapchainAcquire,
1144     ExternalSemaphore(ExternalSemaphoreHandleType),
1145 }
1146 
1147 impl From<ExternalSemaphoreHandleType> for ImportType {
1148     #[inline]
from(handle_type: ExternalSemaphoreHandleType) -> Self1149     fn from(handle_type: ExternalSemaphoreHandleType) -> Self {
1150         Self::ExternalSemaphore(handle_type)
1151     }
1152 }
1153 
1154 /// Parameters to create a new `Semaphore`.
1155 #[derive(Clone, Debug)]
1156 pub struct SemaphoreCreateInfo {
1157     /// The handle types that can be exported from the semaphore.
1158     ///
1159     /// The default value is [`ExternalSemaphoreHandleTypes::empty()`].
1160     pub export_handle_types: ExternalSemaphoreHandleTypes,
1161 
1162     pub _ne: crate::NonExhaustive,
1163 }
1164 
1165 impl Default for SemaphoreCreateInfo {
1166     #[inline]
default() -> Self1167     fn default() -> Self {
1168         Self {
1169             export_handle_types: ExternalSemaphoreHandleTypes::empty(),
1170             _ne: crate::NonExhaustive(()),
1171         }
1172     }
1173 }
1174 
1175 vulkan_bitflags_enum! {
1176     #[non_exhaustive]
1177 
1178     /// A set of [`ExternalSemaphoreHandleType`] values.
1179     ExternalSemaphoreHandleTypes,
1180 
1181     /// The handle type used to export or import semaphores to/from an external source.
1182     ExternalSemaphoreHandleType impl {
1183         /// Returns whether the given handle type has *copy transference* rather than *reference
1184         /// transference*.
1185         ///
1186         /// Imports of handles with copy transference must always be temporary. Exports of such
1187         /// handles must only occur if no queue is waiting on the semaphore, and only if the semaphore
1188         /// is already signaled, or if there is a semaphore signal operation pending in a queue.
1189         #[inline]
1190         pub fn has_copy_transference(self) -> bool {
1191             // As defined by
1192             // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-win32
1193             // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-fd
1194             // https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-fuchsia
1195             matches!(self, Self::SyncFd)
1196         }
1197     },
1198 
1199     = ExternalSemaphoreHandleTypeFlags(u32);
1200 
1201     /// A POSIX file descriptor handle that is only usable with Vulkan and compatible APIs.
1202     ///
1203     /// This handle type has *reference transference*.
1204     OPAQUE_FD, OpaqueFd = OPAQUE_FD,
1205 
1206     /// A Windows NT handle that is only usable with Vulkan and compatible APIs.
1207     ///
1208     /// This handle type has *reference transference*.
1209     OPAQUE_WIN32, OpaqueWin32 = OPAQUE_WIN32,
1210 
1211     /// A Windows global share handle that is only usable with Vulkan and compatible APIs.
1212     ///
1213     /// This handle type has *reference transference*.
1214     OPAQUE_WIN32_KMT, OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
1215 
1216     /// A Windows NT handle that refers to a Direct3D 11 or 12 fence.
1217     ///
1218     /// This handle type has *reference transference*.
1219     D3D12_FENCE, D3D12Fence = D3D12_FENCE,
1220 
1221     /// A POSIX file descriptor handle to a Linux Sync File or Android Fence object.
1222     ///
1223     /// This handle type has *copy transference*.
1224     SYNC_FD, SyncFd = SYNC_FD,
1225 
1226     /// A handle to a Zircon event object.
1227     ///
1228     /// This handle type has *reference transference*.
1229     ///
1230     /// The [`fuchsia_external_semaphore`] extension must be enabled on the device.
1231     ///
1232     /// [`fuchsia_external_semaphore`]: crate::device::DeviceExtensions::fuchsia_external_semaphore
1233     ZIRCON_EVENT, ZirconEvent = ZIRCON_EVENT_FUCHSIA {
1234         device_extensions: [fuchsia_external_semaphore],
1235     },
1236 }
1237 
1238 vulkan_bitflags! {
1239     #[non_exhaustive]
1240 
1241     /// Additional parameters for a semaphore payload import.
1242     SemaphoreImportFlags = SemaphoreImportFlags(u32);
1243 
1244     /// The semaphore payload will be imported only temporarily, regardless of the permanence of the
1245     /// imported handle type.
1246     TEMPORARY = TEMPORARY,
1247 }
1248 
1249 #[cfg(unix)]
1250 #[derive(Debug)]
1251 pub struct ImportSemaphoreFdInfo {
1252     /// Additional parameters for the import operation.
1253     ///
1254     /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
1255     ///
1256     /// The default value is [`SemaphoreImportFlags::empty()`].
1257     pub flags: SemaphoreImportFlags,
1258 
1259     /// The handle type of `file`.
1260     ///
1261     /// There is no default value.
1262     pub handle_type: ExternalSemaphoreHandleType,
1263 
1264     /// The file to import the semaphore from.
1265     ///
1266     /// If `handle_type` is `ExternalSemaphoreHandleType::SyncFd`, then `file` can be `None`.
1267     /// Instead of an imported file descriptor, a dummy file descriptor `-1` is used,
1268     /// which represents a semaphore that is always signaled.
1269     ///
1270     /// The default value is `None`, which must be overridden if `handle_type` is not
1271     /// `ExternalSemaphoreHandleType::SyncFd`.
1272     pub file: Option<File>,
1273 
1274     pub _ne: crate::NonExhaustive,
1275 }
1276 
1277 #[cfg(unix)]
1278 impl ImportSemaphoreFdInfo {
1279     /// Returns an `ImportSemaphoreFdInfo` with the specified `handle_type`.
1280     #[inline]
handle_type(handle_type: ExternalSemaphoreHandleType) -> Self1281     pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
1282         Self {
1283             flags: SemaphoreImportFlags::empty(),
1284             handle_type,
1285             file: None,
1286             _ne: crate::NonExhaustive(()),
1287         }
1288     }
1289 }
1290 
1291 #[cfg(windows)]
1292 #[derive(Debug)]
1293 pub struct ImportSemaphoreWin32HandleInfo {
1294     /// Additional parameters for the import operation.
1295     ///
1296     /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
1297     ///
1298     /// The default value is [`SemaphoreImportFlags::empty()`].
1299     pub flags: SemaphoreImportFlags,
1300 
1301     /// The handle type of `handle`.
1302     ///
1303     /// There is no default value.
1304     pub handle_type: ExternalSemaphoreHandleType,
1305 
1306     /// The handle to import the semaphore from.
1307     ///
1308     /// The default value is `null`, which must be overridden.
1309     pub handle: *mut std::ffi::c_void,
1310 
1311     pub _ne: crate::NonExhaustive,
1312 }
1313 
1314 #[cfg(windows)]
1315 impl ImportSemaphoreWin32HandleInfo {
1316     /// Returns an `ImportSemaphoreWin32HandleInfo` with the specified `handle_type`.
1317     #[inline]
handle_type(handle_type: ExternalSemaphoreHandleType) -> Self1318     pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
1319         Self {
1320             flags: SemaphoreImportFlags::empty(),
1321             handle_type,
1322             handle: ptr::null_mut(),
1323             _ne: crate::NonExhaustive(()),
1324         }
1325     }
1326 }
1327 
1328 #[cfg(target_os = "fuchsia")]
1329 #[derive(Debug)]
1330 pub struct ImportSemaphoreZirconHandleInfo {
1331     /// Additional parameters for the import operation.
1332     ///
1333     /// If `handle_type` has *copy transference*, this must include the `temporary` flag.
1334     ///
1335     /// The default value is [`SemaphoreImportFlags::empty()`].
1336     pub flags: SemaphoreImportFlags,
1337 
1338     /// The handle type of `handle`.
1339     ///
1340     /// There is no default value.
1341     pub handle_type: ExternalSemaphoreHandleType,
1342 
1343     /// The handle to import the semaphore from.
1344     ///
1345     /// The default value is `ZX_HANDLE_INVALID`, which must be overridden.
1346     pub zircon_handle: ash::vk::zx_handle_t,
1347 
1348     pub _ne: crate::NonExhaustive,
1349 }
1350 
1351 #[cfg(target_os = "fuchsia")]
1352 impl ImportSemaphoreZirconHandleInfo {
1353     /// Returns an `ImportSemaphoreZirconHandleInfo` with the specified `handle_type`.
1354     #[inline]
handle_type(handle_type: ExternalSemaphoreHandleType) -> Self1355     pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
1356         Self {
1357             flags: SemaphoreImportFlags::empty(),
1358             handle_type,
1359             zircon_handle: 0,
1360             _ne: crate::NonExhaustive(()),
1361         }
1362     }
1363 }
1364 
1365 /// The semaphore configuration to query in
1366 /// [`PhysicalDevice::external_semaphore_properties`](crate::device::physical::PhysicalDevice::external_semaphore_properties).
1367 #[derive(Clone, Debug, PartialEq, Eq, Hash)]
1368 pub struct ExternalSemaphoreInfo {
1369     /// The external handle type that will be used with the semaphore.
1370     pub handle_type: ExternalSemaphoreHandleType,
1371 
1372     pub _ne: crate::NonExhaustive,
1373 }
1374 
1375 impl ExternalSemaphoreInfo {
1376     /// Returns an `ExternalSemaphoreInfo` with the specified `handle_type`.
1377     #[inline]
handle_type(handle_type: ExternalSemaphoreHandleType) -> Self1378     pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
1379         Self {
1380             handle_type,
1381             _ne: crate::NonExhaustive(()),
1382         }
1383     }
1384 }
1385 
1386 /// The properties for exporting or importing external handles, when a semaphore is created
1387 /// with a specific configuration.
1388 #[derive(Clone, Debug)]
1389 #[non_exhaustive]
1390 pub struct ExternalSemaphoreProperties {
1391     /// Whether a handle can be exported to an external source with the queried
1392     /// external handle type.
1393     pub exportable: bool,
1394 
1395     /// Whether a handle can be imported from an external source with the queried
1396     /// external handle type.
1397     pub importable: bool,
1398 
1399     /// Which external handle types can be re-exported after the queried external handle type has
1400     /// been imported.
1401     pub export_from_imported_handle_types: ExternalSemaphoreHandleTypes,
1402 
1403     /// Which external handle types can be enabled along with the queried external handle type
1404     /// when creating the semaphore.
1405     pub compatible_handle_types: ExternalSemaphoreHandleTypes,
1406 }
1407 
1408 /// Error that can be returned from operations on a semaphore.
1409 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1410 pub enum SemaphoreError {
1411     /// Not enough memory available.
1412     OomError(OomError),
1413 
1414     RequirementNotMet {
1415         required_for: &'static str,
1416         requires_one_of: RequiresOneOf,
1417     },
1418 
1419     /// The provided handle type does not permit more than one export,
1420     /// and a handle of this type was already exported previously.
1421     AlreadyExported,
1422 
1423     /// The provided handle type cannot be exported from the current import handle type.
1424     ExportFromImportedNotSupported {
1425         imported_handle_type: ExternalSemaphoreHandleType,
1426     },
1427 
1428     /// One of the export handle types is not compatible with the other provided handles.
1429     ExportHandleTypesNotCompatible,
1430 
1431     /// A handle type with copy transference was provided, but the semaphore is not signaled and
1432     /// there is no pending queue operation that will signal it.
1433     HandleTypeCopyNotSignaled,
1434 
1435     /// A handle type with copy transference was provided,
1436     /// but the `temporary` import flag was not set.
1437     HandletypeCopyNotTemporary,
1438 
1439     /// The provided export handle type was not set in `export_handle_types` when creating the
1440     /// semaphore.
1441     HandleTypeNotEnabled,
1442 
1443     /// Exporting is not supported for the provided handle type.
1444     HandleTypeNotExportable {
1445         handle_type: ExternalSemaphoreHandleType,
1446     },
1447 
1448     /// The provided handle type is not a POSIX file descriptor handle.
1449     HandleTypeNotFd,
1450 
1451     /// The provided handle type is not a Win32 handle.
1452     HandleTypeNotWin32,
1453 
1454     /// The provided handle type is not a Zircon event handle.
1455     HandleTypeNotZircon,
1456 
1457     /// The semaphore currently has a temporary import for a swapchain acquire operation.
1458     ImportedForSwapchainAcquire,
1459 
1460     /// The semaphore is currently in use by a queue.
1461     InQueue,
1462 
1463     /// A queue is currently waiting on the semaphore.
1464     QueueIsWaiting,
1465 }
1466 
1467 impl Error for SemaphoreError {
source(&self) -> Option<&(dyn Error + 'static)>1468     fn source(&self) -> Option<&(dyn Error + 'static)> {
1469         match self {
1470             Self::OomError(err) => Some(err),
1471             _ => None,
1472         }
1473     }
1474 }
1475 
1476 impl Display for SemaphoreError {
fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError>1477     fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
1478         match self {
1479             Self::OomError(_) => write!(f, "not enough memory available"),
1480             Self::RequirementNotMet {
1481                 required_for,
1482                 requires_one_of,
1483             } => write!(
1484                 f,
1485                 "a requirement was not met for: {}; requires one of: {}",
1486                 required_for, requires_one_of,
1487             ),
1488 
1489             Self::AlreadyExported => write!(
1490                 f,
1491                 "the provided handle type does not permit more than one export, and a handle of \
1492                 this type was already exported previously",
1493             ),
1494             Self::ExportFromImportedNotSupported {
1495                 imported_handle_type,
1496             } => write!(
1497                 f,
1498                 "the provided handle type cannot be exported from the current imported handle type \
1499                 {:?}",
1500                 imported_handle_type,
1501             ),
1502             Self::ExportHandleTypesNotCompatible => write!(
1503                 f,
1504                 "one of the export handle types is not compatible with the other provided handles",
1505             ),
1506             Self::HandleTypeCopyNotSignaled => write!(
1507                 f,
1508                 "a handle type with copy transference was provided, but the semaphore is not \
1509                 signaled and there is no pending queue operation that will signal it",
1510             ),
1511             Self::HandletypeCopyNotTemporary => write!(
1512                 f,
1513                 "a handle type with copy transference was provided, but the `temporary` \
1514                 import flag was not set",
1515             ),
1516             Self::HandleTypeNotEnabled => write!(
1517                 f,
1518                 "the provided export handle type was not set in `export_handle_types` when \
1519                 creating the semaphore",
1520             ),
1521             Self::HandleTypeNotExportable { handle_type } => write!(
1522                 f,
1523                 "exporting is not supported for handles of type {:?}",
1524                 handle_type,
1525             ),
1526             Self::HandleTypeNotFd => write!(
1527                 f,
1528                 "the provided handle type is not a POSIX file descriptor handle",
1529             ),
1530             Self::HandleTypeNotWin32 => {
1531                 write!(f, "the provided handle type is not a Win32 handle")
1532             }
1533             Self::HandleTypeNotZircon => {
1534                 write!(f, "the provided handle type is not a Zircon event handle")
1535             }
1536             Self::ImportedForSwapchainAcquire => write!(
1537                 f,
1538                 "the semaphore currently has a temporary import for a swapchain acquire operation",
1539             ),
1540             Self::InQueue => write!(f, "the semaphore is currently in use by a queue"),
1541             Self::QueueIsWaiting => write!(f, "a queue is currently waiting on the semaphore"),
1542         }
1543     }
1544 }
1545 
1546 impl From<VulkanError> for SemaphoreError {
from(err: VulkanError) -> Self1547     fn from(err: VulkanError) -> Self {
1548         match err {
1549             e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
1550                 Self::OomError(e.into())
1551             }
1552             _ => panic!("unexpected error: {:?}", err),
1553         }
1554     }
1555 }
1556 
1557 impl From<OomError> for SemaphoreError {
from(err: OomError) -> Self1558     fn from(err: OomError) -> Self {
1559         Self::OomError(err)
1560     }
1561 }
1562 
1563 impl From<RequirementNotMet> for SemaphoreError {
from(err: RequirementNotMet) -> Self1564     fn from(err: RequirementNotMet) -> Self {
1565         Self::RequirementNotMet {
1566             required_for: err.required_for,
1567             requires_one_of: err.requires_one_of,
1568         }
1569     }
1570 }
1571 
1572 #[cfg(test)]
1573 mod tests {
1574     #[cfg(unix)]
1575     use crate::{
1576         device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo},
1577         instance::{Instance, InstanceCreateInfo, InstanceExtensions},
1578         sync::semaphore::{
1579             ExternalSemaphoreHandleType, ExternalSemaphoreHandleTypes, SemaphoreCreateInfo,
1580         },
1581         VulkanLibrary,
1582     };
1583     use crate::{sync::semaphore::Semaphore, VulkanObject};
1584 
1585     #[test]
semaphore_create()1586     fn semaphore_create() {
1587         let (device, _) = gfx_dev_and_queue!();
1588         let _ = Semaphore::new(device, Default::default());
1589     }
1590 
1591     #[test]
semaphore_pool()1592     fn semaphore_pool() {
1593         let (device, _) = gfx_dev_and_queue!();
1594 
1595         assert_eq!(device.semaphore_pool().lock().len(), 0);
1596         let sem1_internal_obj = {
1597             let sem = Semaphore::from_pool(device.clone()).unwrap();
1598             assert_eq!(device.semaphore_pool().lock().len(), 0);
1599             sem.handle()
1600         };
1601 
1602         assert_eq!(device.semaphore_pool().lock().len(), 1);
1603         let sem2 = Semaphore::from_pool(device.clone()).unwrap();
1604         assert_eq!(device.semaphore_pool().lock().len(), 0);
1605         assert_eq!(sem2.handle(), sem1_internal_obj);
1606     }
1607 
1608     #[test]
1609     #[cfg(unix)]
semaphore_export_fd()1610     fn semaphore_export_fd() {
1611         let library = match VulkanLibrary::new() {
1612             Ok(x) => x,
1613             Err(_) => return,
1614         };
1615 
1616         let instance = match Instance::new(
1617             library,
1618             InstanceCreateInfo {
1619                 enabled_extensions: InstanceExtensions {
1620                     khr_get_physical_device_properties2: true,
1621                     khr_external_semaphore_capabilities: true,
1622                     ..InstanceExtensions::empty()
1623                 },
1624                 ..Default::default()
1625             },
1626         ) {
1627             Ok(x) => x,
1628             Err(_) => return,
1629         };
1630 
1631         let physical_device = match instance.enumerate_physical_devices() {
1632             Ok(mut x) => x.next().unwrap(),
1633             Err(_) => return,
1634         };
1635 
1636         let (device, _) = match Device::new(
1637             physical_device,
1638             DeviceCreateInfo {
1639                 enabled_extensions: DeviceExtensions {
1640                     khr_external_semaphore: true,
1641                     khr_external_semaphore_fd: true,
1642                     ..DeviceExtensions::empty()
1643                 },
1644                 queue_create_infos: vec![QueueCreateInfo {
1645                     queue_family_index: 0,
1646                     ..Default::default()
1647                 }],
1648                 ..Default::default()
1649             },
1650         ) {
1651             Ok(x) => x,
1652             Err(_) => return,
1653         };
1654 
1655         let sem = Semaphore::new(
1656             device,
1657             SemaphoreCreateInfo {
1658                 export_handle_types: ExternalSemaphoreHandleTypes::OPAQUE_FD,
1659                 ..Default::default()
1660             },
1661         )
1662         .unwrap();
1663         let _fd = sem
1664             .export_fd(ExternalSemaphoreHandleType::OpaqueFd)
1665             .unwrap();
1666     }
1667 }
1668