fix(wayland): proper shm double buffering
This commit is contained in:
@@ -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(),
|
||||||
|
|||||||
@@ -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> {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
Reference in New Issue
Block a user