diff --git a/src/backend.rs b/src/backend.rs index bf07449d..531e858a 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -9,7 +9,7 @@ use { drm_feedback::DrmFeedback, fixed::Fixed, format::Format, - gfx_api::{GfxApi, GfxFramebuffer, SyncFile}, + gfx_api::{FdSync, GfxApi, GfxFramebuffer}, ifs::{ wl_output::OutputId, wl_seat::{ @@ -186,7 +186,7 @@ pub trait HardwareCursorUpdate { fn set_enabled(&mut self, enabled: bool); fn get_buffer(&self) -> Rc; fn set_position(&mut self, x: i32, y: i32); - fn swap_buffer(&mut self, sync_file: Option); + fn swap_buffer(&mut self, sync: Option); fn size(&self) -> (i32, i32); } diff --git a/src/backends/metal/allocator.rs b/src/backends/metal/allocator.rs index 63e24ad7..956de322 100644 --- a/src/backends/metal/allocator.rs +++ b/src/backends/metal/allocator.rs @@ -11,8 +11,8 @@ use { }, format::Format, gfx_api::{ - AcquireSync, GfxBlendBuffer, GfxError, GfxFormat, GfxFramebuffer, GfxTexture, - GfxWriteModifier, ReleaseSync, SyncFile, needs_render_usage, + AcquireSync, FdSync, GfxBlendBuffer, GfxError, GfxFormat, GfxFramebuffer, GfxTexture, + GfxWriteModifier, ReleaseSync, needs_render_usage, }, rect::{DamageQueue, Rect, Region}, udmabuf::{Udmabuf, UdmabufError}, @@ -120,15 +120,15 @@ pub enum RenderBufferError { #[derive(Default)] pub struct RenderBufferCopy { - pub render_block: Option, - pub present_block: Option, + pub render_block: Option, + pub present_block: Option, } impl RenderBufferCopy { - pub fn for_both(sf: Option) -> Self { + pub fn for_both(sync: Option) -> Self { Self { - render_block: sf.clone(), - present_block: sf, + render_block: sync.clone(), + present_block: sync, } } } @@ -138,12 +138,12 @@ impl RenderBuffer { &self, cd: &Rc, region: Option<&Region>, - sync_file: Option, + sync: Option, ) -> Result { match &self.prime { RenderBufferPrime::None => Ok(RenderBufferCopy { render_block: None, - present_block: sync_file, + present_block: sync, }), RenderBufferPrime::Sampling { dev_render_tex, @@ -157,7 +157,7 @@ impl RenderBuffer { dev_render_tex, cd, None, - AcquireSync::from_sync_file(sync_file), + AcquireSync::from_fd_sync(sync), ReleaseSync::None, 0, 0, @@ -175,7 +175,7 @@ impl RenderBuffer { .. } => { let render_block = render_copy - .execute(sync_file.as_ref(), region) + .execute(sync.as_ref(), region) .map_err(RenderBufferError::CopyRenderToUdmabuf)?; let present_block = dev_copy .execute(render_block.as_ref(), region) @@ -189,7 +189,7 @@ impl RenderBuffer { | RenderBufferPrime::CopyDirectPush { render_copy: copy, .. } => copy - .execute(sync_file.as_ref(), region) + .execute(sync.as_ref(), region) .map_err(RenderBufferError::CopyRenderToDev) .map(RenderBufferCopy::for_both), } @@ -201,8 +201,8 @@ impl RenderBuffer { self.damage_queue.damage(&[rect]); } - pub fn clear(&self, cd: &Rc) -> Result, RenderBufferError> { - let sync_file = match &self.prime { + pub fn clear(&self, cd: &Rc) -> Result, RenderBufferError> { + let sync = match &self.prime { RenderBufferPrime::None => { self.render .fb @@ -222,14 +222,14 @@ impl RenderBuffer { self.copy_to_dev(cd, None, sf)?.present_block } }; - Ok(sync_file) + Ok(sync) } pub fn copy_to_new( &self, new: &Self, cd: &Rc, - ) -> Result, RenderBufferError> { + ) -> Result, RenderBufferError> { let old = self; if (old.width, old.height) != (new.width, new.height) { diff --git a/src/backends/metal/present.rs b/src/backends/metal/present.rs index 722faef2..bf211e29 100644 --- a/src/backends/metal/present.rs +++ b/src/backends/metal/present.rs @@ -240,13 +240,8 @@ impl MetalConnector { // current PresentFb if present_fb is None, potentially mutating the fb that is // currently being scanned out, which would render such a wait absurd. self.perform_screencopies(&present_fb, &node, &cd); - if let Some(sync_file) = self.cursor_sync_file.take() - && let Err(e) = self.state.ring.readable(&sync_file).await - { - log::error!( - "Could not wait for cursor sync file to complete: {}", - ErrorFmt(e) - ); + if let Some(sync) = self.cursor_sync.take() { + sync.signaled(&self.state.ring, "cursor").await; } self.await_present_fb(present_fb.as_mut(), PresentFbWait::Scanout) .await; @@ -353,19 +348,14 @@ impl MetalConnector { W::Render => &mut fb.copy.render_block, W::Scanout => &mut fb.copy.present_block, }; - let Some(sync_file) = field.take() else { + let Some(sync) = field.take() else { return; }; - if let Err(e) = self.state.ring.readable(&sync_file).await { - let name = match wait { - W::Render => "render", - W::Scanout => "scanout", - }; - log::error!( - "Could not wait for primary {name} sync file to complete: {}", - ErrorFmt(e), - ); - } + let name = match wait { + W::Render => "render", + W::Scanout => "scanout", + }; + sync.signaled(&self.state.ring, name).await; } fn try_async_flip(&self) -> bool { @@ -554,13 +544,13 @@ impl MetalConnector { self.state.present_hardware_cursor(node, &mut c); let swap_buffers = c.cursor_swap_buffer.is_some(); self.cursor_swap_buffer.set(swap_buffers); - if let Some(sf) = c.cursor_swap_buffer.take() { - let sf = c + if let Some(sync) = c.cursor_swap_buffer.take() { + let sync = c .cursor_buffer - .copy_to_dev(cd, None, sf) + .copy_to_dev(cd, None, sync) .map_err(MetalError::CopyToDev)? .present_block; - self.cursor_sync_file.set(sf); + self.cursor_sync.set(sync); } let mut cursor_changed = false; cursor_changed |= self.cursor_enabled.replace(c.cursor_enabled) != c.cursor_enabled; @@ -886,13 +876,13 @@ impl MetalConnector { tex = buffer.render.tex.clone(); } Some(dsd) => { - let sf = match &dsd.acquire_sync { + let sync = match &dsd.acquire_sync { AcquireSync::None => None, AcquireSync::Implicit => None, - AcquireSync::SyncFile { sync_file } => Some(sync_file.clone()), + AcquireSync::FdSync(sync) => Some(sync.clone()), AcquireSync::Unnecessary => None, }; - copy = RenderBufferCopy::for_both(sf); + copy = RenderBufferCopy::for_both(sync); fb = dsd.fb.clone(); tex = dsd.tex.clone(); } diff --git a/src/backends/metal/transaction.rs b/src/backends/metal/transaction.rs index 79e6d00e..8863a8a1 100644 --- a/src/backends/metal/transaction.rs +++ b/src/backends/metal/transaction.rs @@ -242,7 +242,7 @@ impl MetalDeviceTransaction { let mut unused_crtcs = BinarySearchMap::<_, _, SIZE>::new(); let mut unused_planes = BinarySearchMap::<_, _, SIZE>::new(); let mut crtc_planes = BinarySearchMap::<_, _, SIZE>::new(); - let mut sync_files = vec![]; + let mut syncs = vec![]; let slf = &mut self.common; for (_, crtc) in &mut slf.crtcs { crtc_planes.insert(crtc.obj.id, CrtcPlanes::default()); @@ -615,7 +615,7 @@ impl MetalDeviceTransaction { new_buffer.clear(&cd) }; match res { - Ok(sf) => sync_files.extend(sf), + Ok(sf) => syncs.extend(sf), Err(e) => { log::warn!("Could not clear new buffer: {}", ErrorFmt(e)); } @@ -653,7 +653,7 @@ impl MetalDeviceTransaction { match res { Ok(sf) => { buffer.locked.set(true); - sync_files.extend(sf); + syncs.extend(sf); } Err(e) => { log::error!( @@ -753,19 +753,8 @@ impl MetalDeviceTransaction { plane.new = DrmPlaneState::default(); } } - for sf in sync_files { - let mut pollfd = c::pollfd { - fd: sf.0.raw(), - events: c::POLLIN, - revents: 0, - }; - let res = uapi::poll(slice::from_mut(&mut pollfd), -1); - if let Err(e) = res { - log::warn!( - "Could not wait for sync file to become readable: {}", - ErrorFmt(e) - ); - } + for sync in syncs { + sync.signaled_blocking("transaction"); } Ok(MetalDeviceTransactionWithDrmState { common: self.common, diff --git a/src/backends/metal/video.rs b/src/backends/metal/video.rs index 8b70038d..a15681e0 100644 --- a/src/backends/metal/video.rs +++ b/src/backends/metal/video.rs @@ -26,7 +26,7 @@ use { drm_feedback::DrmFeedback, edid::{CtaDataBlock, Descriptor, EdidExtension}, format::{Format, XRGB8888}, - gfx_api::{GfxApi, GfxContext, GfxFramebuffer, SyncFile}, + gfx_api::{FdSync, GfxApi, GfxContext, GfxFramebuffer}, ifs::{ wl_output::OutputId, wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC, KIND_ZERO_COPY}, @@ -534,7 +534,7 @@ pub struct MetalConnector { pub cursor_enabled: Cell, pub cursor_buffers: CloneCell>>, pub cursor_swap_buffer: Cell, - pub cursor_sync_file: CloneCell>, + pub cursor_sync: CloneCell>, pub drm_feedback: CloneCell>>, pub scanout_buffers: RefCell>, @@ -565,7 +565,7 @@ pub struct MetalHardwareCursor { } pub struct MetalHardwareCursorChange<'a> { - pub cursor_swap_buffer: Option>, + pub cursor_swap_buffer: Option>, pub cursor_enabled: bool, pub cursor_x: i32, pub cursor_y: i32, @@ -603,8 +603,8 @@ impl HardwareCursorUpdate for MetalHardwareCursorChange<'_> { self.cursor_y = y; } - fn swap_buffer(&mut self, sync_file: Option) { - self.cursor_swap_buffer = Some(sync_file); + fn swap_buffer(&mut self, sync: Option) { + self.cursor_swap_buffer = Some(sync); } fn size(&self) -> (i32, i32) { @@ -1127,7 +1127,7 @@ fn create_connector( cursor_changed: Cell::new(false), cursor_damage: Cell::new(false), cursor_swap_buffer: Cell::new(false), - cursor_sync_file: Default::default(), + cursor_sync: Default::default(), drm_feedback: Default::default(), scanout_buffers: Default::default(), active_framebuffer: Default::default(), diff --git a/src/copy_device.rs b/src/copy_device.rs index effbbe1b..b35442b8 100644 --- a/src/copy_device.rs +++ b/src/copy_device.rs @@ -2,7 +2,7 @@ use { crate::{ async_engine::{AsyncEngine, SpawnedFuture}, format::{FORMATS, Format}, - gfx_api::SyncFile, + gfx_api::{FdSync, SyncFile}, io_uring::IoUring, rect::{Rect, Region}, utils::{ @@ -1296,9 +1296,9 @@ impl CopyDeviceCopy { pub fn execute( &self, - sync_file: Option<&SyncFile>, + sync: Option<&FdSync>, region: Option<&Region>, - ) -> Result, CopyDeviceError> { + ) -> Result, CopyDeviceError> { self.ensure_not_busy()?; let slf = &*self.inner; let tt = slf.tt; @@ -1656,7 +1656,9 @@ impl CopyDeviceCopy { } let mut wait_semaphore = None; let mut wait_semaphores = ArrayVec::<_, 1>::new(); - if let Some(sync_file) = sync_file { + if let Some(sync) = sync + && let Some(sync_file) = sync.get_sync_file() + { let semaphore = match slf.dev.semaphores.pop() { Some(s) => s, _ => slf.dev.create_semaphore()?, @@ -1703,7 +1705,7 @@ impl CopyDeviceCopy { fence: Some(signal_fence), }; slf.dev.submissions[tt].pending.push(pending); - Ok(sync_file) + Ok(sync_file.map(FdSync::SyncFile)) } } diff --git a/src/cursor_user.rs b/src/cursor_user.rs index 3b783636..6d911048 100644 --- a/src/cursor_user.rs +++ b/src/cursor_user.rs @@ -514,8 +514,8 @@ impl CursorUser { &cd, ); match res { - Ok(sync_file) => { - hc.swap_buffer(sync_file); + Ok(sync) => { + hc.swap_buffer(sync); } Err(e) => { log::error!("Could not render hardware cursor: {}", ErrorFmt(e)); diff --git a/src/eventfd_cache.rs b/src/eventfd_cache.rs index b282ea7c..e2905bce 100644 --- a/src/eventfd_cache.rs +++ b/src/eventfd_cache.rs @@ -64,12 +64,10 @@ impl EventfdCache { } impl Eventfd { - #[expect(dead_code)] pub fn is_signaled(&self) -> bool { self.signaled.get() } - #[cfg_attr(not(test), expect(dead_code))] pub async fn signaled(&self) -> Result<(), IoUringError> { if self.signaled.get() { return Ok(()); @@ -79,7 +77,6 @@ impl Eventfd { Ok(()) } - #[expect(dead_code)] pub fn signaled_blocking(&self) -> Result<(), OsError> { if self.signaled.get() { return Ok(()); diff --git a/src/gfx_api.rs b/src/gfx_api.rs index 45f9d91f..d5f7bcfb 100644 --- a/src/gfx_api.rs +++ b/src/gfx_api.rs @@ -5,16 +5,22 @@ use { cpu_worker::CpuWorker, cursor::Cursor, damage::DamageVisualizer, + eventfd_cache::Eventfd, fixed::Fixed, format::Format, + io_uring::{IoUring, IoUringError}, rect::{Rect, Region}, renderer::{Renderer, renderer_base::RendererBase}, scale::Scale, state::State, theme::Color, tree::{Node, OutputNode, Transform}, - utils::clonecell::UnsafeCellCloneSafe, - video::{Modifier, dmabuf::DmaBuf, drm::syncobj::SyncobjCtx}, + utils::{clonecell::UnsafeCellCloneSafe, errorfmt::ErrorFmt}, + video::{ + Modifier, + dmabuf::DmaBuf, + drm::syncobj::{Syncobj, SyncobjCtx, SyncobjPoint}, + }, }, ahash::AHashMap, indexmap::{IndexMap, IndexSet}, @@ -22,16 +28,17 @@ use { linearize::Linearize, std::{ any::Any, - cell::Cell, + cell::{Cell, OnceCell}, error::Error, ffi::CString, fmt::{Debug, Formatter}, ops::Deref, rc::Rc, + slice, sync::atomic::{AtomicU64, Ordering::Relaxed}, }, thiserror::Error, - uapi::OwnedFd, + uapi::{OwnedFd, c}, }; #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Linearize)] @@ -285,15 +292,24 @@ unsafe impl UnsafeCellCloneSafe for SyncFile {} pub enum AcquireSync { None, Implicit, - SyncFile { sync_file: SyncFile }, + FdSync(FdSync), Unnecessary, } impl AcquireSync { - pub fn from_sync_file(sync_file: Option) -> Self { - match sync_file { + pub fn from_fd_sync(sync: Option) -> Self { + match sync { None => Self::Unnecessary, - Some(sync_file) => Self::SyncFile { sync_file }, + Some(sync) => Self::FdSync(sync), + } + } + + pub fn get_sync_file(&self) -> Option<&SyncFile> { + match self { + Self::None => None, + Self::Implicit => None, + Self::FdSync(sync) => sync.get_sync_file(), + Self::Unnecessary => None, } } } @@ -310,7 +326,7 @@ impl Debug for AcquireSync { let name = match self { AcquireSync::None => "None", AcquireSync::Implicit => "Implicit", - AcquireSync::SyncFile { .. } => "SyncFile", + AcquireSync::FdSync(d) => return Debug::fmt(d, f), AcquireSync::Unnecessary => "Unnecessary", }; f.debug_struct(name).finish_non_exhaustive() @@ -318,7 +334,7 @@ impl Debug for AcquireSync { } pub trait BufferResv: Debug { - fn set_sync_file(&self, user: BufferResvUser, sync_file: &SyncFile); + fn set_sync(&self, user: BufferResvUser, sync: &FdSync); } #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] @@ -363,7 +379,7 @@ pub trait GfxFramebuffer: Debug { region: &Region, blend_buffer: Option<&Rc>, blend_cd: &Rc, - ) -> Result, GfxError>; + ) -> Result, GfxError>; fn format(&self) -> &'static Format; @@ -398,7 +414,7 @@ impl dyn GfxFramebuffer { clear_cd: &Rc, blend_buffer: Option<&Rc>, blend_cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { self.clone().render_with_region( acquire_sync, release_sync, @@ -417,7 +433,7 @@ impl dyn GfxFramebuffer { acquire_sync: AcquireSync, release_sync: ReleaseSync, cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { self.clear_with( acquire_sync, release_sync, @@ -434,7 +450,7 @@ impl dyn GfxFramebuffer { cd: &Rc, color: &Color, color_cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { self.render( acquire_sync, release_sync, @@ -472,7 +488,7 @@ impl dyn GfxFramebuffer { release_sync: ReleaseSync, x: i32, y: i32, - ) -> Result, GfxError> { + ) -> Result, GfxError> { let mut ops = vec![]; let scale = Scale::from_int(1); let mut renderer = self.renderer_base(&mut ops, scale, Transform::None); @@ -516,7 +532,7 @@ impl dyn GfxFramebuffer { blend_buffer: Option<&Rc>, blend_cd: &Rc, f: &mut dyn FnMut(&mut RendererBase), - ) -> Result, GfxError> { + ) -> Result, GfxError> { let mut ops = vec![]; let mut renderer = self.renderer_base(&mut ops, scale, Transform::None); f(&mut renderer); @@ -569,7 +585,7 @@ impl dyn GfxFramebuffer { region: &Region, blend_buffer: Option<&Rc>, blend_cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { self.clone().render_with_region( acquire_sync, release_sync, @@ -596,7 +612,7 @@ impl dyn GfxFramebuffer { fill_black_in_grace_period: bool, blend_buffer: Option<&Rc>, blend_cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { self.render_node( acquire_sync, release_sync, @@ -631,7 +647,7 @@ impl dyn GfxFramebuffer { transform: Transform, blend_buffer: Option<&Rc>, blend_cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { let pass = self.create_render_pass( node, state, @@ -664,7 +680,7 @@ impl dyn GfxFramebuffer { scale: Scale, transform: Transform, cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { let mut ops = vec![]; let mut renderer = Renderer { base: self.renderer_base(&mut ops, scale, transform), @@ -1087,3 +1103,110 @@ pub fn renderer_base<'a>( pub fn logical_size(physical_size: (i32, i32), transform: Transform) -> (i32, i32) { transform.maybe_swap(physical_size) } + +pub struct ReservedSyncobjPoint { + pub ctx: Rc, + pub syncobj: Rc, + pub point: SyncobjPoint, + pub sync_file: OnceCell>, + pub signaled: Eventfd, +} + +impl Debug for ReservedSyncobjPoint { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + f.debug_struct("ReservedSyncobjPoint") + .field("syncobj", &self.syncobj.id()) + .field("point", &self.point) + .finish_non_exhaustive() + } +} + +#[derive(Clone, Debug)] +pub enum FdSync { + SyncFile(SyncFile), + #[expect(dead_code)] + Syncobj(Rc), +} + +unsafe impl UnsafeCellCloneSafe for FdSync {} + +impl FdSync { + pub async fn try_signaled(&self, ring: &Rc) -> Result<(), IoUringError> { + match self { + FdSync::SyncFile(f) => ring.readable(&f.0).await.map(drop), + FdSync::Syncobj(obj) => obj.signaled.signaled().await, + } + } + + pub async fn signaled(&self, ring: &Rc, name: &str) { + if let Err(e) = self.try_signaled(ring).await { + log::error!( + "Could not wait for {name} sync to become signaled: {}", + ErrorFmt(e), + ); + } + } + + pub fn signaled_blocking(&self, name: &str) { + let res = match self { + FdSync::Syncobj(obj) => obj.signaled.signaled_blocking(), + FdSync::SyncFile(f) => { + let mut pollfd = c::pollfd { + fd: f.raw(), + events: c::POLLIN, + revents: 0, + }; + uapi::poll(slice::from_mut(&mut pollfd), -1) + .map(drop) + .map_err(Into::into) + } + }; + if let Err(e) = res { + log::error!( + "Could not wait for {name} sync to become signaled: {}", + ErrorFmt(e), + ); + } + } + + #[expect(dead_code)] + pub fn is_unsignaled(&self) -> bool { + !self.is_signaled() + } + + pub fn is_signaled(&self) -> bool { + match self { + FdSync::Syncobj(obj) => obj.signaled.is_signaled(), + FdSync::SyncFile(f) => { + let mut pollfd = c::pollfd { + fd: f.raw(), + events: c::POLLIN, + revents: 0, + }; + uapi::poll(slice::from_mut(&mut pollfd), 0) == Ok(1) + } + } + } + + pub fn get_sync_file(&self) -> Option<&SyncFile> { + match self { + FdSync::SyncFile(f) => Some(f), + FdSync::Syncobj(obj) => { + if obj.signaled.is_signaled() { + return None; + } + obj.sync_file + .get_or_init(|| { + match obj.ctx.export_sync_file_blocking(&obj.syncobj, obj.point) { + Ok(sf) => Some(sf), + Err(e) => { + log::error!("Could not export sync file: {}", ErrorFmt(e)); + None + } + } + }) + .as_ref() + } + } + } +} diff --git a/src/gfx_apis/gl.rs b/src/gfx_apis/gl.rs index ff6f7aed..1afd8c9d 100644 --- a/src/gfx_apis/gl.rs +++ b/src/gfx_apis/gl.rs @@ -69,8 +69,8 @@ use { crate::{ cmm::cmm_eotf::Eotf, gfx_api::{ - AcquireSync, CopyTexture, FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxTexture, - ReleaseSync, SyncFile, + AcquireSync, CopyTexture, FdSync, FramebufferRect, GfxApiOpt, GfxContext, GfxError, + GfxTexture, ReleaseSync, SyncFile, }, gfx_apis::gl::{ egl::image::EglImage, @@ -221,7 +221,7 @@ struct GlFillRect { pub color: Color, } -fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option { +fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option { let mut state = fb.ctx.gl_state.borrow_mut(); let state = &mut *state; let mut fill_rect = state.fill_rect.take(); @@ -301,13 +301,14 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option { return None; } }; + let file = FdSync::SyncFile(file); let user = fb.ctx.buffer_resv_user; for op in ops { if let GfxApiOpt::CopyTexture(ct) = op && ct.release_sync == ReleaseSync::Explicit && let Some(resv) = &ct.buffer_resv { - resv.set_sync_file(user, &file); + resv.set_sync(user, &file); } } return Some(file); @@ -417,9 +418,8 @@ fn render_texture(ctx: &GlRenderContext, tex: &CopyTexture) { } fn handle_explicit_sync(ctx: &GlRenderContext, img: Option<&Rc>, sync: &AcquireSync) { - let sync_file = match sync { - AcquireSync::None | AcquireSync::Implicit | AcquireSync::Unnecessary => return, - AcquireSync::SyncFile { sync_file } => sync_file, + let Some(sync_file) = sync.get_sync_file() else { + return; }; let sync_file = match uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0) { Ok(s) => s, diff --git a/src/gfx_apis/gl/renderer/framebuffer.rs b/src/gfx_apis/gl/renderer/framebuffer.rs index 7df3bee8..57d12729 100644 --- a/src/gfx_apis/gl/renderer/framebuffer.rs +++ b/src/gfx_apis/gl/renderer/framebuffer.rs @@ -6,9 +6,9 @@ use { }, format::Format, gfx_api::{ - AcquireSync, AsyncShmGfxTextureCallback, GfxApiOpt, GfxBlendBuffer, GfxError, + AcquireSync, AsyncShmGfxTextureCallback, FdSync, GfxApiOpt, GfxBlendBuffer, GfxError, GfxFramebuffer, GfxInternalFramebuffer, GfxStagingBuffer, PendingShmTransfer, - ReleaseSync, ShmMemory, SyncFile, + ReleaseSync, ShmMemory, }, gfx_apis::gl::{ RenderError, @@ -74,7 +74,7 @@ impl Framebuffer { acquire_sync: AcquireSync, ops: &[GfxApiOpt], clear: Option<&Color>, - ) -> Result, RenderError> { + ) -> Result, RenderError> { let gles = self.ctx.ctx.dpy.gles; self.ctx.ctx.with_current(|| { handle_explicit_sync(&self.ctx, self.gl.rb._img.as_ref(), &acquire_sync); @@ -88,13 +88,13 @@ impl Framebuffer { } (gles.glBlendFunc)(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); } - let fd = run_ops(self, ops); - if fd.is_none() { + let sync = run_ops(self, ops); + if sync.is_none() { unsafe { (gles.glFinish)(); } } - Ok(fd) + Ok(sync) }) } } @@ -115,7 +115,7 @@ impl GfxFramebuffer for Framebuffer { _region: &Region, _blend_buffer: Option<&Rc>, _blend_cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { (*self) .render(acquire_sync, ops, clear) .map_err(|e| e.into()) diff --git a/src/gfx_apis/vulkan/image.rs b/src/gfx_apis/vulkan/image.rs index e4397d02..ee529fe2 100644 --- a/src/gfx_apis/vulkan/image.rs +++ b/src/gfx_apis/vulkan/image.rs @@ -4,9 +4,9 @@ use { format::Format, gfx_api::{ AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, - AsyncShmGfxTextureTransferCancellable, GfxApiOpt, GfxBlendBuffer, GfxBuffer, GfxError, - GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture, - PendingShmTransfer, ReleaseSync, ShmGfxTexture, ShmMemory, SyncFile, + AsyncShmGfxTextureTransferCancellable, FdSync, GfxApiOpt, GfxBlendBuffer, GfxBuffer, + GfxError, GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer, + GfxTexture, PendingShmTransfer, ReleaseSync, ShmGfxTexture, ShmMemory, }, gfx_apis::vulkan::{ VulkanError, allocator::VulkanAllocation, device::VulkanDevice, @@ -563,7 +563,7 @@ impl GfxFramebuffer for VulkanImage { region: &Region, blend_buffer: Option<&Rc>, blend_cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { let mut blend_buffer = blend_buffer .map(|b| b.clone().into_vk(&self.renderer.device.device)) .transpose()?; diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index 44d11c2c..0adea473 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -8,7 +8,7 @@ use { }, cpu_worker::PendingJob, gfx_api::{ - AcquireSync, AlphaMode, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, + AcquireSync, AlphaMode, BufferResv, BufferResvUser, FdSync, GfxApiOpt, GfxBlendBuffer, GfxFormat, GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile, }, gfx_apis::vulkan::{ @@ -1671,10 +1671,12 @@ impl VulkanRenderer { } } } - AcquireSync::SyncFile { sync_file } => { - let fd = uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0) - .map_err(|e| VulkanError::Dupfd(e.into()))?; - import_sync_file(fd)?; + AcquireSync::FdSync(sync) => { + if let Some(sync_file) = sync.get_sync_file() { + let fd = uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0) + .map_err(|e| VulkanError::Dupfd(e.into()))?; + import_sync_file(fd)?; + } } AcquireSync::Unnecessary => {} } @@ -1707,13 +1709,14 @@ impl VulkanRenderer { Some(sync_file) => sync_file, _ => return, }; + let fd_sync = FdSync::SyncFile(sync_file.clone()); let import = |img: &VulkanImage, sync: ReleaseSync, resv: Option>, flag: u32| { if sync == ReleaseSync::None { return; } if let Some(resv) = resv { - resv.set_sync_file(self.buffer_resv_user, sync_file); + resv.set_sync(self.buffer_resv_user, &fd_sync); } else if sync == ReleaseSync::Implicit { if let VulkanImageMemory::DmaBuf(buf) = &img.ty && let Err(e) = buf.template.dmabuf.import_sync_file(flag, sync_file) @@ -1844,7 +1847,7 @@ impl VulkanRenderer { region: &Region, blend_buffer: Option>, blend_cd: &Rc, - ) -> Result, VulkanError> { + ) -> Result, VulkanError> { zone!("execute"); let res = self.try_execute( fb, @@ -1870,7 +1873,7 @@ impl VulkanRenderer { memory.ops_tmp.clear(); memory.release_sync_file.take() }; - res.map(|_| sync_file) + res.map(|_| sync_file.map(FdSync::SyncFile)) } fn allocate_semaphore(&self) -> Result, VulkanError> { diff --git a/src/ifs/ext_image_copy/ext_image_copy_capture_frame_v1.rs b/src/ifs/ext_image_copy/ext_image_copy_capture_frame_v1.rs index c48cfaa0..48fa9038 100644 --- a/src/ifs/ext_image_copy/ext_image_copy_capture_frame_v1.rs +++ b/src/ifs/ext_image_copy/ext_image_copy_capture_frame_v1.rs @@ -3,8 +3,8 @@ use { client::{Client, ClientError}, cmm::cmm_description::ColorDescription, gfx_api::{ - AcquireSync, AsyncShmGfxTextureCallback, BufferResv, GfxError, GfxFramebuffer, - GfxTexture, ReleaseSync, STAGING_DOWNLOAD, SyncFile, + AcquireSync, AsyncShmGfxTextureCallback, BufferResv, FdSync, GfxError, GfxFramebuffer, + GfxTexture, ReleaseSync, STAGING_DOWNLOAD, }, ifs::{ ext_image_capture_source_v1::ImageCaptureSource, @@ -78,7 +78,7 @@ impl ExtImageCopyCaptureFrameV1 { Rc, AcquireSync, ReleaseSync, - ) -> Result, GfxError>, + ) -> Result, GfxError>, ) -> Result<(), FrameFailureReason> { let Some(ctx) = self.client.state.render_ctx.get() else { return Err(FrameFailureReason::BufferConstraints); @@ -183,7 +183,7 @@ impl ExtImageCopyCaptureFrameV1 { Rc, AcquireSync, ReleaseSync, - ) -> Result, GfxError>, + ) -> Result, GfxError>, ) { match self.try_copy(on, size, f) { Ok(()) => self.session.status.set(FrameStatus::Captured), diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 4089efe1..4d59924e 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -30,8 +30,8 @@ use { drm_feedback::DrmFeedback, fixed::Fixed, gfx_api::{ - AlphaMode, AsyncShmGfxTexture, BufferResv, BufferResvUser, GfxError, GfxStagingBuffer, - ReleaseSync, SampleRect, SyncFile, + AlphaMode, AsyncShmGfxTexture, BufferResv, BufferResvUser, FdSync, GfxError, + GfxStagingBuffer, ReleaseSync, SampleRect, }, ifs::{ color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1, @@ -215,7 +215,7 @@ impl NodeVisitorBase for SurfaceSendPreferredColorDescription { pub struct SurfaceBuffer { pub buffer: AttachedBuffer, - sync_files: SmallMap, + syncs: SmallMap, pub release_sync: ReleaseSync, release: Option, _surface_release: SmallVec<[SurfaceRelease; 1]>, @@ -223,14 +223,16 @@ pub struct SurfaceBuffer { impl Drop for SurfaceBuffer { fn drop(&mut self) { - let sync_files = self.sync_files.take(); + let syncs = self.syncs.take(); if let Some(release) = &mut self.release { - release.signal(Some(&sync_files)); + release.signal(Some(&syncs)); return; } if let Some(dmabuf) = &self.buffer.buf.client_dmabuf { - for (_, sync_file) in &sync_files { - if let Err(e) = dmabuf.import_sync_file(DMA_BUF_SYNC_READ, sync_file) { + for (_, sync) in &syncs { + if let Some(sf) = sync.get_sync_file() + && let Err(e) = dmabuf.import_sync_file(DMA_BUF_SYNC_READ, &sf) + { log::error!("Could not import sync file: {}", ErrorFmt(e)); } } @@ -245,8 +247,8 @@ impl Debug for SurfaceBuffer { } impl BufferResv for SurfaceBuffer { - fn set_sync_file(&self, user: BufferResvUser, sync_file: &SyncFile) { - self.sync_files.insert(user, sync_file.clone()); + fn set_sync(&self, user: BufferResvUser, sync: &FdSync) { + self.syncs.insert(user, sync.clone()); } } @@ -1231,7 +1233,7 @@ impl WlSurface { }; let surface_buffer = SurfaceBuffer { buffer, - sync_files: Default::default(), + syncs: Default::default(), release_sync, release: pending.release_point.take(), _surface_release: mem::take(&mut pending.surface_release), @@ -2263,7 +2265,7 @@ pub struct SyncobjRelease { } impl SyncobjRelease { - fn signal(&mut self, sync_files: Option<&SmallVec<[(BufferResvUser, SyncFile); 1]>>) { + fn signal(&mut self, syncs: Option<&SmallVec<[(BufferResvUser, FdSync); 1]>>) { if !self.committed { return; } @@ -2278,10 +2280,14 @@ impl SyncobjRelease { log::error!("Cannot signal release point because there is no syncobj context"); return; }; - if let Some(sync_files) = sync_files - && sync_files.is_not_empty() + if let Some(syncs) = syncs + && syncs.is_not_empty() { - let res = ctx.import_sync_files(&syncobj, self.point, sync_files.iter().map(|f| &f.1)); + let res = ctx.import_sync_files( + &syncobj, + self.point, + syncs.iter().flat_map(|f| f.1.get_sync_file()), + ); match res { Ok(_) => return, Err(e) => { diff --git a/src/it/test_gfx_api.rs b/src/it/test_gfx_api.rs index 5f37a322..24d0fc7c 100644 --- a/src/it/test_gfx_api.rs +++ b/src/it/test_gfx_api.rs @@ -5,11 +5,11 @@ use { cpu_worker::CpuWorker, format::{ARGB8888, Format, XRGB8888}, gfx_api::{ - AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, CopyTexture, FillRect, - FramebufferRect, GfxApi, GfxApiOpt, GfxBlendBuffer, GfxContext, GfxError, GfxFormat, - GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture, - GfxWriteModifier, PendingShmTransfer, ReleaseSync, ResetStatus, ShmGfxTexture, - ShmMemory, SyncFile, + AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, CopyTexture, FdSync, + FillRect, FramebufferRect, GfxApi, GfxApiOpt, GfxBlendBuffer, GfxContext, GfxError, + GfxFormat, GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer, + GfxTexture, GfxWriteModifier, PendingShmTransfer, ReleaseSync, ResetStatus, + ShmGfxTexture, ShmMemory, }, rect::{Rect, Region}, theme::Color, @@ -387,7 +387,7 @@ impl GfxFramebuffer for TestGfxFb { _region: &Region, _blend_buffer: Option<&Rc>, _blend_cd: &Rc, - ) -> Result, GfxError> { + ) -> Result, GfxError> { let fb_points = |width: i32, height: i32, rect: &FramebufferRect| { let points = rect.to_points(); let x1 = points[1][0]; diff --git a/src/state.rs b/src/state.rs index a063cef7..aa57a3f9 100644 --- a/src/state.rs +++ b/src/state.rs @@ -32,9 +32,9 @@ use { forker::ForkerProxy, format::Format, gfx_api::{ - AcquireSync, AlphaMode, BufferResv, GfxApi, GfxBlendBuffer, GfxContext, GfxError, - GfxFramebuffer, GfxTexture, PendingShmTransfer, ReleaseSync, STAGING_DOWNLOAD, - SampleRect, SyncFile, + AcquireSync, AlphaMode, BufferResv, FdSync, GfxApi, GfxBlendBuffer, GfxContext, + GfxError, GfxFramebuffer, GfxTexture, PendingShmTransfer, ReleaseSync, + STAGING_DOWNLOAD, SampleRect, }, gfx_apis::create_gfx_context, globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal}, @@ -1190,8 +1190,8 @@ impl State { render_hw_cursor: bool, blend_buffer: Option<&Rc>, blend_cd: &Rc, - ) -> Result, GfxError> { - let sync_file = fb.render_output( + ) -> Result, GfxError> { + let sync = fb.render_output( acquire_sync, release_sync, cd, @@ -1216,7 +1216,7 @@ impl State { 0, None, ); - Ok(sync_file) + Ok(sync) } pub fn perform_screencopy( @@ -1238,7 +1238,7 @@ impl State { size: Option<(i32, i32)>, transform: Transform, scale: Scale, - ) -> Result, GfxError> { + ) -> Result, GfxError> { let mut ops = vec![]; let mut renderer = Renderer { base: target.renderer_base(&mut ops, scale, target_transform), diff --git a/src/video/drm.rs b/src/video/drm.rs index 20ae55a5..8ff83a59 100644 --- a/src/video/drm.rs +++ b/src/video/drm.rs @@ -139,6 +139,8 @@ pub enum DrmError { Merge(#[source] OsError), #[error("Could not import a sync file into a syncobj")] ImportSyncFile(#[source] OsError), + #[error("Could not export a sync file")] + ExportSyncFile(#[source] OsError), #[error("Could not create a lease")] CreateLease(#[source] OsError), #[error("Could not drop DRM master")] diff --git a/src/video/drm/syncobj.rs b/src/video/drm/syncobj.rs index 694000ff..4450721f 100644 --- a/src/video/drm/syncobj.rs +++ b/src/video/drm/syncobj.rs @@ -15,7 +15,8 @@ use { 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, syncobj_create, + DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE, DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE, + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, sync_ioc_merge, syncobj_create, syncobj_destroy, syncobj_eventfd, syncobj_fd_to_handle, syncobj_handle_to_fd, syncobj_signal, syncobj_transfer, }, @@ -61,6 +62,10 @@ impl Syncobj { pub fn fd(&self) -> &Rc { &self.fd } + + pub fn id(&self) -> SyncobjId { + self.id + } } impl Drop for Syncobj { @@ -118,7 +123,7 @@ impl SyncobjCtx { pub fn create_syncobj(&self) -> Result { let handle = syncobj_create(self.inner.drm.raw(), 0).map_err(DrmError::CreateSyncobj)?; let handle = SyncobjHandle(handle); - let fd = syncobj_handle_to_fd(self.inner.drm.raw(), handle.0, 0); + let fd = syncobj_handle_to_fd(self.inner.drm.raw(), handle.0, 0, 0); if fd.is_err() { destroy(&self.inner.drm, handle); } @@ -138,6 +143,7 @@ impl SyncobjCtx { self.inner.drm.raw(), handle.0, DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE, + 0, ); destroy(&self.inner.drm, handle); fd.map_err(DrmError::ExportSyncobj) @@ -250,7 +256,46 @@ impl SyncobjCtx { } let dummy = self.get_dummy()?; import(0, self.get_handle(&dummy)?)?; - self.transfer(&dummy, SyncobjPoint(0), syncobj, point) + self.transfer(&dummy, SyncobjPoint(0), syncobj, point, 0) + } + + pub fn export_sync_file_blocking( + &self, + syncobj: &Syncobj, + point: SyncobjPoint, + ) -> Result { + let export = |flags: u32, handle: SyncobjHandle, point: SyncobjPoint| { + syncobj_handle_to_fd( + self.inner.drm.raw(), + handle.0, + DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE | flags, + point.0, + ) + .map(Rc::new) + .map(SyncFile) + }; + if self.supports_timeline_import() { + let res = export( + DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE, + self.get_handle(syncobj)?, + point, + ); + match res { + Ok(sf) => return Ok(sf), + Err(e) if e.0 == c::EINVAL => {} + Err(e) => return Err(DrmError::ExportSyncFile(e)), + } + } + let dummy = self.get_dummy()?; + let zero = SyncobjPoint(0); + self.transfer( + syncobj, + point, + &dummy, + zero, + DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT, + )?; + export(0, self.get_handle(&dummy)?, zero).map_err(DrmError::ExportSyncFile) } fn transfer( @@ -259,6 +304,7 @@ impl SyncobjCtx { src_point: SyncobjPoint, dst_syncobj: &Syncobj, dst_point: SyncobjPoint, + flags: u32, ) -> Result<(), DrmError> { let src_handle = self.get_handle(src_syncobj)?; let dst_handle = self.get_handle(dst_syncobj)?; @@ -268,7 +314,7 @@ impl SyncobjCtx { src_point.0, dst_handle.0, dst_point.0, - 0, + flags, ) .map_err(DrmError::TransferPoint) } diff --git a/src/video/drm/sys.rs b/src/video/drm/sys.rs index 0843d4fe..ba61b919 100644 --- a/src/video/drm/sys.rs +++ b/src/video/drm/sys.rs @@ -1223,6 +1223,7 @@ 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; +pub const DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE: u32 = 1 << 1; #[repr(C)] struct drm_syncobj_handle { @@ -1236,13 +1237,18 @@ struct drm_syncobj_handle { const DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD: u64 = drm_iowr::(0xC1); const DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE: u64 = drm_iowr::(0xC2); -pub fn syncobj_handle_to_fd(drm: c::c_int, handle: u32, flags: u32) -> Result { +pub fn syncobj_handle_to_fd( + drm: c::c_int, + handle: u32, + flags: u32, + point: u64, +) -> Result { let mut res = drm_syncobj_handle { handle, flags, fd: 0, pad: 0, - point: 0, + point, }; unsafe { ioctl(drm, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &mut res)?; @@ -1271,7 +1277,7 @@ pub fn syncobj_fd_to_handle( } // pub const DRM_SYNCOBJ_WAIT_FLAGS_WAIT_ALL: u32 = 1 << 0; -// pub const DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT: u32 = 1 << 1; +pub const DRM_SYNCOBJ_WAIT_FLAGS_WAIT_FOR_SUBMIT: u32 = 1 << 1; pub const DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE: u32 = 1 << 2; #[repr(C)]