120 lines
4 KiB
Rust
120 lines
4 KiB
Rust
use {
|
|
crate::{
|
|
utils::{errorfmt::ErrorFmt, numcell::NumCell},
|
|
video::drm::syncobj::{Syncobj, SyncobjCtx},
|
|
vulkan_core::{VulkanCoreError, device::VulkanDeviceInf},
|
|
},
|
|
ash::vk::{
|
|
ExportSemaphoreCreateInfo, ExternalSemaphoreHandleTypeFlags, Semaphore,
|
|
SemaphoreCreateInfo, SemaphoreGetFdInfoKHR, SemaphoreSignalInfo, SemaphoreType,
|
|
SemaphoreTypeCreateInfo,
|
|
},
|
|
run_on_drop::on_drop,
|
|
std::rc::Rc,
|
|
uapi::OwnedFd,
|
|
};
|
|
|
|
pub struct VulkanTimelineSemaphore<D>
|
|
where
|
|
D: VulkanDeviceInf,
|
|
{
|
|
pub(super) device: Rc<D>,
|
|
pub(super) semaphore: Semaphore,
|
|
pub(super) sync_ctx: Rc<SyncobjCtx>,
|
|
pub(super) syncobj: Rc<Syncobj>,
|
|
pub(super) next_point: NumCell<u64>,
|
|
}
|
|
|
|
impl<D> Drop for VulkanTimelineSemaphore<D>
|
|
where
|
|
D: VulkanDeviceInf,
|
|
{
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
self.device.device().destroy_semaphore(self.semaphore, None);
|
|
}
|
|
}
|
|
}
|
|
|
|
pub trait VulkanDeviceTimelineSemaphoreExt: VulkanDeviceInf {
|
|
fn create_timeline_semaphore(
|
|
self: &Rc<Self>,
|
|
) -> Result<Rc<VulkanTimelineSemaphore<Self>>, VulkanCoreError>;
|
|
|
|
fn create_timeline_semaphore_or_log(
|
|
self: &Rc<Self>,
|
|
) -> Option<Rc<VulkanTimelineSemaphore<Self>>>;
|
|
}
|
|
|
|
impl<D> VulkanDeviceTimelineSemaphoreExt for D
|
|
where
|
|
D: VulkanDeviceInf,
|
|
{
|
|
fn create_timeline_semaphore(
|
|
self: &Rc<Self>,
|
|
) -> Result<Rc<VulkanTimelineSemaphore<Self>>, VulkanCoreError> {
|
|
if !self.supports_timeline_opaque_export() {
|
|
return Err(VulkanCoreError::TimelineExportNotSupported);
|
|
}
|
|
let Some(sync_ctx) = self.sync_ctx() else {
|
|
return Err(VulkanCoreError::NoSyncobjCtx);
|
|
};
|
|
let sem = {
|
|
let mut export_info = ExportSemaphoreCreateInfo::default()
|
|
.handle_types(ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
|
|
let mut type_info =
|
|
SemaphoreTypeCreateInfo::default().semaphore_type(SemaphoreType::TIMELINE);
|
|
let info = SemaphoreCreateInfo::default()
|
|
.push_next(&mut export_info)
|
|
.push_next(&mut type_info);
|
|
let sem = unsafe { self.device().create_semaphore(&info, None) };
|
|
sem.map_err(VulkanCoreError::CreateSemaphore)?
|
|
};
|
|
let destroy_sem = on_drop(|| unsafe { self.device().destroy_semaphore(sem, None) });
|
|
let syncobj = {
|
|
let info = SemaphoreGetFdInfoKHR::default()
|
|
.semaphore(sem)
|
|
.handle_type(ExternalSemaphoreHandleTypeFlags::OPAQUE_FD);
|
|
let res = unsafe { self.external_semaphore_fd().get_semaphore_fd(&info) };
|
|
let fd = res.map_err(VulkanCoreError::ExportTimelineSemaphore)?;
|
|
Syncobj::new(&Rc::new(OwnedFd::new(fd)))
|
|
};
|
|
let signal = |p| {
|
|
let info = SemaphoreSignalInfo::default().semaphore(sem).value(p);
|
|
unsafe {
|
|
self.device()
|
|
.signal_semaphore(&info)
|
|
.map_err(VulkanCoreError::SignalSemaphore)
|
|
}
|
|
};
|
|
let next_point = NumCell::new(1);
|
|
for _ in 0..2 {
|
|
let n = next_point.fetch_add(1);
|
|
signal(n)?;
|
|
let signaled = sync_ctx
|
|
.query_last_signaled(&syncobj)
|
|
.map_err(VulkanCoreError::QueryLastSignaled)?;
|
|
if signaled != n {
|
|
return Err(VulkanCoreError::UnsupportedPointMapping);
|
|
}
|
|
}
|
|
destroy_sem.forget();
|
|
Ok(Rc::new(VulkanTimelineSemaphore {
|
|
device: self.clone(),
|
|
semaphore: sem,
|
|
sync_ctx: sync_ctx.clone(),
|
|
syncobj: Rc::new(syncobj),
|
|
next_point,
|
|
}))
|
|
}
|
|
|
|
fn create_timeline_semaphore_or_log(
|
|
self: &Rc<Self>,
|
|
) -> Option<Rc<VulkanTimelineSemaphore<Self>>> {
|
|
self.create_timeline_semaphore()
|
|
.inspect_err(|e| {
|
|
log::warn!("Could not create timeline semaphore: {}", ErrorFmt(e));
|
|
})
|
|
.ok()
|
|
}
|
|
}
|