feat(wayland): broken buffer usage code

This commit is contained in:
Nova
2025-07-17 12:44:57 -07:00
parent 4426d14bc5
commit eca5bb4bf2
7 changed files with 64 additions and 96 deletions

View File

@@ -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<Buffer> = Registry::new();
#[derive(Debug)]
pub struct BufferUsage {
pub buffer: Weak<Buffer>,
message_sink: MessageSink,
}
impl BufferUsage {
pub fn new(client: &Client, buffer: &Arc<Buffer>) -> Arc<Self> {
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<Self> {
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(),

View File

@@ -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,

View File

@@ -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<Popup>),
}
#[derive(Debug, Clone)]
pub struct BufferState {
pub buffer: Arc<Buffer>,
pub usage: Arc<BufferUsage>,
}
#[derive(Debug, Clone)]
pub struct SurfaceState {
pub buffer: Option<Arc<Buffer>>,
pub buffer: Option<BufferState>,
pub density: f32,
pub geometry: Option<Geometry>,
pub min_size: Option<Vector2<u32>>,
@@ -121,10 +128,6 @@ impl Surface {
images: &mut Assets<Image>,
) {
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::<Buffer>(b));
self.state.lock().pending.buffer = buffer.and_then(|b| {
let buffer = client.get::<Buffer>(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, &current_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(())
}

View File

@@ -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<BufferUsage> = Registry::new();
/// Parameters for a shared memory buffer
pub struct DmabufBacking {
message_sink: Option<MessageSink>,
@@ -81,7 +88,10 @@ impl DmabufBacking {
&self,
dmatexes: &ImportedDmatexs,
images: &mut Assets<Image>,
usage: Arc<BufferUsage>,
) -> Option<Handle<Image>> {
IN_USE_DMABUFS.add_raw(usage);
info!("updating dmabuf tex");
self.pending_imported_dmatex
.lock()
.take()

View File

@@ -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<RenderDevice>) {
}
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();
}

View File

@@ -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(),

View File

@@ -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()