1
0
Fork 0
forked from wry/wry

wl_surface: handle buffer release automatically

This commit is contained in:
Julian Orth 2026-02-28 02:19:45 +01:00
parent 6bdd1ff6e7
commit 8f576f498e
5 changed files with 51 additions and 34 deletions

View file

@ -48,6 +48,19 @@ pub struct DmabufBufferParams {
tex_impossible: bool, tex_impossible: bool,
} }
pub struct AttachedBuffer {
pub send_release: bool,
pub buf: Rc<WlBuffer>,
}
impl Drop for AttachedBuffer {
fn drop(&mut self) {
if self.send_release && !self.buf.destroyed() {
self.buf.send_release();
}
}
}
pub struct WlBuffer { pub struct WlBuffer {
pub id: WlBufferId, pub id: WlBufferId,
destroyed: Cell<bool>, destroyed: Cell<bool>,
@ -507,7 +520,7 @@ impl WlBuffer {
Ok(()) Ok(())
} }
pub fn send_release(&self) { fn send_release(&self) {
self.client.event(Release { self_id: self.id }) self.client.event(Release { self_id: self.id })
} }
} }

View file

@ -35,7 +35,7 @@ use {
}, },
ifs::{ ifs::{
color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1, color_management::wp_color_management_surface_feedback_v1::WpColorManagementSurfaceFeedbackV1,
wl_buffer::WlBuffer, wl_buffer::AttachedBuffer,
wl_callback::WlCallback, wl_callback::WlCallback,
wl_seat::{ wl_seat::{
Dnd, NodeSeatState, SeatId, WlSeatGlobal, Dnd, NodeSeatState, SeatId, WlSeatGlobal,
@ -217,7 +217,7 @@ struct SurfaceBufferExplicitRelease {
} }
pub struct SurfaceBuffer { pub struct SurfaceBuffer {
pub buffer: Rc<WlBuffer>, pub buffer: AttachedBuffer,
sync_files: SmallMap<BufferResvUser, SyncFile, 1>, sync_files: SmallMap<BufferResvUser, SyncFile, 1>,
pub release_sync: ReleaseSync, pub release_sync: ReleaseSync,
release: Option<SurfaceBufferExplicitRelease>, release: Option<SurfaceBufferExplicitRelease>,
@ -227,7 +227,7 @@ impl Drop for SurfaceBuffer {
fn drop(&mut self) { fn drop(&mut self) {
let sync_files = self.sync_files.take(); let sync_files = self.sync_files.take();
if let Some(release) = &self.release { if let Some(release) = &self.release {
let Some(ctx) = self.buffer.client.state.render_ctx.get() else { let Some(ctx) = self.buffer.buf.client.state.render_ctx.get() else {
log::error!("Cannot signal release point because there is no render context"); log::error!("Cannot signal release point because there is no render context");
return; return;
}; };
@ -253,16 +253,13 @@ impl Drop for SurfaceBuffer {
} }
return; return;
} }
if let Some(dmabuf) = &self.buffer.client_dmabuf { if let Some(dmabuf) = &self.buffer.buf.client_dmabuf {
for (_, sync_file) in &sync_files { for (_, sync_file) in &sync_files {
if let Err(e) = dmabuf.import_sync_file(DMA_BUF_SYNC_READ, sync_file) { if let Err(e) = dmabuf.import_sync_file(DMA_BUF_SYNC_READ, sync_file) {
log::error!("Could not import sync file: {}", ErrorFmt(e)); log::error!("Could not import sync file: {}", ErrorFmt(e));
} }
} }
} }
if !self.buffer.destroyed() {
self.buffer.send_release();
}
} }
} }
@ -461,7 +458,7 @@ impl SurfaceExt for NoneSurfaceExt {
#[derive(Default)] #[derive(Default)]
struct PendingState { struct PendingState {
buffer: Option<Option<Rc<WlBuffer>>>, buffer: Option<Option<AttachedBuffer>>,
offset: (i32, i32), offset: (i32, i32),
opaque_region: Option<Option<Rc<Region>>>, opaque_region: Option<Option<Rc<Region>>>,
input_region: Option<Option<Rc<Region>>>, input_region: Option<Option<Rc<Region>>>,
@ -505,10 +502,6 @@ impl PendingState {
if next.buffer.is_some() { if next.buffer.is_some() {
if let Some((sync_obj, point)) = self.release_point.take() { if let Some((sync_obj, point)) = self.release_point.take() {
client.state.signal_point(&sync_obj, point); client.state.signal_point(&sync_obj, point);
} else if let Some(Some(prev)) = self.buffer.take() {
if !prev.destroyed() {
prev.send_release();
}
} }
} }
self.presentation_feedback.clear(); self.presentation_feedback.clear();
@ -1074,7 +1067,10 @@ impl WlSurfaceRequestHandler for WlSurface {
} else { } else {
None None
}; };
pending.buffer = Some(buf); pending.buffer = Some(buf.map(|buf| AttachedBuffer {
send_release: false,
buf,
}));
Ok(()) Ok(())
} }
@ -1122,6 +1118,11 @@ impl WlSurfaceRequestHandler for WlSurface {
fn commit(&self, _req: Commit, slf: &Rc<Self>) -> Result<(), Self::Error> { fn commit(&self, _req: Commit, slf: &Rc<Self>) -> Result<(), Self::Error> {
let ext = self.ext.get(); let ext = self.ext.get();
let pending = &mut *self.pending.borrow_mut(); let pending = &mut *self.pending.borrow_mut();
if let Some(Some(buffer)) = &mut pending.buffer
&& pending.release_point.is_none()
{
buffer.send_release = true;
}
self.verify_explicit_sync(pending)?; self.verify_explicit_sync(pending)?;
if ext.commit_requested(pending) == CommitAction::ContinueCommit { if ext.commit_requested(pending) == CommitAction::ContinueCommit {
self.commit_timeline.commit(slf, pending)?; self.commit_timeline.commit(slf, pending)?;
@ -1227,16 +1228,16 @@ impl WlSurface {
if let Some(buffer_change) = pending.buffer.take() { if let Some(buffer_change) = pending.buffer.take() {
buffer_changed = true; buffer_changed = true;
if let Some(buffer) = self.buffer.take() { if let Some(buffer) = self.buffer.take() {
old_raw_size = Some(buffer.buffer.rect); old_raw_size = Some(buffer.buffer.buf.rect);
} }
if let Some(buffer) = buffer_change { if let Some(buffer) = buffer_change {
if buffer.is_shm() { if buffer.buf.is_shm() {
self.shm_textures.flip(); self.shm_textures.flip();
self.shm_textures.front().damage.clear(); self.shm_textures.front().damage.clear();
} else { } else {
self.reset_shm_textures(); self.reset_shm_textures();
} }
buffer.update_texture_or_log(self, false); buffer.buf.update_texture_or_log(self, false);
let release_sync = match pending.explicit_sync { let release_sync = match pending.explicit_sync {
false => ReleaseSync::Implicit, false => ReleaseSync::Implicit,
true => ReleaseSync::Explicit, true => ReleaseSync::Explicit,
@ -1304,11 +1305,10 @@ impl WlSurface {
new_size = Some(size); new_size = Some(size);
} }
if let Some(buffer) = self.buffer.get() { if let Some(buffer) = self.buffer.get() {
let buf = &buffer.buffer.buf;
if new_size.is_none() { if new_size.is_none() {
let (mut width, mut height) = self let (mut width, mut height) =
.buffer_transform self.buffer_transform.get().maybe_swap(buf.rect.size());
.get()
.maybe_swap(buffer.buffer.rect.size());
let scale = self.buffer_scale.get(); let scale = self.buffer_scale.get();
if scale != 1 { if scale != 1 {
width = (width + scale - 1) / scale; width = (width + scale - 1) / scale;
@ -1316,14 +1316,12 @@ impl WlSurface {
} }
new_size = Some((width, height)); new_size = Some((width, height));
} }
if transform_changed || Some(buffer.buffer.rect) != old_raw_size { if transform_changed || Some(buf.rect) != old_raw_size {
let (x1, y1, x2, y2) = if self.src_rect.is_none() { let (x1, y1, x2, y2) = if self.src_rect.is_none() {
(0.0, 0.0, 1.0, 1.0) (0.0, 0.0, 1.0, 1.0)
} else { } else {
let (width, height) = self let (width, height) =
.buffer_transform self.buffer_transform.get().maybe_swap(buf.rect.size());
.get()
.maybe_swap(buffer.buffer.rect.size());
let width = width as f32; let width = width as f32;
let height = height as f32; let height = height as f32;
let x1 = buffer_points.x1 / width; let x1 = buffer_points.x1 / width;
@ -1342,7 +1340,7 @@ impl WlSurface {
y2, y2,
buffer_transform: self.buffer_transform.get(), buffer_transform: self.buffer_transform.get(),
}; };
let (buffer_width, buffer_height) = buffer.buffer.rect.size(); let (buffer_width, buffer_height) = buf.rect.size();
let (mut dst_width, mut dst_height) = new_size.unwrap_or_default(); let (mut dst_width, mut dst_height) = new_size.unwrap_or_default();
client_wire_scale_to_logical!(self.client, dst_width, dst_height); client_wire_scale_to_logical!(self.client, dst_width, dst_height);
let damage_matrix = DamageMatrix::new( let damage_matrix = DamageMatrix::new(
@ -1513,8 +1511,11 @@ impl WlSurface {
let matrix = self.damage_matrix.get(); let matrix = self.damage_matrix.get();
if let Some(buffer) = self.buffer.get() { if let Some(buffer) = self.buffer.get() {
for damage in &pending.buffer_damage { for damage in &pending.buffer_damage {
let mut damage = let mut damage = matrix.apply(
matrix.apply(pos.x1(), pos.y1(), damage.intersect(buffer.buffer.rect)); pos.x1(),
pos.y1(),
damage.intersect(buffer.buffer.buf.rect),
);
if let Some(bounds) = bounds { if let Some(bounds) = bounds {
damage = damage.intersect(bounds); damage = damage.intersect(bounds);
} }

View file

@ -598,6 +598,7 @@ fn schedule_async_upload(
let Some(Some(buf)) = &pending.buffer else { let Some(Some(buf)) = &pending.buffer else {
return Ok(None); return Ok(None);
}; };
let buf = &buf.buf;
let Some(WlBufferStorage::Shm { let Some(WlBufferStorage::Shm {
mem, mem,
stride, stride,
@ -698,6 +699,7 @@ struct CommitDataCollector {
impl CommitDataCollector { impl CommitDataCollector {
fn collect(&mut self, pending: &mut PendingState) { fn collect(&mut self, pending: &mut PendingState) {
if let Some(Some(buffer)) = &pending.buffer { if let Some(Some(buffer)) = &pending.buffer {
let buffer = &buffer.buf;
if buffer.is_shm() { if buffer.is_shm() {
self.shm_uploads += 1; self.shm_uploads += 1;
} }

View file

@ -468,10 +468,11 @@ impl Renderer<'_> {
tsize: (i32, i32), tsize: (i32, i32),
bounds: Option<&Rect>, bounds: Option<&Rect>,
) { ) {
let buf = &buffer.buffer.buf;
let alpha = surface.alpha(); let alpha = surface.alpha();
let cd = surface.color_description(); let cd = surface.color_description();
let alpha_mode = surface.alpha_mode(); let alpha_mode = surface.alpha_mode();
if let Some(tex) = buffer.buffer.get_texture(surface) { if let Some(tex) = buf.get_texture(surface) {
let mut opaque = surface.opaque(); let mut opaque = surface.opaque();
if !opaque && tex.format().has_alpha { if !opaque && tex.format().has_alpha {
opaque = self.bounds_are_opaque(x, y, bounds, surface); opaque = self.bounds_are_opaque(x, y, bounds, surface);
@ -492,7 +493,7 @@ impl Renderer<'_> {
&cd, &cd,
alpha_mode, alpha_mode,
); );
} else if let Some(color) = &buffer.buffer.color { } else if let Some(color) = &buf.color {
if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) { if let Some(rect) = Rect::new_sized(x, y, tsize.0, tsize.1) {
let rect = match bounds { let rect = match bounds {
None => rect, None => rect,

View file

@ -689,10 +689,10 @@ impl State {
for surface in client.data.objects.surfaces.lock().values() { for surface in client.data.objects.surfaces.lock().values() {
let had_shm_texture = surface.reset_shm_textures(); let had_shm_texture = surface.reset_shm_textures();
if let Some(buffer) = surface.buffer.get() { if let Some(buffer) = surface.buffer.get() {
let had_buffer_texture = let buf = &buffer.buffer.buf;
*updated_buffers.get(&Rc::as_ptr(&buffer.buffer)).unwrap(); let had_buffer_texture = *updated_buffers.get(&Rc::as_ptr(buf)).unwrap();
if had_shm_texture || had_buffer_texture { if had_shm_texture || had_buffer_texture {
buffer.buffer.update_texture_or_log(surface, true); buf.update_texture_or_log(surface, true);
} }
} }
} }