feat(wayland): broken buffer usage code
This commit is contained in:
@@ -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(),
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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, ¤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(())
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user