fix(wayland): proper shm double buffering

This commit is contained in:
Nova
2025-07-10 06:32:44 -07:00
parent c1d3a4cbcb
commit 14544bfd3e
4 changed files with 70 additions and 33 deletions

View File

@@ -1,10 +1,12 @@
use std::sync::Arc; use std::sync::{Arc, atomic::AtomicBool};
#[cfg(feature = "dmabuf")] #[cfg(feature = "dmabuf")]
use crate::wayland::dmabuf::buffer_backing::DmabufBacking; use crate::wayland::dmabuf::buffer_backing::DmabufBacking;
use crate::{ use crate::{
core::registry::Registry, core::registry::Registry,
wayland::{GraphicsInfo, core::shm_buffer_backing::ShmBufferBacking}, wayland::{
GraphicsInfo, MessageSink, core::shm_buffer_backing::ShmBufferBacking, util::ClientExt,
},
}; };
use bevy::{ use bevy::{
asset::{Assets, Handle}, asset::{Assets, Handle},
@@ -36,11 +38,21 @@ impl BufferBacking {
pub struct Buffer { pub struct Buffer {
pub id: ObjectId, pub id: ObjectId,
backing: BufferBacking, backing: BufferBacking,
pub message_sink: MessageSink,
pub rendered: AtomicBool,
} }
impl Buffer { impl Buffer {
pub fn new(client: &mut Client, id: ObjectId, backing: BufferBacking) -> Arc<Self> { pub fn new(client: &mut Client, id: ObjectId, backing: BufferBacking) -> Arc<Self> {
let buffer = client.insert(id, Self { id, backing }); let buffer = client.insert(
id,
Self {
id,
backing,
message_sink: client.message_sink(),
rendered: AtomicBool::new(false),
},
);
BUFFER_REGISTRY.add_raw(&buffer); BUFFER_REGISTRY.add_raw(&buffer);
buffer buffer
} }
@@ -71,6 +83,14 @@ impl Buffer {
self.backing.can_release_after_update() self.backing.can_release_after_update()
} }
pub fn is_transparent(&self) -> bool {
match &self.backing {
BufferBacking::Shm(backing) => backing.is_transparent(),
#[cfg(feature = "dmabuf")]
BufferBacking::Dmabuf(backing) => backing.is_transparent(),
}
}
pub fn size(&self) -> Vector2<usize> { pub fn size(&self) -> Vector2<usize> {
match &self.backing { match &self.backing {
BufferBacking::Shm(backing) => backing.size(), BufferBacking::Shm(backing) => backing.size(),

View File

@@ -5,7 +5,8 @@ use bevy::{
render::render_resource::{Extent3d, TextureDimension, TextureFormat}, render::render_resource::{Extent3d, TextureDimension, TextureFormat},
}; };
use mint::Vector2; use mint::Vector2;
use std::sync::{Arc, OnceLock}; use parking_lot::Mutex;
use std::sync::Arc;
use waynest::server::protocol::core::wayland::wl_shm::Format; use waynest::server::protocol::core::wayland::wl_shm::Format;
/// Parameters for a shared memory buffer /// Parameters for a shared memory buffer
@@ -16,7 +17,7 @@ pub struct ShmBufferBacking {
stride: usize, stride: usize,
size: Vector2<usize>, size: Vector2<usize>,
format: Format, format: Format,
image: OnceLock<Handle<Image>>, image: Mutex<Handle<Image>>,
} }
impl ShmBufferBacking { impl ShmBufferBacking {
@@ -33,25 +34,24 @@ impl ShmBufferBacking {
stride, stride,
size, size,
format, format,
image: OnceLock::new(), image: Mutex::new(Handle::default()),
} }
} }
pub fn update_tex(&self, images: &mut Assets<Image>) -> Option<Handle<Image>> { pub fn update_tex(&self, images: &mut Assets<Image>) -> Option<Handle<Image>> {
let image = self.image.get_or_init(|| { let mut image_handle = self.image.lock();
let image = Image::new_fill( images.remove(image_handle.id());
Extent3d { let mut image = Image::new_fill(
width: self.size.x as u32, Extent3d {
height: self.size.y as u32, width: self.size.x as u32,
depth_or_array_layers: 1, height: self.size.y as u32,
}, depth_or_array_layers: 1,
TextureDimension::D2, },
&[255, 0, 255, 255], TextureDimension::D2,
TextureFormat::Rgba8UnormSrgb, &[255, 0, 255, 255],
RenderAssetUsages::all(), TextureFormat::Rgba8UnormSrgb,
); RenderAssetUsages::all(),
images.add(image) );
});
let src_data_lock = self.pool.data_lock(); let src_data_lock = self.pool.data_lock();
let mut src_cursor = self.offset; let mut src_cursor = self.offset;
@@ -64,7 +64,7 @@ impl ShmBufferBacking {
return None; return None;
} }
let dst_data = images.get_mut(image).unwrap().data.get_or_insert_with(|| { let dst_data = image.data.get_or_insert_with(|| {
let length = self.size.x * self.size.y * 4; let length = self.size.x * self.size.y * 4;
vec![255; length] vec![255; length]
}); });
@@ -93,7 +93,16 @@ impl ShmBufferBacking {
src_cursor += self.stride - (self.size.x * 4); src_cursor += self.stride - (self.size.x * 4);
} }
Some(image.clone()) *image_handle = images.add(image);
Some(image_handle.clone())
}
pub fn is_transparent(&self) -> bool {
match self.format {
Format::Xrgb8888 => false,
Format::Argb8888 => true,
_ => true,
}
} }
pub fn size(&self) -> Vector2<usize> { pub fn size(&self) -> Vector2<usize> {

View File

@@ -12,10 +12,11 @@ use crate::{
use bevy::{ use bevy::{
asset::{Assets, Handle}, asset::{Assets, Handle},
image::Image, image::Image,
render::alpha::AlphaMode,
}; };
use mint::Vector2; use mint::Vector2;
use parking_lot::Mutex; use parking_lot::Mutex;
use std::sync::{Arc, OnceLock}; use std::sync::{Arc, OnceLock, atomic::Ordering};
use waynest::{ use waynest::{
server::{ server::{
Client, Dispatcher, Result, Client, Dispatcher, Result,
@@ -139,16 +140,14 @@ impl Surface {
}); });
if let Some(new_tex) = buffer.update_tex(images) { if let Some(new_tex) = buffer.update_tex(images) {
materials buffer.rendered.store(true, Ordering::Relaxed);
.get_mut(material) let material = materials.get_mut(material).unwrap();
.unwrap() material.base_color_texture.replace(new_tex);
.base_color_texture material.alpha_mode = if buffer.is_transparent() {
.replace(new_tex); AlphaMode::Premultiplied
} else {
// For SHM buffers, we can release immediately after copying to GPU AlphaMode::Opaque
if buffer.can_release_after_update() { };
let _ = self.message_sink.send(Message::ReleaseBuffer(buffer));
}
} }
self.apply_surface_materials(); self.apply_surface_materials();

View File

@@ -24,6 +24,7 @@ use core::{
#[cfg(feature = "dmabuf")] #[cfg(feature = "dmabuf")]
use dmabuf::buffer_params::BufferParams; use dmabuf::buffer_params::BufferParams;
use mint::Vector2; use mint::Vector2;
use std::sync::atomic::Ordering;
use std::{ use std::{
fs::{self, OpenOptions}, fs::{self, OpenOptions},
io::{self, ErrorKind}, io::{self, ErrorKind},
@@ -285,6 +286,14 @@ impl Wayland {
pub fn early_frame(graphics_info: &mut GraphicsInfo) { pub fn early_frame(graphics_info: &mut GraphicsInfo) {
for buffer in BUFFER_REGISTRY.get_valid_contents() { for buffer in BUFFER_REGISTRY.get_valid_contents() {
if buffer.can_release_after_update() {
if buffer.rendered.load(Ordering::Relaxed) {
let _ = buffer
.message_sink
.send(Message::ReleaseBuffer(buffer.clone()));
}
buffer.rendered.store(false, Ordering::Relaxed);
}
buffer.init_tex(graphics_info); buffer.init_tex(graphics_info);
} }
for surface in WL_SURFACE_REGISTRY.get_valid_contents() { for surface in WL_SURFACE_REGISTRY.get_valid_contents() {