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/gfx_apis/vulkan/image.rs b/src/gfx_apis/vulkan/image.rs index 21dd6290..45da6861 100644 --- a/src/gfx_apis/vulkan/image.rs +++ b/src/gfx_apis/vulkan/image.rs @@ -101,7 +101,7 @@ pub enum QueueTransfer { pub enum VulkanImageMemory { DmaBuf(VulkanDmaBufImage), Internal(VulkanShmImage), - Blend(#[expect(dead_code)] VulkanAllocation), + Blend(VulkanAllocation), } pub struct VulkanDmaBufImage { diff --git a/src/gfx_apis/vulkan/renderer.rs b/src/gfx_apis/vulkan/renderer.rs index cdb88bcc..29a983a2 100644 --- a/src/gfx_apis/vulkan/renderer.rs +++ b/src/gfx_apis/vulkan/renderer.rs @@ -2117,6 +2117,18 @@ impl Debug for VulkanRenderer { impl VulkanImage { fn assert_device(&self, device: &Device) -> Result<(), VulkanError> { if self.renderer.device.device.handle() != device.handle() { + match &self.ty { + VulkanImageMemory::DmaBuf(v) => { + log::warn!("Mixed device use with dmabuf {}", v.template.dmabuf.id); + } + VulkanImageMemory::Internal(_v) => { + log::warn!("Mixed device use with internal image"); + } + VulkanImageMemory::Blend(_v) => { + log::warn!("Mixed device use with blend buffer"); + } + } + log::info!("Image address {:?}", ptr::from_ref(self)); return Err(VulkanError::MixedVulkanDeviceUse); } Ok(()) diff --git a/src/ifs/wl_buffer.rs b/src/ifs/wl_buffer.rs index 127c656c..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, } @@ -73,16 +74,18 @@ impl WlBuffer { self.shm } - pub fn new_dmabuf( + fn new( id: WlBufferId, client: &Rc, format: &'static Format, - dmabuf: DmaBuf, - img: &Rc, - ) -> Self { - let width = img.width(); - let height = img.height(); - Self { + width: i32, + height: i32, + dmabuf: Option, + storage: Option, + shm: bool, + color: Option<[u32; 4]>, + ) -> Rc { + let slf = Rc::new_cyclic(|slf| Self { id, destroyed: Cell::new(false), client: client.clone(), @@ -90,17 +93,40 @@ impl WlBuffer { format, width, height, - dmabuf: Some(dmabuf), + dmabuf, render_ctx_version: Cell::new(client.state.render_ctx_version.get()), - storage: RefCell::new(Some(WlBufferStorage::Dmabuf { + storage: RefCell::new(storage), + 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( + id: WlBufferId, + client: &Rc, + format: &'static Format, + dmabuf: DmaBuf, + img: &Rc, + ) -> Rc { + Self::new( + id, + client, + format, + img.width(), + img.height(), + Some(dmabuf), + Some(WlBufferStorage::Dmabuf { img: img.clone(), tex: None, fb: None, - })), - shm: false, - tracker: Default::default(), - color: None, - } + }), + false, + None, + ) } #[expect(clippy::too_many_arguments)] @@ -114,7 +140,7 @@ impl WlBuffer { format: &'static Format, mem: &Rc, udmabuf: Option<(&Rc, usize)>, - ) -> Result { + ) -> Result, WlBufferError> { let bytes = stride as u64 * height as u64; let required = bytes + offset as u64; if required > mem.len() as u64 { @@ -150,25 +176,21 @@ impl WlBuffer { tex_impossible: false, }, }; - Ok(Self { + Ok(Self::new( id, - destroyed: Cell::new(false), - client: client.clone(), - rect: Rect::new_sized_saturating(0, 0, width, height), + client, format, - dmabuf: None, - render_ctx_version: Cell::new(client.state.render_ctx_version.get()), - storage: RefCell::new(Some(WlBufferStorage::Shm { + width, + height, + None, + Some(WlBufferStorage::Shm { dmabuf_buffer_params, mem, stride, - })), - shm: true, - width, - height, - tracker: Default::default(), - color: None, - }) + }), + true, + None, + )) } pub fn new_single_pixel( @@ -178,40 +200,37 @@ impl WlBuffer { g: u32, b: u32, a: u32, - ) -> Self { - Self { + ) -> Rc { + Self::new( id, - destroyed: Cell::new(false), - client: client.clone(), - rect: Rect::new_sized_saturating(0, 0, 1, 1), - format: ARGB8888, - dmabuf: None, - render_ctx_version: Cell::new(client.state.render_ctx_version.get()), - storage: RefCell::new(None), - shm: false, - width: 1, - height: 1, - tracker: Default::default(), - color: Some([r, g, b, a]), - } + client, + ARGB8888, + 1, + 1, + None, + None, + false, + Some([r, g, b, a]), + ) } - 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: @@ -227,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_drm.rs b/src/ifs/wl_drm.rs index c26e4512..624cf89d 100644 --- a/src/ifs/wl_drm.rs +++ b/src/ifs/wl_drm.rs @@ -166,13 +166,7 @@ impl WlDrmRequestHandler for WlDrm { } } let img = ctx.dmabuf_img(&dmabuf)?; - let buffer = Rc::new(WlBuffer::new_dmabuf( - req.id, - &self.client, - format, - dmabuf, - &img, - )); + let buffer = WlBuffer::new_dmabuf(req.id, &self.client, format, dmabuf, &img); track!(self.client, buffer); self.client.add_client_obj(&buffer)?; Ok(()) diff --git a/src/ifs/wl_shm_pool.rs b/src/ifs/wl_shm_pool.rs index 8f24db96..fbfec69b 100644 --- a/src/ifs/wl_shm_pool.rs +++ b/src/ifs/wl_shm_pool.rs @@ -62,7 +62,7 @@ impl WlShmPoolRequestHandler for WlShmPool { if req.height < 0 || req.width < 0 || req.stride < 0 || req.offset < 0 { return Err(WlShmPoolError::NegativeParameters); } - let buffer = Rc::new(WlBuffer::new_shm( + let buffer = WlBuffer::new_shm( req.id, &self.client, req.offset as usize, @@ -72,7 +72,7 @@ impl WlShmPoolRequestHandler for WlShmPool { format, &self.mem.get(), None, - )?); + )?; track!(self.client, buffer); self.client.add_client_obj(&buffer)?; Ok(()) 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/ifs/wp_single_pixel_buffer_manager_v1.rs b/src/ifs/wp_single_pixel_buffer_manager_v1.rs index 007735e3..7a5b321c 100644 --- a/src/ifs/wp_single_pixel_buffer_manager_v1.rs +++ b/src/ifs/wp_single_pixel_buffer_manager_v1.rs @@ -76,14 +76,7 @@ impl WpSinglePixelBufferManagerV1RequestHandler for WpSinglePixelBufferManagerV1 req: CreateU32RgbaBuffer, _slf: &Rc, ) -> Result<(), Self::Error> { - let buffer = Rc::new(WlBuffer::new_single_pixel( - req.id, - &self.client, - req.r, - req.g, - req.b, - req.a, - )); + let buffer = WlBuffer::new_single_pixel(req.id, &self.client, req.r, req.g, req.b, req.a); track!(self.client, buffer); self.client.add_client_obj(&buffer)?; Ok(()) diff --git a/src/ifs/zwp_linux_buffer_params_v1.rs b/src/ifs/zwp_linux_buffer_params_v1.rs index f9e62719..269cd02c 100644 --- a/src/ifs/zwp_linux_buffer_params_v1.rs +++ b/src/ifs/zwp_linux_buffer_params_v1.rs @@ -125,7 +125,7 @@ impl ZwpLinuxBufferParamsV1 { ) .map(Rc::new) .map_err(ZwpLinuxBufferParamsV1Error::CreateClientMem)?; - Rc::new(WlBuffer::new_shm( + WlBuffer::new_shm( get_id()?, &self.parent.client, p.offset as usize, @@ -135,16 +135,10 @@ impl ZwpLinuxBufferParamsV1 { format.format, &client_mem, Some((&p.fd, size)), - )?) + )? } else { let img = ctx.dmabuf_img(&dmabuf)?; - Rc::new(WlBuffer::new_dmabuf( - get_id()?, - &self.parent.client, - format.format, - dmabuf, - &img, - )) + WlBuffer::new_dmabuf(get_id()?, &self.parent.client, format.format, dmabuf, &img) }; track!(self.parent.client, buffer); if buffer_id.is_some() { diff --git a/src/renderer/renderer_base.rs b/src/renderer/renderer_base.rs index 4d544998..962c18db 100644 --- a/src/renderer/renderer_base.rs +++ b/src/renderer/renderer_base.rs @@ -182,6 +182,9 @@ impl RendererBase<'_> { opaque: bool, cd: &Rc, ) { + // log::info!("rendering texture {:?}", std::ptr::from_ref(&**texture) as *const u8); + // log::info!("{:?}", backtrace::Backtrace::new()); + let mut texcoord = tpoints.unwrap_or_else(SampleRect::identity); let (twidth, theight) = if let Some(size) = tsize { 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); + } } } }