use crate::{
device::{physical::PhysicalDevice, Device, DeviceOwned},
instance::InstanceOwnedDebugWrapper,
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum, vulkan_enum},
Requires, RequiresAllOf, RequiresOneOf, Validated, ValidationError, Version, VulkanError,
VulkanObject,
};
use core::slice;
use smallvec::SmallVec;
use std::{fs::File, mem::MaybeUninit, num::NonZeroU64, ptr, sync::Arc, time::Duration};
#[derive(Debug)]
pub struct Semaphore {
handle: ash::vk::Semaphore,
device: InstanceOwnedDebugWrapper<Arc<Device>>,
id: NonZeroU64,
semaphore_type: SemaphoreType,
export_handle_types: ExternalSemaphoreHandleTypes,
must_put_in_pool: bool,
}
impl Semaphore {
#[inline]
pub fn new(
device: Arc<Device>,
create_info: SemaphoreCreateInfo,
) -> Result<Semaphore, Validated<VulkanError>> {
Self::validate_new(&device, &create_info)?;
Ok(unsafe { Self::new_unchecked(device, create_info) }?)
}
fn validate_new(
device: &Device,
create_info: &SemaphoreCreateInfo,
) -> 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: SemaphoreCreateInfo,
) -> Result<Semaphore, 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_semaphore)(
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<Semaphore, VulkanError> {
let handle = device.semaphore_pool().lock().pop();
let semaphore = match handle {
Some(handle) => Semaphore {
handle,
device: InstanceOwnedDebugWrapper(device),
id: Self::next_id(),
semaphore_type: SemaphoreType::Binary,
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
must_put_in_pool: true,
},
None => {
let mut semaphore =
unsafe { Semaphore::new_unchecked(device, Default::default()) }?;
semaphore.must_put_in_pool = true;
semaphore
}
};
Ok(semaphore)
}
#[inline]
pub unsafe fn from_handle(
device: Arc<Device>,
handle: ash::vk::Semaphore,
create_info: SemaphoreCreateInfo,
) -> Semaphore {
let SemaphoreCreateInfo {
semaphore_type,
initial_value: _,
export_handle_types,
_ne: _,
} = create_info;
Semaphore {
handle,
device: InstanceOwnedDebugWrapper(device),
id: Self::next_id(),
semaphore_type,
export_handle_types,
must_put_in_pool: false,
}
}
#[inline]
pub fn semaphore_type(&self) -> SemaphoreType {
self.semaphore_type
}
#[inline]
pub fn export_handle_types(&self) -> ExternalSemaphoreHandleTypes {
self.export_handle_types
}
#[inline]
pub fn counter_value(&self) -> Result<u64, Validated<VulkanError>> {
self.validate_counter_value()?;
Ok(unsafe { self.counter_value_unchecked() }?)
}
fn validate_counter_value(&self) -> Result<(), Box<ValidationError>> {
if self.semaphore_type != SemaphoreType::Timeline {
return Err(Box::new(ValidationError {
context: "self.semaphore_type()".into(),
problem: "is not `SemaphoreType::Timeline`".into(),
vuids: &["VUID-vkGetSemaphoreCounterValue-semaphore-03255"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn counter_value_unchecked(&self) -> Result<u64, VulkanError> {
let fns = self.device.fns();
let value = {
let mut output = MaybeUninit::uninit();
if self.device.api_version() >= Version::V1_2 {
unsafe {
(fns.v1_2.get_semaphore_counter_value)(
self.device.handle(),
self.handle,
output.as_mut_ptr(),
)
}
} else {
unsafe {
(fns.khr_timeline_semaphore.get_semaphore_counter_value_khr)(
self.device.handle(),
self.handle,
output.as_mut_ptr(),
)
}
}
.result()
.map_err(VulkanError::from)?;
unsafe { output.assume_init() }
};
Ok(value)
}
#[inline]
pub unsafe fn signal(
&self,
signal_info: SemaphoreSignalInfo,
) -> Result<(), Validated<VulkanError>> {
self.validate_signal(&signal_info)?;
Ok(unsafe { self.signal_unchecked(signal_info) }?)
}
fn validate_signal(
&self,
signal_info: &SemaphoreSignalInfo,
) -> Result<(), Box<ValidationError>> {
if self.semaphore_type != SemaphoreType::Timeline {
return Err(Box::new(ValidationError {
context: "self.semaphore_type()".into(),
problem: "is not `SemaphoreType::Timeline`".into(),
vuids: &["VUID-VkSemaphoreSignalInfo-semaphore-03257"],
..Default::default()
}));
}
signal_info.validate(&self.device)?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn signal_unchecked(
&self,
signal_info: SemaphoreSignalInfo,
) -> Result<(), VulkanError> {
let signal_info_vk = signal_info.to_vk(self.handle());
let fns = self.device.fns();
if self.device.api_version() >= Version::V1_2 {
unsafe { (fns.v1_2.signal_semaphore)(self.device.handle(), &signal_info_vk) }
} else {
unsafe {
(fns.khr_timeline_semaphore.signal_semaphore_khr)(
self.device.handle(),
&signal_info_vk,
)
}
}
.result()
.map_err(VulkanError::from)
}
#[inline]
pub fn wait(
&self,
wait_info: SemaphoreWaitInfo,
timeout: Option<Duration>,
) -> Result<(), Validated<VulkanError>> {
self.validate_wait(&wait_info, timeout)?;
Ok(unsafe { self.wait_unchecked(wait_info, timeout) }?)
}
fn validate_wait(
&self,
wait_info: &SemaphoreWaitInfo,
timeout: Option<Duration>,
) -> Result<(), Box<ValidationError>> {
if self.semaphore_type != SemaphoreType::Timeline {
return Err(Box::new(ValidationError {
context: "self.semaphore_type()".into(),
problem: "is not `SemaphoreType::Timeline`".into(),
vuids: &["VUID-VkSemaphoreWaitInfo-pSemaphores-03256"],
..Default::default()
}));
}
wait_info
.validate(&self.device)
.map_err(|err| err.add_context("wait_info"))?;
if let Some(timeout) = timeout {
if timeout.as_nanos() >= u64::MAX as u128 {
return Err(Box::new(ValidationError {
context: "timeout".into(),
problem: "is not less than `u64::MAX` nanoseconds".into(),
..Default::default()
}));
}
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn wait_unchecked(
&self,
wait_info: SemaphoreWaitInfo,
timeout: Option<Duration>,
) -> Result<(), VulkanError> {
let wait_info_vk = wait_info.to_vk(&self.handle);
let fns = self.device.fns();
if self.device.api_version() >= Version::V1_2 {
unsafe {
(fns.v1_2.wait_semaphores)(
self.device.handle(),
&wait_info_vk,
timeout.map_or(u64::MAX, |duration| {
u64::try_from(duration.as_nanos()).unwrap()
}),
)
}
} else {
unsafe {
(fns.khr_timeline_semaphore.wait_semaphores_khr)(
self.device.handle(),
&wait_info_vk,
timeout.map_or(u64::MAX, |duration| {
u64::try_from(duration.as_nanos()).unwrap()
}),
)
}
}
.result()
.map_err(VulkanError::from)
}
#[inline]
pub fn wait_multiple(
wait_info: SemaphoreWaitMultipleInfo,
timeout: Option<Duration>,
) -> Result<(), Validated<VulkanError>> {
Self::validate_wait_multiple(&wait_info, timeout)?;
Ok(unsafe { Self::wait_multiple_unchecked(wait_info, timeout) }?)
}
fn validate_wait_multiple(
wait_info: &SemaphoreWaitMultipleInfo,
timeout: Option<Duration>,
) -> Result<(), Box<ValidationError>> {
if let Some(timeout) = timeout {
if timeout.as_nanos() >= u64::MAX as u128 {
return Err(Box::new(ValidationError {
context: "timeout".into(),
problem: "is not less than `u64::MAX` nanoseconds".into(),
..Default::default()
}));
}
}
if wait_info.semaphores.is_empty() {
return Ok(());
}
let device = &wait_info.semaphores[0].semaphore.device;
wait_info
.validate(device)
.map_err(|err| err.add_context("wait_info"))?;
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn wait_multiple_unchecked(
wait_info: SemaphoreWaitMultipleInfo,
timeout: Option<Duration>,
) -> Result<(), VulkanError> {
if wait_info.semaphores.is_empty() {
return Ok(());
}
let wait_info_fields1_vk = wait_info.to_vk_fields1();
let wait_info_vk = wait_info.to_vk(&wait_info_fields1_vk);
let device = &wait_info.semaphores[0].semaphore.device;
let fns = device.fns();
if device.api_version() >= Version::V1_2 {
unsafe {
(fns.v1_2.wait_semaphores)(
device.handle(),
&wait_info_vk,
timeout.map_or(u64::MAX, |duration| {
u64::try_from(duration.as_nanos()).unwrap()
}),
)
}
} else {
unsafe {
(fns.khr_timeline_semaphore.wait_semaphores_khr)(
device.handle(),
&wait_info_vk,
timeout.map_or(u64::MAX, |duration| {
u64::try_from(duration.as_nanos()).unwrap()
}),
)
}
}
.result()
.map_err(VulkanError::from)
}
#[inline]
pub unsafe fn export_fd(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> 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: ExternalSemaphoreHandleType,
) -> Result<(), Box<ValidationError>> {
if !self.device.enabled_extensions().khr_external_semaphore_fd {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_external_semaphore_fd",
)])]),
..Default::default()
}));
}
handle_type.validate_device(&self.device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkSemaphoreGetFdInfoKHR-handleType-parameter"])
})?;
if !matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd
) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalSemaphoreHandleType::OpaqueFd` or \
`ExternalSemaphoreHandleType::SyncFd`"
.into(),
vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-01136"],
..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-VkSemaphoreGetFdInfoKHR-handleType-01132"],
..Default::default()
}));
}
if handle_type.has_copy_transference() && self.semaphore_type != SemaphoreType::Binary {
return Err(Box::new(ValidationError {
problem: "`handle_type` has copy transference, but \
`self.semaphore_type()` is not `SemaphoreType::Binary`"
.into(),
vuids: &["VUID-VkSemaphoreGetFdInfoKHR-handleType-03253"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn export_fd_unchecked(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<File, VulkanError> {
let info_vk = ash::vk::SemaphoreGetFdInfoKHR::default()
.semaphore(self.handle)
.handle_type(handle_type.into());
let mut output = MaybeUninit::uninit();
let fns = self.device.fns();
unsafe {
(fns.khr_external_semaphore_fd.get_semaphore_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_semaphore_fd` was somehow enabled on a non-Unix system");
}
}
#[inline]
pub fn export_win32_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> 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: ExternalSemaphoreHandleType,
) -> Result<(), Box<ValidationError>> {
if !self
.device
.enabled_extensions()
.khr_external_semaphore_win32
{
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_external_semaphore_win32",
)])]),
..Default::default()
}));
}
handle_type.validate_device(&self.device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-parameter"])
})?;
if !matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueWin32
| ExternalSemaphoreHandleType::OpaqueWin32Kmt
| ExternalSemaphoreHandleType::D3D12Fence
) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalSemaphoreHandleType::OpaqueWin32`, \
`ExternalSemaphoreHandleType::OpaqueWin32Kmt` or \
`ExternalSemaphoreHandleType::D3D12Fence`"
.into(),
vuids: &["VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01131"],
..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-VkSemaphoreGetWin32HandleInfoKHR-handleType-01126"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn export_win32_handle_unchecked(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<ash::vk::HANDLE, VulkanError> {
let info_vk = ash::vk::SemaphoreGetWin32HandleInfoKHR::default()
.semaphore(self.handle)
.handle_type(handle_type.into());
let handle = {
let mut output = MaybeUninit::uninit();
let fns = self.device.fns();
unsafe {
(fns.khr_external_semaphore_win32
.get_semaphore_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 export_zircon_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<ash::vk::zx_handle_t, Validated<VulkanError>> {
self.validate_export_zircon_handle(handle_type)?;
Ok(unsafe { self.export_zircon_handle_unchecked(handle_type) }?)
}
fn validate_export_zircon_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<(), Box<ValidationError>> {
if !self.device.enabled_extensions().fuchsia_external_semaphore {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"fuchsia_external_semaphore",
)])]),
..Default::default()
}));
}
handle_type.validate_device(&self.device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-parameter"])
})?;
if self.semaphore_type != SemaphoreType::Binary {
return Err(Box::new(ValidationError {
context: "self.semaphore_type()".into(),
problem: "is not `SemaphoreType::Binary`".into(),
vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04763"],
..Default::default()
}));
}
if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalSemaphoreHandleType::ZirconEvent`".into(),
vuids: &["VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04762"],
..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-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04758"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn export_zircon_handle_unchecked(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<ash::vk::zx_handle_t, VulkanError> {
let info_vk = ash::vk::SemaphoreGetZirconHandleInfoFUCHSIA::default()
.semaphore(self.handle)
.handle_type(handle_type.into());
let handle = {
let mut output = MaybeUninit::uninit();
let fns = self.device.fns();
unsafe {
(fns.fuchsia_external_semaphore
.get_semaphore_zircon_handle_fuchsia)(
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_semaphore_fd_info: ImportSemaphoreFdInfo,
) -> Result<(), Validated<VulkanError>> {
self.validate_import_fd(&import_semaphore_fd_info)?;
Ok(unsafe { self.import_fd_unchecked(import_semaphore_fd_info) }?)
}
fn validate_import_fd(
&self,
import_semaphore_fd_info: &ImportSemaphoreFdInfo,
) -> Result<(), Box<ValidationError>> {
if !self.device.enabled_extensions().khr_external_semaphore_fd {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_external_semaphore_fd",
)])]),
..Default::default()
}));
}
import_semaphore_fd_info
.validate(&self.device)
.map_err(|err| err.add_context("import_semaphore_fd_info"))?;
let &ImportSemaphoreFdInfo {
flags,
handle_type: _,
file: _,
_ne: _,
} = import_semaphore_fd_info;
if self.semaphore_type == SemaphoreType::Timeline
&& flags.intersects(SemaphoreImportFlags::TEMPORARY)
{
return Err(Box::new(ValidationError {
problem: "`self.semaphore_type()` is `SemaphoreType::Timeline`, but \
`import_semaphore_fd_info.flags` contains \
`SemaphoreImportFlags::TEMPORARY`"
.into(),
vuids: &["VUID-VkImportSemaphoreFdInfoKHR-flags-03323"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn import_fd_unchecked(
&self,
import_semaphore_fd_info: ImportSemaphoreFdInfo,
) -> Result<(), VulkanError> {
let info_vk = import_semaphore_fd_info.into_vk(self.handle());
let fns = self.device.fns();
unsafe {
(fns.khr_external_semaphore_fd.import_semaphore_fd_khr)(self.device.handle(), &info_vk)
}
.result()
.map_err(VulkanError::from)?;
Ok(())
}
#[inline]
pub unsafe fn import_win32_handle(
&self,
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
) -> Result<(), Validated<VulkanError>> {
self.validate_import_win32_handle(&import_semaphore_win32_handle_info)?;
Ok(unsafe { self.import_win32_handle_unchecked(import_semaphore_win32_handle_info) }?)
}
fn validate_import_win32_handle(
&self,
import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo,
) -> Result<(), Box<ValidationError>> {
if !self
.device
.enabled_extensions()
.khr_external_semaphore_win32
{
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"khr_external_semaphore_win32",
)])]),
..Default::default()
}));
}
import_semaphore_win32_handle_info
.validate(&self.device)
.map_err(|err| err.add_context("import_semaphore_win32_handle_info"))?;
let &ImportSemaphoreWin32HandleInfo {
flags,
handle_type: _,
handle: _,
_ne: _,
} = import_semaphore_win32_handle_info;
if self.semaphore_type == SemaphoreType::Timeline
&& flags.intersects(SemaphoreImportFlags::TEMPORARY)
{
return Err(Box::new(ValidationError {
problem: "`self.semaphore_type()` is `SemaphoreType::Timeline`, but \
`import_semaphore_win32_handle_info.flags` contains \
`SemaphoreImportFlags::TEMPORARY`"
.into(),
vuids: &["VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-03322"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn import_win32_handle_unchecked(
&self,
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
) -> Result<(), VulkanError> {
let info_vk = import_semaphore_win32_handle_info.to_vk(self.handle());
let fns = self.device.fns();
unsafe {
(fns.khr_external_semaphore_win32
.import_semaphore_win32_handle_khr)(self.device.handle(), &info_vk)
}
.result()
.map_err(VulkanError::from)?;
Ok(())
}
#[inline]
pub unsafe fn import_zircon_handle(
&self,
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
) -> Result<(), Validated<VulkanError>> {
self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info)?;
Ok(unsafe { self.import_zircon_handle_unchecked(import_semaphore_zircon_handle_info) }?)
}
fn validate_import_zircon_handle(
&self,
import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo,
) -> Result<(), Box<ValidationError>> {
if !self.device.enabled_extensions().fuchsia_external_semaphore {
return Err(Box::new(ValidationError {
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[Requires::DeviceExtension(
"fuchsia_external_semaphore",
)])]),
..Default::default()
}));
}
import_semaphore_zircon_handle_info
.validate(&self.device)
.map_err(|err| err.add_context("import_semaphore_zircon_handle_info"))?;
if self.semaphore_type == SemaphoreType::Timeline {
return Err(Box::new(ValidationError {
problem: "`self.semaphore_type()` is `SemaphoreType::Timeline`".into(),
vuids: &["VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-semaphoreType-04768"],
..Default::default()
}));
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
pub unsafe fn import_zircon_handle_unchecked(
&self,
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
) -> Result<(), VulkanError> {
let info_vk = import_semaphore_zircon_handle_info.to_vk(self.handle());
let fns = self.device.fns();
unsafe {
(fns.fuchsia_external_semaphore
.import_semaphore_zircon_handle_fuchsia)(self.device.handle(), &info_vk)
}
.result()
.map_err(VulkanError::from)?;
Ok(())
}
}
impl Drop for Semaphore {
#[inline]
fn drop(&mut self) {
if self.must_put_in_pool {
let raw_sem = self.handle;
self.device.semaphore_pool().lock().push(raw_sem);
} else {
let fns = self.device.fns();
unsafe { (fns.v1_0.destroy_semaphore)(self.device.handle(), self.handle, ptr::null()) };
}
}
}
unsafe impl VulkanObject for Semaphore {
type Handle = ash::vk::Semaphore;
#[inline]
fn handle(&self) -> Self::Handle {
self.handle
}
}
unsafe impl DeviceOwned for Semaphore {
#[inline]
fn device(&self) -> &Arc<Device> {
&self.device
}
}
impl_id_counter!(Semaphore);
#[derive(Clone, Debug)]
pub struct SemaphoreCreateInfo {
pub semaphore_type: SemaphoreType,
pub initial_value: u64,
pub export_handle_types: ExternalSemaphoreHandleTypes,
pub _ne: crate::NonExhaustive,
}
impl Default for SemaphoreCreateInfo {
#[inline]
fn default() -> Self {
Self {
semaphore_type: SemaphoreType::Binary,
initial_value: 0,
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
_ne: crate::NonExhaustive(()),
}
}
}
impl SemaphoreCreateInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
semaphore_type,
initial_value,
export_handle_types,
_ne: _,
} = self;
semaphore_type.validate_device(device).map_err(|err| {
err.add_context("semaphore_type")
.set_vuids(&["VUID-VkSemaphoreTypeCreateInfo-semaphoreType-parameter"])
})?;
match semaphore_type {
SemaphoreType::Binary => {
if initial_value != 0 {
return Err(Box::new(ValidationError {
problem: "`semaphore_type` is `SemaphoreType::Binary`, but \
`initial_value` is not `0`"
.into(),
vuids: &["VUID-VkSemaphoreTypeCreateInfo-semaphoreType-03279"],
..Default::default()
}));
}
}
SemaphoreType::Timeline => {
if !device.enabled_features().timeline_semaphore {
return Err(Box::new(ValidationError {
context: "semaphore_type".into(),
problem: "is `SemaphoreType::Timeline`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceFeature("timeline_semaphore"),
])]),
vuids: &["VUID-VkSemaphoreTypeCreateInfo-timelineSemaphore-03252"],
}));
}
}
}
if !export_handle_types.is_empty() {
if !(device.api_version() >= Version::V1_1
|| device.enabled_extensions().khr_external_semaphore)
{
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_semaphore")]),
]),
..Default::default()
}));
}
export_handle_types.validate_device(device).map_err(|err| {
err.add_context("export_handle_types")
.set_vuids(&["VUID-VkExportSemaphoreCreateInfo-handleTypes-parameter"])
})?;
for handle_type in export_handle_types.into_iter() {
let external_semaphore_properties = unsafe {
device
.physical_device()
.external_semaphore_properties_unchecked(ExternalSemaphoreInfo {
semaphore_type,
initial_value,
..ExternalSemaphoreInfo::handle_type(handle_type)
})
};
if !external_semaphore_properties.exportable {
return Err(Box::new(ValidationError {
context: "export_handle_types".into(),
problem: format!(
"the handle type `ExternalSemaphoreHandleTypes::{:?}` is not \
exportable, as returned by \
`PhysicalDevice::external_semaphore_properties`",
ExternalSemaphoreHandleTypes::from(handle_type)
)
.into(),
vuids: &["VUID-VkExportSemaphoreCreateInfo-handleTypes-01124"],
..Default::default()
}));
}
if !external_semaphore_properties
.compatible_handle_types
.contains(export_handle_types)
{
return Err(Box::new(ValidationError {
context: "export_handle_types".into(),
problem: format!(
"the handle type `ExternalSemaphoreHandleTypes::{:?}` is not \
compatible with the other specified handle types, as returned by \
`PhysicalDevice::external_semaphore_properties`",
ExternalSemaphoreHandleTypes::from(handle_type)
)
.into(),
vuids: &["VUID-VkExportSemaphoreCreateInfo-handleTypes-01124"],
..Default::default()
}));
}
}
}
Ok(())
}
pub(crate) fn to_vk<'a>(
&self,
extensions_vk: &'a mut SemaphoreCreateInfoExtensionsVk,
) -> ash::vk::SemaphoreCreateInfo<'a> {
let &Self {
semaphore_type: _,
initial_value: _,
export_handle_types: _,
_ne: _,
} = self;
let mut val_vk =
ash::vk::SemaphoreCreateInfo::default().flags(ash::vk::SemaphoreCreateFlags::empty());
let SemaphoreCreateInfoExtensionsVk { export_vk, type_vk } = extensions_vk;
if let Some(next) = export_vk {
val_vk = val_vk.push_next(next);
}
if let Some(next) = type_vk {
val_vk = val_vk.push_next(next);
}
val_vk
}
pub(crate) fn to_vk_extensions(&self) -> SemaphoreCreateInfoExtensionsVk {
let &Self {
semaphore_type,
initial_value,
export_handle_types,
_ne: _,
} = self;
let export_vk = (!export_handle_types.is_empty()).then(|| {
ash::vk::ExportSemaphoreCreateInfo::default().handle_types(export_handle_types.into())
});
let type_vk = (semaphore_type != SemaphoreType::Binary).then(|| {
ash::vk::SemaphoreTypeCreateInfo::default()
.semaphore_type(semaphore_type.into())
.initial_value(initial_value)
});
SemaphoreCreateInfoExtensionsVk { export_vk, type_vk }
}
}
pub(crate) struct SemaphoreCreateInfoExtensionsVk {
pub(crate) export_vk: Option<ash::vk::ExportSemaphoreCreateInfo<'static>>,
pub(crate) type_vk: Option<ash::vk::SemaphoreTypeCreateInfo<'static>>,
}
vulkan_enum! {
#[non_exhaustive]
SemaphoreType = SemaphoreType(i32);
Binary = BINARY,
Timeline = TIMELINE,
}
vulkan_bitflags_enum! {
#[non_exhaustive]
ExternalSemaphoreHandleTypes,
ExternalSemaphoreHandleType impl {
#[inline]
pub fn has_copy_transference(self) -> bool {
matches!(self, Self::SyncFd)
}
},
= ExternalSemaphoreHandleTypeFlags(u32);
OPAQUE_FD, OpaqueFd = OPAQUE_FD,
OPAQUE_WIN32, OpaqueWin32 = OPAQUE_WIN32,
OPAQUE_WIN32_KMT, OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
D3D12_FENCE, D3D12Fence = D3D12_FENCE,
SYNC_FD, SyncFd = SYNC_FD,
ZIRCON_EVENT, ZirconEvent = ZIRCON_EVENT_FUCHSIA
RequiresOneOf([
RequiresAllOf([DeviceExtension(fuchsia_external_semaphore)]),
]),
}
#[derive(Clone, Debug)]
pub struct SemaphoreSignalInfo {
pub value: u64,
pub _ne: crate::NonExhaustive,
}
impl Default for SemaphoreSignalInfo {
#[inline]
fn default() -> Self {
Self {
value: 0,
_ne: crate::NonExhaustive(()),
}
}
}
impl SemaphoreSignalInfo {
pub(crate) fn validate(&self, _device: &Device) -> Result<(), Box<ValidationError>> {
let &Self { value: _, _ne: _ } = self;
Ok(())
}
pub(crate) fn to_vk(
&self,
semaphore_vk: ash::vk::Semaphore,
) -> ash::vk::SemaphoreSignalInfo<'static> {
let &Self { value, _ne: _ } = self;
ash::vk::SemaphoreSignalInfo::default()
.semaphore(semaphore_vk)
.value(value)
}
}
#[derive(Clone, Debug)]
pub struct SemaphoreWaitInfo {
pub flags: SemaphoreWaitFlags,
pub value: u64,
pub _ne: crate::NonExhaustive,
}
impl Default for SemaphoreWaitInfo {
#[inline]
fn default() -> Self {
Self {
flags: SemaphoreWaitFlags::empty(),
value: 0,
_ne: crate::NonExhaustive(()),
}
}
}
impl SemaphoreWaitInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
flags,
value: _,
_ne: _,
} = self;
flags.validate_device(device).map_err(|err| {
err.add_context("flags")
.set_vuids(&["VUID-VkSemaphoreWaitInfo-flags-parameter"])
})?;
Ok(())
}
pub(crate) fn to_vk<'a>(
&'a self,
semaphore_vk: &'a ash::vk::Semaphore,
) -> ash::vk::SemaphoreWaitInfo<'a> {
let &Self {
flags,
ref value,
_ne: _,
} = self;
ash::vk::SemaphoreWaitInfo::default()
.flags(flags.into())
.semaphores(slice::from_ref(semaphore_vk))
.values(slice::from_ref(value))
}
}
#[derive(Clone, Debug)]
pub struct SemaphoreWaitMultipleInfo {
pub flags: SemaphoreWaitFlags,
pub semaphores: Vec<SemaphoreWaitValueInfo>,
pub _ne: crate::NonExhaustive,
}
impl Default for SemaphoreWaitMultipleInfo {
#[inline]
fn default() -> Self {
Self {
flags: SemaphoreWaitFlags::empty(),
semaphores: Vec::new(),
_ne: crate::NonExhaustive(()),
}
}
}
impl SemaphoreWaitMultipleInfo {
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
flags,
ref semaphores,
_ne,
} = self;
flags.validate_device(device).map_err(|err| {
err.add_context("flags")
.set_vuids(&["VUID-VkSemaphoreWaitInfo-flags-parameter"])
})?;
if semaphores.is_empty() {
return Ok(());
}
for (index, value_info) in semaphores.iter().enumerate() {
value_info
.validate(device)
.map_err(|err| err.add_context(format!("semaphores[{}]", index)))?;
}
Ok(())
}
pub(crate) fn to_vk<'a>(
&self,
fields1_vk: &'a SemaphoreWaitMultipleInfoFields1Vk,
) -> ash::vk::SemaphoreWaitInfo<'a> {
let &Self {
flags,
semaphores: _,
_ne: _,
} = self;
let SemaphoreWaitMultipleInfoFields1Vk {
semaphores_vk,
values_vk,
} = fields1_vk;
ash::vk::SemaphoreWaitInfo::default()
.flags(flags.into())
.semaphores(semaphores_vk)
.values(values_vk)
}
pub(crate) fn to_vk_fields1(&self) -> SemaphoreWaitMultipleInfoFields1Vk {
let &SemaphoreWaitMultipleInfo { ref semaphores, .. } = self;
let mut semaphores_vk: SmallVec<[_; 8]> = SmallVec::with_capacity(semaphores.len());
let mut values_vk: SmallVec<[_; 8]> = SmallVec::with_capacity(semaphores.len());
for value_info in semaphores {
let &SemaphoreWaitValueInfo {
ref semaphore,
value,
_ne: _,
} = value_info;
semaphores_vk.push(semaphore.handle);
values_vk.push(value);
}
SemaphoreWaitMultipleInfoFields1Vk {
semaphores_vk,
values_vk,
}
}
}
pub(crate) struct SemaphoreWaitMultipleInfoFields1Vk {
semaphores_vk: SmallVec<[ash::vk::Semaphore; 8]>,
values_vk: SmallVec<[u64; 8]>,
}
vulkan_bitflags! {
#[non_exhaustive]
SemaphoreWaitFlags = SemaphoreWaitFlags(u32);
ANY = ANY,
}
#[derive(Clone, Debug)]
pub struct SemaphoreWaitValueInfo {
pub semaphore: Arc<Semaphore>,
pub value: u64,
pub _ne: crate::NonExhaustive,
}
impl SemaphoreWaitValueInfo {
#[inline]
pub fn new(semaphore: Arc<Semaphore>, value: u64) -> Self {
Self {
semaphore,
value,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
ref semaphore,
value: _,
_ne: _,
} = self;
assert_eq!(device, semaphore.device.as_ref());
if semaphore.semaphore_type != SemaphoreType::Timeline {
return Err(Box::new(ValidationError {
context: "semaphore.semaphore_type()".into(),
problem: "is not `SemaphoreType::Timeline`".into(),
vuids: &["VUID-VkSemaphoreWaitInfo-pSemaphores-03256"],
..Default::default()
}));
}
Ok(())
}
}
vulkan_bitflags! {
#[non_exhaustive]
SemaphoreImportFlags = SemaphoreImportFlags(u32);
TEMPORARY = TEMPORARY,
}
#[derive(Debug)]
pub struct ImportSemaphoreFdInfo {
pub flags: SemaphoreImportFlags,
pub handle_type: ExternalSemaphoreHandleType,
pub file: Option<File>,
pub _ne: crate::NonExhaustive,
}
impl ImportSemaphoreFdInfo {
#[inline]
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
Self {
flags: SemaphoreImportFlags::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-VkImportSemaphoreFdInfoKHR-flags-parameter"])
})?;
handle_type.validate_device(device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkImportSemaphoreFdInfoKHR-handleType-parameter"])
})?;
if !matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd
) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalSemaphoreHandleType::OpaqueFd` or \
`ExternalSemaphoreHandleType::SyncFd`"
.into(),
vuids: &["VUID-VkImportSemaphoreFdInfoKHR-handleType-01143"],
..Default::default()
}));
}
if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
{
return Err(Box::new(ValidationError {
problem: "`handle_type` has copy transference, but \
`flags` does not contain `SemaphoreImportFlags::TEMPORARY`"
.into(),
vuids: &["VUID-VkImportSemaphoreFdInfoKHR-handleType-07307"],
..Default::default()
}));
}
Ok(())
}
pub(crate) fn into_vk(
self,
semaphore_vk: ash::vk::Semaphore,
) -> ash::vk::ImportSemaphoreFdInfoKHR<'static> {
let Self {
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::ImportSemaphoreFdInfoKHR::default()
.semaphore(semaphore_vk)
.flags(flags.into())
.handle_type(handle_type.into())
.fd(fd)
}
}
#[derive(Debug)]
pub struct ImportSemaphoreWin32HandleInfo {
pub flags: SemaphoreImportFlags,
pub handle_type: ExternalSemaphoreHandleType,
pub handle: ash::vk::HANDLE,
pub _ne: crate::NonExhaustive,
}
impl ImportSemaphoreWin32HandleInfo {
#[inline]
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
Self {
flags: SemaphoreImportFlags::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-VkImportSemaphoreWin32HandleInfoKHR-flags-parameter"])
})?;
handle_type.validate_device(device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140"])
})?;
if !matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueWin32
| ExternalSemaphoreHandleType::OpaqueWin32Kmt
| ExternalSemaphoreHandleType::D3D12Fence
) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalSemaphoreHandleType::OpaqueWin32`, \
`ExternalSemaphoreHandleType::OpaqueWin32Kmt` or \
`ExternalSemaphoreHandleType::D3D12Fence`"
.into(),
vuids: &["VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140"],
..Default::default()
}));
}
if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
{
return Err(Box::new(ValidationError {
problem: "`handle_type` has copy transference, but \
`flags` does not contain `SemaphoreImportFlags::TEMPORARY`"
.into(),
..Default::default()
}));
}
Ok(())
}
pub(crate) fn to_vk(
&self,
semaphore_vk: ash::vk::Semaphore,
) -> ash::vk::ImportSemaphoreWin32HandleInfoKHR<'static> {
let &Self {
flags,
handle_type,
handle,
_ne: _,
} = self;
ash::vk::ImportSemaphoreWin32HandleInfoKHR::default()
.semaphore(semaphore_vk)
.flags(flags.into())
.handle_type(handle_type.into())
.handle(handle)
}
}
#[derive(Debug)]
pub struct ImportSemaphoreZirconHandleInfo {
pub flags: SemaphoreImportFlags,
pub handle_type: ExternalSemaphoreHandleType,
pub zircon_handle: ash::vk::zx_handle_t,
pub _ne: crate::NonExhaustive,
}
impl ImportSemaphoreZirconHandleInfo {
#[inline]
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
Self {
flags: SemaphoreImportFlags::empty(),
handle_type,
zircon_handle: 0,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(&self, device: &Device) -> Result<(), Box<ValidationError>> {
let &Self {
flags,
handle_type,
zircon_handle: _,
_ne: _,
} = self;
flags.validate_device(device).map_err(|err| {
err.add_context("flags")
.set_vuids(&["VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-flags-parameter"])
})?;
handle_type.validate_device(device).map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-parameter"])
})?;
if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
return Err(Box::new(ValidationError {
context: "handle_type".into(),
problem: "is not `ExternalSemaphoreHandleType::ZirconEvent`".into(),
vuids: &["VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-04765"],
..Default::default()
}));
}
if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
{
return Err(Box::new(ValidationError {
problem: "`handle_type` has copy transference, but \
`flags` does not contain `SemaphoreImportFlags::TEMPORARY`"
.into(),
..Default::default()
}));
}
Ok(())
}
pub(crate) fn to_vk(
&self,
semaphore_vk: ash::vk::Semaphore,
) -> ash::vk::ImportSemaphoreZirconHandleInfoFUCHSIA<'static> {
let &Self {
flags,
handle_type,
zircon_handle,
_ne: _,
} = self;
ash::vk::ImportSemaphoreZirconHandleInfoFUCHSIA::default()
.semaphore(semaphore_vk)
.flags(flags.into())
.handle_type(handle_type.into())
.zircon_handle(zircon_handle)
}
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ExternalSemaphoreInfo {
pub handle_type: ExternalSemaphoreHandleType,
pub semaphore_type: SemaphoreType,
pub initial_value: u64,
pub _ne: crate::NonExhaustive,
}
impl ExternalSemaphoreInfo {
#[inline]
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
Self {
handle_type,
semaphore_type: SemaphoreType::Binary,
initial_value: 0,
_ne: crate::NonExhaustive(()),
}
}
pub(crate) fn validate(
&self,
physical_device: &PhysicalDevice,
) -> Result<(), Box<ValidationError>> {
let &Self {
handle_type,
semaphore_type,
initial_value,
_ne: _,
} = self;
handle_type
.validate_physical_device(physical_device)
.map_err(|err| {
err.add_context("handle_type")
.set_vuids(&["VUID-VkPhysicalDeviceExternalSemaphoreInfo-handleType-parameter"])
})?;
semaphore_type
.validate_physical_device(physical_device)
.map_err(|err| {
err.add_context("semaphore_type")
.set_vuids(&["VUID-VkSemaphoreTypeCreateInfo-semaphoreType-parameter"])
})?;
match semaphore_type {
SemaphoreType::Binary => {
if initial_value != 0 {
return Err(Box::new(ValidationError {
problem: "`semaphore_type` is `SemaphoreType::Binary`, but \
`initial_value` is not `0`"
.into(),
vuids: &["VUID-VkSemaphoreTypeCreateInfo-semaphoreType-03279"],
..Default::default()
}));
}
}
SemaphoreType::Timeline => {
if !physical_device.supported_features().timeline_semaphore {
return Err(Box::new(ValidationError {
context: "semaphore_type".into(),
problem: "is `SemaphoreType::Timeline`".into(),
requires_one_of: RequiresOneOf(&[RequiresAllOf(&[
Requires::DeviceFeature("timeline_semaphore"),
])]),
vuids: &["VUID-VkSemaphoreTypeCreateInfo-timelineSemaphore-03252"],
}));
}
}
}
Ok(())
}
pub(crate) fn to_vk<'a>(
&self,
extensions_vk: &'a mut ExternalSemaphoreInfoExtensionsVk,
) -> ash::vk::PhysicalDeviceExternalSemaphoreInfo<'a> {
let &Self {
handle_type,
semaphore_type: _,
initial_value: _,
_ne: _,
} = self;
let mut val_vk =
ash::vk::PhysicalDeviceExternalSemaphoreInfo::default().handle_type(handle_type.into());
let ExternalSemaphoreInfoExtensionsVk { type_vk } = extensions_vk;
if let Some(next) = type_vk {
val_vk = val_vk.push_next(next);
}
val_vk
}
pub(crate) fn to_vk_extensions(&self) -> ExternalSemaphoreInfoExtensionsVk {
let &Self {
handle_type: _,
semaphore_type,
initial_value,
_ne: _,
} = self;
let type_vk = (semaphore_type != SemaphoreType::Binary).then(|| {
ash::vk::SemaphoreTypeCreateInfo::default()
.semaphore_type(semaphore_type.into())
.initial_value(initial_value)
});
ExternalSemaphoreInfoExtensionsVk { type_vk }
}
}
pub(crate) struct ExternalSemaphoreInfoExtensionsVk {
pub(crate) type_vk: Option<ash::vk::SemaphoreTypeCreateInfo<'static>>,
}
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct ExternalSemaphoreProperties {
pub exportable: bool,
pub importable: bool,
pub export_from_imported_handle_types: ExternalSemaphoreHandleTypes,
pub compatible_handle_types: ExternalSemaphoreHandleTypes,
}
impl ExternalSemaphoreProperties {
pub(crate) fn to_mut_vk() -> ash::vk::ExternalSemaphoreProperties<'static> {
ash::vk::ExternalSemaphoreProperties::default()
}
pub(crate) fn from_vk(val_vk: &ash::vk::ExternalSemaphoreProperties<'_>) -> Self {
let &ash::vk::ExternalSemaphoreProperties {
export_from_imported_handle_types,
compatible_handle_types,
external_semaphore_features,
..
} = val_vk;
ExternalSemaphoreProperties {
exportable: external_semaphore_features
.intersects(ash::vk::ExternalSemaphoreFeatureFlags::EXPORTABLE),
importable: external_semaphore_features
.intersects(ash::vk::ExternalSemaphoreFeatureFlags::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::{
device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo},
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
sync::semaphore::{
ExternalSemaphoreHandleType, ExternalSemaphoreHandleTypes, Semaphore,
SemaphoreCreateInfo,
},
VulkanLibrary, VulkanObject,
};
#[test]
fn semaphore_create() {
let (device, _) = gfx_dev_and_queue!();
let _ = Semaphore::new(device, Default::default());
}
#[test]
fn semaphore_pool() {
let (device, _) = gfx_dev_and_queue!();
assert_eq!(device.semaphore_pool().lock().len(), 0);
let sem1_internal_obj = {
let sem = Semaphore::from_pool(device.clone()).unwrap();
assert_eq!(device.semaphore_pool().lock().len(), 0);
sem.handle()
};
assert_eq!(device.semaphore_pool().lock().len(), 1);
let sem2 = Semaphore::from_pool(device.clone()).unwrap();
assert_eq!(device.semaphore_pool().lock().len(), 0);
assert_eq!(sem2.handle(), sem1_internal_obj);
}
#[test]
fn semaphore_export_fd() {
let library = match VulkanLibrary::new() {
Ok(x) => x,
Err(_) => return,
};
let instance = match Instance::new(
library,
InstanceCreateInfo {
enabled_extensions: InstanceExtensions {
khr_get_physical_device_properties2: true,
khr_external_semaphore_capabilities: true,
..InstanceExtensions::empty()
},
..Default::default()
},
) {
Ok(x) => x,
Err(_) => return,
};
let physical_device = match instance.enumerate_physical_devices() {
Ok(mut x) => x.next().unwrap(),
Err(_) => return,
};
let (device, _) = match Device::new(
physical_device,
DeviceCreateInfo {
queue_create_infos: vec![QueueCreateInfo {
queue_family_index: 0,
..Default::default()
}],
enabled_extensions: DeviceExtensions {
khr_external_semaphore: true,
khr_external_semaphore_fd: true,
..DeviceExtensions::empty()
},
..Default::default()
},
) {
Ok(x) => x,
Err(_) => return,
};
let sem = Semaphore::new(
device,
SemaphoreCreateInfo {
export_handle_types: ExternalSemaphoreHandleTypes::OPAQUE_FD,
..Default::default()
},
)
.unwrap();
let _fd = unsafe { sem.export_fd(ExternalSemaphoreHandleType::OpaqueFd) }.unwrap();
}
}