use crate::{
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 smallvec::SmallVec;
use std::{
fs::File,
future::Future,
mem::MaybeUninit,
num::NonZeroU64,
pin::Pin,
ptr,
sync::Arc,
task::{Context, Poll},
time::Duration,
};
#[derive(Debug)]
pub struct Fence {
handle: ash::vk::Fence,
device: InstanceOwnedDebugWrapper<Arc<Device>>,
id: NonZeroU64,
flags: FenceCreateFlags,
export_handle_types: ExternalFenceHandleTypes,
must_put_in_pool: bool,
}
impl Fence {
#[inline]
pub fn new(
device: Arc<Device>,
create_info: FenceCreateInfo,
) -> Result<Fence, Validated<VulkanError>> {
Self::validate_new(&device, &create_info)?;
Ok(unsafe { Self::new_unchecked(device, create_info) }?)
}
fn validate_new(
device: &Device,
create_info: &FenceCreateInfo,
) -> Result<(), Box<ValidationError>> {
create_info
.validate(device)
.map_err(|err| err.add_context("create_info"))?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn new_unchecked(
device: Arc<Device>,
create_info: FenceCreateInfo,
) -> Result<Fence, VulkanError> {
let mut create_info_extensions_vk = create_info.to_vk_extensions();
let create_info_vk = create_info.to_vk(&mut create_info_extensions_vk);
let handle = {
let fns = device.fns();
let mut output = MaybeUninit::uninit();
unsafe {
(fns.v1_0.create_fence)(
device.handle(),
&create_info_vk,
ptr::null(),
output.as_mut_ptr(),
)
.result()
}
.map_err(VulkanError::from)?;
unsafe { output.assume_init() }
};
Ok(unsafe { Self::from_handle(device, handle, create_info) })
}
#[inline]
pub fn from_pool(device: Arc<Device>) -> Result<Fence, VulkanError> {
let handle = device.fence_pool().lock().pop();
let fence = match handle {
Some(handle) => {
let fns = device.fns();
unsafe { (fns.v1_0.reset_fences)(device.handle(), 1, &handle) }
.result()
.map_err(VulkanError::from)?;
Fence {
handle,
device: InstanceOwnedDebugWrapper(device),
id: Self::next_id(),
flags: FenceCreateFlags::empty(),
export_handle_types: ExternalFenceHandleTypes::empty(),
must_put_in_pool: true,
}
}
None => {
let mut fence =
unsafe { Fence::new_unchecked(device, FenceCreateInfo::default()) }?;
fence.must_put_in_pool = true;
fence
}
};
Ok(fence)
}
#[inline]
pub unsafe fn from_handle(
device: Arc<Device>,
handle: ash::vk::Fence,
create_info: FenceCreateInfo,
) -> Fence {
let FenceCreateInfo {
flags,
export_handle_types,
_ne: _,
} = create_info;
Fence {
handle,
device: InstanceOwnedDebugWrapper(device),
id: Self::next_id(),
flags,
export_handle_types,
must_put_in_pool: false,
}
}
#[inline]
pub fn flags(&self) -> FenceCreateFlags {
self.flags
}
#[inline]
pub fn export_handle_types(&self) -> ExternalFenceHandleTypes {
self.export_handle_types
}
#[inline]
pub fn is_signaled(&self) -> Result<bool, VulkanError> {
let fns = self.device.fns();
let result = unsafe { (fns.v1_0.get_fence_status)(self.device.handle(), self.handle) };
match result {
ash::vk::Result::SUCCESS => Ok(true),
ash::vk::Result::NOT_READY => Ok(false),
err => Err(VulkanError::from(err)),
}
}
pub fn wait(&self, timeout: Option<Duration>) -> Result<(), VulkanError> {
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 fns = self.device.fns();
let result = unsafe {
(fns.v1_0.wait_for_fences)(
self.device.handle(),
1,
&self.handle,
ash::vk::TRUE,
timeout_ns,
)
};
match result {
ash::vk::Result::SUCCESS => Ok(()),
err => Err(VulkanError::from(err)),
}
}
pub fn multi_wait<'a>(
fences: impl IntoIterator<Item = &'a Fence>,
timeout: Option<Duration>,
) -> Result<(), Validated<VulkanError>> {
let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
Self::validate_multi_wait(&fences, timeout)?;
Ok(unsafe { Self::multi_wait_unchecked(fences, timeout) }?)
}
fn validate_multi_wait(
fences: &[&Fence],
_timeout: Option<Duration>,
) -> Result<(), Box<ValidationError>> {
if fences.is_empty() {
return Ok(());
}
let device = &fences[0].device;
for fence in fences {
assert_eq!(device, &fence.device);
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn multi_wait_unchecked<'a>(
fences: impl IntoIterator<Item = &'a Fence>,
timeout: Option<Duration>,
) -> Result<(), VulkanError> {
let iter = fences.into_iter();
let mut fences_vk: SmallVec<[_; 8]> = SmallVec::new();
let mut fences: SmallVec<[_; 8]> = SmallVec::new();
for fence in iter {
fences_vk.push(fence.handle);
fences.push(fence);
}
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();
unsafe {
(fns.v1_0.wait_for_fences)(
device.handle(),
fences_vk.len() as u32,
fences_vk.as_ptr(),
ash::vk::TRUE, timeout_ns,
)
}
};
match result {
ash::vk::Result::SUCCESS => Ok(()),
err => Err(VulkanError::from(err)),
}
}
#[inline]
pub unsafe fn reset(&self) -> Result<(), Validated<VulkanError>> {
self.validate_reset()?;
Ok(unsafe { self.reset_unchecked() }?)
}
fn validate_reset(&self) -> Result<(), Box<ValidationError>> {
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn reset_unchecked(&self) -> Result<(), VulkanError> {
let fns = self.device.fns();
unsafe { (fns.v1_0.reset_fences)(self.device.handle(), 1, &self.handle) }
.result()
.map_err(VulkanError::from)?;
Ok(())
}
pub unsafe fn multi_reset<'a>(
fences: impl IntoIterator<Item = &'a Fence>,
) -> Result<(), Validated<VulkanError>> {
let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
Self::validate_multi_reset(&fences)?;
Ok(unsafe { Self::multi_reset_unchecked(fences) }?)
}
fn validate_multi_reset(fences: &[&Fence]) -> Result<(), Box<ValidationError>> {
if fences.is_empty() {
return Ok(());
}
let device = &fences[0].device;
for fence in fences {
assert_eq!(device, &fence.device);
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn multi_reset_unchecked<'a>(
fences: impl IntoIterator<Item = &'a Fence>,
) -> Result<(), VulkanError> {
let fences: SmallVec<[_; 8]> = fences.into_iter().collect();
if fences.is_empty() {
return Ok(());
}
let device = &fences[0].device;
let fences_vk: SmallVec<[_; 8]> = fences.iter().map(|fence| fence.handle).collect();
let fns = device.fns();
unsafe {
(fns.v1_0.reset_fences)(device.handle(), fences_vk.len() as u32, fences_vk.as_ptr())
}
.result()
.map_err(VulkanError::from)?;
Ok(())
}
#[inline]
pub unsafe fn export_fd(
&self,
handle_type: ExternalFenceHandleType,
) -> Result<File, Validated<VulkanError>> {
self.validate_export_fd(handle_type)?;
Ok(unsafe { self.export_fd_unchecked(handle_type) }?)
}
fn validate_export_fd(
&self,
handle_type: ExternalFenceHandleType,
) -> Result<(), Box<ValidationError>> {
if !self.device.enabled_extensions().khr_external_fence_fd {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_external_fence_fd",
)])]),
..Default::default()
}));
}
handle_type.validate_device(&self.device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkFenceGetFdInfoKHR-handleType-parameter"])
})?;
if !matches!(
handle_type,
ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd
) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalFenceHandleType::OpaqueFd` or \
`ExternalFenceHandleType::SyncFd`"
.into(),
vuids: &["VUID-VkFenceGetFdInfoKHR-handleType-01456"],
..Default::default()
}));
}
if !self.export_handle_types.intersects(handle_type.into()) {
return Err(Box::new(ValidationError {
problem: "`self.export_handle_types()` does not contain `handle_type`".into(),
vuids: &["VUID-VkFenceGetFdInfoKHR-handleType-01453"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn export_fd_unchecked(
&self,
handle_type: ExternalFenceHandleType,
) -> Result<File, VulkanError> {
let info_vk = ash::vk::FenceGetFdInfoKHR::default()
.fence(self.handle)
.handle_type(handle_type.into());
let mut output = MaybeUninit::uninit();
let fns = self.device.fns();
unsafe {
(fns.khr_external_fence_fd.get_fence_fd_khr)(
self.device.handle(),
&info_vk,
output.as_mut_ptr(),
)
}
.result()
.map_err(VulkanError::from)?;
#[cfg(unix)]
{
use std::os::unix::io::FromRawFd;
let raw_fd = unsafe { output.assume_init() };
Ok(unsafe { File::from_raw_fd(raw_fd) })
}
#[cfg(not(unix))]
{
let _ = output;
unreachable!("`khr_external_fence_fd` was somehow enabled on a non-Unix system");
}
}
#[inline]
pub fn export_win32_handle(
&self,
handle_type: ExternalFenceHandleType,
) -> Result<ash::vk::HANDLE, Validated<VulkanError>> {
self.validate_export_win32_handle(handle_type)?;
Ok(unsafe { self.export_win32_handle_unchecked(handle_type) }?)
}
fn validate_export_win32_handle(
&self,
handle_type: ExternalFenceHandleType,
) -> Result<(), Box<ValidationError>> {
if !self.device.enabled_extensions().khr_external_fence_win32 {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_external_fence_win32",
)])]),
..Default::default()
}));
}
handle_type.validate_device(&self.device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkFenceGetWin32HandleInfoKHR-handleType-parameter"])
})?;
if !matches!(
handle_type,
ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt
) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalFenceHandleType::OpaqueWin32` or \
`ExternalFenceHandleType::OpaqueWin32Kmt`"
.into(),
vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01452"],
..Default::default()
}));
}
if !self.export_handle_types.intersects(handle_type.into()) {
return Err(Box::new(ValidationError {
problem: "`self.export_handle_types()` does not contain `handle_type`".into(),
vuids: &["VUID-VkFenceGetWin32HandleInfoKHR-handleType-01448"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn export_win32_handle_unchecked(
&self,
handle_type: ExternalFenceHandleType,
) -> Result<ash::vk::HANDLE, VulkanError> {
let info_vk = ash::vk::FenceGetWin32HandleInfoKHR::default()
.fence(self.handle)
.handle_type(handle_type.into());
let handle = {
let mut output = MaybeUninit::uninit();
let fns = self.device.fns();
unsafe {
(fns.khr_external_fence_win32.get_fence_win32_handle_khr)(
self.device.handle(),
&info_vk,
output.as_mut_ptr(),
)
}
.result()
.map_err(VulkanError::from)?;
unsafe { output.assume_init() }
};
Ok(handle)
}
#[inline]
pub unsafe fn import_fd(
&self,
import_fence_fd_info: ImportFenceFdInfo,
) -> Result<(), Validated<VulkanError>> {
self.validate_import_fd(&import_fence_fd_info)?;
Ok(unsafe { self.import_fd_unchecked(import_fence_fd_info) }?)
}
fn validate_import_fd(
&self,
import_fence_fd_info: &ImportFenceFdInfo,
) -> Result<(), Box<ValidationError>> {
if !self.device.enabled_extensions().khr_external_fence_fd {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_external_fence_fd",
)])]),
..Default::default()
}));
}
import_fence_fd_info
.validate(&self.device)
.map_err(|err| err.add_context("import_fence_fd_info"))?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn import_fd_unchecked(
&self,
import_fence_fd_info: ImportFenceFdInfo,
) -> Result<(), VulkanError> {
let info_vk = import_fence_fd_info.into_vk(self.handle());
let fns = self.device.fns();
unsafe { (fns.khr_external_fence_fd.import_fence_fd_khr)(self.device.handle(), &info_vk) }
.result()
.map_err(VulkanError::from)?;
Ok(())
}
#[inline]
pub unsafe fn import_win32_handle(
&self,
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
) -> Result<(), Validated<VulkanError>> {
self.validate_import_win32_handle(&import_fence_win32_handle_info)?;
Ok(unsafe { self.import_win32_handle_unchecked(import_fence_win32_handle_info) }?)
}
fn validate_import_win32_handle(
&self,
import_fence_win32_handle_info: &ImportFenceWin32HandleInfo,
) -> Result<(), Box<ValidationError>> {
if !self.device.enabled_extensions().khr_external_fence_win32 {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_external_fence_win32",
)])]),
..Default::default()
}));
}
import_fence_win32_handle_info
.validate(&self.device)
.map_err(|err| err.add_context("import_fence_win32_handle_info"))?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn import_win32_handle_unchecked(
&self,
import_fence_win32_handle_info: ImportFenceWin32HandleInfo,
) -> Result<(), VulkanError> {
let info_vk = import_fence_win32_handle_info.to_vk(self.handle());
let fns = self.device.fns();
unsafe {
(fns.khr_external_fence_win32.import_fence_win32_handle_khr)(
self.device.handle(),
&info_vk,
)
}
.result()
.map_err(VulkanError::from)?;
Ok(())
}
pub(crate) fn poll_impl(&self, cx: &mut Context<'_>) -> Poll<Result<(), VulkanError>> {
match self.is_signaled() {
Err(e) => return Poll::Ready(Err(e)),
Ok(signalled) => {
if signalled {
return Poll::Ready(Ok(()));
}
}
}
cx.waker().wake_by_ref();
Poll::Pending
}
}
impl Drop for Fence {
#[inline]
fn drop(&mut self) {
if self.must_put_in_pool {
let raw_fence = self.handle;
self.device.fence_pool().lock().push(raw_fence);
} else {
let fns = self.device.fns();
unsafe { (fns.v1_0.destroy_fence)(self.device.handle(), self.handle, ptr::null()) };
}
}
}
impl Future for Fence {
type Output = Result<(), VulkanError>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
self.poll_impl(cx)
}
}
unsafe impl VulkanObject for Fence {
type Handle = ash::vk::Fence;
#[inline]
fn handle(&self) -> Self::Handle {
self.handle
}
}
unsafe impl DeviceOwned for Fence {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl_id_counter!(Fence);
#[derive(Clone, Debug)]
pub struct FenceCreateInfo {
pub flags: FenceCreateFlags,
pub export_handle_types: ExternalFenceHandleTypes,
pub _ne: crate::NonExhaustive,
}
impl Default for FenceCreateInfo {
#[inline]
fn default() -> Self {
Self {
flags: FenceCreateFlags::empty(),
export_handle_types: ExternalFenceHandleTypes::empty(),
_ne: crate::NonExhaustive(()),
}
}
}
impl FenceCreateInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
flags,
export_handle_types,
_ne: _,
} = self;
flags.validate_device(device).map_err(|err| {
err.add_context("flags")
.set_vuids(&["VUID-VkFenceCreateInfo-flags-parameter"])
})?;
if !export_handle_types.is_empty() {
if !(device.api_version() >= Version::V1_1
|| device.enabled_extensions().khr_external_fence)
{
return Err(Box::new(ValidationError {
context: "export_handle_types".into(),
problem: "is not empty".into(),
requires_one_of: RequiresOneOf(&[
RequiresAllOf(&[Requires::APIVersion(Version::V1_1)]),
RequiresAllOf(&[Requires::DeviceExtension("khr_external_fence")]),
]),
..Default::default()
}));
}
export_handle_types.validate_device(device).map_err(|err| {
err.add_context("export_handle_types")
.set_vuids(&["VUID-VkExportFenceCreateInfo-handleTypes-parameter"])
})?;
for handle_type in export_handle_types.into_iter() {
let external_fence_properties = unsafe {
device
.physical_device()
.external_fence_properties_unchecked(ExternalFenceInfo::handle_type(
handle_type,
))
};
if !external_fence_properties.exportable {
return Err(Box::new(ValidationError {
context: "export_handle_types".into(),
problem: format!(
"the handle type `ExternalFenceHandleTypes::{:?}` is not exportable, \
as returned by `PhysicalDevice::external_fence_properties`",
ExternalFenceHandleTypes::from(handle_type)
)
.into(),
vuids: &["VUID-VkExportFenceCreateInfo-handleTypes-01446"],
..Default::default()
}));
}
if !external_fence_properties
.compatible_handle_types
.contains(export_handle_types)
{
return Err(Box::new(ValidationError {
context: "export_handle_types".into(),
problem: format!(
"the handle type `ExternalFenceHandleTypes::{:?}` is not compatible \
with the other specified handle types, as returned by \
`PhysicalDevice::external_fence_properties`",
ExternalFenceHandleTypes::from(handle_type)
)
.into(),
vuids: &["VUID-VkExportFenceCreateInfo-handleTypes-01446"],
..Default::default()
}));
}
}
}
Ok(())
}
pub(crate) fn to_vk<'a>(
&self,
extensions_vk: &'a mut FenceCreateInfoExtensionsVk,
) -> ash::vk::FenceCreateInfo<'a> {
let &Self {
flags,
export_handle_types: _,
_ne: _,
} = self;
let mut val_vk = ash::vk::FenceCreateInfo::default().flags(flags.into());
let FenceCreateInfoExtensionsVk { export_vk } = extensions_vk;
if let Some(next) = export_vk {
val_vk = val_vk.push_next(next);
}
val_vk
}
pub(crate) fn to_vk_extensions(&self) -> FenceCreateInfoExtensionsVk {
let &Self {
flags: _,
export_handle_types,
_ne: _,
} = self;
let export_vk = (!export_handle_types.is_empty()).then(|| {
ash::vk::ExportFenceCreateInfo::default().handle_types(export_handle_types.into())
});
FenceCreateInfoExtensionsVk { export_vk }
}
}
pub(crate) struct FenceCreateInfoExtensionsVk {
pub(crate) export_vk: Option<ash::vk::ExportFenceCreateInfo<'static>>,
}
vulkan_bitflags! {
#[non_exhaustive]
FenceCreateFlags = FenceCreateFlags(u32);
SIGNALED = SIGNALED,
}
vulkan_bitflags_enum! {
#[non_exhaustive]
ExternalFenceHandleTypes,
ExternalFenceHandleType impl {
#[inline]
pub fn has_copy_transference(self) -> bool {
matches!(self, Self::SyncFd)
}
},
= ExternalFenceHandleTypeFlags(u32);
OPAQUE_FD, OpaqueFd = OPAQUE_FD,
OPAQUE_WIN32, OpaqueWin32 = OPAQUE_WIN32,
OPAQUE_WIN32_KMT, OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
SYNC_FD, SyncFd = SYNC_FD,
}
vulkan_bitflags! {
#[non_exhaustive]
FenceImportFlags = FenceImportFlags(u32);
TEMPORARY = TEMPORARY,
}
#[derive(Debug)]
pub struct ImportFenceFdInfo {
pub flags: FenceImportFlags,
pub handle_type: ExternalFenceHandleType,
pub file: Option<File>,
pub _ne: crate::NonExhaustive,
}
impl ImportFenceFdInfo {
#[inline]
pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
Self {
flags: FenceImportFlags::empty(),
handle_type,
file: None,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
flags,
handle_type,
file: _,
_ne: _,
} = self;
flags.validate_device(device).map_err(|err| {
err.add_context("flags")
.set_vuids(&["VUID-VkImportFenceFdInfoKHR-flags-parameter"])
})?;
handle_type.validate_device(device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkImportFenceFdInfoKHR-handleType-parameter"])
})?;
if !matches!(
handle_type,
ExternalFenceHandleType::OpaqueFd | ExternalFenceHandleType::SyncFd
) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalFenceHandleType::OpaqueFd` or \
`ExternalFenceHandleType::SyncFd`"
.into(),
vuids: &["VUID-VkImportFenceFdInfoKHR-handleType-01464"],
..Default::default()
}));
}
if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) {
return Err(Box::new(ValidationError {
problem: "`handle_type` has copy transference, but \
`flags` does not contain `FenceImportFlags::TEMPORARY`"
.into(),
vuids: &["VUID-VkImportFenceFdInfoKHR-handleType-07306"],
..Default::default()
}));
}
Ok(())
}
pub(crate) fn into_vk(
self,
fence_vk: ash::vk::Fence,
) -> ash::vk::ImportFenceFdInfoKHR<'static> {
let ImportFenceFdInfo {
flags,
handle_type,
file,
_ne: _,
} = self;
#[cfg(unix)]
let fd = {
use std::os::fd::IntoRawFd;
file.map_or(-1, |file| file.into_raw_fd())
};
#[cfg(not(unix))]
let fd = {
let _ = file;
-1
};
ash::vk::ImportFenceFdInfoKHR::default()
.fence(fence_vk)
.flags(flags.into())
.handle_type(handle_type.into())
.fd(fd)
}
}
#[derive(Debug)]
pub struct ImportFenceWin32HandleInfo {
pub flags: FenceImportFlags,
pub handle_type: ExternalFenceHandleType,
pub handle: ash::vk::HANDLE,
pub _ne: crate::NonExhaustive,
}
impl ImportFenceWin32HandleInfo {
#[inline]
pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
Self {
flags: FenceImportFlags::empty(),
handle_type,
handle: 0,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
flags,
handle_type,
handle: _,
_ne: _,
} = self;
flags.validate_device(device).map_err(|err| {
err.add_context("flags")
.set_vuids(&["VUID-VkImportFenceWin32HandleInfoKHR-flags-parameter"])
})?;
handle_type.validate_device(device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457"])
})?;
if !matches!(
handle_type,
ExternalFenceHandleType::OpaqueWin32 | ExternalFenceHandleType::OpaqueWin32Kmt
) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalFenceHandleType::OpaqueWin32` or \
`ExternalFenceHandleType::OpaqueWin32Kmt`"
.into(),
vuids: &["VUID-VkImportFenceWin32HandleInfoKHR-handleType-01457"],
..Default::default()
}));
}
if handle_type.has_copy_transference() && !flags.intersects(FenceImportFlags::TEMPORARY) {
return Err(Box::new(ValidationError {
problem: "`handle_type` has copy transference, but \
`flags` does not contain `FenceImportFlags::TEMPORARY`"
.into(),
..Default::default()
}));
}
Ok(())
}
pub(crate) fn to_vk(
&self,
fence_vk: ash::vk::Fence,
) -> ash::vk::ImportFenceWin32HandleInfoKHR<'static> {
let &Self {
flags,
handle_type,
handle,
_ne: _,
} = self;
ash::vk::ImportFenceWin32HandleInfoKHR::default()
.fence(fence_vk)
.flags(flags.into())
.handle_type(handle_type.into())
.handle(handle)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ExternalFenceInfo {
pub handle_type: ExternalFenceHandleType,
pub _ne: crate::NonExhaustive,
}
impl ExternalFenceInfo {
#[inline]
pub fn handle_type(handle_type: ExternalFenceHandleType) -> Self {
Self {
handle_type,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(
&self,
physical_device: &PhysicalDevice,
) -> Result<(), Box<ValidationError>> {
let &Self {
handle_type,
_ne: _,
} = self;
handle_type
.validate_physical_device(physical_device)
.map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkPhysicalDeviceExternalFenceInfo-handleType-parameter"])
})?;
Ok(())
}
pub(crate) fn to_vk(&self) -> ash::vk::PhysicalDeviceExternalFenceInfo<'static> {
let &Self {
handle_type,
_ne: _,
} = self;
ash::vk::PhysicalDeviceExternalFenceInfo::default().handle_type(handle_type.into())
}
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct ExternalFenceProperties {
pub exportable: bool,
pub importable: bool,
pub export_from_imported_handle_types: ExternalFenceHandleTypes,
pub compatible_handle_types: ExternalFenceHandleTypes,
}
impl ExternalFenceProperties {
pub(crate) fn to_mut_vk() -> ash::vk::ExternalFenceProperties<'static> {
ash::vk::ExternalFenceProperties::default()
}
pub(crate) fn from_vk(val_vk: &ash::vk::ExternalFenceProperties<'_>) -> Self {
let &ash::vk::ExternalFenceProperties {
export_from_imported_handle_types,
compatible_handle_types,
external_fence_features,
..
} = val_vk;
ExternalFenceProperties {
exportable: external_fence_features
.intersects(ash::vk::ExternalFenceFeatureFlags::EXPORTABLE),
importable: external_fence_features
.intersects(ash::vk::ExternalFenceFeatureFlags::IMPORTABLE),
export_from_imported_handle_types: export_from_imported_handle_types.into(),
compatible_handle_types: compatible_handle_types.into(),
}
}
}
#[cfg(test)]
mod tests {
use crate::{
sync::fence::{Fence, FenceCreateFlags, FenceCreateInfo},
VulkanObject,
};
use std::time::Duration;
#[test]
fn fence_create() {
let (device, _) = gfx_dev_and_queue!();
let fence = Fence::new(device, Default::default()).unwrap();
assert!(!fence.is_signaled().unwrap());
}
#[test]
fn fence_create_signaled() {
let (device, _) = gfx_dev_and_queue!();
let fence = Fence::new(
device,
FenceCreateInfo {
flags: FenceCreateFlags::SIGNALED,
..Default::default()
},
)
.unwrap();
assert!(fence.is_signaled().unwrap());
}
#[test]
fn fence_signaled_wait() {
let (device, _) = gfx_dev_and_queue!();
let fence = Fence::new(
device,
FenceCreateInfo {
flags: FenceCreateFlags::SIGNALED,
..Default::default()
},
)
.unwrap();
fence.wait(Some(Duration::new(0, 10))).unwrap();
}
#[test]
fn fence_reset() {
let (device, _) = gfx_dev_and_queue!();
let fence = Fence::new(
device,
FenceCreateInfo {
flags: FenceCreateFlags::SIGNALED,
..Default::default()
},
)
.unwrap();
unsafe { fence.reset() }.unwrap();
assert!(!fence.is_signaled().unwrap());
}
#[test]
fn multiwait_different_devices() {
let (device1, _) = gfx_dev_and_queue!();
let (device2, _) = gfx_dev_and_queue!();
assert_should_panic!({
let fence1 = Fence::new(
device1.clone(),
FenceCreateInfo {
flags: FenceCreateFlags::SIGNALED,
..Default::default()
},
)
.unwrap();
let fence2 = Fence::new(
device2.clone(),
FenceCreateInfo {
flags: FenceCreateFlags::SIGNALED,
..Default::default()
},
)
.unwrap();
let _ = Fence::multi_wait(
[&fence1, &fence2].iter().cloned(),
Some(Duration::new(0, 10)),
);
});
}
#[test]
fn multireset_different_devices() {
let (device1, _) = gfx_dev_and_queue!();
let (device2, _) = gfx_dev_and_queue!();
assert_should_panic!({
let fence1 = Fence::new(
device1.clone(),
FenceCreateInfo {
flags: FenceCreateFlags::SIGNALED,
..Default::default()
},
)
.unwrap();
let fence2 = Fence::new(
device2.clone(),
FenceCreateInfo {
flags: FenceCreateFlags::SIGNALED,
..Default::default()
},
)
.unwrap();
let _ = unsafe { Fence::multi_reset([&fence1, &fence2]) };
});
}
#[test]
fn fence_pool() {
let (device, _) = gfx_dev_and_queue!();
assert_eq!(device.fence_pool().lock().len(), 0);
let fence1_internal_obj = {
let fence = Fence::from_pool(device.clone()).unwrap();
assert_eq!(device.fence_pool().lock().len(), 0);
fence.handle()
};
assert_eq!(device.fence_pool().lock().len(), 1);
let fence2 = Fence::from_pool(device.clone()).unwrap();
assert_eq!(device.fence_pool().lock().len(), 0);
assert_eq!(fence2.handle(), fence1_internal_obj);
}
}