blob: ac0ca56ad52c4e1019d3061317f5319c97912577 [file] [log] [blame]
// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// https://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or https://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.
//! A semaphore provides synchronization between multiple queues, with non-command buffer
//! commands on the same queue, or between the device and an external source.
use crate::{
device::{Device, DeviceOwned, Queue},
macros::{impl_id_counter, vulkan_bitflags, vulkan_bitflags_enum},
OomError, RequirementNotMet, RequiresOneOf, Version, VulkanError, VulkanObject,
};
use parking_lot::{Mutex, MutexGuard};
#[cfg(unix)]
use std::fs::File;
use std::{
error::Error,
fmt::{Display, Error as FmtError, Formatter},
mem::MaybeUninit,
num::NonZeroU64,
ptr,
sync::{Arc, Weak},
};
/// Used to provide synchronization between command buffers during their execution.
///
/// It is similar to a fence, except that it is purely on the GPU side. The CPU can't query a
/// semaphore's status or wait for it to be signaled.
#[derive(Debug)]
pub struct Semaphore {
handle: ash::vk::Semaphore,
device: Arc<Device>,
id: NonZeroU64,
must_put_in_pool: bool,
export_handle_types: ExternalSemaphoreHandleTypes,
state: Mutex<SemaphoreState>,
}
impl Semaphore {
/// Creates a new `Semaphore`.
#[inline]
pub fn new(
device: Arc<Device>,
create_info: SemaphoreCreateInfo,
) -> Result<Semaphore, SemaphoreError> {
Self::validate_new(&device, &create_info)?;
unsafe { Ok(Self::new_unchecked(device, create_info)?) }
}
fn validate_new(
device: &Device,
create_info: &SemaphoreCreateInfo,
) -> Result<(), SemaphoreError> {
let &SemaphoreCreateInfo {
export_handle_types,
_ne: _,
} = create_info;
if !export_handle_types.is_empty() {
if !(device.api_version() >= Version::V1_1
|| device.enabled_extensions().khr_external_semaphore)
{
return Err(SemaphoreError::RequirementNotMet {
required_for: "`create_info.export_handle_types` is not empty",
requires_one_of: RequiresOneOf {
api_version: Some(Version::V1_1),
device_extensions: &["khr_external_semaphore"],
..Default::default()
},
});
}
// VUID-VkExportSemaphoreCreateInfo-handleTypes-parameter
export_handle_types.validate_device(device)?;
// VUID-VkExportSemaphoreCreateInfo-handleTypes-01124
for handle_type in export_handle_types.into_iter() {
let external_semaphore_properties = unsafe {
device
.physical_device()
.external_semaphore_properties_unchecked(
ExternalSemaphoreInfo::handle_type(handle_type),
)
};
if !external_semaphore_properties.exportable {
return Err(SemaphoreError::HandleTypeNotExportable { handle_type });
}
if !external_semaphore_properties
.compatible_handle_types
.contains(export_handle_types)
{
return Err(SemaphoreError::ExportHandleTypesNotCompatible);
}
}
}
Ok(())
}
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn new_unchecked(
device: Arc<Device>,
create_info: SemaphoreCreateInfo,
) -> Result<Semaphore, VulkanError> {
let SemaphoreCreateInfo {
export_handle_types,
_ne: _,
} = create_info;
let mut create_info_vk = ash::vk::SemaphoreCreateInfo {
flags: ash::vk::SemaphoreCreateFlags::empty(),
..Default::default()
};
let mut export_semaphore_create_info_vk = None;
if !export_handle_types.is_empty() {
let _ = export_semaphore_create_info_vk.insert(ash::vk::ExportSemaphoreCreateInfo {
handle_types: export_handle_types.into(),
..Default::default()
});
};
if let Some(info) = export_semaphore_create_info_vk.as_mut() {
info.p_next = create_info_vk.p_next;
create_info_vk.p_next = info as *const _ as *const _;
}
let handle = {
let fns = device.fns();
let mut output = MaybeUninit::uninit();
(fns.v1_0.create_semaphore)(
device.handle(),
&create_info_vk,
ptr::null(),
output.as_mut_ptr(),
)
.result()
.map_err(VulkanError::from)?;
output.assume_init()
};
Ok(Semaphore {
handle,
device,
id: Self::next_id(),
must_put_in_pool: false,
export_handle_types,
state: Mutex::new(Default::default()),
})
}
/// Takes a semaphore from the vulkano-provided semaphore pool.
/// If the pool is empty, a new semaphore will be allocated.
/// Upon `drop`, the semaphore is put back into the pool.
///
/// For most applications, using the pool should be preferred,
/// in order to avoid creating new semaphores every frame.
#[inline]
pub fn from_pool(device: Arc<Device>) -> Result<Semaphore, SemaphoreError> {
let handle = device.semaphore_pool().lock().pop();
let semaphore = match handle {
Some(handle) => Semaphore {
handle,
device,
id: Self::next_id(),
must_put_in_pool: true,
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
state: Mutex::new(Default::default()),
},
None => {
// Pool is empty, alloc new semaphore
let mut semaphore = Semaphore::new(device, Default::default())?;
semaphore.must_put_in_pool = true;
semaphore
}
};
Ok(semaphore)
}
/// Creates a new `Semaphore` from a raw object handle.
///
/// # Safety
///
/// - `handle` must be a valid Vulkan object handle created from `device`.
/// - `create_info` must match the info used to create the object.
#[inline]
pub unsafe fn from_handle(
device: Arc<Device>,
handle: ash::vk::Semaphore,
create_info: SemaphoreCreateInfo,
) -> Semaphore {
let SemaphoreCreateInfo {
export_handle_types,
_ne: _,
} = create_info;
Semaphore {
handle,
device,
id: Self::next_id(),
must_put_in_pool: false,
export_handle_types,
state: Mutex::new(Default::default()),
}
}
/// Exports the semaphore into a POSIX file descriptor. The caller owns the returned `File`.
#[cfg(unix)]
#[inline]
pub fn export_fd(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<File, SemaphoreError> {
let mut state = self.state.lock();
self.validate_export_fd(handle_type, &state)?;
unsafe { Ok(self.export_fd_unchecked_locked(handle_type, &mut state)?) }
}
#[cfg(unix)]
fn validate_export_fd(
&self,
handle_type: ExternalSemaphoreHandleType,
state: &SemaphoreState,
) -> Result<(), SemaphoreError> {
if !self.device.enabled_extensions().khr_external_semaphore_fd {
return Err(SemaphoreError::RequirementNotMet {
required_for: "`Semaphore::export_fd`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_external_semaphore_fd"],
..Default::default()
},
});
}
// VUID-VkSemaphoreGetFdInfoKHR-handleType-parameter
handle_type.validate_device(&self.device)?;
// VUID-VkSemaphoreGetFdInfoKHR-handleType-01132
if !self.export_handle_types.intersects(handle_type.into()) {
return Err(SemaphoreError::HandleTypeNotEnabled);
}
// VUID-VkSemaphoreGetFdInfoKHR-semaphore-01133
if let Some(imported_handle_type) = state.current_import {
match imported_handle_type {
ImportType::SwapchainAcquire => {
return Err(SemaphoreError::ImportedForSwapchainAcquire)
}
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(SemaphoreError::ExportFromImportedNotSupported {
imported_handle_type,
});
}
}
}
}
if handle_type.has_copy_transference() {
// VUID-VkSemaphoreGetFdInfoKHR-handleType-01134
if state.is_wait_pending() {
return Err(SemaphoreError::QueueIsWaiting);
}
// VUID-VkSemaphoreGetFdInfoKHR-handleType-01135
// VUID-VkSemaphoreGetFdInfoKHR-handleType-03254
if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
return Err(SemaphoreError::HandleTypeCopyNotSignaled);
}
}
// VUID-VkSemaphoreGetFdInfoKHR-handleType-01136
if !matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd
) {
return Err(SemaphoreError::HandleTypeNotFd);
}
Ok(())
}
#[cfg(unix)]
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn export_fd_unchecked(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<File, VulkanError> {
let mut state = self.state.lock();
self.export_fd_unchecked_locked(handle_type, &mut state)
}
#[cfg(unix)]
unsafe fn export_fd_unchecked_locked(
&self,
handle_type: ExternalSemaphoreHandleType,
state: &mut SemaphoreState,
) -> Result<File, VulkanError> {
use std::os::unix::io::FromRawFd;
let info = ash::vk::SemaphoreGetFdInfoKHR {
semaphore: self.handle,
handle_type: handle_type.into(),
..Default::default()
};
let mut output = MaybeUninit::uninit();
let fns = self.device.fns();
(fns.khr_external_semaphore_fd.get_semaphore_fd_khr)(
self.device.handle(),
&info,
output.as_mut_ptr(),
)
.result()
.map_err(VulkanError::from)?;
state.export(handle_type);
Ok(File::from_raw_fd(output.assume_init()))
}
/// Exports the semaphore into a Win32 handle.
///
/// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
/// extension must be enabled on the device.
#[cfg(windows)]
#[inline]
pub fn export_win32_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<*mut std::ffi::c_void, SemaphoreError> {
let mut state = self.state.lock();
self.validate_export_win32_handle(handle_type, &state)?;
unsafe { Ok(self.export_win32_handle_unchecked_locked(handle_type, &mut state)?) }
}
#[cfg(windows)]
fn validate_export_win32_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
state: &SemaphoreState,
) -> Result<(), SemaphoreError> {
if !self
.device
.enabled_extensions()
.khr_external_semaphore_win32
{
return Err(SemaphoreError::RequirementNotMet {
required_for: "`Semaphore::export_win32_handle`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_external_semaphore_win32"],
..Default::default()
},
});
}
// VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-parameter
handle_type.validate_device(&self.device)?;
// VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01126
if !self.export_handle_types.intersects(handle_type.into()) {
return Err(SemaphoreError::HandleTypeNotEnabled);
}
// VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01127
if matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueWin32 | ExternalSemaphoreHandleType::D3D12Fence
) && state.is_exported(handle_type)
{
return Err(SemaphoreError::AlreadyExported);
}
// VUID-VkSemaphoreGetWin32HandleInfoKHR-semaphore-01128
if let Some(imported_handle_type) = state.current_import {
match imported_handle_type {
ImportType::SwapchainAcquire => {
return Err(SemaphoreError::ImportedForSwapchainAcquire)
}
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(SemaphoreError::ExportFromImportedNotSupported {
imported_handle_type,
});
}
}
}
}
if handle_type.has_copy_transference() {
// VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01129
if state.is_wait_pending() {
return Err(SemaphoreError::QueueIsWaiting);
}
// VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01130
if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
return Err(SemaphoreError::HandleTypeCopyNotSignaled);
}
}
// VUID-VkSemaphoreGetWin32HandleInfoKHR-handleType-01131
if !matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueWin32
| ExternalSemaphoreHandleType::OpaqueWin32Kmt
| ExternalSemaphoreHandleType::D3D12Fence
) {
return Err(SemaphoreError::HandleTypeNotWin32);
}
Ok(())
}
#[cfg(windows)]
#[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)
}
#[cfg(windows)]
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,
handle_type: handle_type.into(),
..Default::default()
};
let mut output = MaybeUninit::uninit();
let fns = self.device.fns();
(fns.khr_external_semaphore_win32
.get_semaphore_win32_handle_khr)(
self.device.handle(), &info_vk, output.as_mut_ptr()
)
.result()
.map_err(VulkanError::from)?;
state.export(handle_type);
Ok(output.assume_init())
}
/// Exports the semaphore into a Zircon event handle.
#[cfg(target_os = "fuchsia")]
#[inline]
pub fn export_zircon_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<ash::vk::zx_handle_t, SemaphoreError> {
let mut state = self.state.lock();
self.validate_export_zircon_handle(handle_type, &state)?;
unsafe { Ok(self.export_zircon_handle_unchecked_locked(handle_type, &mut state)?) }
}
#[cfg(target_os = "fuchsia")]
fn validate_export_zircon_handle(
&self,
handle_type: ExternalSemaphoreHandleType,
state: &SemaphoreState,
) -> Result<(), SemaphoreError> {
if !self.device.enabled_extensions().fuchsia_external_semaphore {
return Err(SemaphoreError::RequirementNotMet {
required_for: "`Semaphore::export_zircon_handle`",
requires_one_of: RequiresOneOf {
device_extensions: &["fuchsia_external_semaphore"],
..Default::default()
},
});
}
// VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-parameter
handle_type.validate_device(&self.device)?;
// VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04758
if !self.export_handle_types.intersects(&handle_type.into()) {
return Err(SemaphoreError::HandleTypeNotEnabled);
}
// VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-semaphore-04759
if let Some(imported_handle_type) = state.current_import {
match imported_handle_type {
ImportType::SwapchainAcquire => {
return Err(SemaphoreError::ImportedForSwapchainAcquire)
}
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(SemaphoreError::ExportFromImportedNotSupported {
imported_handle_type,
});
}
}
}
}
if handle_type.has_copy_transference() {
// VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04760
if state.is_wait_pending() {
return Err(SemaphoreError::QueueIsWaiting);
}
// VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04761
if !(state.is_signaled().unwrap_or(false) || state.is_signal_pending()) {
return Err(SemaphoreError::HandleTypeCopyNotSignaled);
}
}
// VUID-VkSemaphoreGetZirconHandleInfoFUCHSIA-handleType-04762
if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
return Err(SemaphoreError::HandleTypeNotZircon);
}
Ok(())
}
#[cfg(target_os = "fuchsia")]
#[cfg_attr(not(feature = "document_unchecked"), doc(hidden))]
#[inline]
pub unsafe fn export_zircon_handle_unchecked(
&self,
handle_type: ExternalSemaphoreHandleType,
) -> Result<ash::vk::zx_handle_t, VulkanError> {
let mut state = self.state.lock();
self.export_zircon_handle_unchecked_locked(handle_type, &mut state)
}
#[cfg(target_os = "fuchsia")]
unsafe fn export_zircon_handle_unchecked_locked(
&self,
handle_type: ExternalSemaphoreHandleType,
state: &mut SemaphoreState,
) -> Result<ash::vk::zx_handle_t, VulkanError> {
let info = ash::vk::SemaphoreGetZirconHandleInfoFUCHSIA {
semaphore: self.handle,
handle_type: handle_type.into(),
..Default::default()
};
let mut output = MaybeUninit::uninit();
let fns = self.device.fns();
(fns.fuchsia_external_semaphore
.get_semaphore_zircon_handle_fuchsia)(
self.device.handle(), &info, output.as_mut_ptr()
)
.result()
.map_err(VulkanError::from)?;
state.export(handle_type);
Ok(output.assume_init())
}
/// Imports a semaphore from a POSIX file descriptor.
///
/// The [`khr_external_semaphore_fd`](crate::device::DeviceExtensions::khr_external_semaphore_fd)
/// extension must be enabled on the device.
///
/// # Safety
///
/// - 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
/// `self`.
#[cfg(unix)]
#[inline]
pub unsafe fn import_fd(
&self,
import_semaphore_fd_info: ImportSemaphoreFdInfo,
) -> Result<(), SemaphoreError> {
let mut state = self.state.lock();
self.validate_import_fd(&import_semaphore_fd_info, &state)?;
Ok(self.import_fd_unchecked_locked(import_semaphore_fd_info, &mut state)?)
}
#[cfg(unix)]
fn validate_import_fd(
&self,
import_semaphore_fd_info: &ImportSemaphoreFdInfo,
state: &SemaphoreState,
) -> Result<(), SemaphoreError> {
if !self.device.enabled_extensions().khr_external_semaphore_fd {
return Err(SemaphoreError::RequirementNotMet {
required_for: "`Semaphore::import_fd`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_external_semaphore_fd"],
..Default::default()
},
});
}
// VUID-vkImportSemaphoreFdKHR-semaphore-01142
if state.is_in_queue() {
return Err(SemaphoreError::InQueue);
}
let &ImportSemaphoreFdInfo {
flags,
handle_type,
file: _,
_ne: _,
} = import_semaphore_fd_info;
// VUID-VkImportSemaphoreFdInfoKHR-flags-parameter
flags.validate_device(&self.device)?;
// VUID-VkImportSemaphoreFdInfoKHR-handleType-parameter
handle_type.validate_device(&self.device)?;
// VUID-VkImportSemaphoreFdInfoKHR-handleType-01143
if !matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueFd | ExternalSemaphoreHandleType::SyncFd
) {
return Err(SemaphoreError::HandleTypeNotFd);
}
// VUID-VkImportSemaphoreFdInfoKHR-fd-01544
// VUID-VkImportSemaphoreFdInfoKHR-handleType-03263
// Can't validate, therefore unsafe
// VUID-VkImportSemaphoreFdInfoKHR-handleType-07307
if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
{
return Err(SemaphoreError::HandletypeCopyNotTemporary);
}
Ok(())
}
#[cfg(unix)]
#[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)
}
#[cfg(unix)]
unsafe fn import_fd_unchecked_locked(
&self,
import_semaphore_fd_info: ImportSemaphoreFdInfo,
state: &mut SemaphoreState,
) -> Result<(), VulkanError> {
use std::os::unix::io::IntoRawFd;
let ImportSemaphoreFdInfo {
flags,
handle_type,
file,
_ne: _,
} = import_semaphore_fd_info;
let info_vk = ash::vk::ImportSemaphoreFdInfoKHR {
semaphore: self.handle,
flags: flags.into(),
handle_type: handle_type.into(),
fd: file.map_or(-1, |file| file.into_raw_fd()),
..Default::default()
};
let fns = self.device.fns();
(fns.khr_external_semaphore_fd.import_semaphore_fd_khr)(self.device.handle(), &info_vk)
.result()
.map_err(VulkanError::from)?;
state.import(
handle_type,
flags.intersects(SemaphoreImportFlags::TEMPORARY),
);
Ok(())
}
/// Imports a semaphore from a Win32 handle.
///
/// The [`khr_external_semaphore_win32`](crate::device::DeviceExtensions::khr_external_semaphore_win32)
/// extension must be enabled on the device.
///
/// # Safety
///
/// - 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`.
#[cfg(windows)]
#[inline]
pub unsafe fn import_win32_handle(
&self,
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
) -> Result<(), SemaphoreError> {
let mut state = self.state.lock();
self.validate_import_win32_handle(&import_semaphore_win32_handle_info, &state)?;
Ok(self
.import_win32_handle_unchecked_locked(import_semaphore_win32_handle_info, &mut state)?)
}
#[cfg(windows)]
fn validate_import_win32_handle(
&self,
import_semaphore_win32_handle_info: &ImportSemaphoreWin32HandleInfo,
state: &SemaphoreState,
) -> Result<(), SemaphoreError> {
if !self
.device
.enabled_extensions()
.khr_external_semaphore_win32
{
return Err(SemaphoreError::RequirementNotMet {
required_for: "`Semaphore::import_win32_handle`",
requires_one_of: RequiresOneOf {
device_extensions: &["khr_external_semaphore_win32"],
..Default::default()
},
});
}
// VUID?
if state.is_in_queue() {
return Err(SemaphoreError::InQueue);
}
let &ImportSemaphoreWin32HandleInfo {
flags,
handle_type,
handle: _,
_ne: _,
} = import_semaphore_win32_handle_info;
// VUID-VkImportSemaphoreWin32HandleInfoKHR-flags-parameter
flags.validate_device(&self.device)?;
// VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140
handle_type.validate_device(&self.device)?;
// VUID-VkImportSemaphoreWin32HandleInfoKHR-handleType-01140
if !matches!(
handle_type,
ExternalSemaphoreHandleType::OpaqueWin32
| ExternalSemaphoreHandleType::OpaqueWin32Kmt
| ExternalSemaphoreHandleType::D3D12Fence
) {
return Err(SemaphoreError::HandleTypeNotWin32);
}
// VUID-VkImportSemaphoreWin32HandleInfoKHR-handle-01542
// Can't validate, therefore unsafe
// VUID?
if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
{
return Err(SemaphoreError::HandletypeCopyNotTemporary);
}
Ok(())
}
#[cfg(windows)]
#[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)
}
#[cfg(windows)]
unsafe fn import_win32_handle_unchecked_locked(
&self,
import_semaphore_win32_handle_info: ImportSemaphoreWin32HandleInfo,
state: &mut SemaphoreState,
) -> Result<(), VulkanError> {
let ImportSemaphoreWin32HandleInfo {
flags,
handle_type,
handle,
_ne: _,
} = import_semaphore_win32_handle_info;
let info_vk = ash::vk::ImportSemaphoreWin32HandleInfoKHR {
semaphore: self.handle,
flags: flags.into(),
handle_type: handle_type.into(),
handle,
name: ptr::null(), // TODO: support?
..Default::default()
};
let fns = self.device.fns();
(fns.khr_external_semaphore_win32
.import_semaphore_win32_handle_khr)(self.device.handle(), &info_vk)
.result()
.map_err(VulkanError::from)?;
state.import(
handle_type,
flags.intersects(SemaphoreImportFlags::TEMPORARY),
);
Ok(())
}
/// Imports a semaphore from a Zircon event handle.
///
/// The [`fuchsia_external_semaphore`](crate::device::DeviceExtensions::fuchsia_external_semaphore)
/// extension must be enabled on the device.
///
/// # Safety
///
/// - In `import_semaphore_zircon_handle_info`, `zircon_handle` must have `ZX_RIGHTS_BASIC` and
/// `ZX_RIGHTS_SIGNAL`.
#[cfg(target_os = "fuchsia")]
#[inline]
pub unsafe fn import_zircon_handle(
&self,
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
) -> Result<(), SemaphoreError> {
let mut state = self.state.lock();
self.validate_import_zircon_handle(&import_semaphore_zircon_handle_info, &state)?;
Ok(self.import_zircon_handle_unchecked_locked(
import_semaphore_zircon_handle_info,
&mut state,
)?)
}
#[cfg(target_os = "fuchsia")]
fn validate_import_zircon_handle(
&self,
import_semaphore_zircon_handle_info: &ImportSemaphoreZirconHandleInfo,
state: &SemaphoreState,
) -> Result<(), SemaphoreError> {
if !self.device.enabled_extensions().fuchsia_external_semaphore {
return Err(SemaphoreError::RequirementNotMet {
required_for: "`Semaphore::import_zircon_handle`",
requires_one_of: RequiresOneOf {
device_extensions: &["fuchsia_external_semaphore"],
..Default::default()
},
});
}
// VUID-vkImportSemaphoreZirconHandleFUCHSIA-semaphore-04764
if state.is_in_queue() {
return Err(SemaphoreError::InQueue);
}
let &ImportSemaphoreZirconHandleInfo {
flags,
handle_type,
zircon_handle: _,
_ne: _,
} = import_semaphore_zircon_handle_info;
// VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-flags-parameter
flags.validate_device(&self.device)?;
// VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-parameter
handle_type.validate_device(&self.device)?;
// VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-handleType-04765
if !matches!(handle_type, ExternalSemaphoreHandleType::ZirconEvent) {
return Err(SemaphoreError::HandleTypeNotFd);
}
// VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04766
// VUID-VkImportSemaphoreZirconHandleInfoFUCHSIA-zirconHandle-04767
// Can't validate, therefore unsafe
if handle_type.has_copy_transference() && !flags.intersects(SemaphoreImportFlags::TEMPORARY)
{
return Err(SemaphoreError::HandletypeCopyNotTemporary);
}
Ok(())
}
#[cfg(target_os = "fuchsia")]
#[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)
}
#[cfg(target_os = "fuchsia")]
unsafe fn import_zircon_handle_unchecked_locked(
&self,
import_semaphore_zircon_handle_info: ImportSemaphoreZirconHandleInfo,
state: &mut SemaphoreState,
) -> Result<(), VulkanError> {
let ImportSemaphoreZirconHandleInfo {
flags,
handle_type,
zircon_handle,
_ne: _,
} = import_semaphore_zircon_handle_info;
let info_vk = ash::vk::ImportSemaphoreZirconHandleInfoFUCHSIA {
semaphore: self.handle,
flags: flags.into(),
handle_type: handle_type.into(),
zircon_handle,
..Default::default()
};
let fns = self.device.fns();
(fns.fuchsia_external_semaphore
.import_semaphore_zircon_handle_fuchsia)(self.device.handle(), &info_vk)
.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 {
#[inline]
fn drop(&mut self) {
unsafe {
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();
(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(Debug, Default)]
pub(crate) struct SemaphoreState {
is_signaled: bool,
pending_signal: Option<SignalType>,
pending_wait: Option<Weak<Queue>>,
reference_exported: bool,
exported_handle_types: ExternalSemaphoreHandleTypes,
current_import: Option<ImportType>,
permanent_import: Option<ExternalSemaphoreHandleType>,
}
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<bool> {
// 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<Queue>) {
self.pending_signal = Some(SignalType::Queue(Arc::downgrade(queue)));
}
#[inline]
pub(crate) unsafe fn add_queue_wait(&mut self, queue: &Arc<Queue>) {
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<Queue>),
SwapchainAcquire,
}
#[derive(Clone, Copy, Debug)]
enum ImportType {
SwapchainAcquire,
ExternalSemaphore(ExternalSemaphoreHandleType),
}
impl From<ExternalSemaphoreHandleType> for ImportType {
#[inline]
fn from(handle_type: ExternalSemaphoreHandleType) -> Self {
Self::ExternalSemaphore(handle_type)
}
}
/// Parameters to create a new `Semaphore`.
#[derive(Clone, Debug)]
pub struct SemaphoreCreateInfo {
/// The handle types that can be exported from the semaphore.
///
/// The default value is [`ExternalSemaphoreHandleTypes::empty()`].
pub export_handle_types: ExternalSemaphoreHandleTypes,
pub _ne: crate::NonExhaustive,
}
impl Default for SemaphoreCreateInfo {
#[inline]
fn default() -> Self {
Self {
export_handle_types: ExternalSemaphoreHandleTypes::empty(),
_ne: crate::NonExhaustive(()),
}
}
}
vulkan_bitflags_enum! {
#[non_exhaustive]
/// A set of [`ExternalSemaphoreHandleType`] values.
ExternalSemaphoreHandleTypes,
/// The handle type used to export or import semaphores to/from an external source.
ExternalSemaphoreHandleType impl {
/// Returns whether the given handle type has *copy transference* rather than *reference
/// transference*.
///
/// Imports of handles with copy transference must always be temporary. Exports of such
/// handles must only occur if no queue is waiting on the semaphore, and only if the semaphore
/// is already signaled, or if there is a semaphore signal operation pending in a queue.
#[inline]
pub fn has_copy_transference(self) -> bool {
// As defined by
// https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-win32
// https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-fd
// https://registry.khronos.org/vulkan/specs/1.3-extensions/html/chap7.html#synchronization-semaphore-handletypes-fuchsia
matches!(self, Self::SyncFd)
}
},
= ExternalSemaphoreHandleTypeFlags(u32);
/// A POSIX file descriptor handle that is only usable with Vulkan and compatible APIs.
///
/// This handle type has *reference transference*.
OPAQUE_FD, OpaqueFd = OPAQUE_FD,
/// A Windows NT handle that is only usable with Vulkan and compatible APIs.
///
/// This handle type has *reference transference*.
OPAQUE_WIN32, OpaqueWin32 = OPAQUE_WIN32,
/// A Windows global share handle that is only usable with Vulkan and compatible APIs.
///
/// This handle type has *reference transference*.
OPAQUE_WIN32_KMT, OpaqueWin32Kmt = OPAQUE_WIN32_KMT,
/// A Windows NT handle that refers to a Direct3D 11 or 12 fence.
///
/// This handle type has *reference transference*.
D3D12_FENCE, D3D12Fence = D3D12_FENCE,
/// A POSIX file descriptor handle to a Linux Sync File or Android Fence object.
///
/// This handle type has *copy transference*.
SYNC_FD, SyncFd = SYNC_FD,
/// A handle to a Zircon event object.
///
/// This handle type has *reference transference*.
///
/// The [`fuchsia_external_semaphore`] extension must be enabled on the device.
///
/// [`fuchsia_external_semaphore`]: crate::device::DeviceExtensions::fuchsia_external_semaphore
ZIRCON_EVENT, ZirconEvent = ZIRCON_EVENT_FUCHSIA {
device_extensions: [fuchsia_external_semaphore],
},
}
vulkan_bitflags! {
#[non_exhaustive]
/// Additional parameters for a semaphore payload import.
SemaphoreImportFlags = SemaphoreImportFlags(u32);
/// The semaphore payload will be imported only temporarily, regardless of the permanence of the
/// imported handle type.
TEMPORARY = TEMPORARY,
}
#[cfg(unix)]
#[derive(Debug)]
pub struct ImportSemaphoreFdInfo {
/// Additional parameters for the import operation.
///
/// If `handle_type` has *copy transference*, this must include the `temporary` flag.
///
/// The default value is [`SemaphoreImportFlags::empty()`].
pub flags: SemaphoreImportFlags,
/// The handle type of `file`.
///
/// There is no default value.
pub handle_type: ExternalSemaphoreHandleType,
/// The file to import the semaphore from.
///
/// If `handle_type` is `ExternalSemaphoreHandleType::SyncFd`, then `file` can be `None`.
/// Instead of an imported file descriptor, a dummy file descriptor `-1` is used,
/// which represents a semaphore that is always signaled.
///
/// The default value is `None`, which must be overridden if `handle_type` is not
/// `ExternalSemaphoreHandleType::SyncFd`.
pub file: Option<File>,
pub _ne: crate::NonExhaustive,
}
#[cfg(unix)]
impl ImportSemaphoreFdInfo {
/// Returns an `ImportSemaphoreFdInfo` with the specified `handle_type`.
#[inline]
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
Self {
flags: SemaphoreImportFlags::empty(),
handle_type,
file: None,
_ne: crate::NonExhaustive(()),
}
}
}
#[cfg(windows)]
#[derive(Debug)]
pub struct ImportSemaphoreWin32HandleInfo {
/// Additional parameters for the import operation.
///
/// If `handle_type` has *copy transference*, this must include the `temporary` flag.
///
/// The default value is [`SemaphoreImportFlags::empty()`].
pub flags: SemaphoreImportFlags,
/// The handle type of `handle`.
///
/// There is no default value.
pub handle_type: ExternalSemaphoreHandleType,
/// The handle to import the semaphore from.
///
/// The default value is `null`, which must be overridden.
pub handle: *mut std::ffi::c_void,
pub _ne: crate::NonExhaustive,
}
#[cfg(windows)]
impl ImportSemaphoreWin32HandleInfo {
/// Returns an `ImportSemaphoreWin32HandleInfo` with the specified `handle_type`.
#[inline]
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
Self {
flags: SemaphoreImportFlags::empty(),
handle_type,
handle: ptr::null_mut(),
_ne: crate::NonExhaustive(()),
}
}
}
#[cfg(target_os = "fuchsia")]
#[derive(Debug)]
pub struct ImportSemaphoreZirconHandleInfo {
/// Additional parameters for the import operation.
///
/// If `handle_type` has *copy transference*, this must include the `temporary` flag.
///
/// The default value is [`SemaphoreImportFlags::empty()`].
pub flags: SemaphoreImportFlags,
/// The handle type of `handle`.
///
/// There is no default value.
pub handle_type: ExternalSemaphoreHandleType,
/// The handle to import the semaphore from.
///
/// The default value is `ZX_HANDLE_INVALID`, which must be overridden.
pub zircon_handle: ash::vk::zx_handle_t,
pub _ne: crate::NonExhaustive,
}
#[cfg(target_os = "fuchsia")]
impl ImportSemaphoreZirconHandleInfo {
/// Returns an `ImportSemaphoreZirconHandleInfo` with the specified `handle_type`.
#[inline]
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
Self {
flags: SemaphoreImportFlags::empty(),
handle_type,
zircon_handle: 0,
_ne: crate::NonExhaustive(()),
}
}
}
/// The semaphore configuration to query in
/// [`PhysicalDevice::external_semaphore_properties`](crate::device::physical::PhysicalDevice::external_semaphore_properties).
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ExternalSemaphoreInfo {
/// The external handle type that will be used with the semaphore.
pub handle_type: ExternalSemaphoreHandleType,
pub _ne: crate::NonExhaustive,
}
impl ExternalSemaphoreInfo {
/// Returns an `ExternalSemaphoreInfo` with the specified `handle_type`.
#[inline]
pub fn handle_type(handle_type: ExternalSemaphoreHandleType) -> Self {
Self {
handle_type,
_ne: crate::NonExhaustive(()),
}
}
}
/// The properties for exporting or importing external handles, when a semaphore is created
/// with a specific configuration.
#[derive(Clone, Debug)]
#[non_exhaustive]
pub struct ExternalSemaphoreProperties {
/// Whether a handle can be exported to an external source with the queried
/// external handle type.
pub exportable: bool,
/// Whether a handle can be imported from an external source with the queried
/// external handle type.
pub importable: bool,
/// Which external handle types can be re-exported after the queried external handle type has
/// been imported.
pub export_from_imported_handle_types: ExternalSemaphoreHandleTypes,
/// Which external handle types can be enabled along with the queried external handle type
/// when creating the semaphore.
pub compatible_handle_types: ExternalSemaphoreHandleTypes,
}
/// Error that can be returned from operations on a semaphore.
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum SemaphoreError {
/// Not enough memory available.
OomError(OomError),
RequirementNotMet {
required_for: &'static str,
requires_one_of: RequiresOneOf,
},
/// The provided handle type does not permit more than one export,
/// and a handle of this type was already exported previously.
AlreadyExported,
/// The provided handle type cannot be exported from the current import handle type.
ExportFromImportedNotSupported {
imported_handle_type: ExternalSemaphoreHandleType,
},
/// One of the export handle types is not compatible with the other provided handles.
ExportHandleTypesNotCompatible,
/// A handle type with copy transference was provided, but the semaphore is not signaled and
/// there is no pending queue operation that will signal it.
HandleTypeCopyNotSignaled,
/// A handle type with copy transference was provided,
/// but the `temporary` import flag was not set.
HandletypeCopyNotTemporary,
/// The provided export handle type was not set in `export_handle_types` when creating the
/// semaphore.
HandleTypeNotEnabled,
/// Exporting is not supported for the provided handle type.
HandleTypeNotExportable {
handle_type: ExternalSemaphoreHandleType,
},
/// The provided handle type is not a POSIX file descriptor handle.
HandleTypeNotFd,
/// The provided handle type is not a Win32 handle.
HandleTypeNotWin32,
/// The provided handle type is not a Zircon event handle.
HandleTypeNotZircon,
/// The semaphore currently has a temporary import for a swapchain acquire operation.
ImportedForSwapchainAcquire,
/// The semaphore is currently in use by a queue.
InQueue,
/// A queue is currently waiting on the semaphore.
QueueIsWaiting,
}
impl Error for SemaphoreError {
fn source(&self) -> Option<&(dyn Error + 'static)> {
match self {
Self::OomError(err) => Some(err),
_ => None,
}
}
}
impl Display for SemaphoreError {
fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), FmtError> {
match self {
Self::OomError(_) => write!(f, "not enough memory available"),
Self::RequirementNotMet {
required_for,
requires_one_of,
} => write!(
f,
"a requirement was not met for: {}; requires one of: {}",
required_for, requires_one_of,
),
Self::AlreadyExported => write!(
f,
"the provided handle type does not permit more than one export, and a handle of \
this type was already exported previously",
),
Self::ExportFromImportedNotSupported {
imported_handle_type,
} => write!(
f,
"the provided handle type cannot be exported from the current imported handle type \
{:?}",
imported_handle_type,
),
Self::ExportHandleTypesNotCompatible => write!(
f,
"one of the export handle types is not compatible with the other provided handles",
),
Self::HandleTypeCopyNotSignaled => write!(
f,
"a handle type with copy transference was provided, but the semaphore is not \
signaled and there is no pending queue operation that will signal it",
),
Self::HandletypeCopyNotTemporary => write!(
f,
"a handle type with copy transference was provided, but the `temporary` \
import flag was not set",
),
Self::HandleTypeNotEnabled => write!(
f,
"the provided export handle type was not set in `export_handle_types` when \
creating the semaphore",
),
Self::HandleTypeNotExportable { handle_type } => write!(
f,
"exporting is not supported for handles of type {:?}",
handle_type,
),
Self::HandleTypeNotFd => write!(
f,
"the provided handle type is not a POSIX file descriptor handle",
),
Self::HandleTypeNotWin32 => {
write!(f, "the provided handle type is not a Win32 handle")
}
Self::HandleTypeNotZircon => {
write!(f, "the provided handle type is not a Zircon event handle")
}
Self::ImportedForSwapchainAcquire => write!(
f,
"the semaphore currently has a temporary import for a swapchain acquire operation",
),
Self::InQueue => write!(f, "the semaphore is currently in use by a queue"),
Self::QueueIsWaiting => write!(f, "a queue is currently waiting on the semaphore"),
}
}
}
impl From<VulkanError> for SemaphoreError {
fn from(err: VulkanError) -> Self {
match err {
e @ VulkanError::OutOfHostMemory | e @ VulkanError::OutOfDeviceMemory => {
Self::OomError(e.into())
}
_ => panic!("unexpected error: {:?}", err),
}
}
}
impl From<OomError> for SemaphoreError {
fn from(err: OomError) -> Self {
Self::OomError(err)
}
}
impl From<RequirementNotMet> for SemaphoreError {
fn from(err: RequirementNotMet) -> Self {
Self::RequirementNotMet {
required_for: err.required_for,
requires_one_of: err.requires_one_of,
}
}
}
#[cfg(test)]
mod tests {
#[cfg(unix)]
use crate::{
device::{Device, DeviceCreateInfo, DeviceExtensions, QueueCreateInfo},
instance::{Instance, InstanceCreateInfo, InstanceExtensions},
sync::semaphore::{
ExternalSemaphoreHandleType, ExternalSemaphoreHandleTypes, SemaphoreCreateInfo,
},
VulkanLibrary,
};
use crate::{sync::semaphore::Semaphore, 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]
#[cfg(unix)]
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 {
enabled_extensions: DeviceExtensions {
khr_external_semaphore: true,
khr_external_semaphore_fd: true,
..DeviceExtensions::empty()
},
queue_create_infos: vec![QueueCreateInfo {
queue_family_index: 0,
..Default::default()
}],
..Default::default()
},
) {
Ok(x) => x,
Err(_) => return,
};
let sem = Semaphore::new(
device,
SemaphoreCreateInfo {
export_handle_types: ExternalSemaphoreHandleTypes::OPAQUE_FD,
..Default::default()
},
)
.unwrap();
let _fd = sem
.export_fd(ExternalSemaphoreHandleType::OpaqueFd)
.unwrap();
}
}