From 52fae0b9321251ee98cab37f86517b2b24b84d48 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sun, 1 Mar 2026 11:54:17 +0100 Subject: [PATCH 1/2] sync-obj: move sync-file merging to separate function --- src/video/drm/sync_obj.rs | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/src/video/drm/sync_obj.rs b/src/video/drm/sync_obj.rs index 7b04fd9f..70c7e52e 100644 --- a/src/video/drm/sync_obj.rs +++ b/src/video/drm/sync_obj.rs @@ -190,16 +190,9 @@ impl SyncObjCtx { where I: IntoIterator, { - let mut sync_files = sync_files.into_iter(); - let Some(first) = sync_files.next() else { + let Some(fd) = merge_sync_files(sync_files)? else { return self.signal(sync_obj, point); }; - let mut stash; - let mut fd = &*first.0; - for next in sync_files { - stash = sync_ioc_merge(fd.raw(), next.raw()).map_err(DrmError::Merge)?; - fd = &stash; - } let dummy = self.get_dummy()?; sync_obj_fd_to_handle( self.inner.drm.raw(), @@ -258,3 +251,24 @@ fn destroy(drm: &OwnedFd, handle: SyncObjHandle) { log::error!("Could not destroy sync obj: {}", ErrorFmt(e)); } } + +fn merge_sync_files<'a, I>(sync_files: I) -> Result, DrmError> +where + I: IntoIterator, +{ + let mut sync_files = sync_files.into_iter(); + let Some(first) = sync_files.next() else { + return Ok(None); + }; + let Some(second) = sync_files.next() else { + return Ok(Some(first.clone())); + }; + let merge = |left: &OwnedFd, right: &OwnedFd| { + sync_ioc_merge(left.raw(), right.raw()).map_err(DrmError::Merge) + }; + let mut fd = merge(first, second)?; + for next in sync_files { + fd = merge(&fd, next)?; + } + Ok(Some(SyncFile(Rc::new(fd)))) +} From 660dc286392d3b464abf1069922e9774d251b1f2 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Sun, 1 Mar 2026 11:50:44 +0100 Subject: [PATCH 2/2] sync-obj: use DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE --- src/video/drm/sync_obj.rs | 65 ++++++++++++++++++++++++++++++++++----- src/video/drm/sys.rs | 6 ++++ 2 files changed, 63 insertions(+), 8 deletions(-) diff --git a/src/video/drm/sync_obj.rs b/src/video/drm/sync_obj.rs index 70c7e52e..a4223640 100644 --- a/src/video/drm/sync_obj.rs +++ b/src/video/drm/sync_obj.rs @@ -13,6 +13,7 @@ use { DrmError, sys::{ DRM_SYNCOBJ_CREATE_SIGNALED, DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE, + DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE, DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE, sync_ioc_merge, sync_obj_create, sync_obj_destroy, sync_obj_eventfd, sync_obj_fd_to_handle, sync_obj_handle_to_fd, @@ -21,6 +22,7 @@ use { }, }, std::{ + cell::OnceCell, rc::Rc, sync::atomic::{AtomicU64, Ordering::Relaxed}, }, @@ -84,6 +86,7 @@ struct Handles { pub struct SyncObjCtx { inner: Rc, dummy: CloneCell>>, + supports_timeline_import: OnceCell, } impl SyncObjCtx { @@ -95,6 +98,7 @@ impl SyncObjCtx { links: Default::default(), }), dummy: Default::default(), + supports_timeline_import: Default::default(), } } @@ -102,7 +106,7 @@ impl SyncObjCtx { if let Some(handle) = self.inner.handles.get(&sync_obj.id) { return Ok(handle); } - let handle = sync_obj_fd_to_handle(self.inner.drm.raw(), sync_obj.fd.raw(), 0, 0) + let handle = sync_obj_fd_to_handle(self.inner.drm.raw(), sync_obj.fd.raw(), 0, 0, 0) .map_err(DrmError::ImportSyncObj)?; let handle = SyncObjHandle(handle); let link = sync_obj.importers.add_last(self.inner.clone()); @@ -176,6 +180,40 @@ impl SyncObjCtx { Ok(()) } + fn supports_timeline_import(&self) -> bool { + *self + .supports_timeline_import + .get_or_init(|| match self.test_timeline_import() { + Ok(_) => { + log::info!("Kernel supports sync file timeline import"); + true + } + Err(e) => { + log::warn!( + "Kernel does not support sync file timeline import: {}", + ErrorFmt(e), + ); + false + } + }) + } + + fn test_timeline_import(&self) -> Result<(), DrmError> { + let sync_obj = self.create_sync_obj()?; + let sync_obj = self.get_handle(&sync_obj)?; + let sync_file = self.create_signaled_sync_file()?; + sync_obj_fd_to_handle( + self.inner.drm.raw(), + sync_file.raw(), + DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE + | DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE, + sync_obj.0, + 123, + ) + .map(drop) + .map_err(DrmError::ImportSyncFile) + } + pub fn signal(&self, sync_obj: &SyncObj, point: SyncObjPoint) -> Result<(), DrmError> { let handle = self.get_handle(sync_obj)?; sync_obj_signal(self.inner.drm.raw(), handle.0, point.0).map_err(DrmError::SignalSyncObj) @@ -193,14 +231,25 @@ impl SyncObjCtx { let Some(fd) = merge_sync_files(sync_files)? else { return self.signal(sync_obj, point); }; + let import = |flags: u32, handle: SyncObjHandle| { + sync_obj_fd_to_handle( + self.inner.drm.raw(), + fd.raw(), + DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE | flags, + handle.0, + point.0, + ) + .map(drop) + .map_err(DrmError::ImportSyncFile) + }; + if self.supports_timeline_import() { + return import( + DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE, + self.get_handle(sync_obj)?, + ); + } let dummy = self.get_dummy()?; - sync_obj_fd_to_handle( - self.inner.drm.raw(), - fd.raw(), - DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE, - self.get_handle(&dummy)?.0, - ) - .map_err(DrmError::ImportSyncFile)?; + import(0, self.get_handle(&dummy)?)?; self.transfer(&dummy, SyncObjPoint(0), sync_obj, point) } diff --git a/src/video/drm/sys.rs b/src/video/drm/sys.rs index 8cd29a95..f39ca14a 100644 --- a/src/video/drm/sys.rs +++ b/src/video/drm/sys.rs @@ -1220,6 +1220,8 @@ pub fn sync_obj_destroy(drm: c::c_int, handle: u32) -> Result<(), OsError> { } pub const DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE: u32 = 1 << 0; +pub const DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE: u32 = 1 << 1; + pub const DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE: u32 = 1 << 0; #[repr(C)] @@ -1228,6 +1230,7 @@ struct drm_syncobj_handle { flags: u32, fd: i32, pad: u32, + point: u64, } const DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD: u64 = drm_iowr::(0xC1); @@ -1239,6 +1242,7 @@ pub fn sync_obj_handle_to_fd(drm: c::c_int, handle: u32, flags: u32) -> Result Result { let mut res = drm_syncobj_handle { handle, flags, fd, pad: 0, + point, }; unsafe { ioctl(drm, DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE, &mut res)?;