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