From e21a95fb769dbcc8e3ff33d8a84b24c90fde7cea Mon Sep 17 00:00:00 2001 From: Julian Orth Date: Tue, 6 Feb 2024 14:39:55 +0100 Subject: [PATCH] wayland: implement wp_single_pixel_buffer_manager_v1 --- src/globals.rs | 2 + src/ifs.rs | 1 + src/ifs/wl_buffer.rs | 37 +++++- src/ifs/wp_single_pixel_buffer_manager_v1.rs | 113 +++++++++++++++++++ src/renderer.rs | 8 +- src/theme.rs | 12 ++ wire/wp_single_pixel_buffer_manager_v1.txt | 12 ++ 7 files changed, 183 insertions(+), 2 deletions(-) create mode 100644 src/ifs/wp_single_pixel_buffer_manager_v1.rs create mode 100644 wire/wp_single_pixel_buffer_manager_v1.txt diff --git a/src/globals.rs b/src/globals.rs index 4ba88519..bdfb0594 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -22,6 +22,7 @@ use { wl_surface::xwayland_shell_v1::XwaylandShellV1Global, wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1Global, wp_presentation::WpPresentationGlobal, + wp_single_pixel_buffer_manager_v1::WpSinglePixelBufferManagerV1Global, wp_tearing_control_manager_v1::WpTearingControlManagerV1Global, wp_viewporter::WpViewporterGlobal, xdg_wm_base::XdgWmBaseGlobal, @@ -156,6 +157,7 @@ impl Globals { add_singleton!(ZwpPointerConstraintsV1Global); add_singleton!(XwaylandShellV1Global); add_singleton!(WpTearingControlManagerV1Global); + add_singleton!(WpSinglePixelBufferManagerV1Global); } pub fn add_backend_singletons(&self, backend: &Rc) { diff --git a/src/ifs.rs b/src/ifs.rs index c3d5ab02..ac406a85 100644 --- a/src/ifs.rs +++ b/src/ifs.rs @@ -30,6 +30,7 @@ pub mod wl_surface; pub mod wp_fractional_scale_manager_v1; pub mod wp_presentation; pub mod wp_presentation_feedback; +pub mod wp_single_pixel_buffer_manager_v1; pub mod wp_tearing_control_manager_v1; pub mod wp_viewporter; pub mod xdg_positioner; diff --git a/src/ifs/wl_buffer.rs b/src/ifs/wl_buffer.rs index 5926435f..6d4b117b 100644 --- a/src/ifs/wl_buffer.rs +++ b/src/ifs/wl_buffer.rs @@ -2,11 +2,12 @@ use { crate::{ client::{Client, ClientError}, clientmem::{ClientMem, ClientMemError, ClientMemOffset}, - format::Format, + format::{Format, ARGB8888}, gfx_api::{GfxError, GfxFramebuffer, GfxImage, GfxTexture}, leaks::Tracker, object::Object, rect::Rect, + theme::Color, utils::{ buffd::{MsgParser, MsgParserError}, clonecell::CloneCell, @@ -26,6 +27,7 @@ use { pub enum WlBufferStorage { Shm { mem: ClientMemOffset, stride: i32 }, Dmabuf(Rc), + Color(Color), } pub struct WlBuffer { @@ -114,6 +116,33 @@ impl WlBuffer { }) } + pub fn new_single_pixel( + id: WlBufferId, + client: &Rc, + r: u32, + g: u32, + b: u32, + a: u32, + ) -> Self { + Self { + id, + destroyed: Cell::new(false), + client: client.clone(), + rect: Rect::new_sized(0, 0, 1, 1).unwrap(), + format: ARGB8888, + dmabuf: None, + render_ctx_version: Cell::new(client.state.render_ctx_version.get()), + storage: RefCell::new(Some(WlBufferStorage::Color( + Color::from_u32_rgba_premultiplied(r, g, b, a), + ))), + width: 1, + height: 1, + texture: CloneCell::new(None), + tracker: Default::default(), + famebuffer: Default::default(), + } + } + pub fn handle_gfx_context_change(&self) { let ctx_version = self.client.state.render_ctx_version.get(); if self.render_ctx_version.replace(ctx_version) == ctx_version { @@ -168,6 +197,9 @@ impl WlBuffer { self.texture.set(Some(img.clone().to_texture()?)); } } + WlBufferStorage::Color(_) => { + // nothing + } } Ok(()) } @@ -187,6 +219,9 @@ impl WlBuffer { self.famebuffer.set(Some(img.clone().to_framebuffer()?)); } } + WlBufferStorage::Color(_) => { + // nothing + } } Ok(()) } diff --git a/src/ifs/wp_single_pixel_buffer_manager_v1.rs b/src/ifs/wp_single_pixel_buffer_manager_v1.rs new file mode 100644 index 00000000..5b71518e --- /dev/null +++ b/src/ifs/wp_single_pixel_buffer_manager_v1.rs @@ -0,0 +1,113 @@ +use { + crate::{ + client::{Client, ClientError}, + globals::{Global, GlobalName}, + ifs::wl_buffer::WlBuffer, + leaks::Tracker, + object::Object, + utils::buffd::{MsgParser, MsgParserError}, + wire::{wp_single_pixel_buffer_manager_v1::*, WpSinglePixelBufferManagerV1Id}, + }, + std::rc::Rc, + thiserror::Error, +}; + +pub struct WpSinglePixelBufferManagerV1Global { + name: GlobalName, +} + +impl WpSinglePixelBufferManagerV1Global { + pub fn new(name: GlobalName) -> Self { + Self { name } + } + + fn bind_( + self: Rc, + id: WpSinglePixelBufferManagerV1Id, + client: &Rc, + _version: u32, + ) -> Result<(), WpSinglePixelBufferManagerV1Error> { + let obj = Rc::new(WpSinglePixelBufferManagerV1 { + id, + client: client.clone(), + tracker: Default::default(), + }); + track!(client, obj); + client.add_client_obj(&obj)?; + Ok(()) + } +} + +global_base!( + WpSinglePixelBufferManagerV1Global, + WpSinglePixelBufferManagerV1, + WpSinglePixelBufferManagerV1Error +); + +impl Global for WpSinglePixelBufferManagerV1Global { + fn singleton(&self) -> bool { + true + } + + fn version(&self) -> u32 { + 1 + } +} + +simple_add_global!(WpSinglePixelBufferManagerV1Global); + +pub struct WpSinglePixelBufferManagerV1 { + pub id: WpSinglePixelBufferManagerV1Id, + pub client: Rc, + pub tracker: Tracker, +} + +impl WpSinglePixelBufferManagerV1 { + pub fn destroy( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), WpSinglePixelBufferManagerV1Error> { + let _req: Destroy = self.client.parse(self, parser)?; + self.client.remove_obj(self)?; + Ok(()) + } + + pub fn create_u32_rgba_buffer( + &self, + parser: MsgParser<'_, '_>, + ) -> Result<(), WpSinglePixelBufferManagerV1Error> { + let req: CreateU32RgbaBuffer = self.client.parse(self, parser)?; + let buffer = Rc::new(WlBuffer::new_single_pixel( + req.id, + &self.client, + req.r, + req.g, + req.b, + req.a, + )); + track!(self.client, buffer); + self.client.add_client_obj(&buffer)?; + Ok(()) + } +} + +object_base! { + self = WpSinglePixelBufferManagerV1; + + DESTROY => destroy, + CREATE_U32_RGBA_BUFFER => create_u32_rgba_buffer, +} + +impl Object for WpSinglePixelBufferManagerV1 {} + +simple_add_obj!(WpSinglePixelBufferManagerV1); + +#[derive(Debug, Error)] +pub enum WpSinglePixelBufferManagerV1Error { + #[error("Parsing failed")] + MsgParserError(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(WpSinglePixelBufferManagerV1Error, ClientError); +efrom!(WpSinglePixelBufferManagerV1Error, MsgParserError); diff --git a/src/renderer.rs b/src/renderer.rs index 2eabb3da..3b20dcb6 100644 --- a/src/renderer.rs +++ b/src/renderer.rs @@ -3,7 +3,7 @@ use { format::ARGB8888, gfx_api::{BufferPoints, GfxApiOpt}, ifs::{ - wl_buffer::WlBuffer, + wl_buffer::{WlBuffer, WlBufferStorage}, wl_callback::WlCallback, wl_surface::{ xdg_surface::XdgSurface, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1, WlSurface, @@ -400,6 +400,12 @@ impl Renderer<'_> { max_width, max_height, ); + } else if let Some(WlBufferStorage::Color(color)) = &*buffer.storage.borrow() { + if let Some(rect) = + Rect::new_sized(x, y, tsize.0.min(max_width), tsize.1.min(max_height)) + { + self.base.fill_boxes(&[rect], color); + } } } diff --git a/src/theme.rs b/src/theme.rs index f018cf63..575be67b 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -51,6 +51,18 @@ impl Color { } } + pub fn from_u32_rgba_premultiplied(r: u32, g: u32, b: u32, a: u32) -> Self { + fn to_f32(c: u32) -> f32 { + ((c as f64) / (u32::MAX as f64)) as f32 + } + Self { + r: to_f32(r), + g: to_f32(g), + b: to_f32(b), + a: to_f32(a), + } + } + pub fn from_rgba_straight(r: u8, g: u8, b: u8, a: u8) -> Self { let alpha = to_f32(a); Self { diff --git a/wire/wp_single_pixel_buffer_manager_v1.txt b/wire/wp_single_pixel_buffer_manager_v1.txt new file mode 100644 index 00000000..b6f508da --- /dev/null +++ b/wire/wp_single_pixel_buffer_manager_v1.txt @@ -0,0 +1,12 @@ +# requests + +msg destroy = 0 { +} + +msg create_u32_rgba_buffer = 1 { + id: id(wl_buffer), + r: u32, + g: u32, + b: u32, + a: u32, +}