From b53f40e85f0feb12e84022dcddcb7e63402a9364 Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 10 Feb 2026 18:48:47 +0100 Subject: [PATCH] gfx: handle context change when buffer is attached to multiple surfaces --- src/client.rs | 4 ++++ src/ifs/wl_buffer.rs | 40 ++++++++++++++++++++-------------------- src/ifs/wl_surface.rs | 4 +++- src/state.rs | 25 +++++++++++++------------ 4 files changed, 40 insertions(+), 33 deletions(-) diff --git a/src/client.rs b/src/client.rs index 75f1ea6e..b676ea38 100644 --- a/src/client.rs +++ b/src/client.rs @@ -7,6 +7,7 @@ use { clm::{CL_CHANGED_DESTROYED, CL_CHANGED_NEW, ClMatcherChange}, }, ifs::{ + wl_buffer::WlBuffer, wl_display::WlDisplay, wl_registry::WlRegistry, wl_surface::{WlSurface, commit_timeline::CommitTimelines}, @@ -21,6 +22,7 @@ use { buffd::{MsgFormatter, MsgParser, MsgParserError, OutBufferSwapchain}, copyhashmap::{CopyHashMap, Locked}, errorfmt::ErrorFmt, + event_listener::EventSource, numcell::NumCell, pending_serial::PendingSerial, pid_info::{PidInfo, get_pid_info, get_socket_creds}, @@ -194,6 +196,7 @@ impl Clients { changed_properties: Default::default(), destroyed: Default::default(), acceptor: acceptor.clone(), + gfx_ctx_changed: Default::default(), }); track!(data, data); global.update_capabilities(&data, bounding_caps, set_bounding_caps_for_children); @@ -321,6 +324,7 @@ pub struct Client { pub changed_properties: Cell, pub destroyed: CopyHashMap>>>, pub acceptor: Rc, + pub gfx_ctx_changed: EventSource, } pub const NUM_CACHED_SERIAL_RANGES: usize = 64; diff --git a/src/ifs/wl_buffer.rs b/src/ifs/wl_buffer.rs index eda76c12..e7df2349 100644 --- a/src/ifs/wl_buffer.rs +++ b/src/ifs/wl_buffer.rs @@ -8,7 +8,7 @@ use { leaks::Tracker, object::{Object, Version}, rect::{Rect, Region}, - utils::{errorfmt::ErrorFmt, page_size::page_size}, + utils::{errorfmt::ErrorFmt, event_listener::EventListener, page_size::page_size}, video::{ LINEAR_MODIFIER, dmabuf::{DmaBuf, DmaBufPlane}, @@ -61,6 +61,7 @@ pub struct WlBuffer { pub color: Option<[u32; 4]>, width: i32, height: i32, + gfx_ctx_changed: EventListener, pub tracker: Tracker, } @@ -84,7 +85,7 @@ impl WlBuffer { shm: bool, color: Option<[u32; 4]>, ) -> Rc { - Rc::new(Self { + let slf = Rc::new_cyclic(|slf| Self { id, destroyed: Cell::new(false), client: client.clone(), @@ -98,7 +99,10 @@ impl WlBuffer { shm, tracker: Default::default(), color, - }) + gfx_ctx_changed: EventListener::new(slf.clone()), + }); + slf.gfx_ctx_changed.attach(&client.gfx_ctx_changed); + slf } pub fn new_dmabuf( @@ -210,22 +214,23 @@ impl WlBuffer { ) } - pub fn handle_gfx_context_change(&self, surface: Option<&WlSurface>) { + pub fn handle_gfx_context_change(&self) -> bool { let ctx_version = self.client.state.render_ctx_version.get(); - if self.render_ctx_version.replace(ctx_version) == ctx_version { - return; - } - let had_texture = self.reset_gfx_objects(surface); - if had_texture && let Some(surface) = surface { - self.update_texture_or_log(surface, true); - } - } - - fn reset_gfx_objects(&self, surface: Option<&WlSurface>) -> bool { + let up_to_date = self.render_ctx_version.replace(ctx_version) == ctx_version; let mut storage = self.storage.borrow_mut(); let Some(s) = &mut *storage else { return false; }; + if up_to_date { + let tex = match s { + WlBufferStorage::Shm { + dmabuf_buffer_params: DmabufBufferParams { tex, .. }, + .. + } => tex, + WlBufferStorage::Dmabuf { tex, .. } => tex, + }; + return tex.is_some(); + } let had_texture = match s { WlBufferStorage::Shm { dmabuf_buffer_params: @@ -241,13 +246,8 @@ impl WlBuffer { } => { host_buffer.take(); *host_buffer_impossible = *udmabuf_impossible; - let mut had_texture = tex.take().is_some(); + let had_texture = tex.take().is_some(); *tex_impossible = *udmabuf_impossible; - if let Some(s) = surface { - s.shm_staging.take(); - s.shm_textures.back().tex.take(); - had_texture |= s.shm_textures.front().tex.take().is_some(); - } return had_texture; } WlBufferStorage::Dmabuf { tex, .. } => tex.is_some(), diff --git a/src/ifs/wl_surface.rs b/src/ifs/wl_surface.rs index 4dd47217..343d78bb 100644 --- a/src/ifs/wl_surface.rs +++ b/src/ifs/wl_surface.rs @@ -1481,12 +1481,14 @@ impl WlSurface { Ok(()) } - pub fn reset_shm_textures(&self) { + pub fn reset_shm_textures(&self) -> bool { + let had_texture = self.shm_textures.front().tex.is_some(); self.shm_staging.take(); for tex in &*self.shm_textures { tex.tex.take(); tex.damage.clear(); } + had_texture } fn apply_damage(&self, pending: &PendingState) { diff --git a/src/state.rs b/src/state.rs index 85cdba2b..80fe12d3 100644 --- a/src/state.rs +++ b/src/state.rs @@ -133,7 +133,7 @@ use { }, xwayland::{self, XWaylandEvent}, }, - ahash::{AHashMap, AHashSet}, + ahash::AHashMap, bstr::ByteSlice, jay_config::{ PciId, @@ -676,19 +676,20 @@ impl State { } } Walker.visit_display(&self.root); + let mut updated_buffers = AHashMap::new(); for client in self.clients.clients.borrow_mut().values() { - let mut updated_buffers = AHashSet::new(); - for surface in client.data.objects.surfaces.lock().values() { - if let Some(buffer) = surface.buffer.get() { - updated_buffers.insert(buffer.buffer.id); - buffer.buffer.handle_gfx_context_change(Some(surface)); - } else { - surface.reset_shm_textures(); - } + updated_buffers.clear(); + for buffer in client.data.gfx_ctx_changed.iter() { + let had_buffer_texture = buffer.handle_gfx_context_change(); + updated_buffers.insert(buffer.id, had_buffer_texture); } - for buffer in client.data.objects.buffers.lock().values() { - if !updated_buffers.contains(&buffer.id) { - buffer.handle_gfx_context_change(None); + for surface in client.data.objects.surfaces.lock().values() { + let had_shm_texture = surface.reset_shm_textures(); + if let Some(buffer) = surface.buffer.get() { + let had_buffer_texture = *updated_buffers.get(&buffer.buffer.id).unwrap(); + if had_shm_texture || had_buffer_texture { + buffer.buffer.update_texture_or_log(surface, true); + } } } }