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