mirror of
https://github.com/vulkano-rs/vulkano.git
synced 2024-11-22 23:05:43 +00:00
Add support for semaphore file descriptor export (#1606)
* Add external semaphore device extensions & function * Add semaphore export functionality * Fix test failing due to missing extensions * Add semaphore module * Add builder pattern for semaphore * Add check for supported extensions before running test * Add missing file * Fix use with super instead of crate * Fix pool semaphore built incorrectly; Fix semaphore types export * Add pool parameter as semaphore builder function * Fix test not checking instance extensions
This commit is contained in:
parent
e3e210f968
commit
698d457235
@ -36,6 +36,7 @@ use crate::swapchain::PresentRegion;
|
||||
use crate::swapchain::Surface;
|
||||
use crate::swapchain::SurfaceSwapchainLock;
|
||||
use crate::swapchain::SurfaceTransform;
|
||||
use crate::sync::semaphore::SemaphoreError;
|
||||
use crate::sync::AccessCheckError;
|
||||
use crate::sync::AccessError;
|
||||
use crate::sync::AccessFlags;
|
||||
@ -1369,6 +1370,9 @@ pub enum AcquireError {
|
||||
/// The surface has changed in a way that makes the swapchain unusable. You must query the
|
||||
/// surface's new properties and recreate a new swapchain if you want to continue drawing.
|
||||
OutOfDate,
|
||||
|
||||
/// Error during semaphore creation
|
||||
SemaphoreError(SemaphoreError),
|
||||
}
|
||||
|
||||
impl error::Error for AcquireError {
|
||||
@ -1396,11 +1400,18 @@ impl fmt::Display for AcquireError {
|
||||
AcquireError::FullscreenExclusiveLost => {
|
||||
"the swapchain no longer has fullscreen exclusivity"
|
||||
}
|
||||
AcquireError::SemaphoreError(_) => "error creating semaphore",
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SemaphoreError> for AcquireError {
|
||||
fn from(err: SemaphoreError) -> Self {
|
||||
AcquireError::SemaphoreError(err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OomError> for AcquireError {
|
||||
#[inline]
|
||||
fn from(err: OomError) -> AcquireError {
|
||||
|
@ -122,13 +122,15 @@ pub use self::pipeline::AccessFlags;
|
||||
pub use self::pipeline::PipelineMemoryAccess;
|
||||
pub use self::pipeline::PipelineStage;
|
||||
pub use self::pipeline::PipelineStages;
|
||||
pub use self::semaphore::ExternalSemaphoreHandleType;
|
||||
pub use self::semaphore::Semaphore;
|
||||
pub use self::semaphore::SemaphoreError;
|
||||
|
||||
mod event;
|
||||
mod fence;
|
||||
mod future;
|
||||
mod pipeline;
|
||||
mod semaphore;
|
||||
pub(crate) mod semaphore;
|
||||
|
||||
/// Declares in which queue(s) a resource can be used.
|
||||
///
|
||||
|
@ -1,160 +0,0 @@
|
||||
// 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.
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::OomError;
|
||||
use crate::SafeDeref;
|
||||
use crate::VulkanObject;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// 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<D = Arc<Device>>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
semaphore: ash::vk::Semaphore,
|
||||
device: D,
|
||||
must_put_in_pool: bool,
|
||||
}
|
||||
|
||||
impl<D> Semaphore<D>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
/// 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.
|
||||
pub fn from_pool(device: D) -> Result<Semaphore<D>, OomError> {
|
||||
let maybe_raw_sem = device.semaphore_pool().lock().unwrap().pop();
|
||||
match maybe_raw_sem {
|
||||
Some(raw_sem) => Ok(Semaphore {
|
||||
device: device,
|
||||
semaphore: raw_sem,
|
||||
must_put_in_pool: true,
|
||||
}),
|
||||
None => {
|
||||
// Pool is empty, alloc new semaphore
|
||||
Semaphore::alloc_impl(device, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a new semaphore.
|
||||
#[inline]
|
||||
pub fn alloc(device: D) -> Result<Semaphore<D>, OomError> {
|
||||
Semaphore::alloc_impl(device, false)
|
||||
}
|
||||
|
||||
fn alloc_impl(device: D, must_put_in_pool: bool) -> Result<Semaphore<D>, OomError> {
|
||||
let semaphore = unsafe {
|
||||
// since the creation is constant, we use a `static` instead of a struct on the stack
|
||||
let infos = ash::vk::SemaphoreCreateInfo {
|
||||
flags: ash::vk::SemaphoreCreateFlags::empty(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let fns = device.fns();
|
||||
let mut output = MaybeUninit::uninit();
|
||||
check_errors(fns.v1_0.create_semaphore(
|
||||
device.internal_object(),
|
||||
&infos,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
))?;
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
Ok(Semaphore {
|
||||
device: device,
|
||||
semaphore: semaphore,
|
||||
must_put_in_pool: must_put_in_pool,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for Semaphore {
|
||||
#[inline]
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<D> VulkanObject for Semaphore<D>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
type Object = ash::vk::Semaphore;
|
||||
|
||||
#[inline]
|
||||
fn internal_object(&self) -> ash::vk::Semaphore {
|
||||
self.semaphore
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> Drop for Semaphore<D>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.must_put_in_pool {
|
||||
let raw_sem = self.semaphore;
|
||||
self.device.semaphore_pool().lock().unwrap().push(raw_sem);
|
||||
} else {
|
||||
let fns = self.device.fns();
|
||||
fns.v1_0.destroy_semaphore(
|
||||
self.device.internal_object(),
|
||||
self.semaphore,
|
||||
ptr::null(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::sync::Semaphore;
|
||||
use crate::VulkanObject;
|
||||
|
||||
#[test]
|
||||
fn semaphore_create() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
let _ = Semaphore::alloc(device.clone());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn semaphore_pool() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
|
||||
let sem1_internal_obj = {
|
||||
let sem = Semaphore::from_pool(device.clone()).unwrap();
|
||||
assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
|
||||
sem.internal_object()
|
||||
};
|
||||
|
||||
assert_eq!(device.semaphore_pool().lock().unwrap().len(), 1);
|
||||
let sem2 = Semaphore::from_pool(device.clone()).unwrap();
|
||||
assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
|
||||
assert_eq!(sem2.internal_object(), sem1_internal_obj);
|
||||
}
|
||||
}
|
101
vulkano/src/sync/semaphore/external_semaphore_handle_type.rs
Normal file
101
vulkano/src/sync/semaphore/external_semaphore_handle_type.rs
Normal file
@ -0,0 +1,101 @@
|
||||
// Copyright (c) 2021 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.
|
||||
|
||||
use std::ops::BitOr;
|
||||
|
||||
/// Describes the handle type used for Vulkan external semaphore APIs. This is **not**
|
||||
/// just a suggestion. Check out VkExternalSemaphoreHandleTypeFlagBits in the Vulkan
|
||||
/// spec.
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct ExternalSemaphoreHandleType {
|
||||
pub opaque_fd: bool,
|
||||
pub opaque_win32: bool,
|
||||
pub opaque_win32_kmt: bool,
|
||||
pub d3d12_fence: bool,
|
||||
pub sync_fd: bool,
|
||||
}
|
||||
|
||||
impl ExternalSemaphoreHandleType {
|
||||
/// Builds a `ExternalSemaphoreHandleType` with all values set to false. Useful as a default value.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use vulkano::sync::ExternalSemaphoreHandleType as ExternalSemaphoreHandleType;
|
||||
///
|
||||
/// let _handle_type = ExternalSemaphoreHandleType {
|
||||
/// opaque_fd: true,
|
||||
/// .. ExternalSemaphoreHandleType::none()
|
||||
/// };
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn none() -> ExternalSemaphoreHandleType {
|
||||
ExternalSemaphoreHandleType {
|
||||
opaque_fd: false,
|
||||
opaque_win32: false,
|
||||
opaque_win32_kmt: false,
|
||||
d3d12_fence: false,
|
||||
sync_fd: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds an `ExternalSemaphoreHandleType` for a posix file descriptor.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```rust
|
||||
/// use vulkano::sync::ExternalSemaphoreHandleType as ExternalSemaphoreHandleType;
|
||||
///
|
||||
/// let _handle_type = ExternalSemaphoreHandleType::posix();
|
||||
/// ```
|
||||
#[inline]
|
||||
pub fn posix() -> ExternalSemaphoreHandleType {
|
||||
ExternalSemaphoreHandleType {
|
||||
opaque_fd: true,
|
||||
..ExternalSemaphoreHandleType::none()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ExternalSemaphoreHandleType> for ash::vk::ExternalSemaphoreHandleTypeFlags {
|
||||
#[inline]
|
||||
fn from(val: ExternalSemaphoreHandleType) -> Self {
|
||||
let mut result = ash::vk::ExternalSemaphoreHandleTypeFlags::empty();
|
||||
if val.opaque_fd {
|
||||
result |= ash::vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_FD;
|
||||
}
|
||||
if val.opaque_win32 {
|
||||
result |= ash::vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_WIN32;
|
||||
}
|
||||
if val.opaque_win32_kmt {
|
||||
result |= ash::vk::ExternalSemaphoreHandleTypeFlags::OPAQUE_WIN32_KMT;
|
||||
}
|
||||
if val.d3d12_fence {
|
||||
result |= ash::vk::ExternalSemaphoreHandleTypeFlags::D3D12_FENCE;
|
||||
}
|
||||
if val.sync_fd {
|
||||
result |= ash::vk::ExternalSemaphoreHandleTypeFlags::SYNC_FD;
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
impl BitOr for ExternalSemaphoreHandleType {
|
||||
type Output = Self;
|
||||
|
||||
fn bitor(self, rhs: Self) -> Self {
|
||||
ExternalSemaphoreHandleType {
|
||||
opaque_fd: self.opaque_fd || rhs.opaque_fd,
|
||||
opaque_win32: self.opaque_win32 || rhs.opaque_win32,
|
||||
opaque_win32_kmt: self.opaque_win32_kmt || rhs.opaque_win32_kmt,
|
||||
d3d12_fence: self.d3d12_fence || rhs.d3d12_fence,
|
||||
sync_fd: self.sync_fd || rhs.sync_fd,
|
||||
}
|
||||
}
|
||||
}
|
15
vulkano/src/sync/semaphore/mod.rs
Normal file
15
vulkano/src/sync/semaphore/mod.rs
Normal file
@ -0,0 +1,15 @@
|
||||
// Copyright (c) 2021 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.
|
||||
|
||||
pub use self::external_semaphore_handle_type::ExternalSemaphoreHandleType;
|
||||
pub use self::semaphore::Semaphore;
|
||||
pub use self::semaphore::SemaphoreError;
|
||||
|
||||
mod external_semaphore_handle_type;
|
||||
mod semaphore;
|
355
vulkano/src/sync/semaphore/semaphore.rs
Normal file
355
vulkano/src/sync/semaphore/semaphore.rs
Normal file
@ -0,0 +1,355 @@
|
||||
// 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.
|
||||
|
||||
use crate::check_errors;
|
||||
use crate::device::Device;
|
||||
use crate::device::DeviceOwned;
|
||||
use crate::Error;
|
||||
use crate::OomError;
|
||||
use crate::SafeDeref;
|
||||
use crate::VulkanObject;
|
||||
use std::fmt;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::fs::File;
|
||||
use std::mem::MaybeUninit;
|
||||
#[cfg(target_os = "linux")]
|
||||
use std::os::unix::io::FromRawFd;
|
||||
use std::ptr;
|
||||
use std::sync::Arc;
|
||||
|
||||
use crate::sync::semaphore::ExternalSemaphoreHandleType;
|
||||
|
||||
/// 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<D = Arc<Device>>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
semaphore: ash::vk::Semaphore,
|
||||
device: D,
|
||||
must_put_in_pool: bool,
|
||||
}
|
||||
|
||||
// TODO: Add support for VkExportSemaphoreWin32HandleInfoKHR
|
||||
// TODO: Add suport for importable semaphores
|
||||
pub struct SemaphoreBuilder<D = Arc<Device>>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
device: D,
|
||||
export_info: Option<ash::vk::ExportSemaphoreCreateInfo>,
|
||||
create: ash::vk::SemaphoreCreateInfo,
|
||||
must_put_in_pool: bool,
|
||||
}
|
||||
|
||||
impl<D> SemaphoreBuilder<D>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
pub fn new(device: D) -> Self {
|
||||
let create = ash::vk::SemaphoreCreateInfo::default();
|
||||
|
||||
Self {
|
||||
device,
|
||||
export_info: None,
|
||||
create,
|
||||
must_put_in_pool: false,
|
||||
}
|
||||
}
|
||||
/// Configures the semaphore to be added to the semaphore pool once it is destroyed.
|
||||
pub(crate) fn in_pool(mut self) -> Self {
|
||||
self.must_put_in_pool = true;
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets an optional field for exportable allocations in the `SemaphoreBuilder`.
|
||||
///
|
||||
/// # Panic
|
||||
///
|
||||
/// - Panics if the export info has already been set.
|
||||
pub fn export_info(mut self, handle_types: ExternalSemaphoreHandleType) -> Self {
|
||||
assert!(self.export_info.is_none());
|
||||
let export_info = ash::vk::ExportSemaphoreCreateInfo {
|
||||
handle_types: handle_types.into(),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
self.export_info = Some(export_info);
|
||||
self.create.p_next = unsafe { std::mem::transmute(&export_info) };
|
||||
|
||||
self
|
||||
}
|
||||
|
||||
pub fn build(self) -> Result<Semaphore<D>, SemaphoreError> {
|
||||
if self.export_info.is_some()
|
||||
&& !self
|
||||
.device
|
||||
.instance()
|
||||
.loaded_extensions()
|
||||
.khr_external_semaphore_capabilities
|
||||
{
|
||||
Err(SemaphoreError::MissingExtension(
|
||||
"khr_external_semaphore_capabilities",
|
||||
))
|
||||
} else {
|
||||
let semaphore = unsafe {
|
||||
let fns = self.device.fns();
|
||||
let mut output = MaybeUninit::uninit();
|
||||
check_errors(fns.v1_0.create_semaphore(
|
||||
self.device.internal_object(),
|
||||
&self.create,
|
||||
ptr::null(),
|
||||
output.as_mut_ptr(),
|
||||
))?;
|
||||
output.assume_init()
|
||||
};
|
||||
|
||||
Ok(Semaphore {
|
||||
device: self.device,
|
||||
semaphore,
|
||||
must_put_in_pool: self.must_put_in_pool,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> Semaphore<D>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
/// 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.
|
||||
pub fn from_pool(device: D) -> Result<Semaphore<D>, SemaphoreError> {
|
||||
let maybe_raw_sem = device.semaphore_pool().lock().unwrap().pop();
|
||||
match maybe_raw_sem {
|
||||
Some(raw_sem) => Ok(Semaphore {
|
||||
device,
|
||||
semaphore: raw_sem,
|
||||
must_put_in_pool: true,
|
||||
}),
|
||||
None => {
|
||||
// Pool is empty, alloc new semaphore
|
||||
SemaphoreBuilder::new(device).in_pool().build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Builds a new semaphore.
|
||||
#[inline]
|
||||
pub fn alloc(device: D) -> Result<Semaphore<D>, SemaphoreError> {
|
||||
SemaphoreBuilder::new(device).build()
|
||||
}
|
||||
|
||||
/// Same as `alloc`, but allows exportable opaque file descriptor on Linux
|
||||
#[inline]
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn alloc_with_exportable_fd(device: D) -> Result<Semaphore<D>, SemaphoreError> {
|
||||
SemaphoreBuilder::new(device)
|
||||
.export_info(ExternalSemaphoreHandleType::posix())
|
||||
.build()
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
pub fn export_opaque_fd(&self) -> Result<File, SemaphoreError> {
|
||||
let fns = self.device.fns();
|
||||
|
||||
assert!(self.device.loaded_extensions().khr_external_semaphore);
|
||||
assert!(self.device.loaded_extensions().khr_external_semaphore_fd);
|
||||
|
||||
let fd = unsafe {
|
||||
let info = ash::vk::SemaphoreGetFdInfoKHR {
|
||||
semaphore: self.semaphore,
|
||||
handle_type: ash::vk::ExternalSemaphoreHandleTypeFlagsKHR::OPAQUE_FD,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let mut output = MaybeUninit::uninit();
|
||||
check_errors(fns.khr_external_semaphore_fd.get_semaphore_fd_khr(
|
||||
self.device.internal_object(),
|
||||
&info,
|
||||
output.as_mut_ptr(),
|
||||
))?;
|
||||
output.assume_init()
|
||||
};
|
||||
let file = unsafe { File::from_raw_fd(fd) };
|
||||
Ok(file)
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl DeviceOwned for Semaphore {
|
||||
#[inline]
|
||||
fn device(&self) -> &Arc<Device> {
|
||||
&self.device
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<D> VulkanObject for Semaphore<D>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
type Object = ash::vk::Semaphore;
|
||||
|
||||
#[inline]
|
||||
fn internal_object(&self) -> ash::vk::Semaphore {
|
||||
self.semaphore
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> Drop for Semaphore<D>
|
||||
where
|
||||
D: SafeDeref<Target = Device>,
|
||||
{
|
||||
#[inline]
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
if self.must_put_in_pool {
|
||||
let raw_sem = self.semaphore;
|
||||
self.device.semaphore_pool().lock().unwrap().push(raw_sem);
|
||||
} else {
|
||||
let fns = self.device.fns();
|
||||
fns.v1_0.destroy_semaphore(
|
||||
self.device.internal_object(),
|
||||
self.semaphore,
|
||||
ptr::null(),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
pub enum SemaphoreError {
|
||||
/// Not enough memory available.
|
||||
OomError(OomError),
|
||||
/// An extensions is missing.
|
||||
MissingExtension(&'static str),
|
||||
}
|
||||
|
||||
impl fmt::Display for SemaphoreError {
|
||||
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match *self {
|
||||
SemaphoreError::OomError(_) => write!(fmt, "not enough memory available"),
|
||||
SemaphoreError::MissingExtension(s) => {
|
||||
write!(fmt, "Missing the following extension: {}", s)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Error> for SemaphoreError {
|
||||
#[inline]
|
||||
fn from(err: Error) -> SemaphoreError {
|
||||
match err {
|
||||
e @ Error::OutOfHostMemory | e @ Error::OutOfDeviceMemory => {
|
||||
SemaphoreError::OomError(e.into())
|
||||
}
|
||||
_ => panic!("unexpected error: {:?}", err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for SemaphoreError {
|
||||
#[inline]
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match *self {
|
||||
SemaphoreError::OomError(ref err) => Some(err),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OomError> for SemaphoreError {
|
||||
#[inline]
|
||||
fn from(err: OomError) -> SemaphoreError {
|
||||
SemaphoreError::OomError(err)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use crate::device::{Device, DeviceExtensions};
|
||||
use crate::instance::{Instance, InstanceExtensions, PhysicalDevice};
|
||||
use crate::VulkanObject;
|
||||
use crate::{sync::Semaphore, Version};
|
||||
|
||||
#[test]
|
||||
fn semaphore_create() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
let _ = Semaphore::alloc(device.clone());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn semaphore_pool() {
|
||||
let (device, _) = gfx_dev_and_queue!();
|
||||
|
||||
assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
|
||||
let sem1_internal_obj = {
|
||||
let sem = Semaphore::from_pool(device.clone()).unwrap();
|
||||
assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
|
||||
sem.internal_object()
|
||||
};
|
||||
|
||||
assert_eq!(device.semaphore_pool().lock().unwrap().len(), 1);
|
||||
let sem2 = Semaphore::from_pool(device.clone()).unwrap();
|
||||
assert_eq!(device.semaphore_pool().lock().unwrap().len(), 0);
|
||||
assert_eq!(sem2.internal_object(), sem1_internal_obj);
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[cfg(target_os = "linux")]
|
||||
fn semaphore_export() {
|
||||
let supported_ext = InstanceExtensions::supported_by_core().unwrap();
|
||||
if supported_ext.khr_get_display_properties2
|
||||
&& supported_ext.khr_external_semaphore_capabilities
|
||||
{
|
||||
let instance = Instance::new(
|
||||
None,
|
||||
Version::V1_1,
|
||||
&InstanceExtensions {
|
||||
khr_get_physical_device_properties2: true,
|
||||
khr_external_semaphore_capabilities: true,
|
||||
..InstanceExtensions::none()
|
||||
},
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let physical = PhysicalDevice::enumerate(&instance).next().unwrap();
|
||||
|
||||
let queue_family = physical.queue_families().next().unwrap();
|
||||
|
||||
let device_ext = DeviceExtensions {
|
||||
khr_external_semaphore: true,
|
||||
khr_external_semaphore_fd: true,
|
||||
..DeviceExtensions::none()
|
||||
};
|
||||
let (device, _) = Device::new(
|
||||
physical,
|
||||
physical.supported_features(),
|
||||
&device_ext,
|
||||
[(queue_family, 0.5)].iter().cloned(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let supported_ext = DeviceExtensions::supported_by_device(physical.clone());
|
||||
if supported_ext.khr_external_semaphore && supported_ext.khr_external_semaphore_fd {
|
||||
let sem = Semaphore::alloc_with_exportable_fd(device.clone()).unwrap();
|
||||
let fd = sem.export_opaque_fd().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user