1
0
Fork 0
forked from wry/wry

gfx-api: add support for syncobj synchronization

This commit is contained in:
Julian Orth 2026-03-01 20:29:53 +01:00
parent 80a69ba7ef
commit 7e6facf4e3
20 changed files with 323 additions and 159 deletions

View file

@ -9,7 +9,7 @@ use {
drm_feedback::DrmFeedback, drm_feedback::DrmFeedback,
fixed::Fixed, fixed::Fixed,
format::Format, format::Format,
gfx_api::{GfxApi, GfxFramebuffer, SyncFile}, gfx_api::{FdSync, GfxApi, GfxFramebuffer},
ifs::{ ifs::{
wl_output::OutputId, wl_output::OutputId,
wl_seat::{ wl_seat::{
@ -186,7 +186,7 @@ pub trait HardwareCursorUpdate {
fn set_enabled(&mut self, enabled: bool); fn set_enabled(&mut self, enabled: bool);
fn get_buffer(&self) -> Rc<dyn GfxFramebuffer>; fn get_buffer(&self) -> Rc<dyn GfxFramebuffer>;
fn set_position(&mut self, x: i32, y: i32); fn set_position(&mut self, x: i32, y: i32);
fn swap_buffer(&mut self, sync_file: Option<SyncFile>); fn swap_buffer(&mut self, sync: Option<FdSync>);
fn size(&self) -> (i32, i32); fn size(&self) -> (i32, i32);
} }

View file

@ -11,8 +11,8 @@ use {
}, },
format::Format, format::Format,
gfx_api::{ gfx_api::{
AcquireSync, GfxBlendBuffer, GfxError, GfxFormat, GfxFramebuffer, GfxTexture, AcquireSync, FdSync, GfxBlendBuffer, GfxError, GfxFormat, GfxFramebuffer, GfxTexture,
GfxWriteModifier, ReleaseSync, SyncFile, needs_render_usage, GfxWriteModifier, ReleaseSync, needs_render_usage,
}, },
rect::{DamageQueue, Rect, Region}, rect::{DamageQueue, Rect, Region},
udmabuf::{Udmabuf, UdmabufError}, udmabuf::{Udmabuf, UdmabufError},
@ -120,15 +120,15 @@ pub enum RenderBufferError {
#[derive(Default)] #[derive(Default)]
pub struct RenderBufferCopy { pub struct RenderBufferCopy {
pub render_block: Option<SyncFile>, pub render_block: Option<FdSync>,
pub present_block: Option<SyncFile>, pub present_block: Option<FdSync>,
} }
impl RenderBufferCopy { impl RenderBufferCopy {
pub fn for_both(sf: Option<SyncFile>) -> Self { pub fn for_both(sync: Option<FdSync>) -> Self {
Self { Self {
render_block: sf.clone(), render_block: sync.clone(),
present_block: sf, present_block: sync,
} }
} }
} }
@ -138,12 +138,12 @@ impl RenderBuffer {
&self, &self,
cd: &Rc<ColorDescription>, cd: &Rc<ColorDescription>,
region: Option<&Region>, region: Option<&Region>,
sync_file: Option<SyncFile>, sync: Option<FdSync>,
) -> Result<RenderBufferCopy, RenderBufferError> { ) -> Result<RenderBufferCopy, RenderBufferError> {
match &self.prime { match &self.prime {
RenderBufferPrime::None => Ok(RenderBufferCopy { RenderBufferPrime::None => Ok(RenderBufferCopy {
render_block: None, render_block: None,
present_block: sync_file, present_block: sync,
}), }),
RenderBufferPrime::Sampling { RenderBufferPrime::Sampling {
dev_render_tex, dev_render_tex,
@ -157,7 +157,7 @@ impl RenderBuffer {
dev_render_tex, dev_render_tex,
cd, cd,
None, None,
AcquireSync::from_sync_file(sync_file), AcquireSync::from_fd_sync(sync),
ReleaseSync::None, ReleaseSync::None,
0, 0,
0, 0,
@ -175,7 +175,7 @@ impl RenderBuffer {
.. ..
} => { } => {
let render_block = render_copy let render_block = render_copy
.execute(sync_file.as_ref(), region) .execute(sync.as_ref(), region)
.map_err(RenderBufferError::CopyRenderToUdmabuf)?; .map_err(RenderBufferError::CopyRenderToUdmabuf)?;
let present_block = dev_copy let present_block = dev_copy
.execute(render_block.as_ref(), region) .execute(render_block.as_ref(), region)
@ -189,7 +189,7 @@ impl RenderBuffer {
| RenderBufferPrime::CopyDirectPush { | RenderBufferPrime::CopyDirectPush {
render_copy: copy, .. render_copy: copy, ..
} => copy } => copy
.execute(sync_file.as_ref(), region) .execute(sync.as_ref(), region)
.map_err(RenderBufferError::CopyRenderToDev) .map_err(RenderBufferError::CopyRenderToDev)
.map(RenderBufferCopy::for_both), .map(RenderBufferCopy::for_both),
} }
@ -201,8 +201,8 @@ impl RenderBuffer {
self.damage_queue.damage(&[rect]); self.damage_queue.damage(&[rect]);
} }
pub fn clear(&self, cd: &Rc<ColorDescription>) -> Result<Option<SyncFile>, RenderBufferError> { pub fn clear(&self, cd: &Rc<ColorDescription>) -> Result<Option<FdSync>, RenderBufferError> {
let sync_file = match &self.prime { let sync = match &self.prime {
RenderBufferPrime::None => { RenderBufferPrime::None => {
self.render self.render
.fb .fb
@ -222,14 +222,14 @@ impl RenderBuffer {
self.copy_to_dev(cd, None, sf)?.present_block self.copy_to_dev(cd, None, sf)?.present_block
} }
}; };
Ok(sync_file) Ok(sync)
} }
pub fn copy_to_new( pub fn copy_to_new(
&self, &self,
new: &Self, new: &Self,
cd: &Rc<ColorDescription>, cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, RenderBufferError> { ) -> Result<Option<FdSync>, RenderBufferError> {
let old = self; let old = self;
if (old.width, old.height) != (new.width, new.height) { if (old.width, old.height) != (new.width, new.height) {

View file

@ -240,13 +240,8 @@ impl MetalConnector {
// current PresentFb if present_fb is None, potentially mutating the fb that is // current PresentFb if present_fb is None, potentially mutating the fb that is
// currently being scanned out, which would render such a wait absurd. // currently being scanned out, which would render such a wait absurd.
self.perform_screencopies(&present_fb, &node, &cd); self.perform_screencopies(&present_fb, &node, &cd);
if let Some(sync_file) = self.cursor_sync_file.take() if let Some(sync) = self.cursor_sync.take() {
&& let Err(e) = self.state.ring.readable(&sync_file).await sync.signaled(&self.state.ring, "cursor").await;
{
log::error!(
"Could not wait for cursor sync file to complete: {}",
ErrorFmt(e)
);
} }
self.await_present_fb(present_fb.as_mut(), PresentFbWait::Scanout) self.await_present_fb(present_fb.as_mut(), PresentFbWait::Scanout)
.await; .await;
@ -353,19 +348,14 @@ impl MetalConnector {
W::Render => &mut fb.copy.render_block, W::Render => &mut fb.copy.render_block,
W::Scanout => &mut fb.copy.present_block, W::Scanout => &mut fb.copy.present_block,
}; };
let Some(sync_file) = field.take() else { let Some(sync) = field.take() else {
return; return;
}; };
if let Err(e) = self.state.ring.readable(&sync_file).await { let name = match wait {
let name = match wait { W::Render => "render",
W::Render => "render", W::Scanout => "scanout",
W::Scanout => "scanout", };
}; sync.signaled(&self.state.ring, name).await;
log::error!(
"Could not wait for primary {name} sync file to complete: {}",
ErrorFmt(e),
);
}
} }
fn try_async_flip(&self) -> bool { fn try_async_flip(&self) -> bool {
@ -554,13 +544,13 @@ impl MetalConnector {
self.state.present_hardware_cursor(node, &mut c); self.state.present_hardware_cursor(node, &mut c);
let swap_buffers = c.cursor_swap_buffer.is_some(); let swap_buffers = c.cursor_swap_buffer.is_some();
self.cursor_swap_buffer.set(swap_buffers); self.cursor_swap_buffer.set(swap_buffers);
if let Some(sf) = c.cursor_swap_buffer.take() { if let Some(sync) = c.cursor_swap_buffer.take() {
let sf = c let sync = c
.cursor_buffer .cursor_buffer
.copy_to_dev(cd, None, sf) .copy_to_dev(cd, None, sync)
.map_err(MetalError::CopyToDev)? .map_err(MetalError::CopyToDev)?
.present_block; .present_block;
self.cursor_sync_file.set(sf); self.cursor_sync.set(sync);
} }
let mut cursor_changed = false; let mut cursor_changed = false;
cursor_changed |= self.cursor_enabled.replace(c.cursor_enabled) != c.cursor_enabled; cursor_changed |= self.cursor_enabled.replace(c.cursor_enabled) != c.cursor_enabled;
@ -886,13 +876,13 @@ impl MetalConnector {
tex = buffer.render.tex.clone(); tex = buffer.render.tex.clone();
} }
Some(dsd) => { Some(dsd) => {
let sf = match &dsd.acquire_sync { let sync = match &dsd.acquire_sync {
AcquireSync::None => None, AcquireSync::None => None,
AcquireSync::Implicit => None, AcquireSync::Implicit => None,
AcquireSync::SyncFile { sync_file } => Some(sync_file.clone()), AcquireSync::FdSync(sync) => Some(sync.clone()),
AcquireSync::Unnecessary => None, AcquireSync::Unnecessary => None,
}; };
copy = RenderBufferCopy::for_both(sf); copy = RenderBufferCopy::for_both(sync);
fb = dsd.fb.clone(); fb = dsd.fb.clone();
tex = dsd.tex.clone(); tex = dsd.tex.clone();
} }

View file

@ -242,7 +242,7 @@ impl MetalDeviceTransaction {
let mut unused_crtcs = BinarySearchMap::<_, _, SIZE>::new(); let mut unused_crtcs = BinarySearchMap::<_, _, SIZE>::new();
let mut unused_planes = BinarySearchMap::<_, _, SIZE>::new(); let mut unused_planes = BinarySearchMap::<_, _, SIZE>::new();
let mut crtc_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; let slf = &mut self.common;
for (_, crtc) in &mut slf.crtcs { for (_, crtc) in &mut slf.crtcs {
crtc_planes.insert(crtc.obj.id, CrtcPlanes::default()); crtc_planes.insert(crtc.obj.id, CrtcPlanes::default());
@ -615,7 +615,7 @@ impl MetalDeviceTransaction {
new_buffer.clear(&cd) new_buffer.clear(&cd)
}; };
match res { match res {
Ok(sf) => sync_files.extend(sf), Ok(sf) => syncs.extend(sf),
Err(e) => { Err(e) => {
log::warn!("Could not clear new buffer: {}", ErrorFmt(e)); log::warn!("Could not clear new buffer: {}", ErrorFmt(e));
} }
@ -653,7 +653,7 @@ impl MetalDeviceTransaction {
match res { match res {
Ok(sf) => { Ok(sf) => {
buffer.locked.set(true); buffer.locked.set(true);
sync_files.extend(sf); syncs.extend(sf);
} }
Err(e) => { Err(e) => {
log::error!( log::error!(
@ -753,19 +753,8 @@ impl MetalDeviceTransaction {
plane.new = DrmPlaneState::default(); plane.new = DrmPlaneState::default();
} }
} }
for sf in sync_files { for sync in syncs {
let mut pollfd = c::pollfd { sync.signaled_blocking("transaction");
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)
);
}
} }
Ok(MetalDeviceTransactionWithDrmState { Ok(MetalDeviceTransactionWithDrmState {
common: self.common, common: self.common,

View file

@ -26,7 +26,7 @@ use {
drm_feedback::DrmFeedback, drm_feedback::DrmFeedback,
edid::{CtaDataBlock, Descriptor, EdidExtension}, edid::{CtaDataBlock, Descriptor, EdidExtension},
format::{Format, XRGB8888}, format::{Format, XRGB8888},
gfx_api::{GfxApi, GfxContext, GfxFramebuffer, SyncFile}, gfx_api::{FdSync, GfxApi, GfxContext, GfxFramebuffer},
ifs::{ ifs::{
wl_output::OutputId, wl_output::OutputId,
wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC, KIND_ZERO_COPY}, wp_presentation_feedback::{KIND_HW_COMPLETION, KIND_VSYNC, KIND_ZERO_COPY},
@ -534,7 +534,7 @@ pub struct MetalConnector {
pub cursor_enabled: Cell<bool>, pub cursor_enabled: Cell<bool>,
pub cursor_buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>, pub cursor_buffers: CloneCell<Option<Rc<[RenderBuffer; 2]>>>,
pub cursor_swap_buffer: Cell<bool>, pub cursor_swap_buffer: Cell<bool>,
pub cursor_sync_file: CloneCell<Option<SyncFile>>, pub cursor_sync: CloneCell<Option<FdSync>>,
pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>, pub drm_feedback: CloneCell<Option<Rc<DrmFeedback>>>,
pub scanout_buffers: RefCell<AHashMap<DmaBufId, DirectScanoutCache>>, pub scanout_buffers: RefCell<AHashMap<DmaBufId, DirectScanoutCache>>,
@ -565,7 +565,7 @@ pub struct MetalHardwareCursor {
} }
pub struct MetalHardwareCursorChange<'a> { pub struct MetalHardwareCursorChange<'a> {
pub cursor_swap_buffer: Option<Option<SyncFile>>, pub cursor_swap_buffer: Option<Option<FdSync>>,
pub cursor_enabled: bool, pub cursor_enabled: bool,
pub cursor_x: i32, pub cursor_x: i32,
pub cursor_y: i32, pub cursor_y: i32,
@ -603,8 +603,8 @@ impl HardwareCursorUpdate for MetalHardwareCursorChange<'_> {
self.cursor_y = y; self.cursor_y = y;
} }
fn swap_buffer(&mut self, sync_file: Option<SyncFile>) { fn swap_buffer(&mut self, sync: Option<FdSync>) {
self.cursor_swap_buffer = Some(sync_file); self.cursor_swap_buffer = Some(sync);
} }
fn size(&self) -> (i32, i32) { fn size(&self) -> (i32, i32) {
@ -1127,7 +1127,7 @@ fn create_connector(
cursor_changed: Cell::new(false), cursor_changed: Cell::new(false),
cursor_damage: Cell::new(false), cursor_damage: Cell::new(false),
cursor_swap_buffer: Cell::new(false), cursor_swap_buffer: Cell::new(false),
cursor_sync_file: Default::default(), cursor_sync: Default::default(),
drm_feedback: Default::default(), drm_feedback: Default::default(),
scanout_buffers: Default::default(), scanout_buffers: Default::default(),
active_framebuffer: Default::default(), active_framebuffer: Default::default(),

View file

@ -2,7 +2,7 @@ use {
crate::{ crate::{
async_engine::{AsyncEngine, SpawnedFuture}, async_engine::{AsyncEngine, SpawnedFuture},
format::{FORMATS, Format}, format::{FORMATS, Format},
gfx_api::SyncFile, gfx_api::{FdSync, SyncFile},
io_uring::IoUring, io_uring::IoUring,
rect::{Rect, Region}, rect::{Rect, Region},
utils::{ utils::{
@ -1296,9 +1296,9 @@ impl CopyDeviceCopy {
pub fn execute( pub fn execute(
&self, &self,
sync_file: Option<&SyncFile>, sync: Option<&FdSync>,
region: Option<&Region>, region: Option<&Region>,
) -> Result<Option<SyncFile>, CopyDeviceError> { ) -> Result<Option<FdSync>, CopyDeviceError> {
self.ensure_not_busy()?; self.ensure_not_busy()?;
let slf = &*self.inner; let slf = &*self.inner;
let tt = slf.tt; let tt = slf.tt;
@ -1656,7 +1656,9 @@ impl CopyDeviceCopy {
} }
let mut wait_semaphore = None; let mut wait_semaphore = None;
let mut wait_semaphores = ArrayVec::<_, 1>::new(); 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() { let semaphore = match slf.dev.semaphores.pop() {
Some(s) => s, Some(s) => s,
_ => slf.dev.create_semaphore()?, _ => slf.dev.create_semaphore()?,
@ -1703,7 +1705,7 @@ impl CopyDeviceCopy {
fence: Some(signal_fence), fence: Some(signal_fence),
}; };
slf.dev.submissions[tt].pending.push(pending); slf.dev.submissions[tt].pending.push(pending);
Ok(sync_file) Ok(sync_file.map(FdSync::SyncFile))
} }
} }

View file

@ -514,8 +514,8 @@ impl CursorUser {
&cd, &cd,
); );
match res { match res {
Ok(sync_file) => { Ok(sync) => {
hc.swap_buffer(sync_file); hc.swap_buffer(sync);
} }
Err(e) => { Err(e) => {
log::error!("Could not render hardware cursor: {}", ErrorFmt(e)); log::error!("Could not render hardware cursor: {}", ErrorFmt(e));

View file

@ -64,12 +64,10 @@ impl EventfdCache {
} }
impl Eventfd { impl Eventfd {
#[expect(dead_code)]
pub fn is_signaled(&self) -> bool { pub fn is_signaled(&self) -> bool {
self.signaled.get() self.signaled.get()
} }
#[cfg_attr(not(test), expect(dead_code))]
pub async fn signaled(&self) -> Result<(), IoUringError> { pub async fn signaled(&self) -> Result<(), IoUringError> {
if self.signaled.get() { if self.signaled.get() {
return Ok(()); return Ok(());
@ -79,7 +77,6 @@ impl Eventfd {
Ok(()) Ok(())
} }
#[expect(dead_code)]
pub fn signaled_blocking(&self) -> Result<(), OsError> { pub fn signaled_blocking(&self) -> Result<(), OsError> {
if self.signaled.get() { if self.signaled.get() {
return Ok(()); return Ok(());

View file

@ -5,16 +5,22 @@ use {
cpu_worker::CpuWorker, cpu_worker::CpuWorker,
cursor::Cursor, cursor::Cursor,
damage::DamageVisualizer, damage::DamageVisualizer,
eventfd_cache::Eventfd,
fixed::Fixed, fixed::Fixed,
format::Format, format::Format,
io_uring::{IoUring, IoUringError},
rect::{Rect, Region}, rect::{Rect, Region},
renderer::{Renderer, renderer_base::RendererBase}, renderer::{Renderer, renderer_base::RendererBase},
scale::Scale, scale::Scale,
state::State, state::State,
theme::Color, theme::Color,
tree::{Node, OutputNode, Transform}, tree::{Node, OutputNode, Transform},
utils::clonecell::UnsafeCellCloneSafe, utils::{clonecell::UnsafeCellCloneSafe, errorfmt::ErrorFmt},
video::{Modifier, dmabuf::DmaBuf, drm::syncobj::SyncobjCtx}, video::{
Modifier,
dmabuf::DmaBuf,
drm::syncobj::{Syncobj, SyncobjCtx, SyncobjPoint},
},
}, },
ahash::AHashMap, ahash::AHashMap,
indexmap::{IndexMap, IndexSet}, indexmap::{IndexMap, IndexSet},
@ -22,16 +28,17 @@ use {
linearize::Linearize, linearize::Linearize,
std::{ std::{
any::Any, any::Any,
cell::Cell, cell::{Cell, OnceCell},
error::Error, error::Error,
ffi::CString, ffi::CString,
fmt::{Debug, Formatter}, fmt::{Debug, Formatter},
ops::Deref, ops::Deref,
rc::Rc, rc::Rc,
slice,
sync::atomic::{AtomicU64, Ordering::Relaxed}, sync::atomic::{AtomicU64, Ordering::Relaxed},
}, },
thiserror::Error, thiserror::Error,
uapi::OwnedFd, uapi::{OwnedFd, c},
}; };
#[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Linearize)] #[derive(Copy, Clone, Debug, Hash, Eq, PartialEq, Linearize)]
@ -285,15 +292,24 @@ unsafe impl UnsafeCellCloneSafe for SyncFile {}
pub enum AcquireSync { pub enum AcquireSync {
None, None,
Implicit, Implicit,
SyncFile { sync_file: SyncFile }, FdSync(FdSync),
Unnecessary, Unnecessary,
} }
impl AcquireSync { impl AcquireSync {
pub fn from_sync_file(sync_file: Option<SyncFile>) -> Self { pub fn from_fd_sync(sync: Option<FdSync>) -> Self {
match sync_file { match sync {
None => Self::Unnecessary, 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 { let name = match self {
AcquireSync::None => "None", AcquireSync::None => "None",
AcquireSync::Implicit => "Implicit", AcquireSync::Implicit => "Implicit",
AcquireSync::SyncFile { .. } => "SyncFile", AcquireSync::FdSync(d) => return Debug::fmt(d, f),
AcquireSync::Unnecessary => "Unnecessary", AcquireSync::Unnecessary => "Unnecessary",
}; };
f.debug_struct(name).finish_non_exhaustive() f.debug_struct(name).finish_non_exhaustive()
@ -318,7 +334,7 @@ impl Debug for AcquireSync {
} }
pub trait BufferResv: Debug { 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)] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
@ -363,7 +379,7 @@ pub trait GfxFramebuffer: Debug {
region: &Region, region: &Region,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError>; ) -> Result<Option<FdSync>, GfxError>;
fn format(&self) -> &'static Format; fn format(&self) -> &'static Format;
@ -398,7 +414,7 @@ impl dyn GfxFramebuffer {
clear_cd: &Rc<LinearColorDescription>, clear_cd: &Rc<LinearColorDescription>,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
self.clone().render_with_region( self.clone().render_with_region(
acquire_sync, acquire_sync,
release_sync, release_sync,
@ -417,7 +433,7 @@ impl dyn GfxFramebuffer {
acquire_sync: AcquireSync, acquire_sync: AcquireSync,
release_sync: ReleaseSync, release_sync: ReleaseSync,
cd: &Rc<ColorDescription>, cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
self.clear_with( self.clear_with(
acquire_sync, acquire_sync,
release_sync, release_sync,
@ -434,7 +450,7 @@ impl dyn GfxFramebuffer {
cd: &Rc<ColorDescription>, cd: &Rc<ColorDescription>,
color: &Color, color: &Color,
color_cd: &Rc<LinearColorDescription>, color_cd: &Rc<LinearColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
self.render( self.render(
acquire_sync, acquire_sync,
release_sync, release_sync,
@ -472,7 +488,7 @@ impl dyn GfxFramebuffer {
release_sync: ReleaseSync, release_sync: ReleaseSync,
x: i32, x: i32,
y: i32, y: i32,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
let mut ops = vec![]; let mut ops = vec![];
let scale = Scale::from_int(1); let scale = Scale::from_int(1);
let mut renderer = self.renderer_base(&mut ops, scale, Transform::None); let mut renderer = self.renderer_base(&mut ops, scale, Transform::None);
@ -516,7 +532,7 @@ impl dyn GfxFramebuffer {
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
f: &mut dyn FnMut(&mut RendererBase), f: &mut dyn FnMut(&mut RendererBase),
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
let mut ops = vec![]; let mut ops = vec![];
let mut renderer = self.renderer_base(&mut ops, scale, Transform::None); let mut renderer = self.renderer_base(&mut ops, scale, Transform::None);
f(&mut renderer); f(&mut renderer);
@ -569,7 +585,7 @@ impl dyn GfxFramebuffer {
region: &Region, region: &Region,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
self.clone().render_with_region( self.clone().render_with_region(
acquire_sync, acquire_sync,
release_sync, release_sync,
@ -596,7 +612,7 @@ impl dyn GfxFramebuffer {
fill_black_in_grace_period: bool, fill_black_in_grace_period: bool,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
self.render_node( self.render_node(
acquire_sync, acquire_sync,
release_sync, release_sync,
@ -631,7 +647,7 @@ impl dyn GfxFramebuffer {
transform: Transform, transform: Transform,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
let pass = self.create_render_pass( let pass = self.create_render_pass(
node, node,
state, state,
@ -664,7 +680,7 @@ impl dyn GfxFramebuffer {
scale: Scale, scale: Scale,
transform: Transform, transform: Transform,
cd: &Rc<ColorDescription>, cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
let mut ops = vec![]; let mut ops = vec![];
let mut renderer = Renderer { let mut renderer = Renderer {
base: self.renderer_base(&mut ops, scale, transform), 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) { pub fn logical_size(physical_size: (i32, i32), transform: Transform) -> (i32, i32) {
transform.maybe_swap(physical_size) transform.maybe_swap(physical_size)
} }
pub struct ReservedSyncobjPoint {
pub ctx: Rc<SyncobjCtx>,
pub syncobj: Rc<Syncobj>,
pub point: SyncobjPoint,
pub sync_file: OnceCell<Option<SyncFile>>,
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<ReservedSyncobjPoint>),
}
unsafe impl UnsafeCellCloneSafe for FdSync {}
impl FdSync {
pub async fn try_signaled(&self, ring: &Rc<IoUring>) -> 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<IoUring>, 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()
}
}
}
}

View file

@ -69,8 +69,8 @@ use {
crate::{ crate::{
cmm::cmm_eotf::Eotf, cmm::cmm_eotf::Eotf,
gfx_api::{ gfx_api::{
AcquireSync, CopyTexture, FramebufferRect, GfxApiOpt, GfxContext, GfxError, GfxTexture, AcquireSync, CopyTexture, FdSync, FramebufferRect, GfxApiOpt, GfxContext, GfxError,
ReleaseSync, SyncFile, GfxTexture, ReleaseSync, SyncFile,
}, },
gfx_apis::gl::{ gfx_apis::gl::{
egl::image::EglImage, egl::image::EglImage,
@ -221,7 +221,7 @@ struct GlFillRect {
pub color: Color, pub color: Color,
} }
fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<SyncFile> { fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<FdSync> {
let mut state = fb.ctx.gl_state.borrow_mut(); let mut state = fb.ctx.gl_state.borrow_mut();
let state = &mut *state; let state = &mut *state;
let mut fill_rect = state.fill_rect.take(); let mut fill_rect = state.fill_rect.take();
@ -301,13 +301,14 @@ fn run_ops(fb: &Framebuffer, ops: &[GfxApiOpt]) -> Option<SyncFile> {
return None; return None;
} }
}; };
let file = FdSync::SyncFile(file);
let user = fb.ctx.buffer_resv_user; let user = fb.ctx.buffer_resv_user;
for op in ops { for op in ops {
if let GfxApiOpt::CopyTexture(ct) = op if let GfxApiOpt::CopyTexture(ct) = op
&& ct.release_sync == ReleaseSync::Explicit && ct.release_sync == ReleaseSync::Explicit
&& let Some(resv) = &ct.buffer_resv && let Some(resv) = &ct.buffer_resv
{ {
resv.set_sync_file(user, &file); resv.set_sync(user, &file);
} }
} }
return Some(file); return Some(file);
@ -417,9 +418,8 @@ fn render_texture(ctx: &GlRenderContext, tex: &CopyTexture) {
} }
fn handle_explicit_sync(ctx: &GlRenderContext, img: Option<&Rc<EglImage>>, sync: &AcquireSync) { fn handle_explicit_sync(ctx: &GlRenderContext, img: Option<&Rc<EglImage>>, sync: &AcquireSync) {
let sync_file = match sync { let Some(sync_file) = sync.get_sync_file() else {
AcquireSync::None | AcquireSync::Implicit | AcquireSync::Unnecessary => return, return;
AcquireSync::SyncFile { sync_file } => sync_file,
}; };
let sync_file = match uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0) { let sync_file = match uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0) {
Ok(s) => s, Ok(s) => s,

View file

@ -6,9 +6,9 @@ use {
}, },
format::Format, format::Format,
gfx_api::{ gfx_api::{
AcquireSync, AsyncShmGfxTextureCallback, GfxApiOpt, GfxBlendBuffer, GfxError, AcquireSync, AsyncShmGfxTextureCallback, FdSync, GfxApiOpt, GfxBlendBuffer, GfxError,
GfxFramebuffer, GfxInternalFramebuffer, GfxStagingBuffer, PendingShmTransfer, GfxFramebuffer, GfxInternalFramebuffer, GfxStagingBuffer, PendingShmTransfer,
ReleaseSync, ShmMemory, SyncFile, ReleaseSync, ShmMemory,
}, },
gfx_apis::gl::{ gfx_apis::gl::{
RenderError, RenderError,
@ -74,7 +74,7 @@ impl Framebuffer {
acquire_sync: AcquireSync, acquire_sync: AcquireSync,
ops: &[GfxApiOpt], ops: &[GfxApiOpt],
clear: Option<&Color>, clear: Option<&Color>,
) -> Result<Option<SyncFile>, RenderError> { ) -> Result<Option<FdSync>, RenderError> {
let gles = self.ctx.ctx.dpy.gles; let gles = self.ctx.ctx.dpy.gles;
self.ctx.ctx.with_current(|| { self.ctx.ctx.with_current(|| {
handle_explicit_sync(&self.ctx, self.gl.rb._img.as_ref(), &acquire_sync); 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); (gles.glBlendFunc)(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
} }
let fd = run_ops(self, ops); let sync = run_ops(self, ops);
if fd.is_none() { if sync.is_none() {
unsafe { unsafe {
(gles.glFinish)(); (gles.glFinish)();
} }
} }
Ok(fd) Ok(sync)
}) })
} }
} }
@ -115,7 +115,7 @@ impl GfxFramebuffer for Framebuffer {
_region: &Region, _region: &Region,
_blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, _blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
_blend_cd: &Rc<ColorDescription>, _blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
(*self) (*self)
.render(acquire_sync, ops, clear) .render(acquire_sync, ops, clear)
.map_err(|e| e.into()) .map_err(|e| e.into())

View file

@ -4,9 +4,9 @@ use {
format::Format, format::Format,
gfx_api::{ gfx_api::{
AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback,
AsyncShmGfxTextureTransferCancellable, GfxApiOpt, GfxBlendBuffer, GfxBuffer, GfxError, AsyncShmGfxTextureTransferCancellable, FdSync, GfxApiOpt, GfxBlendBuffer, GfxBuffer,
GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture, GfxError, GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer,
PendingShmTransfer, ReleaseSync, ShmGfxTexture, ShmMemory, SyncFile, GfxTexture, PendingShmTransfer, ReleaseSync, ShmGfxTexture, ShmMemory,
}, },
gfx_apis::vulkan::{ gfx_apis::vulkan::{
VulkanError, allocator::VulkanAllocation, device::VulkanDevice, VulkanError, allocator::VulkanAllocation, device::VulkanDevice,
@ -563,7 +563,7 @@ impl GfxFramebuffer for VulkanImage {
region: &Region, region: &Region,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
let mut blend_buffer = blend_buffer let mut blend_buffer = blend_buffer
.map(|b| b.clone().into_vk(&self.renderer.device.device)) .map(|b| b.clone().into_vk(&self.renderer.device.device))
.transpose()?; .transpose()?;

View file

@ -8,7 +8,7 @@ use {
}, },
cpu_worker::PendingJob, cpu_worker::PendingJob,
gfx_api::{ gfx_api::{
AcquireSync, AlphaMode, BufferResv, BufferResvUser, GfxApiOpt, GfxBlendBuffer, AcquireSync, AlphaMode, BufferResv, BufferResvUser, FdSync, GfxApiOpt, GfxBlendBuffer,
GfxFormat, GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile, GfxFormat, GfxTexture, GfxWriteModifier, ReleaseSync, SyncFile,
}, },
gfx_apis::vulkan::{ gfx_apis::vulkan::{
@ -1671,10 +1671,12 @@ impl VulkanRenderer {
} }
} }
} }
AcquireSync::SyncFile { sync_file } => { AcquireSync::FdSync(sync) => {
let fd = uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0) if let Some(sync_file) = sync.get_sync_file() {
.map_err(|e| VulkanError::Dupfd(e.into()))?; let fd = uapi::fcntl_dupfd_cloexec(sync_file.raw(), 0)
import_sync_file(fd)?; .map_err(|e| VulkanError::Dupfd(e.into()))?;
import_sync_file(fd)?;
}
} }
AcquireSync::Unnecessary => {} AcquireSync::Unnecessary => {}
} }
@ -1707,13 +1709,14 @@ impl VulkanRenderer {
Some(sync_file) => sync_file, Some(sync_file) => sync_file,
_ => return, _ => return,
}; };
let fd_sync = FdSync::SyncFile(sync_file.clone());
let import = let import =
|img: &VulkanImage, sync: ReleaseSync, resv: Option<Rc<dyn BufferResv>>, flag: u32| { |img: &VulkanImage, sync: ReleaseSync, resv: Option<Rc<dyn BufferResv>>, flag: u32| {
if sync == ReleaseSync::None { if sync == ReleaseSync::None {
return; return;
} }
if let Some(resv) = resv { 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 { } else if sync == ReleaseSync::Implicit {
if let VulkanImageMemory::DmaBuf(buf) = &img.ty if let VulkanImageMemory::DmaBuf(buf) = &img.ty
&& let Err(e) = buf.template.dmabuf.import_sync_file(flag, sync_file) && let Err(e) = buf.template.dmabuf.import_sync_file(flag, sync_file)
@ -1844,7 +1847,7 @@ impl VulkanRenderer {
region: &Region, region: &Region,
blend_buffer: Option<Rc<VulkanImage>>, blend_buffer: Option<Rc<VulkanImage>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, VulkanError> { ) -> Result<Option<FdSync>, VulkanError> {
zone!("execute"); zone!("execute");
let res = self.try_execute( let res = self.try_execute(
fb, fb,
@ -1870,7 +1873,7 @@ impl VulkanRenderer {
memory.ops_tmp.clear(); memory.ops_tmp.clear();
memory.release_sync_file.take() memory.release_sync_file.take()
}; };
res.map(|_| sync_file) res.map(|_| sync_file.map(FdSync::SyncFile))
} }
fn allocate_semaphore(&self) -> Result<Rc<VulkanSemaphore>, VulkanError> { fn allocate_semaphore(&self) -> Result<Rc<VulkanSemaphore>, VulkanError> {

View file

@ -3,8 +3,8 @@ use {
client::{Client, ClientError}, client::{Client, ClientError},
cmm::cmm_description::ColorDescription, cmm::cmm_description::ColorDescription,
gfx_api::{ gfx_api::{
AcquireSync, AsyncShmGfxTextureCallback, BufferResv, GfxError, GfxFramebuffer, AcquireSync, AsyncShmGfxTextureCallback, BufferResv, FdSync, GfxError, GfxFramebuffer,
GfxTexture, ReleaseSync, STAGING_DOWNLOAD, SyncFile, GfxTexture, ReleaseSync, STAGING_DOWNLOAD,
}, },
ifs::{ ifs::{
ext_image_capture_source_v1::ImageCaptureSource, ext_image_capture_source_v1::ImageCaptureSource,
@ -78,7 +78,7 @@ impl ExtImageCopyCaptureFrameV1 {
Rc<dyn GfxFramebuffer>, Rc<dyn GfxFramebuffer>,
AcquireSync, AcquireSync,
ReleaseSync, ReleaseSync,
) -> Result<Option<SyncFile>, GfxError>, ) -> Result<Option<FdSync>, GfxError>,
) -> Result<(), FrameFailureReason> { ) -> Result<(), FrameFailureReason> {
let Some(ctx) = self.client.state.render_ctx.get() else { let Some(ctx) = self.client.state.render_ctx.get() else {
return Err(FrameFailureReason::BufferConstraints); return Err(FrameFailureReason::BufferConstraints);
@ -183,7 +183,7 @@ impl ExtImageCopyCaptureFrameV1 {
Rc<dyn GfxFramebuffer>, Rc<dyn GfxFramebuffer>,
AcquireSync, AcquireSync,
ReleaseSync, ReleaseSync,
) -> Result<Option<SyncFile>, GfxError>, ) -> Result<Option<FdSync>, GfxError>,
) { ) {
match self.try_copy(on, size, f) { match self.try_copy(on, size, f) {
Ok(()) => self.session.status.set(FrameStatus::Captured), Ok(()) => self.session.status.set(FrameStatus::Captured),

View file

@ -30,8 +30,8 @@ use {
drm_feedback::DrmFeedback, drm_feedback::DrmFeedback,
fixed::Fixed, fixed::Fixed,
gfx_api::{ gfx_api::{
AlphaMode, AsyncShmGfxTexture, BufferResv, BufferResvUser, GfxError, GfxStagingBuffer, AlphaMode, AsyncShmGfxTexture, BufferResv, BufferResvUser, FdSync, GfxError,
ReleaseSync, SampleRect, SyncFile, GfxStagingBuffer, ReleaseSync, SampleRect,
}, },
ifs::{ ifs::{
color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1, color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1,
@ -215,7 +215,7 @@ impl NodeVisitorBase for SurfaceSendPreferredColorDescription {
pub struct SurfaceBuffer { pub struct SurfaceBuffer {
pub buffer: AttachedBuffer, pub buffer: AttachedBuffer,
sync_files: SmallMap<BufferResvUser, SyncFile, 1>, syncs: SmallMap<BufferResvUser, FdSync, 1>,
pub release_sync: ReleaseSync, pub release_sync: ReleaseSync,
release: Option<SyncobjRelease>, release: Option<SyncobjRelease>,
_surface_release: SmallVec<[SurfaceRelease; 1]>, _surface_release: SmallVec<[SurfaceRelease; 1]>,
@ -223,14 +223,16 @@ pub struct SurfaceBuffer {
impl Drop for SurfaceBuffer { impl Drop for SurfaceBuffer {
fn drop(&mut self) { fn drop(&mut self) {
let sync_files = self.sync_files.take(); let syncs = self.syncs.take();
if let Some(release) = &mut self.release { if let Some(release) = &mut self.release {
release.signal(Some(&sync_files)); release.signal(Some(&syncs));
return; return;
} }
if let Some(dmabuf) = &self.buffer.buf.client_dmabuf { if let Some(dmabuf) = &self.buffer.buf.client_dmabuf {
for (_, sync_file) in &sync_files { for (_, sync) in &syncs {
if let Err(e) = dmabuf.import_sync_file(DMA_BUF_SYNC_READ, sync_file) { 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)); log::error!("Could not import sync file: {}", ErrorFmt(e));
} }
} }
@ -245,8 +247,8 @@ impl Debug for SurfaceBuffer {
} }
impl BufferResv for SurfaceBuffer { impl BufferResv for SurfaceBuffer {
fn set_sync_file(&self, user: BufferResvUser, sync_file: &SyncFile) { fn set_sync(&self, user: BufferResvUser, sync: &FdSync) {
self.sync_files.insert(user, sync_file.clone()); self.syncs.insert(user, sync.clone());
} }
} }
@ -1231,7 +1233,7 @@ impl WlSurface {
}; };
let surface_buffer = SurfaceBuffer { let surface_buffer = SurfaceBuffer {
buffer, buffer,
sync_files: Default::default(), syncs: Default::default(),
release_sync, release_sync,
release: pending.release_point.take(), release: pending.release_point.take(),
_surface_release: mem::take(&mut pending.surface_release), _surface_release: mem::take(&mut pending.surface_release),
@ -2263,7 +2265,7 @@ pub struct SyncobjRelease {
} }
impl 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 { if !self.committed {
return; return;
} }
@ -2278,10 +2280,14 @@ impl SyncobjRelease {
log::error!("Cannot signal release point because there is no syncobj context"); log::error!("Cannot signal release point because there is no syncobj context");
return; return;
}; };
if let Some(sync_files) = sync_files if let Some(syncs) = syncs
&& sync_files.is_not_empty() && 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 { match res {
Ok(_) => return, Ok(_) => return,
Err(e) => { Err(e) => {

View file

@ -5,11 +5,11 @@ use {
cpu_worker::CpuWorker, cpu_worker::CpuWorker,
format::{ARGB8888, Format, XRGB8888}, format::{ARGB8888, Format, XRGB8888},
gfx_api::{ gfx_api::{
AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, CopyTexture, FillRect, AcquireSync, AsyncShmGfxTexture, AsyncShmGfxTextureCallback, CopyTexture, FdSync,
FramebufferRect, GfxApi, GfxApiOpt, GfxBlendBuffer, GfxContext, GfxError, GfxFormat, FillRect, FramebufferRect, GfxApi, GfxApiOpt, GfxBlendBuffer, GfxContext, GfxError,
GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer, GfxTexture, GfxFormat, GfxFramebuffer, GfxImage, GfxInternalFramebuffer, GfxStagingBuffer,
GfxWriteModifier, PendingShmTransfer, ReleaseSync, ResetStatus, ShmGfxTexture, GfxTexture, GfxWriteModifier, PendingShmTransfer, ReleaseSync, ResetStatus,
ShmMemory, SyncFile, ShmGfxTexture, ShmMemory,
}, },
rect::{Rect, Region}, rect::{Rect, Region},
theme::Color, theme::Color,
@ -387,7 +387,7 @@ impl GfxFramebuffer for TestGfxFb {
_region: &Region, _region: &Region,
_blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, _blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
_blend_cd: &Rc<ColorDescription>, _blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
let fb_points = |width: i32, height: i32, rect: &FramebufferRect| { let fb_points = |width: i32, height: i32, rect: &FramebufferRect| {
let points = rect.to_points(); let points = rect.to_points();
let x1 = points[1][0]; let x1 = points[1][0];

View file

@ -32,9 +32,9 @@ use {
forker::ForkerProxy, forker::ForkerProxy,
format::Format, format::Format,
gfx_api::{ gfx_api::{
AcquireSync, AlphaMode, BufferResv, GfxApi, GfxBlendBuffer, GfxContext, GfxError, AcquireSync, AlphaMode, BufferResv, FdSync, GfxApi, GfxBlendBuffer, GfxContext,
GfxFramebuffer, GfxTexture, PendingShmTransfer, ReleaseSync, STAGING_DOWNLOAD, GfxError, GfxFramebuffer, GfxTexture, PendingShmTransfer, ReleaseSync,
SampleRect, SyncFile, STAGING_DOWNLOAD, SampleRect,
}, },
gfx_apis::create_gfx_context, gfx_apis::create_gfx_context,
globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal}, globals::{Globals, GlobalsError, RemovableWaylandGlobal, WaylandGlobal},
@ -1190,8 +1190,8 @@ impl State {
render_hw_cursor: bool, render_hw_cursor: bool,
blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>, blend_buffer: Option<&Rc<dyn GfxBlendBuffer>>,
blend_cd: &Rc<ColorDescription>, blend_cd: &Rc<ColorDescription>,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
let sync_file = fb.render_output( let sync = fb.render_output(
acquire_sync, acquire_sync,
release_sync, release_sync,
cd, cd,
@ -1216,7 +1216,7 @@ impl State {
0, 0,
None, None,
); );
Ok(sync_file) Ok(sync)
} }
pub fn perform_screencopy( pub fn perform_screencopy(
@ -1238,7 +1238,7 @@ impl State {
size: Option<(i32, i32)>, size: Option<(i32, i32)>,
transform: Transform, transform: Transform,
scale: Scale, scale: Scale,
) -> Result<Option<SyncFile>, GfxError> { ) -> Result<Option<FdSync>, GfxError> {
let mut ops = vec![]; let mut ops = vec![];
let mut renderer = Renderer { let mut renderer = Renderer {
base: target.renderer_base(&mut ops, scale, target_transform), base: target.renderer_base(&mut ops, scale, target_transform),

View file

@ -139,6 +139,8 @@ pub enum DrmError {
Merge(#[source] OsError), Merge(#[source] OsError),
#[error("Could not import a sync file into a syncobj")] #[error("Could not import a sync file into a syncobj")]
ImportSyncFile(#[source] OsError), ImportSyncFile(#[source] OsError),
#[error("Could not export a sync file")]
ExportSyncFile(#[source] OsError),
#[error("Could not create a lease")] #[error("Could not create a lease")]
CreateLease(#[source] OsError), CreateLease(#[source] OsError),
#[error("Could not drop DRM master")] #[error("Could not drop DRM master")]

View file

@ -15,7 +15,8 @@ use {
DRM_SYNCOBJ_CREATE_SIGNALED, DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE, DRM_SYNCOBJ_CREATE_SIGNALED, DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_IMPORT_SYNC_FILE,
DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE, DRM_SYNCOBJ_FD_TO_HANDLE_FLAGS_TIMELINE,
DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE, 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_destroy, syncobj_eventfd, syncobj_fd_to_handle, syncobj_handle_to_fd,
syncobj_signal, syncobj_transfer, syncobj_signal, syncobj_transfer,
}, },
@ -61,6 +62,10 @@ impl Syncobj {
pub fn fd(&self) -> &Rc<OwnedFd> { pub fn fd(&self) -> &Rc<OwnedFd> {
&self.fd &self.fd
} }
pub fn id(&self) -> SyncobjId {
self.id
}
} }
impl Drop for Syncobj { impl Drop for Syncobj {
@ -118,7 +123,7 @@ impl SyncobjCtx {
pub fn create_syncobj(&self) -> Result<Syncobj, DrmError> { pub fn create_syncobj(&self) -> Result<Syncobj, DrmError> {
let handle = syncobj_create(self.inner.drm.raw(), 0).map_err(DrmError::CreateSyncobj)?; let handle = syncobj_create(self.inner.drm.raw(), 0).map_err(DrmError::CreateSyncobj)?;
let handle = SyncobjHandle(handle); 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() { if fd.is_err() {
destroy(&self.inner.drm, handle); destroy(&self.inner.drm, handle);
} }
@ -138,6 +143,7 @@ impl SyncobjCtx {
self.inner.drm.raw(), self.inner.drm.raw(),
handle.0, handle.0,
DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE, DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_EXPORT_SYNC_FILE,
0,
); );
destroy(&self.inner.drm, handle); destroy(&self.inner.drm, handle);
fd.map_err(DrmError::ExportSyncobj) fd.map_err(DrmError::ExportSyncobj)
@ -250,7 +256,46 @@ impl SyncobjCtx {
} }
let dummy = self.get_dummy()?; let dummy = self.get_dummy()?;
import(0, self.get_handle(&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<SyncFile, DrmError> {
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( fn transfer(
@ -259,6 +304,7 @@ impl SyncobjCtx {
src_point: SyncobjPoint, src_point: SyncobjPoint,
dst_syncobj: &Syncobj, dst_syncobj: &Syncobj,
dst_point: SyncobjPoint, dst_point: SyncobjPoint,
flags: u32,
) -> Result<(), DrmError> { ) -> Result<(), DrmError> {
let src_handle = self.get_handle(src_syncobj)?; let src_handle = self.get_handle(src_syncobj)?;
let dst_handle = self.get_handle(dst_syncobj)?; let dst_handle = self.get_handle(dst_syncobj)?;
@ -268,7 +314,7 @@ impl SyncobjCtx {
src_point.0, src_point.0,
dst_handle.0, dst_handle.0,
dst_point.0, dst_point.0,
0, flags,
) )
.map_err(DrmError::TransferPoint) .map_err(DrmError::TransferPoint)
} }

View file

@ -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_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_EXPORT_SYNC_FILE: u32 = 1 << 0;
pub const DRM_SYNCOBJ_HANDLE_TO_FD_FLAGS_TIMELINE: u32 = 1 << 1;
#[repr(C)] #[repr(C)]
struct drm_syncobj_handle { struct drm_syncobj_handle {
@ -1236,13 +1237,18 @@ struct drm_syncobj_handle {
const DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD: u64 = drm_iowr::<drm_syncobj_handle>(0xC1); const DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD: u64 = drm_iowr::<drm_syncobj_handle>(0xC1);
const DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE: u64 = drm_iowr::<drm_syncobj_handle>(0xC2); const DRM_IOCTL_SYNCOBJ_FD_TO_HANDLE: u64 = drm_iowr::<drm_syncobj_handle>(0xC2);
pub fn syncobj_handle_to_fd(drm: c::c_int, handle: u32, flags: u32) -> Result<OwnedFd, OsError> { pub fn syncobj_handle_to_fd(
drm: c::c_int,
handle: u32,
flags: u32,
point: u64,
) -> Result<OwnedFd, OsError> {
let mut res = drm_syncobj_handle { let mut res = drm_syncobj_handle {
handle, handle,
flags, flags,
fd: 0, fd: 0,
pad: 0, pad: 0,
point: 0, point,
}; };
unsafe { unsafe {
ioctl(drm, DRM_IOCTL_SYNCOBJ_HANDLE_TO_FD, &mut res)?; 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_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; pub const DRM_SYNCOBJ_WAIT_FLAGS_WAIT_AVAILABLE: u32 = 1 << 2;
#[repr(C)] #[repr(C)]