> {
+ let &Self {
+ ref semaphore,
+ _ne: _,
+ } = self;
+
+ // VUID-VkPresentInfoKHR-commonparent
+ assert_eq!(device, semaphore.device().as_ref());
+
+ Ok(())
+ }
+}
+
/// Represents a swapchain image being presented on the screen.
#[must_use = "Dropping this object will immediately block the thread until the GPU has finished processing the submission"]
pub struct PresentFuture
@@ -640,13 +829,16 @@ where
Ok(match self.previous.build_submission()? {
SubmitAnyBuilder::Empty => SubmitAnyBuilder::QueuePresent(PresentInfo {
- swapchain_infos: vec![self.swapchain_info.clone()],
+ swapchains: vec![self.swapchain_info.clone()],
..Default::default()
}),
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
SubmitAnyBuilder::QueuePresent(PresentInfo {
- wait_semaphores: semaphores.into_iter().collect(),
- swapchain_infos: vec![self.swapchain_info.clone()],
+ wait_semaphores: semaphores
+ .into_iter()
+ .map(SemaphorePresentInfo::new)
+ .collect(),
+ swapchains: vec![self.swapchain_info.clone()],
..Default::default()
})
}
@@ -654,7 +846,7 @@ where
self.previous.flush()?;
SubmitAnyBuilder::QueuePresent(PresentInfo {
- swapchain_infos: vec![self.swapchain_info.clone()],
+ swapchains: vec![self.swapchain_info.clone()],
..Default::default()
})
}
@@ -662,26 +854,24 @@ where
self.previous.flush()?;
SubmitAnyBuilder::QueuePresent(PresentInfo {
- swapchain_infos: vec![self.swapchain_info.clone()],
+ swapchains: vec![self.swapchain_info.clone()],
..Default::default()
})
}
SubmitAnyBuilder::QueuePresent(mut present_info) => {
- if present_info.swapchain_infos.first().map_or(false, |prev| {
+ if present_info.swapchains.first().map_or(false, |prev| {
prev.present_mode.is_some() != self.swapchain_info.present_mode.is_some()
}) {
// If the present mode Option variants don't match, create a new command.
self.previous.flush()?;
SubmitAnyBuilder::QueuePresent(PresentInfo {
- swapchain_infos: vec![self.swapchain_info.clone()],
+ swapchains: vec![self.swapchain_info.clone()],
..Default::default()
})
} else {
// Otherwise, add our swapchain to the previous.
- present_info
- .swapchain_infos
- .push(self.swapchain_info.clone());
+ present_info.swapchains.push(self.swapchain_info.clone());
SubmitAnyBuilder::QueuePresent(present_info)
}
@@ -701,21 +891,17 @@ where
SubmitAnyBuilder::QueuePresent(present_info) => {
let PresentInfo {
wait_semaphores: _,
- swapchain_infos,
+ swapchains,
_ne: _,
} = &present_info;
- let has_present_mode = swapchain_infos
- .first()
- .map_or(false, |first| first.present_mode.is_some());
-
- for swapchain_info in swapchain_infos {
+ for swapchain_info in swapchains {
let &SwapchainPresentInfo {
ref swapchain,
image_index: _,
present_id,
present_regions: _,
- present_mode,
+ present_mode: _,
_ne: _,
} = swapchain_info;
@@ -731,25 +917,6 @@ where
})
.into());
}
-
- if let Some(present_mode) = present_mode {
- assert!(has_present_mode);
-
- if !swapchain.present_modes().contains(&present_mode) {
- return Err(Box::new(ValidationError {
- problem: "the requested present mode is not one of the modes \
- in `swapchain.present_modes()`"
- .into(),
- vuids: &[
- "VUID-VkSwapchainPresentModeInfoEXT-pPresentModes-07761",
- ],
- ..Default::default()
- })
- .into());
- }
- } else {
- assert!(!has_present_mode);
- }
}
match self.previous.check_swapchain_image_acquired(
@@ -769,9 +936,7 @@ where
}
}
- Ok(self
- .queue
- .with(|mut q| q.present_unchecked(present_info))?
+ Ok(queue_present(&self.queue, present_info)?
.map(|r| r.map(|_| ()))
.fold(Ok(()), Result::and)?)
}
diff --git a/vulkano/src/sync/fence.rs b/vulkano/src/sync/fence.rs
index b8c629b1..f69f74dd 100644
--- a/vulkano/src/sync/fence.rs
+++ b/vulkano/src/sync/fence.rs
@@ -9,15 +9,38 @@
//! A fence provides synchronization between the device and the host, or between an external source
//! and the host.
+//!
+//! A fence has two states: **signaled** and **unsignaled**.
+//!
+//! The device can only perform one operation on a fence:
+//! - A **fence signal operation** will put the fence into the signaled state.
+//!
+//! The host can poll a fence's status, wait for it to become signaled, or reset the fence back
+//! to the unsignaled state.
+//!
+//! # Queue-to-host synchronization
+//!
+//! The primary use of a fence is to know when a queue operation has completed executing.
+//! When adding a command to a queue, a fence can be provided with the command, to be signaled
+//! when the operation finishes. You can check for a fence's current status by calling
+//! `is_signaled`, `wait` or `await` on it. If the fence is found to be signaled, that means that
+//! the queue has completed the operation that is associated with the fence, and all operations
+//! that happened-before it have been completed as well.
+//!
+//! # Safety
+//!
+//! - There must never be more than one fence signal operation queued at any given time.
+//! - The fence must be unsignaled at the time the function (for example [`submit`]) is called.
+//!
+//! [`submit`]: crate::device::QueueGuard::submit
use crate::{
- device::{physical::PhysicalDevice, Device, DeviceOwned, Queue},
+ device::{physical::PhysicalDevice, Device, DeviceOwned},
instance::InstanceOwnedDebugWrapper,
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
VulkanObject,
};
-use parking_lot::{Mutex, MutexGuard};
use smallvec::SmallVec;
use std::fs::File;
use std::{
@@ -26,32 +49,12 @@ use std::{
num::NonZeroU64,
pin::Pin,
ptr,
- sync::{Arc, Weak},
+ sync::Arc,
task::{Context, Poll},
time::Duration,
};
/// A two-state synchronization primitive that is signalled by the device and waited on by the host.
-///
-/// # Queue-to-host synchronization
-///
-/// The primary use of a fence is to know when a queue operation has completed executing.
-/// When adding a command to a queue, a fence can be provided with the command, to be signaled
-/// when the operation finishes. You can check for a fence's current status by calling
-/// `is_signaled`, `wait` or `await` on it. If the fence is found to be signaled, that means that
-/// the queue has completed the operation that is associated with the fence, and all operations that
-/// were submitted before it have been completed as well.
-///
-/// When a queue command accesses a resource, it must be kept alive until the queue command has
-/// finished executing, and you may not be allowed to perform certain other operations (or even any)
-/// while the resource is in use. By calling `is_signaled`, `wait` or `await`, the queue will be
-/// notified when the fence is signaled, so that all resources of the associated queue operation and
-/// preceding operations can be released.
-///
-/// Because of this, it is highly recommended to call `is_signaled`, `wait` or `await` on your fences.
-/// Otherwise, the queue will hold onto resources indefinitely (using up memory)
-/// and resource locks will not be released, which may cause errors when submitting future
-/// queue operations.
#[derive(Debug)]
pub struct Fence {
handle: ash::vk::Fence,
@@ -62,7 +65,6 @@ pub struct Fence {
export_handle_types: ExternalFenceHandleTypes,
must_put_in_pool: bool,
- state: Mutex,
}
impl Fence {
@@ -141,10 +143,6 @@ impl Fence {
export_handle_types,
must_put_in_pool: false,
- state: Mutex::new(FenceState {
- is_signaled: flags.intersects(FenceCreateFlags::SIGNALED),
- ..Default::default()
- }),
})
}
@@ -176,7 +174,6 @@ impl Fence {
export_handle_types: ExternalFenceHandleTypes::empty(),
must_put_in_pool: true,
- state: Mutex::new(Default::default()),
}
}
None => {
@@ -218,10 +215,6 @@ impl Fence {
export_handle_types,
must_put_in_pool: false,
- state: Mutex::new(FenceState {
- is_signaled: flags.intersects(FenceCreateFlags::SIGNALED),
- ..Default::default()
- }),
}
}
@@ -240,84 +233,44 @@ impl Fence {
/// Returns true if the fence is signaled.
#[inline]
pub fn is_signaled(&self) -> Result {
- let queue_to_signal = {
- let mut state = self.state();
-
- // If the fence is already signaled, or it's unsignaled but there's no queue that
- // could signal it, return the currently known value.
- if let Some(is_signaled) = state.is_signaled() {
- return Ok(is_signaled);
- }
-
- // We must ask Vulkan for the state.
- let result = unsafe {
- let fns = self.device.fns();
- (fns.v1_0.get_fence_status)(self.device.handle(), self.handle)
- };
-
- match result {
- ash::vk::Result::SUCCESS => unsafe { state.set_signaled() },
- ash::vk::Result::NOT_READY => return Ok(false),
- err => return Err(VulkanError::from(err)),
- }
+ let result = unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.get_fence_status)(self.device.handle(), self.handle)
};
- // If we have a queue that we need to signal our status to,
- // do so now after the state lock is dropped, to avoid deadlocks.
- if let Some(queue) = queue_to_signal {
- unsafe {
- queue.with(|mut q| q.fence_signaled(self));
- }
+ match result {
+ ash::vk::Result::SUCCESS => Ok(true),
+ ash::vk::Result::NOT_READY => Ok(false),
+ err => Err(VulkanError::from(err)),
}
-
- Ok(true)
}
/// Waits until the fence is signaled, or at least until the timeout duration has elapsed.
///
/// If you pass a duration of 0, then the function will return without blocking.
pub fn wait(&self, timeout: Option) -> Result<(), VulkanError> {
- let queue_to_signal = {
- let mut state = self.state.lock();
+ let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
+ timeout
+ .as_secs()
+ .saturating_mul(1_000_000_000)
+ .saturating_add(timeout.subsec_nanos() as u64)
+ });
- // If the fence is already signaled, we don't need to wait.
- if state.is_signaled().unwrap_or(false) {
- return Ok(());
- }
-
- let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
- timeout
- .as_secs()
- .saturating_mul(1_000_000_000)
- .saturating_add(timeout.subsec_nanos() as u64)
- });
-
- let result = unsafe {
- let fns = self.device.fns();
- (fns.v1_0.wait_for_fences)(
- self.device.handle(),
- 1,
- &self.handle,
- ash::vk::TRUE,
- timeout_ns,
- )
- };
-
- match result {
- ash::vk::Result::SUCCESS => unsafe { state.set_signaled() },
- err => return Err(VulkanError::from(err)),
- }
+ let result = unsafe {
+ let fns = self.device.fns();
+ (fns.v1_0.wait_for_fences)(
+ self.device.handle(),
+ 1,
+ &self.handle,
+ ash::vk::TRUE,
+ timeout_ns,
+ )
};
- // If we have a queue that we need to signal our status to,
- // do so now after the state lock is dropped, to avoid deadlocks.
- if let Some(queue) = queue_to_signal {
- unsafe {
- queue.with(|mut q| q.fence_signaled(self));
- }
+ match result {
+ ash::vk::Result::SUCCESS => Ok(()),
+ err => Err(VulkanError::from(err)),
}
-
- Ok(())
}
/// Waits for multiple fences at once.
@@ -358,153 +311,96 @@ impl Fence {
fences: impl IntoIterator- ,
timeout: Option,
) -> Result<(), VulkanError> {
- let queues_to_signal: SmallVec<[_; 8]> = {
- let iter = fences.into_iter();
- let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new();
- let mut fences: SmallVec<[_; 8]> = SmallVec::new();
- let mut states: SmallVec<[_; 8]> = SmallVec::new();
+ let iter = fences.into_iter();
+ let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new();
+ let mut fences: SmallVec<[_; 8]> = SmallVec::new();
- for fence in iter {
- let state = fence.state.lock();
-
- // Skip the fences that are already signaled.
- if !state.is_signaled().unwrap_or(false) {
- fences_vk.push(fence.handle);
- fences.push(fence);
- states.push(state);
- }
- }
-
- // VUID-vkWaitForFences-fenceCount-arraylength
- // If there are no fences, or all the fences are signaled, we don't need to wait.
- if fences_vk.is_empty() {
- return Ok(());
- }
-
- let device = &fences[0].device;
- let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
- timeout
- .as_secs()
- .saturating_mul(1_000_000_000)
- .saturating_add(timeout.subsec_nanos() as u64)
- });
-
- let result = {
- let fns = device.fns();
- (fns.v1_0.wait_for_fences)(
- device.handle(),
- fences_vk.len() as u32,
- fences_vk.as_ptr(),
- ash::vk::TRUE, // TODO: let the user choose false here?
- timeout_ns,
- )
- };
-
- match result {
- ash::vk::Result::SUCCESS => fences
- .into_iter()
- .zip(&mut states)
- .filter_map(|(fence, state)| state.set_signaled().map(|state| (state, fence)))
- .collect(),
- err => return Err(VulkanError::from(err)),
- }
- };
-
- // If we have queues that we need to signal our status to,
- // do so now after the state locks are dropped, to avoid deadlocks.
- for (queue, fence) in queues_to_signal {
- queue.with(|mut q| q.fence_signaled(fence));
+ for fence in iter {
+ fences_vk.push(fence.handle);
+ fences.push(fence);
}
- Ok(())
+ // VUID-vkWaitForFences-fenceCount-arraylength
+ // If there are no fences, we don't need to wait.
+ if fences_vk.is_empty() {
+ return Ok(());
+ }
+
+ let device = &fences[0].device;
+ let timeout_ns = timeout.map_or(u64::MAX, |timeout| {
+ timeout
+ .as_secs()
+ .saturating_mul(1_000_000_000)
+ .saturating_add(timeout.subsec_nanos() as u64)
+ });
+
+ let result = {
+ let fns = device.fns();
+ (fns.v1_0.wait_for_fences)(
+ device.handle(),
+ fences_vk.len() as u32,
+ fences_vk.as_ptr(),
+ ash::vk::TRUE, // TODO: let the user choose false here?
+ timeout_ns,
+ )
+ };
+
+ match result {
+ ash::vk::Result::SUCCESS => Ok(()),
+ err => Err(VulkanError::from(err)),
+ }
}
/// Resets the fence.
///
- /// The fence must not be in use by a queue operation.
+ /// # Safety
+ ///
+ /// - The fence must not be in use by the device.
#[inline]
- pub fn reset(&self) -> Result<(), Validated> {
- let mut state = self.state.lock();
- self.validate_reset(&state)?;
+ pub unsafe fn reset(&self) -> Result<(), Validated> {
+ self.validate_reset()?;
- unsafe { Ok(self.reset_unchecked_locked(&mut state)?) }
+ unsafe { Ok(self.reset_unchecked()?) }
}
- fn validate_reset(&self, state: &FenceState) -> Result<(), Box> {
- if state.is_in_queue() {
- return Err(Box::new(ValidationError {
- problem: "the fence is in use".into(),
- vuids: &["VUID-vkResetFences-pFences-01123"],
- ..Default::default()
- }));
- }
-
+ fn validate_reset(&self) -> Result<(), Box> {
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn reset_unchecked(&self) -> Result<(), VulkanError> {
- let mut state = self.state.lock();
-
- self.reset_unchecked_locked(&mut state)
- }
-
- unsafe fn reset_unchecked_locked(&self, state: &mut FenceState) -> Result<(), VulkanError> {
let fns = self.device.fns();
(fns.v1_0.reset_fences)(self.device.handle(), 1, &self.handle)
.result()
.map_err(VulkanError::from)?;
- state.reset();
-
Ok(())
}
/// Resets multiple fences at once.
///
- /// The fences must not be in use by a queue operation.
+ /// # Safety
///
- /// # Panics
- ///
- /// - Panics if not all fences belong to the same device.
- pub fn multi_reset<'a>(
+ /// - The elements of `fences` must not be in use by the device.
+ pub unsafe fn multi_reset<'a>(
fences: impl IntoIterator
- ,
) -> Result<(), Validated> {
- let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences
- .into_iter()
- .map(|fence| {
- let state = fence.state.lock();
- (fence, state)
- })
- .unzip();
- Self::validate_multi_reset(&fences, &states)?;
+ let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
+ Self::validate_multi_reset(&fences)?;
- unsafe { Ok(Self::multi_reset_unchecked_locked(&fences, &mut states)?) }
+ unsafe { Ok(Self::multi_reset_unchecked(fences)?) }
}
- fn validate_multi_reset(
- fences: &[&Fence],
- states: &[MutexGuard<'_, FenceState>],
- ) -> Result<(), Box> {
+ fn validate_multi_reset(fences: &[&Fence]) -> Result<(), Box> {
if fences.is_empty() {
return Ok(());
}
let device = &fences[0].device;
- for (fence_index, (fence, state)) in fences.iter().zip(states).enumerate() {
+ for fence in fences {
// VUID-vkResetFences-pFences-parent
assert_eq!(device, &fence.device);
-
- if state.is_in_queue() {
- return Err(Box::new(ValidationError {
- context: format!("fences[{}]", fence_index).into(),
- problem: "the fence is in use".into(),
- vuids: &["VUID-vkResetFences-pFences-01123"],
- ..Default::default()
- }));
- }
}
Ok(())
@@ -514,21 +410,8 @@ impl Fence {
pub unsafe fn multi_reset_unchecked<'a>(
fences: impl IntoIterator
- ,
) -> Result<(), VulkanError> {
- let (fences, mut states): (SmallVec<[_; 8]>, SmallVec<[_; 8]>) = fences
- .into_iter()
- .map(|fence| {
- let state = fence.state.lock();
- (fence, state)
- })
- .unzip();
+ let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
- Self::multi_reset_unchecked_locked(&fences, &mut states)
- }
-
- unsafe fn multi_reset_unchecked_locked(
- fences: &[&Fence],
- states: &mut [MutexGuard<'_, FenceState>],
- ) -> Result<(), VulkanError> {
if fences.is_empty() {
return Ok(());
}
@@ -541,10 +424,6 @@ impl Fence {
.result()
.map_err(VulkanError::from)?;
- for state in states {
- state.reset();
- }
-
Ok(())
}
@@ -552,21 +431,27 @@ impl Fence {
///
/// The [`khr_external_fence_fd`](crate::device::DeviceExtensions::khr_external_fence_fd)
/// extension must be enabled on the device.
+ ///
+ /// # Safety
+ ///
+ /// - If `handle_type` has copy transference, then the fence must be signaled, or a signal
+ /// operation on the fence must be pending.
+ /// - The fence must not currently have an imported payload from a swapchain acquire operation.
+ /// - If the fence has an imported payload, its handle type must allow re-exporting as
+ /// `handle_type`, as returned by [`PhysicalDevice::external_fence_properties`].
#[inline]
- pub fn export_fd(
+ pub unsafe fn export_fd(
&self,
handle_type: ExternalFenceHandleType,
) -> Result> {
- let mut state = self.state.lock();
- self.validate_export_fd(handle_type, &state)?;
+ self.validate_export_fd(handle_type)?;
- unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
+ unsafe { Ok(self.export_fd_unchecked(handle_type)?) }
}
fn validate_export_fd(
&self,
handle_type: ExternalFenceHandleType,
- state: &FenceState,
) -> Result<(), Box> {
if !self.device.enabled_extensions().khr_external_fence_fd {
return Err(Box::new(ValidationError {
@@ -604,73 +489,13 @@ impl Fence {
}));
}
- if handle_type.has_copy_transference()
- && !(state.is_signaled().unwrap_or(false) || state.is_in_queue())
- {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` has copy transference, but \
- the fence is not signaled, and \
- a signal operation on the fence is not pending"
- .into(),
- vuids: &["VUID-VkFenceGetFdInfoKHR-handleType-01454"],
- ..Default::default()
- }));
- }
-
- if let Some(imported_handle_type) = state.current_import {
- match imported_handle_type {
- ImportType::SwapchainAcquire => {
- return Err(Box::new(ValidationError {
- problem: "the fence currently has an imported payload from a \
- swapchain acquire operation"
- .into(),
- vuids: &["VUID-VkFenceGetFdInfoKHR-fence-01455"],
- ..Default::default()
- }));
- }
- ImportType::ExternalFence(imported_handle_type) => {
- let external_fence_properties = unsafe {
- self.device
- .physical_device()
- .external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
- handle_type,
- ))
- };
-
- if !external_fence_properties
- .export_from_imported_handle_types
- .intersects(imported_handle_type.into())
- {
- return Err(Box::new(ValidationError {
- problem: "the fence currently has an imported payload, whose type \
- does not allow re-exporting as `handle_type`, as \
- returned by `PhysicalDevice::external_fence_properties`"
- .into(),
- vuids: &["VUID-VkFenceGetFdInfoKHR-fence-01455"],
- ..Default::default()
- }));
- }
- }
- }
- }
-
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn export_fd_unchecked(
&self,
handle_type: ExternalFenceHandleType,
- ) -> Result {
- let mut state = self.state.lock();
- self.export_fd_unchecked_locked(handle_type, &mut state)
- }
-
- unsafe fn export_fd_unchecked_locked(
- &self,
- handle_type: ExternalFenceHandleType,
- state: &mut FenceState,
) -> Result {
let info_vk = ash::vk::FenceGetFdInfoKHR {
fence: self.handle,
@@ -688,8 +513,6 @@ impl Fence {
.result()
.map_err(VulkanError::from)?;
- state.export(handle_type);
-
#[cfg(unix)]
{
use std::os::unix::io::FromRawFd;
@@ -707,21 +530,29 @@ impl Fence {
///
/// The [`khr_external_fence_win32`](crate::device::DeviceExtensions::khr_external_fence_win32)
/// extension must be enabled on the device.
+ ///
+ /// # Safety
+ ///
+ /// - If `handle_type` has copy transference, then the fence must be signaled, or a signal
+ /// operation on the fence must be pending.
+ /// - The fence must not currently have an imported payload from a swapchain acquire operation.
+ /// - If the fence has an imported payload, its handle type must allow re-exporting as
+ /// `handle_type`, as returned by [`PhysicalDevice::external_fence_properties`].
+ /// - If `handle_type` is `ExternalFenceHandleType::OpaqueWin32`, then a handle of this type
+ /// must not have been already exported from this fence.
#[inline]
pub fn export_win32_handle(
&self,
handle_type: ExternalFenceHandleType,
) -> Result<*mut std::ffi::c_void, Validated> {
- let mut state = self.state.lock();
- self.validate_export_win32_handle(handle_type, &state)?;
+ self.validate_export_win32_handle(handle_type)?;
- unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
+ unsafe { Ok(self.export_win32_handle_unchecked(handle_type)?) }
}
fn validate_export_win32_handle(
&self,
handle_type: ExternalFenceHandleType,
- state: &FenceState,
) -> Result<(), Box> {
if !self.device.enabled_extensions().khr_external_fence_win32 {
return Err(Box::new(ValidationError {
@@ -759,85 +590,13 @@ impl Fence {
}));
}
- if matches!(handle_type, ExternalFenceHandleType::OpaqueWin32)
- && state.is_exported(handle_type)
- {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` is `ExternalFenceHandleType::OpaqueWin32`, but \
- a handle of this type has already been exported from this fence"
- .into(),
- vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01449"],
- ..Default::default()
- }));
- }
-
- if handle_type.has_copy_transference()
- && !(state.is_signaled().unwrap_or(false) || state.is_in_queue())
- {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` has copy transference, but \
- the fence is not signaled, and \
- a signal operation on the fence is not pending"
- .into(),
- vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01451"],
- ..Default::default()
- }));
- }
-
- if let Some(imported_handle_type) = state.current_import {
- match imported_handle_type {
- ImportType::SwapchainAcquire => {
- return Err(Box::new(ValidationError {
- problem: "the fence currently has an imported payload from a \
- swapchain acquire operation"
- .into(),
- vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-fence-01450"],
- ..Default::default()
- }));
- }
- ImportType::ExternalFence(imported_handle_type) => {
- let external_fence_properties = unsafe {
- self.device
- .physical_device()
- .external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
- handle_type,
- ))
- };
-
- if !external_fence_properties
- .export_from_imported_handle_types
- .intersects(imported_handle_type.into())
- {
- return Err(Box::new(ValidationError {
- problem: "the fence currently has an imported payload, whose type \
- does not allow re-exporting as `handle_type`, as \
- returned by `PhysicalDevice::external_fence_properties`"
- .into(),
- vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-fence-01450"],
- ..Default::default()
- }));
- }
- }
- }
- }
-
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn export_win32_handle_unchecked(
&self,
handle_type: ExternalFenceHandleType,
- ) -> Result<*mut std::ffi::c_void, VulkanError> {
- let mut state = self.state.lock();
- self.export_win32_handle_unchecked_locked(handle_type, &mut state)
- }
-
- unsafe fn export_win32_handle_unchecked_locked(
- &self,
- handle_type: ExternalFenceHandleType,
- state: &mut FenceState,
) -> Result<*mut std::ffi::c_void, VulkanError> {
let info_vk = ash::vk::FenceGetWin32HandleInfoKHR {
fence: self.handle,
@@ -855,8 +614,6 @@ impl Fence {
.result()
.map_err(VulkanError::from)?;
- state.export(handle_type);
-
Ok(output.assume_init())
}
@@ -867,6 +624,7 @@ impl Fence {
///
/// # Safety
///
+ /// - The fence must not be in use by the device.
/// - If in `import_fence_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
/// then `file` must represent a fence that was exported from Vulkan or a compatible API,
/// with a driver and device UUID equal to those of the device that owns `self`.
@@ -875,16 +633,14 @@ impl Fence {
&self,
import_fence_fd_info: ImportFenceFdInfo,
) -> Result<(), Validated> {
- let mut state = self.state.lock();
- self.validate_import_fd(&import_fence_fd_info, &state)?;
+ self.validate_import_fd(&import_fence_fd_info)?;
- Ok(self.import_fd_unchecked_locked(import_fence_fd_info, &mut state)?)
+ Ok(self.import_fd_unchecked(import_fence_fd_info)?)
}
fn validate_import_fd(
&self,
import_fence_fd_info: &ImportFenceFdInfo,
- state: &FenceState,
) -> Result<(), Box> {
if !self.device.enabled_extensions().khr_external_fence_fd {
return Err(Box::new(ValidationError {
@@ -895,14 +651,6 @@ impl Fence {
}));
}
- if state.is_in_queue() {
- return Err(Box::new(ValidationError {
- problem: "the fence is in use".into(),
- vuids: &["VUID-vkImportFenceFdKHR-fence-01463"],
- ..Default::default()
- }));
- }
-
import_fence_fd_info
.validate(&self.device)
.map_err(|err| err.add_context("import_fence_fd_info"))?;
@@ -911,19 +659,9 @@ impl Fence {
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn import_fd_unchecked(
&self,
import_fence_fd_info: ImportFenceFdInfo,
- ) -> Result<(), VulkanError> {
- let mut state = self.state.lock();
- self.import_fd_unchecked_locked(import_fence_fd_info, &mut state)
- }
-
- unsafe fn import_fd_unchecked_locked(
- &self,
- import_fence_fd_info: ImportFenceFdInfo,
- state: &mut FenceState,
) -> Result<(), VulkanError> {
let ImportFenceFdInfo {
flags,
@@ -957,8 +695,6 @@ impl Fence {
.result()
.map_err(VulkanError::from)?;
- state.import(handle_type, flags.intersects(FenceImportFlags::TEMPORARY));
-
Ok(())
}
@@ -969,6 +705,7 @@ impl Fence {
///
/// # Safety
///
+ /// - The fence must not be in use by the device.
/// - In `import_fence_win32_handle_info`, `handle` must represent a fence that was exported
/// from Vulkan or a compatible API, with a driver and device UUID equal to those of the
/// device that owns `self`.
@@ -977,16 +714,14 @@ impl Fence {
&self,
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
) -> Result<(), Validated> {
- let mut state = self.state.lock();
- self.validate_import_win32_handle(&import_fence_win32_handle_info, &state)?;
+ self.validate_import_win32_handle(&import_fence_win32_handle_info)?;
- Ok(self.import_win32_handle_unchecked_locked(import_fence_win32_handle_info, &mut state)?)
+ Ok(self.import_win32_handle_unchecked(import_fence_win32_handle_info)?)
}
fn validate_import_win32_handle(
&self,
import_fence_win32_handle_info: &ImportFenceWin32HandleInfo,
- state: &FenceState,
) -> Result<(), Box> {
if !self.device.enabled_extensions().khr_external_fence_win32 {
return Err(Box::new(ValidationError {
@@ -997,14 +732,6 @@ impl Fence {
}));
}
- if state.is_in_queue() {
- return Err(Box::new(ValidationError {
- problem: "the fence is in use".into(),
- vuids: &["VUID-vkImportFenceWin32HandleKHR-fence-04448"],
- ..Default::default()
- }));
- }
-
import_fence_win32_handle_info
.validate(&self.device)
.map_err(|err| err.add_context("import_fence_win32_handle_info"))?;
@@ -1013,19 +740,9 @@ impl Fence {
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn import_win32_handle_unchecked(
&self,
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
- ) -> Result<(), VulkanError> {
- let mut state = self.state.lock();
- self.import_win32_handle_unchecked_locked(import_fence_win32_handle_info, &mut state)
- }
-
- unsafe fn import_win32_handle_unchecked_locked(
- &self,
- import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
- state: &mut FenceState,
) -> Result<(), VulkanError> {
let ImportFenceWin32HandleInfo {
flags,
@@ -1051,15 +768,9 @@ impl Fence {
.result()
.map_err(VulkanError::from)?;
- state.import(handle_type, flags.intersects(FenceImportFlags::TEMPORARY));
-
Ok(())
}
- pub(crate) fn state(&self) -> MutexGuard<'_, FenceState> {
- self.state.lock()
- }
-
// Shared by Fence and FenceSignalFuture
pub(crate) fn poll_impl(&self, cx: &mut Context<'_>) -> Poll> {
// Vulkan only allows polling of the fence status, so we have to use a spin future.
@@ -1527,124 +1238,6 @@ pub struct ExternalFenceProperties {
pub compatible_handle_types: ExternalFenceHandleTypes,
}
-#[derive(Debug, Default)]
-pub(crate) struct FenceState {
- is_signaled: bool,
- pending_signal: Option>,
-
- reference_exported: bool,
- exported_handle_types: ExternalFenceHandleTypes,
- current_import: Option,
- permanent_import: Option,
-}
-
-impl FenceState {
- /// If the fence is not in a queue and has no external references, returns the current status.
- #[inline]
- fn is_signaled(&self) -> Option {
- // If either of these is true, we can't be certain of the status.
- if self.is_in_queue() || self.has_external_reference() {
- None
- } else {
- Some(self.is_signaled)
- }
- }
-
- #[inline]
- fn is_in_queue(&self) -> bool {
- self.pending_signal.is_some()
- }
-
- /// Returns whether there are any potential external references to the fence payload.
- /// That is, the fence has been exported by reference transference, or imported.
- #[inline]
- fn has_external_reference(&self) -> bool {
- self.reference_exported || self.current_import.is_some()
- }
-
- #[allow(dead_code)]
- #[inline]
- fn is_exported(&self, handle_type: ExternalFenceHandleType) -> bool {
- self.exported_handle_types.intersects(handle_type.into())
- }
-
- #[inline]
- pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc) {
- self.pending_signal = Some(Arc::downgrade(queue));
- }
-
- /// Called when a fence first discovers that it is signaled.
- /// Returns the queue that should be informed about it.
- #[inline]
- unsafe fn set_signaled(&mut self) -> Option> {
- self.is_signaled = true;
-
- // Fences with external references can't be used to determine queue completion.
- if self.has_external_reference() {
- self.pending_signal = None;
- None
- } else {
- self.pending_signal.take().and_then(|queue| queue.upgrade())
- }
- }
-
- /// Called when a queue is unlocking resources.
- #[inline]
- pub(crate) unsafe fn set_signal_finished(&mut self) {
- self.is_signaled = true;
- self.pending_signal = None;
- }
-
- #[inline]
- unsafe fn reset(&mut self) {
- debug_assert!(!self.is_in_queue());
- self.current_import = self.permanent_import.map(Into::into);
- self.is_signaled = false;
- }
-
- #[allow(dead_code)]
- #[inline]
- unsafe fn export(&mut self, handle_type: ExternalFenceHandleType) {
- self.exported_handle_types |= handle_type.into();
-
- if handle_type.has_copy_transference() {
- self.reset();
- } else {
- self.reference_exported = true;
- }
- }
-
- #[allow(dead_code)]
- #[inline]
- unsafe fn import(&mut self, handle_type: ExternalFenceHandleType, temporary: bool) {
- debug_assert!(!self.is_in_queue());
- self.current_import = Some(handle_type.into());
-
- if !temporary {
- self.permanent_import = Some(handle_type);
- }
- }
-
- #[inline]
- pub(crate) unsafe fn import_swapchain_acquire(&mut self) {
- debug_assert!(!self.is_in_queue());
- self.current_import = Some(ImportType::SwapchainAcquire);
- }
-}
-
-#[derive(Clone, Copy, Debug)]
-enum ImportType {
- SwapchainAcquire,
- ExternalFence(ExternalFenceHandleType),
-}
-
-impl From for ImportType {
- #[inline]
- fn from(handle_type: ExternalFenceHandleType) -> Self {
- Self::ExternalFence(handle_type)
- }
-}
-
#[cfg(test)]
mod tests {
use crate::{
@@ -1703,7 +1296,11 @@ mod tests {
},
)
.unwrap();
- fence.reset().unwrap();
+
+ unsafe {
+ fence.reset().unwrap();
+ }
+
assert!(!fence.is_signaled().unwrap());
}
@@ -1760,7 +1357,7 @@ mod tests {
)
.unwrap();
- let _ = Fence::multi_reset([&fence1, &fence2]);
+ let _ = unsafe { Fence::multi_reset([&fence1, &fence2]) };
});
}
diff --git a/vulkano/src/sync/future/fence_signal.rs b/vulkano/src/sync/future/fence_signal.rs
index 02c5b586..7b5b950b 100644
--- a/vulkano/src/sync/future/fence_signal.rs
+++ b/vulkano/src/sync/future/fence_signal.rs
@@ -16,7 +16,7 @@ use crate::{
swapchain::Swapchain,
sync::{
fence::Fence,
- future::{AccessError, SubmitAnyBuilder},
+ future::{queue_bind_sparse, queue_present, queue_submit, AccessError, SubmitAnyBuilder},
PipelineStages,
},
DeviceSize, Validated, ValidationError, VulkanError,
@@ -243,35 +243,36 @@ where
SubmitAnyBuilder::Empty => {
debug_assert!(!partially_flushed);
- queue
- .with(|mut q| {
- q.submit_unchecked([Default::default()], Some(new_fence.clone()))
- })
- .map_err(|err| OutcomeErr::Full(err.into()))
+ queue_submit(
+ &queue,
+ Default::default(),
+ Some(new_fence.clone()),
+ &previous,
+ )
+ .map_err(OutcomeErr::Full)
}
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
debug_assert!(!partially_flushed);
- queue
- .with(|mut q| {
- q.submit_unchecked(
- [SubmitInfo {
- wait_semaphores: semaphores
- .into_iter()
- .map(|semaphore| {
- SemaphoreSubmitInfo {
- // TODO: correct stages ; hard
- stages: PipelineStages::ALL_COMMANDS,
- ..SemaphoreSubmitInfo::semaphore(semaphore)
- }
- })
- .collect(),
- ..Default::default()
- }],
- None,
- )
- })
- .map_err(|err| OutcomeErr::Full(err.into()))
+ queue_submit(
+ &queue,
+ SubmitInfo {
+ wait_semaphores: semaphores
+ .into_iter()
+ .map(|semaphore| {
+ SemaphoreSubmitInfo {
+ // TODO: correct stages ; hard
+ stages: PipelineStages::ALL_COMMANDS,
+ ..SemaphoreSubmitInfo::new(semaphore)
+ }
+ })
+ .collect(),
+ ..Default::default()
+ },
+ None,
+ &previous,
+ )
+ .map_err(OutcomeErr::Full)
}
SubmitAnyBuilder::CommandBuffer(submit_info, fence) => {
debug_assert!(!partially_flushed);
@@ -282,15 +283,7 @@ where
// assertion.
assert!(fence.is_none());
- queue
- .with(|mut q| {
- q.submit_with_future(
- submit_info,
- Some(new_fence.clone()),
- &previous,
- &queue,
- )
- })
+ queue_submit(&queue, submit_info, Some(new_fence.clone()), &previous)
.map_err(OutcomeErr::Full)
}
SubmitAnyBuilder::BindSparse(bind_infos, fence) => {
@@ -302,19 +295,20 @@ where
.queue_flags
.intersects(QueueFlags::SPARSE_BINDING));
- queue
- .with(|mut q| q.bind_sparse_unchecked(bind_infos, Some(new_fence.clone())))
- .map_err(|err| OutcomeErr::Full(err.into()))
+ queue_bind_sparse(&queue, bind_infos, Some(new_fence.clone()))
+ .map_err(OutcomeErr::Full)
}
SubmitAnyBuilder::QueuePresent(present_info) => {
if partially_flushed {
- queue
- .with(|mut q| {
- q.submit_unchecked([Default::default()], Some(new_fence.clone()))
- })
- .map_err(|err| OutcomeErr::Partial(err.into()))
+ queue_submit(
+ &queue,
+ Default::default(),
+ Some(new_fence.clone()),
+ &previous,
+ )
+ .map_err(OutcomeErr::Partial)
} else {
- for swapchain_info in &present_info.swapchain_infos {
+ for swapchain_info in &present_info.swapchains {
if swapchain_info.present_id.map_or(false, |present_id| {
!swapchain_info.swapchain.try_claim_present_id(present_id)
}) {
@@ -346,20 +340,18 @@ where
}
}
- let intermediary_result = queue
- .with(|mut q| q.present_unchecked(present_info))?
+ let intermediary_result = queue_present(&queue, present_info)?
.map(|r| r.map(|_| ()))
.fold(Ok(()), Result::and);
match intermediary_result {
- Ok(()) => queue
- .with(|mut q| {
- q.submit_unchecked(
- [Default::default()],
- Some(new_fence.clone()),
- )
- })
- .map_err(|err| OutcomeErr::Partial(err.into())),
+ Ok(()) => queue_submit(
+ &queue,
+ Default::default(),
+ Some(new_fence.clone()),
+ &previous,
+ )
+ .map_err(OutcomeErr::Partial),
Err(err) => Err(OutcomeErr::Full(err.into())),
}
}
diff --git a/vulkano/src/sync/future/mod.rs b/vulkano/src/sync/future/mod.rs
index b186dfe1..2537aef6 100644
--- a/vulkano/src/sync/future/mod.rs
+++ b/vulkano/src/sync/future/mod.rs
@@ -98,22 +98,26 @@ pub use self::{
};
use super::{fence::Fence, semaphore::Semaphore};
use crate::{
- buffer::Buffer,
+ buffer::{Buffer, BufferState},
command_buffer::{
- CommandBufferExecError, CommandBufferExecFuture, PrimaryCommandBufferAbstract, SubmitInfo,
+ CommandBufferExecError, CommandBufferExecFuture, CommandBufferResourcesUsage,
+ CommandBufferState, CommandBufferSubmitInfo, CommandBufferUsage,
+ PrimaryCommandBufferAbstract, SubmitInfo,
},
device::{DeviceOwned, Queue},
- image::{Image, ImageLayout},
+ image::{Image, ImageLayout, ImageState},
memory::BindSparseInfo,
swapchain::{self, PresentFuture, PresentInfo, Swapchain, SwapchainPresentInfo},
- DeviceSize, Validated, VulkanError,
+ DeviceSize, Validated, ValidationError, VulkanError, VulkanObject,
};
-use smallvec::SmallVec;
+use ahash::HashMap;
+use parking_lot::MutexGuard;
+use smallvec::{smallvec, SmallVec};
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
ops::Range,
- sync::Arc,
+ sync::{atomic::Ordering, Arc},
};
mod fence_signal;
@@ -554,3 +558,321 @@ impl From for AccessCheckError {
AccessCheckError::Denied(err)
}
}
+
+pub(crate) unsafe fn queue_bind_sparse(
+ queue: &Arc,
+ bind_infos: impl IntoIterator
- ,
+ fence: Option>,
+) -> Result<(), Validated> {
+ let bind_infos: SmallVec<[_; 4]> = bind_infos.into_iter().collect();
+ queue.with(|mut queue_guard| queue_guard.bind_sparse_unchecked(&bind_infos, fence.as_ref()))?;
+
+ Ok(())
+}
+
+pub(crate) unsafe fn queue_present(
+ queue: &Arc,
+ present_info: PresentInfo,
+) -> Result>, Validated> {
+ let results: SmallVec<[_; 1]> = queue
+ .with(|mut queue_guard| queue_guard.present(&present_info))?
+ .collect();
+
+ let PresentInfo {
+ wait_semaphores: _,
+ swapchains,
+ _ne: _,
+ } = &present_info;
+
+ // If a presentation results in a loss of full-screen exclusive mode,
+ // signal that to the relevant swapchain.
+ for (&result, swapchain_info) in results.iter().zip(swapchains) {
+ if result == Err(VulkanError::FullScreenExclusiveModeLost) {
+ swapchain_info
+ .swapchain
+ .full_screen_exclusive_held()
+ .store(false, Ordering::SeqCst);
+ }
+ }
+
+ Ok(results.into_iter())
+}
+
+pub(crate) unsafe fn queue_submit(
+ queue: &Arc,
+ submit_info: SubmitInfo,
+ fence: Option>,
+ future: &dyn GpuFuture,
+) -> Result<(), Validated> {
+ let submit_infos: SmallVec<[_; 4]> = smallvec![submit_info];
+ let mut states = States::from_submit_infos(&submit_infos);
+
+ for submit_info in &submit_infos {
+ for command_buffer_submit_info in &submit_info.command_buffers {
+ let &CommandBufferSubmitInfo {
+ ref command_buffer,
+ _ne: _,
+ } = command_buffer_submit_info;
+
+ let state = states
+ .command_buffers
+ .get(&command_buffer.handle())
+ .unwrap();
+
+ match command_buffer.usage() {
+ CommandBufferUsage::OneTimeSubmit => {
+ if state.has_been_submitted() {
+ return Err(Box::new(ValidationError {
+ problem: "a command buffer, or one of the secondary \
+ command buffers it executes, was created with the \
+ `CommandBufferUsage::OneTimeSubmit` usage, but \
+ it has already been submitted in the past"
+ .into(),
+ vuids: &["VUID-vkQueueSubmit2-commandBuffer-03874"],
+ ..Default::default()
+ })
+ .into());
+ }
+ }
+ CommandBufferUsage::MultipleSubmit => {
+ if state.is_submit_pending() {
+ return Err(Box::new(ValidationError {
+ problem: "a command buffer, or one of the secondary \
+ command buffers it executes, was not created with the \
+ `CommandBufferUsage::SimultaneousUse` usage, but \
+ it is already in use by the device"
+ .into(),
+ vuids: &["VUID-vkQueueSubmit2-commandBuffer-03875"],
+ ..Default::default()
+ })
+ .into());
+ }
+ }
+ CommandBufferUsage::SimultaneousUse => (),
+ }
+
+ let CommandBufferResourcesUsage {
+ buffers,
+ images,
+ buffer_indices: _,
+ image_indices: _,
+ } = command_buffer.resources_usage();
+
+ for usage in buffers {
+ let state = states.buffers.get_mut(&usage.buffer.handle()).unwrap();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ match future.check_buffer_access(
+ &usage.buffer,
+ range.clone(),
+ range_usage.mutable,
+ queue,
+ ) {
+ Err(AccessCheckError::Denied(error)) => {
+ return Err(Box::new(ValidationError {
+ problem: format!(
+ "access to a resource has been denied \
+ (resource use: {:?}, error: {})",
+ range_usage.first_use, error
+ )
+ .into(),
+ ..Default::default()
+ })
+ .into());
+ }
+ Err(AccessCheckError::Unknown) => {
+ let result = if range_usage.mutable {
+ state.check_gpu_write(range.clone())
+ } else {
+ state.check_gpu_read(range.clone())
+ };
+
+ if let Err(error) = result {
+ return Err(Box::new(ValidationError {
+ problem: format!(
+ "access to a resource has been denied \
+ (resource use: {:?}, error: {})",
+ range_usage.first_use, error
+ )
+ .into(),
+ ..Default::default()
+ })
+ .into());
+ }
+ }
+ _ => (),
+ }
+ }
+ }
+
+ for usage in images {
+ let state = states.images.get_mut(&usage.image.handle()).unwrap();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ match future.check_image_access(
+ &usage.image,
+ range.clone(),
+ range_usage.mutable,
+ range_usage.expected_layout,
+ queue,
+ ) {
+ Err(AccessCheckError::Denied(error)) => {
+ return Err(Box::new(ValidationError {
+ problem: format!(
+ "access to a resource has been denied \
+ (resource use: {:?}, error: {})",
+ range_usage.first_use, error
+ )
+ .into(),
+ ..Default::default()
+ })
+ .into());
+ }
+ Err(AccessCheckError::Unknown) => {
+ let result = if range_usage.mutable {
+ state.check_gpu_write(range.clone(), range_usage.expected_layout)
+ } else {
+ state.check_gpu_read(range.clone(), range_usage.expected_layout)
+ };
+
+ if let Err(error) = result {
+ return Err(Box::new(ValidationError {
+ problem: format!(
+ "access to a resource has been denied \
+ (resource use: {:?}, error: {})",
+ range_usage.first_use, error
+ )
+ .into(),
+ ..Default::default()
+ })
+ .into());
+ }
+ }
+ _ => (),
+ };
+ }
+ }
+ }
+ }
+
+ queue.with(|mut queue_guard| queue_guard.submit(&submit_infos, fence.as_ref()))?;
+
+ for submit_info in &submit_infos {
+ let SubmitInfo {
+ wait_semaphores: _,
+ command_buffers,
+ signal_semaphores: _,
+ _ne: _,
+ } = submit_info;
+
+ for command_buffer_submit_info in command_buffers {
+ let CommandBufferSubmitInfo {
+ command_buffer,
+ _ne: _,
+ } = command_buffer_submit_info;
+
+ let state = states
+ .command_buffers
+ .get_mut(&command_buffer.handle())
+ .unwrap();
+ state.add_queue_submit();
+
+ let CommandBufferResourcesUsage {
+ buffers,
+ images,
+ buffer_indices: _,
+ image_indices: _,
+ } = command_buffer.resources_usage();
+
+ for usage in buffers {
+ let state = states.buffers.get_mut(&usage.buffer.handle()).unwrap();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ if range_usage.mutable {
+ state.gpu_write_lock(range.clone());
+ } else {
+ state.gpu_read_lock(range.clone());
+ }
+ }
+ }
+
+ for usage in images {
+ let state = states.images.get_mut(&usage.image.handle()).unwrap();
+
+ for (range, range_usage) in usage.ranges.iter() {
+ if range_usage.mutable {
+ state.gpu_write_lock(range.clone(), range_usage.final_layout);
+ } else {
+ state.gpu_read_lock(range.clone());
+ }
+ }
+ }
+ }
+ }
+
+ Ok(())
+}
+
+// This struct exists to ensure that every object gets locked exactly once.
+// Otherwise we get deadlocks.
+#[derive(Debug)]
+struct States<'a> {
+ buffers: HashMap>,
+ command_buffers: HashMap>,
+ images: HashMap>,
+}
+
+impl<'a> States<'a> {
+ fn from_submit_infos(submit_infos: &'a [SubmitInfo]) -> Self {
+ let mut buffers = HashMap::default();
+ let mut command_buffers = HashMap::default();
+ let mut images = HashMap::default();
+
+ for submit_info in submit_infos {
+ let SubmitInfo {
+ wait_semaphores: _,
+ command_buffers: info_command_buffers,
+ signal_semaphores: _,
+ _ne: _,
+ } = submit_info;
+
+ for command_buffer_submit_info in info_command_buffers {
+ let &CommandBufferSubmitInfo {
+ ref command_buffer,
+ _ne: _,
+ } = command_buffer_submit_info;
+
+ command_buffers
+ .entry(command_buffer.handle())
+ .or_insert_with(|| command_buffer.state());
+
+ let CommandBufferResourcesUsage {
+ buffers: buffers_usage,
+ images: images_usage,
+ buffer_indices: _,
+ image_indices: _,
+ } = command_buffer.resources_usage();
+
+ for usage in buffers_usage {
+ let buffer = &usage.buffer;
+ buffers
+ .entry(buffer.handle())
+ .or_insert_with(|| buffer.state());
+ }
+
+ for usage in images_usage {
+ let image = &usage.image;
+ images
+ .entry(image.handle())
+ .or_insert_with(|| image.state());
+ }
+ }
+ }
+
+ Self {
+ buffers,
+ command_buffers,
+ images,
+ }
+ }
+}
diff --git a/vulkano/src/sync/future/semaphore_signal.rs b/vulkano/src/sync/future/semaphore_signal.rs
index 2442edcd..61246ed8 100644
--- a/vulkano/src/sync/future/semaphore_signal.rs
+++ b/vulkano/src/sync/future/semaphore_signal.rs
@@ -7,14 +7,18 @@
// notice may not be copied, modified, or distributed except
// according to those terms.
-use super::{AccessCheckError, GpuFuture, SubmitAnyBuilder};
+use super::{queue_present, AccessCheckError, GpuFuture, SubmitAnyBuilder};
use crate::{
buffer::Buffer,
command_buffer::{SemaphoreSubmitInfo, SubmitInfo},
device::{Device, DeviceOwned, Queue},
image::{Image, ImageLayout},
swapchain::Swapchain,
- sync::{future::AccessError, semaphore::Semaphore, PipelineStages},
+ sync::{
+ future::{queue_submit, AccessError},
+ semaphore::Semaphore,
+ PipelineStages,
+ },
DeviceSize, Validated, ValidationError, VulkanError,
};
use parking_lot::Mutex;
@@ -89,51 +93,49 @@ where
match self.previous.build_submission()? {
SubmitAnyBuilder::Empty => {
- queue.with(|mut q| {
- q.submit_unchecked(
- [SubmitInfo {
- signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
- self.semaphore.clone(),
- )],
- ..Default::default()
- }],
- None,
- )
- })?;
+ queue_submit(
+ &queue,
+ SubmitInfo {
+ signal_semaphores: vec![SemaphoreSubmitInfo::new(
+ self.semaphore.clone(),
+ )],
+ ..Default::default()
+ },
+ None,
+ &self.previous,
+ )?;
}
SubmitAnyBuilder::SemaphoresWait(semaphores) => {
- queue.with(|mut q| {
- q.submit_unchecked(
- [SubmitInfo {
- wait_semaphores: semaphores
- .into_iter()
- .map(|semaphore| {
- SemaphoreSubmitInfo {
- // TODO: correct stages ; hard
- stages: PipelineStages::ALL_COMMANDS,
- ..SemaphoreSubmitInfo::semaphore(semaphore)
- }
- })
- .collect(),
- signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
- self.semaphore.clone(),
- )],
- ..Default::default()
- }],
- None,
- )
- })?;
+ queue_submit(
+ &queue,
+ SubmitInfo {
+ wait_semaphores: semaphores
+ .into_iter()
+ .map(|semaphore| {
+ SemaphoreSubmitInfo {
+ // TODO: correct stages ; hard
+ stages: PipelineStages::ALL_COMMANDS,
+ ..SemaphoreSubmitInfo::new(semaphore)
+ }
+ })
+ .collect(),
+ signal_semaphores: vec![SemaphoreSubmitInfo::new(
+ self.semaphore.clone(),
+ )],
+ ..Default::default()
+ },
+ None,
+ &self.previous,
+ )?;
}
SubmitAnyBuilder::CommandBuffer(mut submit_info, fence) => {
debug_assert!(submit_info.signal_semaphores.is_empty());
submit_info
.signal_semaphores
- .push(SemaphoreSubmitInfo::semaphore(self.semaphore.clone()));
+ .push(SemaphoreSubmitInfo::new(self.semaphore.clone()));
- queue.with(|mut q| {
- q.submit_with_future(submit_info, fence, &self.previous, &queue)
- })?;
+ queue_submit(&queue, submit_info, fence, &self.previous)?;
}
SubmitAnyBuilder::BindSparse(_, _) => {
unimplemented!() // TODO: how to do that?
@@ -142,7 +144,7 @@ where
builder.submit(&queue)?;*/
}
SubmitAnyBuilder::QueuePresent(present_info) => {
- for swapchain_info in &present_info.swapchain_infos {
+ for swapchain_info in &present_info.swapchains {
if swapchain_info.present_id.map_or(false, |present_id| {
!swapchain_info.swapchain.try_claim_present_id(present_id)
}) {
@@ -174,22 +176,22 @@ where
}
}
- queue.with(|mut q| {
- q.present_unchecked(present_info)?
- .map(|r| r.map(|_| ()))
- .fold(Ok(()), Result::and)?;
- // FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice
- q.submit_unchecked(
- [SubmitInfo {
- signal_semaphores: vec![SemaphoreSubmitInfo::semaphore(
- self.semaphore.clone(),
- )],
- ..Default::default()
- }],
- None,
- )?;
- Ok::<_, Validated>(())
- })?;
+ queue_present(&queue, present_info)?
+ .map(|r| r.map(|_| ()))
+ .fold(Ok(()), Result::and)?;
+
+ // FIXME: problematic because if we return an error and flush() is called again, then we'll submit the present twice
+ queue_submit(
+ &queue,
+ SubmitInfo {
+ signal_semaphores: vec![SemaphoreSubmitInfo::new(
+ self.semaphore.clone(),
+ )],
+ ..Default::default()
+ },
+ None,
+ &self.previous,
+ )?;
}
};
@@ -267,7 +269,10 @@ where
self.flush().unwrap();
// Block until the queue finished.
self.queue().unwrap().with(|mut q| q.wait_idle()).unwrap();
- unsafe { self.previous.signal_finished() };
+
+ unsafe {
+ self.signal_finished();
+ }
}
}
}
diff --git a/vulkano/src/sync/semaphore.rs b/vulkano/src/sync/semaphore.rs
index ab145014..dec0a019 100644
--- a/vulkano/src/sync/semaphore.rs
+++ b/vulkano/src/sync/semaphore.rs
@@ -9,22 +9,42 @@
//! A semaphore provides synchronization between multiple queues, with non-command buffer
//! commands on the same queue, or between the device and an external source.
+//!
+//! A semaphore has two states: **signaled** and **unsignaled**.
+//! Only the device can perform operations on a semaphore,
+//! the host cannot perform any operations on it.
+//!
+//! Two operations can be performed on a semaphore:
+//! - A **semaphore signal operation** will put the semaphore into the signaled state.
+//! - A **semaphore wait operation** will block execution of the operation is associated with,
+//! as long as the semaphore is in the unsignaled state. Once the semaphore is in the signaled
+//! state, the semaphore is put back in the unsignaled state and execution continues.
+//!
+//! Semaphore signals and waits must always occur in pairs: one signal operation is paired with one
+//! wait operation. If a semaphore is signaled without waiting for it, it stays in the signaled
+//! state until it is waited for, or destroyed.
+//!
+//! # Safety
+//!
+//! - When a semaphore signal operation is executed on the device,
+//! the semaphore must be in the unsignaled state.
+//! In other words, the same semaphore cannot be signalled by multiple commands;
+//! there must always be a wait operation in between them.
+//! - There must never be more than one semaphore wait operation executing on the same semaphore
+//! at the same time.
+//! - When a semaphore wait operation is queued as part of a command,
+//! the semaphore must already be in the signaled state, or
+//! the signal operation that it waits for must have been queued previously
+//! (as part of a previous command, or an earlier batch within the same command).
use crate::{
- device::{physical::PhysicalDevice, Device, DeviceOwned, Queue},
+ device::{physical::PhysicalDevice, Device, DeviceOwned},
instance::InstanceOwnedDebugWrapper,
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
VulkanObject,
};
-use parking_lot::{Mutex, MutexGuard};
-use std::{
- fs::File,
- mem::MaybeUninit,
- num::NonZeroU64,
- ptr,
- sync::{Arc, Weak},
-};
+use std::{fs::File, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc};
/// Used to provide synchronization between command buffers during their execution.
///
@@ -39,7 +59,6 @@ pub struct Semaphore {
export_handle_types: ExternalSemaphoreHandleTypes,
must_put_in_pool: bool,
- state: Mutex,
}
impl Semaphore {
@@ -128,7 +147,6 @@ impl Semaphore {
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
must_put_in_pool: true,
- state: Mutex::new(Default::default()),
},
None => {
// Pool is empty, alloc new semaphore
@@ -167,7 +185,6 @@ impl Semaphore {
export_handle_types,
must_put_in_pool: false,
- state: Mutex::new(Default::default()),
}
}
@@ -178,21 +195,28 @@ impl Semaphore {
}
/// Exports the semaphore into a POSIX file descriptor. The caller owns the returned `File`.
+ ///
+ /// # Safety
+ ///
+ /// - If `handle_type` has copy transference, then the semaphore must be signaled, or a signal
+ /// operation on the semaphore must be pending, and no wait operations must be pending.
+ /// - The semaphore must not currently have an imported payload from a swapchain acquire
+ /// operation.
+ /// - If the semaphore has an imported payload, its handle type must allow re-exporting as
+ /// `handle_type`, as returned by [`PhysicalDevice::external_semaphore_properties`].
#[inline]
- pub fn export_fd(
+ pub unsafe fn export_fd(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result> {
- let mut state = self.state.lock();
- self.validate_export_fd(handle_type, &state)?;
+ self.validate_export_fd(handle_type)?;
- unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
+ unsafe { Ok(self.export_fd_unchecked(handle_type)?) }
}
fn validate_export_fd(
&self,
handle_type: ExternalSemaphoreHandleType,
- state: &SemaphoreState,
) -> Result<(), Box> {
if !self.device.enabled_extensions().khr_external_semaphore_fd {
return Err(Box::new(ValidationError {
@@ -230,86 +254,13 @@ impl Semaphore {
}));
}
- if let Some(imported_handle_type) = state.current_import {
- match imported_handle_type {
- ImportType::SwapchainAcquire => {
- return Err(Box::new(ValidationError {
- problem: "the semaphore currently has an imported payload from a \
- swapchain acquire operation"
- .into(),
- vuids: &["VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133"],
- ..Default::default()
- }));
- }
- ImportType::ExternalSemaphore(imported_handle_type) => {
- let external_semaphore_properties = unsafe {
- self.device
- .physical_device()
- .external_semaphore_properties_unchecked(
- ExternalSemaphoreInfo::handle_type(handle_type),
- )
- };
-
- if !external_semaphore_properties
- .export_from_imported_handle_types
- .intersects(imported_handle_type.into())
- {
- return Err(Box::new(ValidationError {
- problem: "the semaphore currently has an imported payload, whose type \
- does not allow re-exporting as `handle_type`, as \
- returned by `PhysicalDevice::external_semaphore_properties`"
- .into(),
- vuids: &["VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133"],
- ..Default::default()
- }));
- }
- }
- }
- }
-
- if handle_type.has_copy_transference() {
- if state.is_wait_pending() {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` has copy transference, but \
- a wait operation on the semaphore is pending"
- .into(),
- vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-01134"],
- ..Default::default()
- }));
- }
-
- if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` has copy transference, but \
- the semaphore is not signaled, and \
- a signal operation on the semaphore is not pending"
- .into(),
- vuids: &[
- "VUID-VkSemaphoreGetFdInfoKHR-handleType-01135",
- "VUID-VkSemaphoreGetFdInfoKHR-handleType-03254",
- ],
- ..Default::default()
- }));
- }
- }
-
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn export_fd_unchecked(
&self,
handle_type: ExternalSemaphoreHandleType,
- ) -> Result {
- let mut state = self.state.lock();
- self.export_fd_unchecked_locked(handle_type, &mut state)
- }
-
- unsafe fn export_fd_unchecked_locked(
- &self,
- handle_type: ExternalSemaphoreHandleType,
- state: &mut SemaphoreState,
) -> Result {
let info_vk = ash::vk::SemaphoreGetFdInfoKHR {
semaphore: self.handle,
@@ -327,8 +278,6 @@ impl Semaphore {
.result()
.map_err(VulkanError::from)?;
- state.export(handle_type);
-
#[cfg(unix)]
{
use std::os::unix::io::FromRawFd;
@@ -346,21 +295,31 @@ impl Semaphore {
///
/// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
/// extension must be enabled on the device.
+ ///
+ /// # Safety
+ ///
+ /// - If `handle_type` has copy transference, then the semaphore must be signaled, or a signal
+ /// operation on the semaphore must be pending, and no wait operations must be pending.
+ /// - The semaphore must not currently have an imported payload from a swapchain acquire
+ /// operation.
+ /// - If the semaphore has an imported payload, its handle type must allow re-exporting as
+ /// `handle_type`, as returned by [`PhysicalDevice::external_semaphore_properties`].
+ /// - If `handle_type` is `ExternalSemaphoreHandleType::OpaqueWin32` or
+ /// `ExternalSemaphoreHandleType::D3D12Fence`, then a handle of this type must not have been
+ /// already exported from this semaphore.
#[inline]
pub fn export_win32_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<*mut std::ffi::c_void, Validated> {
- let mut state = self.state.lock();
- self.validate_export_win32_handle(handle_type, &state)?;
+ self.validate_export_win32_handle(handle_type)?;
- unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
+ unsafe { Ok(self.export_win32_handle_unchecked(handle_type)?) }
}
fn validate_export_win32_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
- state: &SemaphoreState,
) -> Result<(), Box> {
if !self
.device
@@ -405,98 +364,13 @@ impl Semaphore {
}));
}
- if matches!(
- handle_type,
- ExternalSemaphoreHandleType::OpaqueWin32 | ExternalSemaphoreHandleType::D3D12Fence
- ) && state.is_exported(handle_type)
- {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` is `ExternalSemaphoreHandleType::OpaqueWin32` or \
- `ExternalSemaphoreHandleType::D3D12Fence`, but \
- a handle of this type has already been exported from this semaphore"
- .into(),
- vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01127"],
- ..Default::default()
- }));
- }
-
- if let Some(imported_handle_type) = state.current_import {
- match imported_handle_type {
- ImportType::SwapchainAcquire => {
- return Err(Box::new(ValidationError {
- problem: "the semaphore currently has an imported payload from a \
- swapchain acquire operation"
- .into(),
- vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128"],
- ..Default::default()
- }));
- }
- ImportType::ExternalSemaphore(imported_handle_type) => {
- let external_semaphore_properties = unsafe {
- self.device
- .physical_device()
- .external_semaphore_properties_unchecked(
- ExternalSemaphoreInfo::handle_type(handle_type),
- )
- };
-
- if !external_semaphore_properties
- .export_from_imported_handle_types
- .intersects(imported_handle_type.into())
- {
- return Err(Box::new(ValidationError {
- problem: "the semaphore currently has an imported payload, whose type \
- does not allow re-exporting as `handle_type`, as \
- returned by `PhysicalDevice::external_semaphore_properties`"
- .into(),
- vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128"],
- ..Default::default()
- }));
- }
- }
- }
- }
-
- if handle_type.has_copy_transference() {
- if state.is_wait_pending() {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` has copy transference, but \
- a wait operation on the semaphore is pending"
- .into(),
- vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01129"],
- ..Default::default()
- }));
- }
-
- if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` has copy transference, but \
- the semaphore is not signaled, and \
- a signal operation on the semaphore is not pending"
- .into(),
- vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01130"],
- ..Default::default()
- }));
- }
- }
-
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn export_win32_handle_unchecked(
&self,
handle_type: ExternalSemaphoreHandleType,
- ) -> Result<*mut std::ffi::c_void, VulkanError> {
- let mut state = self.state.lock();
- self.export_win32_handle_unchecked_locked(handle_type, &mut state)
- }
-
- unsafe fn export_win32_handle_unchecked_locked(
- &self,
- handle_type: ExternalSemaphoreHandleType,
- state: &mut SemaphoreState,
) -> Result<*mut std::ffi::c_void, VulkanError> {
let info_vk = ash::vk::SemaphoreGetWin32HandleInfoKHR {
semaphore: self.handle,
@@ -513,27 +387,32 @@ impl Semaphore {
.result()
.map_err(VulkanError::from)?;
- state.export(handle_type);
-
Ok(output.assume_init())
}
/// Exports the semaphore into a Zircon event handle.
+ ///
+ /// # Safety
+ ///
+ /// - If `handle_type` has copy transference, then the semaphore must be signaled, or a signal
+ /// operation on the semaphore must be pending, and no wait operations must be pending.
+ /// - The semaphore must not currently have an imported payload from a swapchain acquire
+ /// operation.
+ /// - If the semaphore has an imported payload, its handle type must allow re-exporting as
+ /// `handle_type`, as returned by [`PhysicalDevice::external_semaphore_properties`].
#[inline]
- pub fn export_zircon_handle(
+ pub unsafe fn export_zircon_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result> {
- let mut state = self.state.lock();
- self.validate_export_zircon_handle(handle_type, &state)?;
+ self.validate_export_zircon_handle(handle_type)?;
- unsafe { Ok(self.export_zircon_handle_unchecked_locked(handle_type, &mut state)?) }
+ unsafe { Ok(self.export_zircon_handle_unchecked(handle_type)?) }
}
fn validate_export_zircon_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
- state: &SemaphoreState,
) -> Result<(), Box> {
if !self.device.enabled_extensions().fuchsia_external_semaphore {
return Err(Box::new(ValidationError {
@@ -566,83 +445,13 @@ impl Semaphore {
}));
}
- if let Some(imported_handle_type) = state.current_import {
- match imported_handle_type {
- ImportType::SwapchainAcquire => {
- return Err(Box::new(ValidationError {
- problem: "the semaphore currently has an imported payload from a \
- swapchain acquire operation"
- .into(),
- vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759"],
- ..Default::default()
- }));
- }
- ImportType::ExternalSemaphore(imported_handle_type) => {
- let external_semaphore_properties = unsafe {
- self.device
- .physical_device()
- .external_semaphore_properties_unchecked(
- ExternalSemaphoreInfo::handle_type(handle_type),
- )
- };
-
- if !external_semaphore_properties
- .export_from_imported_handle_types
- .intersects(imported_handle_type.into())
- {
- return Err(Box::new(ValidationError {
- problem: "the semaphore currently has an imported payload, whose type \
- does not allow re-exporting as `handle_type`, as \
- returned by `PhysicalDevice::external_semaphore_properties`"
- .into(),
- vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759"],
- ..Default::default()
- }));
- }
- }
- }
- }
-
- if handle_type.has_copy_transference() {
- if state.is_wait_pending() {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` has copy transference, but \
- a wait operation on the semaphore is pending"
- .into(),
- vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04760"],
- ..Default::default()
- }));
- }
-
- if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
- return Err(Box::new(ValidationError {
- problem: "`handle_type` has copy transference, but \
- the semaphore is not signaled, and \
- a signal operation on the semaphore is not pending"
- .into(),
- vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04761"],
- ..Default::default()
- }));
- }
- }
-
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn export_zircon_handle_unchecked(
&self,
handle_type: ExternalSemaphoreHandleType,
- ) -> Result {
- let mut state = self.state.lock();
- self.export_zircon_handle_unchecked_locked(handle_type, &mut state)
- }
-
- unsafe fn export_zircon_handle_unchecked_locked(
- &self,
- handle_type: ExternalSemaphoreHandleType,
- state: &mut SemaphoreState,
) -> Result {
let info_vk = ash::vk::SemaphoreGetZirconHandleInfoFUCHSIA {
semaphore: self.handle,
@@ -661,8 +470,6 @@ impl Semaphore {
.result()
.map_err(VulkanError::from)?;
- state.export(handle_type);
-
Ok(output.assume_init())
}
@@ -673,6 +480,7 @@ impl Semaphore {
///
/// # Safety
///
+ /// - The semaphore must not be in use by the device.
/// - If in `import_semaphore_fd_info`, `handle_type` is `ExternalHandleType::OpaqueFd`,
/// then `file` must represent a binary semaphore that was exported from Vulkan or a
/// compatible API, with a driver and device UUID equal to those of the device that owns
@@ -682,16 +490,14 @@ impl Semaphore {
&self,
import_semaphore_fd_info: ImportSemaphoreFdInfo,
) -> Result<(), Validated> {
- let mut state = self.state.lock();
- self.validate_import_fd(&import_semaphore_fd_info, &state)?;
+ self.validate_import_fd(&import_semaphore_fd_info)?;
- Ok(self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)?)
+ Ok(self.import_fd_unchecked(import_semaphore_fd_info)?)
}
fn validate_import_fd(
&self,
import_semaphore_fd_info: &ImportSemaphoreFdInfo,
- state: &SemaphoreState,
) -> Result<(), Box> {
if !self.device.enabled_extensions().khr_external_semaphore_fd {
return Err(Box::new(ValidationError {
@@ -702,14 +508,6 @@ impl Semaphore {
}));
}
- if state.is_in_queue() {
- return Err(Box::new(ValidationError {
- problem: "the semaphore is in use".into(),
- vuids: &["VUID-vkImportSemaphoreFdKHR-semaphore-01142"],
- ..Default::default()
- }));
- }
-
import_semaphore_fd_info
.validate(&self.device)
.map_err(|err| err.add_context("import_semaphore_fd_info"))?;
@@ -718,19 +516,9 @@ impl Semaphore {
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn import_fd_unchecked(
&self,
import_semaphore_fd_info: ImportSemaphoreFdInfo,
- ) -> Result<(), VulkanError> {
- let mut state = self.state.lock();
- self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)
- }
-
- unsafe fn import_fd_unchecked_locked(
- &self,
- import_semaphore_fd_info: ImportSemaphoreFdInfo,
- state: &mut SemaphoreState,
) -> Result<(), VulkanError> {
let ImportSemaphoreFdInfo {
flags,
@@ -764,11 +552,6 @@ impl Semaphore {
.result()
.map_err(VulkanError::from)?;
- state.import(
- handle_type,
- flags.intersects(SemaphoreImportFlags::TEMPORARY),
- );
-
Ok(())
}
@@ -779,6 +562,7 @@ impl Semaphore {
///
/// # Safety
///
+ /// - The semaphore must not be in use by the device.
/// - In `import_semaphore_win32_handle_info`, `handle` must represent a binary semaphore that
/// was exported from Vulkan or a compatible API, with a driver and device UUID equal to
/// those of the device that owns `self`.
@@ -787,17 +571,14 @@ impl Semaphore {
&self,
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
) -> Result<(), Validated> {
- let mut state = self.state.lock();
- self.validate_import_win32_handle(&import_semaphore_win32_handle_info, &state)?;
+ self.validate_import_win32_handle(&import_semaphore_win32_handle_info)?;
- Ok(self
- .import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)?)
+ Ok(self.import_win32_handle_unchecked(import_semaphore_win32_handle_info)?)
}
fn validate_import_win32_handle(
&self,
import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo,
- state: &SemaphoreState,
) -> Result<(), Box> {
if !self
.device
@@ -812,14 +593,6 @@ impl Semaphore {
}));
}
- if state.is_in_queue() {
- return Err(Box::new(ValidationError {
- problem: "the semaphore is in use".into(),
- // vuids?
- ..Default::default()
- }));
- }
-
import_semaphore_win32_handle_info
.validate(&self.device)
.map_err(|err| err.add_context("import_semaphore_win32_handle_info"))?;
@@ -828,19 +601,9 @@ impl Semaphore {
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn import_win32_handle_unchecked(
&self,
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
- ) -> Result<(), VulkanError> {
- let mut state = self.state.lock();
- self.import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)
- }
-
- unsafe fn import_win32_handle_unchecked_locked(
- &self,
- import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
- state: &mut SemaphoreState,
) -> Result<(), VulkanError> {
let ImportSemaphoreWin32HandleInfo {
flags,
@@ -864,11 +627,6 @@ impl Semaphore {
.result()
.map_err(VulkanError::from)?;
- state.import(
- handle_type,
- flags.intersects(SemaphoreImportFlags::TEMPORARY),
- );
-
Ok(())
}
@@ -879,6 +637,7 @@ impl Semaphore {
///
/// # Safety
///
+ /// - The semaphore must not be in use by the device.
/// - In `import_semaphore_zircon_handle_info`, `zircon_handle` must have `ZX_RIGHTS_BASIC` and
/// `ZX_RIGHTS_SIGNAL`.
#[inline]
@@ -886,19 +645,14 @@ impl Semaphore {
&self,
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
) -> Result<(), Validated> {
- let mut state = self.state.lock();
- self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info, &state)?;
+ self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info)?;
- Ok(self.import_zircon_handle_unchecked_locked(
- import_semaphore_zircon_handle_info,
- &mut state,
- )?)
+ Ok(self.import_zircon_handle_unchecked(import_semaphore_zircon_handle_info)?)
}
fn validate_import_zircon_handle(
&self,
import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo,
- state: &SemaphoreState,
) -> Result<(), Box> {
if !self.device.enabled_extensions().fuchsia_external_semaphore {
return Err(Box::new(ValidationError {
@@ -909,14 +663,6 @@ impl Semaphore {
}));
}
- if state.is_in_queue() {
- return Err(Box::new(ValidationError {
- problem: "the semaphore is in use".into(),
- vuids: &["VUID-vkImportSemaphoreZirconHandleFUCHSIA-semaphore-04764"],
- ..Default::default()
- }));
- }
-
import_semaphore_zircon_handle_info
.validate(&self.device)
.map_err(|err| err.add_context("import_semaphore_zircon_handle_info"))?;
@@ -925,19 +671,9 @@ impl Semaphore {
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
- #[inline]
pub unsafe fn import_zircon_handle_unchecked(
&self,
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
- ) -> Result<(), VulkanError> {
- let mut state = self.state.lock();
- self.import_zircon_handle_unchecked_locked(import_semaphore_zircon_handle_info, &mut state)
- }
-
- unsafe fn import_zircon_handle_unchecked_locked(
- &self,
- import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
- state: &mut SemaphoreState,
) -> Result<(), VulkanError> {
let ImportSemaphoreZirconHandleInfo {
flags,
@@ -960,17 +696,8 @@ impl Semaphore {
.result()
.map_err(VulkanError::from)?;
- state.import(
- handle_type,
- flags.intersects(SemaphoreImportFlags::TEMPORARY),
- );
-
Ok(())
}
-
- pub(crate) fn state(&self) -> MutexGuard<'_, SemaphoreState> {
- self.state.lock()
- }
}
impl Drop for Semaphore {
@@ -1498,136 +1225,6 @@ pub struct ExternalSemaphoreProperties {
pub compatible_handle_types: ExternalSemaphoreHandleTypes,
}
-#[derive(Debug, Default)]
-pub(crate) struct SemaphoreState {
- is_signaled: bool,
- pending_signal: Option,
- pending_wait: Option>,
-
- reference_exported: bool,
- exported_handle_types: ExternalSemaphoreHandleTypes,
- current_import: Option,
- permanent_import: Option,
-}
-
-impl SemaphoreState {
- /// If the semaphore does not have a pending operation and has no external references,
- /// returns the current status.
- #[inline]
- fn is_signaled(&self) -> Option {
- // If any of these is true, we can't be certain of the status.
- if self.pending_signal.is_some()
- || self.pending_wait.is_some()
- || self.has_external_reference()
- {
- None
- } else {
- Some(self.is_signaled)
- }
- }
-
- #[inline]
- fn is_signal_pending(&self) -> bool {
- self.pending_signal.is_some()
- }
-
- #[inline]
- fn is_wait_pending(&self) -> bool {
- self.pending_wait.is_some()
- }
-
- #[inline]
- fn is_in_queue(&self) -> bool {
- matches!(self.pending_signal, Some(SignalType::Queue(_))) || self.pending_wait.is_some()
- }
-
- /// Returns whether there are any potential external references to the semaphore payload.
- /// That is, the semaphore has been exported by reference transference, or imported.
- #[inline]
- fn has_external_reference(&self) -> bool {
- self.reference_exported || self.current_import.is_some()
- }
-
- #[allow(dead_code)]
- #[inline]
- fn is_exported(&self, handle_type: ExternalSemaphoreHandleType) -> bool {
- self.exported_handle_types.intersects(handle_type.into())
- }
-
- #[inline]
- pub(crate) unsafe fn add_queue_signal(&mut self, queue: &Arc) {
- self.pending_signal = Some(SignalType::Queue(Arc::downgrade(queue)));
- }
-
- #[inline]
- pub(crate) unsafe fn add_queue_wait(&mut self, queue: &Arc) {
- self.pending_wait = Some(Arc::downgrade(queue));
- }
-
- /// Called when a queue is unlocking resources.
- #[inline]
- pub(crate) unsafe fn set_signal_finished(&mut self) {
- self.pending_signal = None;
- self.is_signaled = true;
- }
-
- /// Called when a queue is unlocking resources.
- #[inline]
- pub(crate) unsafe fn set_wait_finished(&mut self) {
- self.pending_wait = None;
- self.current_import = self.permanent_import.map(Into::into);
- self.is_signaled = false;
- }
-
- #[allow(dead_code)]
- #[inline]
- unsafe fn export(&mut self, handle_type: ExternalSemaphoreHandleType) {
- self.exported_handle_types |= handle_type.into();
-
- if handle_type.has_copy_transference() {
- self.current_import = self.permanent_import.map(Into::into);
- self.is_signaled = false;
- } else {
- self.reference_exported = true;
- }
- }
-
- #[allow(dead_code)]
- #[inline]
- unsafe fn import(&mut self, handle_type: ExternalSemaphoreHandleType, temporary: bool) {
- self.current_import = Some(handle_type.into());
-
- if !temporary {
- self.permanent_import = Some(handle_type);
- }
- }
-
- #[inline]
- pub(crate) unsafe fn swapchain_acquire(&mut self) {
- self.pending_signal = Some(SignalType::SwapchainAcquire);
- self.current_import = Some(ImportType::SwapchainAcquire);
- }
-}
-
-#[derive(Clone, Debug)]
-enum SignalType {
- Queue(Weak),
- SwapchainAcquire,
-}
-
-#[derive(Clone, Copy, Debug)]
-enum ImportType {
- SwapchainAcquire,
- ExternalSemaphore(ExternalSemaphoreHandleType),
-}
-
-impl From for ImportType {
- #[inline]
- fn from(handle_type: ExternalSemaphoreHandleType) -> Self {
- Self::ExternalSemaphore(handle_type)
- }
-}
-
#[cfg(test)]
mod tests {
use crate::{
@@ -1717,8 +1314,9 @@ mod tests {
},
)
.unwrap();
- let _fd = sem
- .export_fd(ExternalSemaphoreHandleType::OpaqueFd)
- .unwrap();
+ let _fd = unsafe {
+ sem.export_fd(ExternalSemaphoreHandleType::OpaqueFd)
+ .unwrap()
+ };
}
}