diff --git a/src/wayland/core/buffer.rs b/src/wayland/core/buffer.rs index 9437b30..a180578 100644 --- a/src/wayland/core/buffer.rs +++ b/src/wayland/core/buffer.rs @@ -1,58 +1,59 @@ -use std::sync::{Arc, atomic::AtomicBool}; - +use crate::wayland::Message; use crate::wayland::dmabuf::buffer_backing::DmabufBacking; -use crate::{ - core::registry::Registry, - wayland::{MessageSink, core::shm_buffer_backing::ShmBufferBacking, util::ClientExt}, -}; +use crate::wayland::{MessageSink, core::shm_buffer_backing::ShmBufferBacking, util::ClientExt}; use bevy::{ asset::{Assets, Handle}, image::Image, }; use bevy_dmabuf::import::ImportedDmatexs; use mint::Vector2; +use std::sync::{Arc, Weak}; pub use waynest::server::protocol::core::wayland::wl_buffer::*; use waynest::{ server::{Client, Dispatcher, Result}, wire::ObjectId, }; -pub static WL_BUFFER_REGISTRY: Registry = Registry::new(); +#[derive(Debug)] +pub struct BufferUsage { + pub buffer: Weak, + message_sink: MessageSink, +} +impl BufferUsage { + pub fn new(client: &Client, buffer: &Arc) -> Arc { + Arc::new(Self { + buffer: Arc::downgrade(buffer), + message_sink: client.message_sink(), + }) + } +} +impl Drop for BufferUsage { + fn drop(&mut self) { + if let Some(buffer) = self.buffer.upgrade() { + self.message_sink + .send(Message::ReleaseBuffer(buffer)) + .unwrap(); + } + } +} #[derive(Debug)] pub enum BufferBacking { Shm(ShmBufferBacking), Dmabuf(DmabufBacking), } -impl BufferBacking { - // Returns true if the buffer can be released immediately after texture update - pub fn can_release_after_update(&self) -> bool { - matches!(self, BufferBacking::Shm(_)) - } -} +impl BufferBacking {} #[derive(Debug, Dispatcher)] pub struct Buffer { pub id: ObjectId, backing: BufferBacking, - pub message_sink: MessageSink, - pub rendered: AtomicBool, } impl Buffer { #[tracing::instrument(level = "debug", skip_all)] pub fn new(client: &mut Client, id: ObjectId, backing: BufferBacking) -> Arc { - let buffer = client.insert( - id, - Self { - id, - backing, - message_sink: client.message_sink(), - rendered: AtomicBool::new(false), - }, - ); - WL_BUFFER_REGISTRY.add_raw(&buffer); - buffer + client.insert(id, Self { id, backing }) } /// Returns the tex if it was updated @@ -69,10 +70,6 @@ impl Buffer { } } - pub fn can_release_after_update(&self) -> bool { - self.backing.can_release_after_update() - } - pub fn is_transparent(&self) -> bool { match &self.backing { BufferBacking::Shm(backing) => backing.is_transparent(), diff --git a/src/wayland/core/shm_buffer_backing.rs b/src/wayland/core/shm_buffer_backing.rs index 5bcd27c..b1b798c 100644 --- a/src/wayland/core/shm_buffer_backing.rs +++ b/src/wayland/core/shm_buffer_backing.rs @@ -1,6 +1,5 @@ -use crate::wayland::{RENDER_DEVICE, vulkano_data::VULKANO_CONTEXT}; - use super::shm_pool::ShmPool; +use crate::wayland::{RENDER_DEVICE, vulkano_data::VULKANO_CONTEXT}; use bevy::{ asset::{Assets, Handle}, image::Image as BevyImage, @@ -159,6 +158,7 @@ impl ShmBufferBacking { }; let imported_texture = import_texture(bevy_render_dev, dmatex, DropCallback(None)).unwrap(); + Self { pool, offset, diff --git a/src/wayland/core/surface.rs b/src/wayland/core/surface.rs index f4f8bf2..bdee0cd 100644 --- a/src/wayland/core/surface.rs +++ b/src/wayland/core/surface.rs @@ -5,6 +5,7 @@ use crate::{ nodes::{drawable::model::ModelPart, items::panel::Geometry}, wayland::{ Message, MessageSink, + core::buffer::BufferUsage, util::{ClientExt, DoubleBuffer}, xdg::{popup::Popup, toplevel::Toplevel}, }, @@ -17,7 +18,7 @@ use bevy::{ use bevy_dmabuf::import::ImportedDmatexs; use mint::Vector2; use parking_lot::Mutex; -use std::sync::{Arc, OnceLock, atomic::Ordering}; +use std::sync::{Arc, OnceLock}; use waynest::{ server::{ Client, Dispatcher, Result, @@ -34,9 +35,15 @@ pub enum SurfaceRole { XDGPopup(Arc), } +#[derive(Debug, Clone)] +pub struct BufferState { + pub buffer: Arc, + pub usage: Arc, +} + #[derive(Debug, Clone)] pub struct SurfaceState { - pub buffer: Option>, + pub buffer: Option, pub density: f32, pub geometry: Option, pub min_size: Option>, @@ -121,10 +128,6 @@ impl Surface { images: &mut Assets, ) { let state_lock = self.state.lock(); - if state_lock.current().clean_lock.get().is_some() { - // then we don't need to reupload the texture - return; - } let Some(buffer) = state_lock.current().buffer.clone() else { return; }; @@ -145,11 +148,10 @@ impl Surface { }) }); - if let Some(new_tex) = buffer.update_tex(dmatexes, images) { - buffer.rendered.store(true, Ordering::Relaxed); + if let Some(new_tex) = buffer.buffer.update_tex(dmatexes, images) { let material = materials.get_mut(material).unwrap(); material.base_color_texture.replace(new_tex); - material.alpha_mode = if buffer.is_transparent() { + material.alpha_mode = if buffer.buffer.is_transparent() { AlphaMode::Premultiplied } else { AlphaMode::Opaque @@ -177,11 +179,7 @@ impl Surface { } self.pending_material_applications.clear(); } - #[tracing::instrument(level = "debug", skip_all)] - fn mark_dirty(&self) { - self.state.lock().pending.clean_lock = Default::default(); - } - #[tracing::instrument(level = "debug", skip_all)] + #[tracing::instrument("debug", skip_all)] pub fn current_state(&self) -> SurfaceState { self.state.lock().current().clone() } @@ -231,7 +229,13 @@ impl WlSurface for Surface { _x: i32, _y: i32, ) -> Result<()> { - self.state.lock().pending.buffer = buffer.and_then(|b| client.get::(b)); + self.state.lock().pending.buffer = buffer.and_then(|b| { + let buffer = client.get::(b)?; + Some(BufferState { + usage: BufferUsage::new(client, &buffer), + buffer, + }) + }); Ok(()) } @@ -246,8 +250,6 @@ impl WlSurface for Surface { _width: i32, _height: i32, ) -> Result<()> { - // should be more intelligent about this but for now just make it copy everything to gpu next frame again - self.mark_dirty(); Ok(()) } @@ -291,32 +293,7 @@ impl WlSurface for Surface { /// https://wayland.app/protocols/wayland#wl_surface:request:commit #[tracing::instrument(level = "debug", skip_all)] async fn commit(&self, _client: &mut Client, _sender_id: ObjectId) -> Result<()> { - { - let mut lock = self.state.lock(); - - // If we're getting a new buffer and the current one is DMA-BUF, release it - if let Some(new_buffer) = &lock.pending.buffer { - if let Some(current_buffer) = &lock.current().buffer { - // Don't release if it's the same buffer being reused - if !Arc::ptr_eq(new_buffer, current_buffer) - && !current_buffer.can_release_after_update() - { - let _ = self - .message_sink - .send(Message::ReleaseBuffer(current_buffer.clone())); - } - } - } - - let dirty = lock.current().clean_lock.get().is_none() - || lock.pending.clean_lock.take().is_none(); - lock.apply(); - - if !dirty { - let _ = lock.current().clean_lock.set(()); - } - } - + self.state.lock().apply(); let current_state = self.current_state(); let mut handlers = self.on_commit_handlers.lock(); handlers.retain(|f| (f)(self, ¤t_state)); @@ -358,8 +335,6 @@ impl WlSurface for Surface { _width: i32, _height: i32, ) -> Result<()> { - // we should upload only chunks to the gpu and do subimage copy but that's a lot rn so we won't - self.mark_dirty(); Ok(()) } diff --git a/src/wayland/dmabuf/buffer_backing.rs b/src/wayland/dmabuf/buffer_backing.rs index 0fcc276..7b13880 100644 --- a/src/wayland/dmabuf/buffer_backing.rs +++ b/src/wayland/dmabuf/buffer_backing.rs @@ -1,5 +1,8 @@ use super::buffer_params::BufferParams; -use crate::wayland::{MessageSink, RENDER_DEVICE}; +use crate::{ + core::registry::Registry, + wayland::{MessageSink, RENDER_DEVICE, core::buffer::BufferUsage}, +}; use bevy::{ asset::{Assets, Handle}, image::Image, @@ -12,8 +15,12 @@ use drm_fourcc::DrmFourcc; use mint::Vector2; use parking_lot::Mutex; use std::sync::{Arc, OnceLock}; +use tracing::info; use waynest::server::protocol::stable::linux_dmabuf_v1::zwp_linux_buffer_params_v1::Flags; +// clear this out on end frame, add to it whenever a commit with the surface with the buffer is present +const IN_USE_DMABUFS: Registry = Registry::new(); + /// Parameters for a shared memory buffer pub struct DmabufBacking { message_sink: Option, @@ -81,7 +88,10 @@ impl DmabufBacking { &self, dmatexes: &ImportedDmatexs, images: &mut Assets, + usage: Arc, ) -> Option> { + IN_USE_DMABUFS.add_raw(usage); + info!("updating dmabuf tex"); self.pending_imported_dmatex .lock() .take() diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index 6afbda7..1138434 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -21,15 +21,9 @@ use bevy::render::{Render, RenderApp}; use bevy::{asset::Assets, ecs::resource::Resource, image::Image}; use bevy_dmabuf::import::ImportedDmatexs; use cluFlock::{FlockLock, ToFlock}; -use core::{ - buffer::{Buffer, WL_BUFFER_REGISTRY}, - callback::Callback, - display::Display, - surface::WL_SURFACE_REGISTRY, -}; +use core::{buffer::Buffer, callback::Callback, display::Display, surface::WL_SURFACE_REGISTRY}; use mint::Vector2; use std::fs::File; -use std::sync::atomic::Ordering; use std::{ fs::{self, OpenOptions}, io::{self, ErrorKind}, @@ -307,14 +301,6 @@ fn init_render_device(dev: Res) { } fn early_frame() { - for buffer in WL_BUFFER_REGISTRY.get_valid_contents() { - if buffer.rendered.load(Ordering::Relaxed) { - let _ = buffer - .message_sink - .send(Message::ReleaseBuffer(buffer.clone())); - } - buffer.rendered.store(false, Ordering::Relaxed); - } for surface in WL_SURFACE_REGISTRY.get_valid_contents() { surface.frame_event(); } diff --git a/src/wayland/xdg/backend.rs b/src/wayland/xdg/backend.rs index 5e140ad..c33d0ba 100644 --- a/src/wayland/xdg/backend.rs +++ b/src/wayland/xdg/backend.rs @@ -46,7 +46,7 @@ impl Backend for XdgBackend { let size = surface_state .buffer - .map(|b| [b.size().x as u32, b.size().y as u32].into()) + .map(|b| [b.buffer.size().x as u32, b.buffer.size().y as u32].into()) .unwrap_or([0; 2].into()); let toplevel = ToplevelInfo { parent: self.toplevel().parent(), diff --git a/src/wayland/xdg/surface.rs b/src/wayland/xdg/surface.rs index b0006f0..54bfc29 100644 --- a/src/wayland/xdg/surface.rs +++ b/src/wayland/xdg/surface.rs @@ -93,7 +93,7 @@ impl XdgSurface for Surface { let has_valid_buffer = state .buffer .as_ref() - .is_some_and(|b| b.size().x > 0 && b.size().y > 0); + .is_some_and(|b| b.buffer.size().x > 0 && b.buffer.size().y > 0); let mut mapped_lock = toplevel.mapped.lock(); if mapped_lock.is_none() @@ -161,7 +161,7 @@ impl XdgSurface for Surface { // let has_valid_buffer = state // .buffer // .as_ref() - // .is_some_and(|b| b.size().x > 0 && b.size().y > 0); + // .is_some_and(|b| b.buffer.size().x > 0 && b.buffer.size().y > 0); // let mut mapped_lock = popup.mapped.lock(); // if mapped_lock.is_none()