vulkan: use sync objects if possible
This commit is contained in:
parent
2ac3519f2d
commit
3d3132fe39
23 changed files with 535 additions and 86 deletions
|
|
@ -1,6 +1,21 @@
|
|||
use ash::{Device, khr::external_fence_fd};
|
||||
use {
|
||||
crate::{
|
||||
eventfd_cache::EventfdCache, video::drm::syncobj::SyncobjCtx,
|
||||
vulkan_core::VulkanCoreInstance,
|
||||
},
|
||||
ash::{
|
||||
Device,
|
||||
khr::{external_fence_fd, external_semaphore_fd},
|
||||
},
|
||||
std::rc::Rc,
|
||||
};
|
||||
|
||||
pub trait VulkanDeviceInf: Sized {
|
||||
fn instance(&self) -> &VulkanCoreInstance;
|
||||
fn device(&self) -> &Device;
|
||||
fn external_fence_fd(&self) -> &external_fence_fd::Device;
|
||||
fn external_semaphore_fd(&self) -> &external_semaphore_fd::Device;
|
||||
fn supports_timeline_opaque_export(&self) -> bool;
|
||||
fn sync_ctx(&self) -> &Rc<SyncobjCtx>;
|
||||
fn eventfd_cache(&self) -> &Rc<EventfdCache>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,15 +1,17 @@
|
|||
use {
|
||||
crate::{
|
||||
gfx_api::FdSync,
|
||||
gfx_api::{FdSync, ReservedSyncobjPoint},
|
||||
utils::errorfmt::ErrorFmt,
|
||||
video::drm::syncobj::SyncobjPoint,
|
||||
vulkan_core::{
|
||||
VulkanCoreError,
|
||||
device::VulkanDeviceInf,
|
||||
fence::{VulkanDeviceFenceExt, VulkanFence},
|
||||
timeline_semaphore::VulkanTimelineSemaphore,
|
||||
},
|
||||
},
|
||||
ash::vk::Fence,
|
||||
std::rc::Rc,
|
||||
ash::vk::{Fence, PipelineStageFlags2, SemaphoreSubmitInfo, SemaphoreWaitInfo, SubmitInfo2},
|
||||
std::{rc::Rc, slice},
|
||||
};
|
||||
|
||||
pub enum VulkanSync<D>
|
||||
|
|
@ -17,6 +19,10 @@ where
|
|||
D: VulkanDeviceInf,
|
||||
{
|
||||
Fence(Rc<VulkanFence<D>>),
|
||||
TimelineSemaphore {
|
||||
tls: Rc<VulkanTimelineSemaphore<D>>,
|
||||
pending: Rc<ReservedSyncobjPoint>,
|
||||
},
|
||||
}
|
||||
|
||||
impl<D> VulkanSync<D>
|
||||
|
|
@ -24,12 +30,22 @@ where
|
|||
D: VulkanDeviceInf,
|
||||
{
|
||||
pub fn handle_validation(&self) {
|
||||
// nothing
|
||||
if let VulkanSync::TimelineSemaphore { tls, pending } = self
|
||||
&& tls.device.instance().validation
|
||||
{
|
||||
let info = SemaphoreWaitInfo::default()
|
||||
.semaphores(slice::from_ref(&tls.semaphore))
|
||||
.values(slice::from_ref(&pending.point.0));
|
||||
unsafe {
|
||||
let _ = tls.device.device().wait_semaphores(&info, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn fence(&self) -> Fence {
|
||||
match self {
|
||||
VulkanSync::Fence(f) => f.fence,
|
||||
VulkanSync::TimelineSemaphore { .. } => Fence::null(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -47,19 +63,74 @@ where
|
|||
};
|
||||
release_sync_file.map(FdSync::SyncFile)
|
||||
}
|
||||
VulkanSync::TimelineSemaphore { pending, .. } => Some(FdSync::Syncobj(pending.clone())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait VulkanDeviceSyncExt: VulkanDeviceInf {
|
||||
fn create_sync(self: &Rc<Self>) -> Result<VulkanSync<Self>, VulkanCoreError>;
|
||||
fn create_sync<'a>(
|
||||
self: &Rc<Self>,
|
||||
tls: Option<&Rc<VulkanTimelineSemaphore<Self>>>,
|
||||
semaphore_submit_info: &'a mut SemaphoreSubmitInfo,
|
||||
submit_info: &mut SubmitInfo2<'a>,
|
||||
) -> Result<VulkanSync<Self>, VulkanCoreError>;
|
||||
}
|
||||
|
||||
impl<D> VulkanDeviceSyncExt for D
|
||||
where
|
||||
D: VulkanDeviceInf,
|
||||
{
|
||||
fn create_sync(self: &Rc<Self>) -> Result<VulkanSync<Self>, VulkanCoreError> {
|
||||
fn create_sync<'a>(
|
||||
self: &Rc<Self>,
|
||||
tls: Option<&Rc<VulkanTimelineSemaphore<Self>>>,
|
||||
semaphore_submit_info: &'a mut SemaphoreSubmitInfo,
|
||||
submit_info: &mut SubmitInfo2<'a>,
|
||||
) -> Result<VulkanSync<Self>, VulkanCoreError> {
|
||||
if let Some(tls) = tls {
|
||||
match create_tls_sync(self, tls, semaphore_submit_info, submit_info) {
|
||||
Ok(s) => return Ok(s),
|
||||
Err(e) => {
|
||||
log::warn!("Could not create sync obj sync: {}", ErrorFmt(e));
|
||||
}
|
||||
}
|
||||
}
|
||||
self.create_fence().map(VulkanSync::Fence)
|
||||
}
|
||||
}
|
||||
|
||||
fn create_tls_sync<'a, D>(
|
||||
device: &Rc<D>,
|
||||
tls: &Rc<VulkanTimelineSemaphore<D>>,
|
||||
semaphore_submit_info: &'a mut SemaphoreSubmitInfo,
|
||||
submit_info: &mut SubmitInfo2<'a>,
|
||||
) -> Result<VulkanSync<D>, VulkanCoreError>
|
||||
where
|
||||
D: VulkanDeviceInf,
|
||||
{
|
||||
let point = SyncobjPoint(tls.next_point.fetch_add(1));
|
||||
let eventfd = device
|
||||
.eventfd_cache()
|
||||
.acquire()
|
||||
.map_err(VulkanCoreError::AcquireEventfd)?;
|
||||
device
|
||||
.sync_ctx()
|
||||
.wait_for_point(&eventfd.fd, &tls.syncobj, point, true)
|
||||
.map_err(VulkanCoreError::CreateSyncobjWait)?;
|
||||
let pending = Rc::new(ReservedSyncobjPoint {
|
||||
ctx: device.sync_ctx().clone(),
|
||||
syncobj: tls.syncobj.clone(),
|
||||
point,
|
||||
sync_file: Default::default(),
|
||||
signaled: eventfd,
|
||||
});
|
||||
*semaphore_submit_info = SemaphoreSubmitInfo::default()
|
||||
.semaphore(tls.semaphore)
|
||||
.value(point.0)
|
||||
.stage_mask(PipelineStageFlags2::ALL_COMMANDS);
|
||||
*submit_info = submit_info.signal_semaphore_infos(slice::from_ref(semaphore_submit_info));
|
||||
Ok(VulkanSync::TimelineSemaphore {
|
||||
tls: tls.clone(),
|
||||
pending,
|
||||
})
|
||||
}
|
||||
|
|
|
|||
116
src/vulkan_core/timeline_semaphore.rs
Normal file
116
src/vulkan_core/timeline_semaphore.rs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
use {
|
||||
crate::{
|
||||
utils::{errorfmt::ErrorFmt, numcell::NumCell},
|
||||
video::drm::syncobj::Syncobj,
|
||||
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) 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 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 = self
|
||||
.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,
|
||||
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()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue