1
0
Fork 0
forked from wry/wry

wl_surface: handle explicit sync release automatically

This commit is contained in:
Julian Orth 2026-02-28 02:47:22 +01:00
parent 8f576f498e
commit 382c0b6c71
3 changed files with 64 additions and 63 deletions

View file

@ -76,6 +76,7 @@ use {
object::{Object, Version},
rect::{DamageQueue, Rect, Region},
renderer::Renderer,
state::State,
tree::{
BeforeLatchListener, BeforeLatchResult, ContainerNode, FindTreeResult, FoundNode,
LatchListener, Node, NodeId, NodeLayerLink, NodeLocation, NodeVisitor, NodeVisitorBase,
@ -99,6 +100,7 @@ use {
},
ahash::AHashMap,
isnt::std_1::{primitive::IsntSliceExt, vec::IsntVecExt},
smallvec::SmallVec,
std::{
cell::{Cell, RefCell},
collections::hash_map::{Entry, OccupiedEntry},
@ -211,46 +213,18 @@ impl NodeVisitorBase for SurfaceSendPreferredColorDescription {
}
}
struct SurfaceBufferExplicitRelease {
sync_obj: Rc<SyncObj>,
point: SyncObjPoint,
}
pub struct SurfaceBuffer {
pub buffer: AttachedBuffer,
sync_files: SmallMap<BufferResvUser, SyncFile, 1>,
pub release_sync: ReleaseSync,
release: Option<SurfaceBufferExplicitRelease>,
release: Option<SyncObjRelease>,
}
impl Drop for SurfaceBuffer {
fn drop(&mut self) {
let sync_files = self.sync_files.take();
if let Some(release) = &self.release {
let Some(ctx) = self.buffer.buf.client.state.render_ctx.get() else {
log::error!("Cannot signal release point because there is no render context");
return;
};
let Some(ctx) = ctx.sync_obj_ctx() else {
log::error!("Cannot signal release point because there is no syncobj context");
return;
};
if sync_files.is_not_empty() {
let res = ctx.import_sync_files(
&release.sync_obj,
release.point,
sync_files.iter().map(|f| &f.1),
);
match res {
Ok(_) => return,
Err(e) => {
log::error!("Could not import sync files into sync obj: {}", ErrorFmt(e));
}
}
}
if let Err(e) = ctx.signal(&release.sync_obj, release.point) {
log::error!("Could not signal release point: {}", ErrorFmt(e));
}
if let Some(release) = &mut self.release {
release.signal(Some(&sync_files));
return;
}
if let Some(dmabuf) = &self.buffer.buf.client_dmabuf {
@ -478,7 +452,7 @@ struct PendingState {
layer_surface: Option<Box<PendingLayerSurfaceData>>,
subsurfaces: AHashMap<SubsurfaceId, AttachedSubsurfaceState>,
acquire_point: Option<(Rc<SyncObj>, SyncObjPoint)>,
release_point: Option<(Rc<SyncObj>, SyncObjPoint)>,
release_point: Option<SyncObjRelease>,
alpha_multiplier: Option<Option<f32>>,
explicit_sync: bool,
fifo_barrier_set: bool,
@ -499,11 +473,6 @@ impl PendingState {
fn merge(&mut self, next: &mut Self, client: &Rc<Client>) {
// discard state
if next.buffer.is_some() {
if let Some((sync_obj, point)) = self.release_point.take() {
client.state.signal_point(&sync_obj, point);
}
}
self.presentation_feedback.clear();
// overwrite state
@ -1123,6 +1092,9 @@ impl WlSurfaceRequestHandler for WlSurface {
{
buffer.send_release = true;
}
if let Some(release) = &mut pending.release_point {
release.committed = true;
}
self.verify_explicit_sync(pending)?;
if ext.commit_requested(pending) == CommitAction::ContinueCommit {
self.commit_timeline.commit(slf, pending)?;
@ -1242,15 +1214,11 @@ impl WlSurface {
false => ReleaseSync::Implicit,
true => ReleaseSync::Explicit,
};
let release = pending
.release_point
.take()
.map(|(sync_obj, point)| SurfaceBufferExplicitRelease { sync_obj, point });
let surface_buffer = SurfaceBuffer {
buffer,
sync_files: Default::default(),
release_sync,
release,
release: pending.release_point.take(),
};
self.buffer.set(Some(Rc::new(surface_buffer)));
} else {
@ -2268,3 +2236,49 @@ impl Drop for FrameRequest {
let _ = self.cb.client.remove_obj(&*self.cb);
}
}
pub struct SyncObjRelease {
state: Rc<State>,
committed: bool,
syncobj: Option<Rc<SyncObj>>,
point: SyncObjPoint,
}
impl SyncObjRelease {
fn signal(&mut self, sync_files: Option<&SmallVec<[(BufferResvUser, SyncFile); 1]>>) {
if !self.committed {
return;
}
let Some(sync_obj) = self.syncobj.take() else {
return;
};
let Some(ctx) = self.state.render_ctx.get() else {
log::error!("Cannot signal release point because there is no render context");
return;
};
let Some(ctx) = ctx.sync_obj_ctx() else {
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()
{
let res = ctx.import_sync_files(&sync_obj, self.point, sync_files.iter().map(|f| &f.1));
match res {
Ok(_) => return,
Err(e) => {
log::error!("Could not import sync files into sync obj: {}", ErrorFmt(e));
}
}
}
if let Err(e) = ctx.signal(&sync_obj, self.point) {
log::error!("Could not signal release point: {}", ErrorFmt(e));
}
}
}
impl Drop for SyncObjRelease {
fn drop(&mut self) {
self.signal(None);
}
}

View file

@ -1,7 +1,7 @@
use {
crate::{
client::{Client, ClientError},
ifs::wl_surface::WlSurface,
ifs::wl_surface::{SyncObjRelease, WlSurface},
leaks::Tracker,
object::{Object, Version},
video::drm::sync_obj::SyncObjPoint,
@ -66,7 +66,12 @@ impl WpLinuxDrmSyncobjSurfaceV1RequestHandler for WpLinuxDrmSyncobjSurfaceV1 {
fn set_release_point(&self, req: SetReleasePoint, _slf: &Rc<Self>) -> Result<(), Self::Error> {
let point = SyncObjPoint(req.point);
let timeline = self.client.lookup(req.timeline)?;
self.surface.pending.borrow_mut().release_point = Some((timeline.sync_obj.clone(), point));
self.surface.pending.borrow_mut().release_point = Some(SyncObjRelease {
state: self.client.state.clone(),
committed: false,
syncobj: Some(timeline.sync_obj.clone()),
point,
});
Ok(())
}
}