diff --git a/build.rs b/build.rs index 389d107b..30a98a6e 100644 --- a/build.rs +++ b/build.rs @@ -144,6 +144,11 @@ fn write_egl_procs(f: &mut W) -> anyhow::Result<()> { "()", &[("target", "GLenum"), ("image", "GLeglImageOES")][..], ), + ( + "glEGLImageTargetTexture2DOES", + "()", + &[("target", "GLenum"), ("image", "GLeglImageOES")][..], + ), ]; writeln!(f, "use std::ptr;")?; diff --git a/src/backend.rs b/src/backend.rs index 36170db6..79c507bc 100644 --- a/src/backend.rs +++ b/src/backend.rs @@ -39,6 +39,7 @@ pub enum ScrollAxis { #[derive(Debug)] pub enum SeatEvent { OutputPosition(OutputId, Fixed, Fixed), + #[allow(dead_code)] Motion(Fixed, Fixed), Button(u32, KeyState), Scroll(i32, ScrollAxis), diff --git a/src/client/mod.rs b/src/client/mod.rs index f4c18934..1c2e274d 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -25,6 +25,8 @@ use crate::ifs::wl_surface::xdg_surface::{XdgSurface, XdgSurfaceError, XdgSurfac use crate::ifs::wl_surface::{WlSurface, WlSurfaceError, WlSurfaceId}; use crate::ifs::xdg_positioner::{XdgPositioner, XdgPositionerError}; use crate::ifs::xdg_wm_base::{XdgWmBaseError, XdgWmBaseObj}; +use crate::ifs::zwp_linux_buffer_params_v1::{ZwpLinuxBufferParamsV1, ZwpLinuxBufferParamsV1Error}; +use crate::ifs::zwp_linux_dmabuf_v1::{ZwpLinuxDmabufV1Error, ZwpLinuxDmabufV1Obj}; use crate::object::{Object, ObjectId, WL_DISPLAY_ID}; use crate::state::State; use crate::utils::buffd::{BufFdError, MsgFormatter, MsgParser, MsgParserError}; @@ -39,6 +41,7 @@ use std::mem; use std::rc::Rc; use thiserror::Error; use uapi::{c, OwnedFd}; +use crate::ifs::wl_drm::{WlDrmError, WlDrmObj}; mod objects; mod tasks; @@ -135,6 +138,12 @@ pub enum ClientError { WlDataOfferError(#[source] Box), #[error("An error occurred in a `wl_data_source`")] WlDataSourceError(#[source] Box), + #[error("An error occurred in a `zwp_linx_dmabuf_v1`")] + ZwpLinuxDmabufV1Error(#[source] Box), + #[error("An error occurred in a `zwp_linx_buffer_params_v1`")] + ZwpLinuxBufferParamsV1Error(#[source] Box), + #[error("An error occurred in a `wl_drm`")] + WlDrmError(#[source] Box), } efrom!(ClientError, ParserError, MsgParserError); @@ -166,6 +175,13 @@ efrom!( efrom!(ClientError, WlDataDeviceError, WlDataDeviceError); efrom!(ClientError, WlDataSourceError, WlDataSourceError); efrom!(ClientError, WlDataOfferError, WlDataOfferError); +efrom!(ClientError, ZwpLinuxDmabufV1Error, ZwpLinuxDmabufV1Error); +efrom!( + ClientError, + ZwpLinuxBufferParamsV1Error, + ZwpLinuxBufferParamsV1Error +); +efrom!(ClientError, WlDrmError, WlDrmError); impl ClientError { fn peer_closed(&self) -> bool { @@ -340,7 +356,7 @@ pub struct Client { pub dispatch_frame_requests: AsyncQueue>, } -const MAX_PENDING_EVENTS: usize = 100; +const MAX_PENDING_EVENTS: usize = 10000; impl Client { pub fn invalid_request(&self, obj: &dyn Object, request: u32) { @@ -364,6 +380,10 @@ impl Client { } } + pub fn new_id>(&self) -> Result { + self.objects.id(self) + } + pub fn display(&self) -> Result, ClientError> { match self.objects.display.get() { Some(d) => Ok(d), @@ -538,6 +558,9 @@ simple_add_obj!(WlDataDeviceManagerObj); simple_add_obj!(WlDataDevice); simple_add_obj!(WlDataOffer); simple_add_obj!(WlDataSource); +simple_add_obj!(ZwpLinuxDmabufV1Obj); +simple_add_obj!(ZwpLinuxBufferParamsV1); +simple_add_obj!(WlDrmObj); macro_rules! dedicated_add_obj { ($ty:ty, $field:ident) => { diff --git a/src/client/objects.rs b/src/client/objects.rs index 452d356c..940ff0f2 100644 --- a/src/client/objects.rs +++ b/src/client/objects.rs @@ -64,8 +64,7 @@ impl Objects { self.buffers.clear(); } - #[allow(dead_code)] - fn id(&self, client_data: &Client) -> Result + pub fn id(&self, client_data: &Client) -> Result where ObjectId: Into, { diff --git a/src/drm/drm.rs b/src/drm/drm.rs index 9322faab..eb8d7c50 100644 --- a/src/drm/drm.rs +++ b/src/drm/drm.rs @@ -21,9 +21,11 @@ pub enum DrmError { GetDevice(#[source] std::io::Error), } +#[allow(dead_code)] const DRM_NODE_PRIMARY: c::c_int = 0; +#[allow(dead_code)] const DRM_NODE_CONTROL: c::c_int = 1; -const DRM_NODE_RENDER: c::c_int = 2; +pub const DRM_NODE_RENDER: c::c_int = 2; const DRM_NODE_MAX: c::c_int = 3; const DRM_BUS_PCI: c::c_int = 0; diff --git a/src/drm/gbm.rs b/src/drm/gbm.rs index f061eb78..d7cfea8b 100644 --- a/src/drm/gbm.rs +++ b/src/drm/gbm.rs @@ -23,11 +23,16 @@ pub enum GbmError { type Device = u8; type Bo = u8; +#[allow(dead_code)] pub const GBM_BO_USE_SCANOUT: u32 = 1 << 0; +#[allow(dead_code)] pub const GBM_BO_USE_CURSOR: u32 = 1 << 1; pub const GBM_BO_USE_RENDERING: u32 = 1 << 2; +#[allow(dead_code)] pub const GBM_BO_USE_WRITE: u32 = 1 << 3; +#[allow(dead_code)] pub const GBM_BO_USE_LINEAR: u32 = 1 << 4; +#[allow(dead_code)] pub const GBM_BO_USE_PROTECTED: u32 = 1 << 5; #[link(name = "gbm")] @@ -48,17 +53,19 @@ extern "C" { fn gbm_bo_get_plane_count(bo: *mut Bo) -> c::c_int; fn gbm_bo_get_width(bo: *mut Bo) -> u32; fn gbm_bo_get_height(bo: *mut Bo) -> u32; + #[allow(dead_code)] fn gbm_bo_get_stride(bo: *mut Bo) -> u32; fn gbm_bo_get_modifier(bo: *mut Bo) -> u64; fn gbm_bo_get_stride_for_plane(bo: *mut Bo, plane: c::c_int) -> u32; fn gbm_bo_get_fd_for_plane(bo: *mut Bo, plane: c::c_int) -> c::c_int; fn gbm_bo_get_offset(bo: *mut Bo, plane: c::c_int) -> u32; fn gbm_bo_get_format(bo: *mut Bo) -> u32; + #[allow(dead_code)] fn gbm_bo_get_bpp(bo: *mut Bo) -> u32; } pub struct GbmDevice { - drm: Drm, + _drm: Drm, dev: *mut Device, } @@ -67,7 +74,7 @@ struct BoHolder { } pub struct GbmBo { - bo: BoHolder, + _bo: BoHolder, dma: DmaBuf, } @@ -110,7 +117,7 @@ impl GbmDevice { if dev.is_null() { Err(GbmError::CreateDevice) } else { - Ok(Self { drm, dev }) + Ok(Self { _drm: drm, dev }) } } @@ -141,7 +148,7 @@ impl GbmDevice { } let bo = BoHolder { bo }; let dma = export_bo(bo.bo)?; - Ok(GbmBo { bo, dma }) + Ok(GbmBo { _bo: bo, dma }) } } } diff --git a/src/format.rs b/src/format.rs index f8c9a9f8..1d8fdf56 100644 --- a/src/format.rs +++ b/src/format.rs @@ -45,6 +45,7 @@ pub fn map_wayland_format_id(id: u32) -> u32 { } } +#[allow(dead_code)] pub static ARGB8888: &Format = &FORMATS[0]; pub static XRGB8888: &Format = &FORMATS[1]; diff --git a/src/globals.rs b/src/globals.rs index a1349d2a..cd941a3f 100644 --- a/src/globals.rs +++ b/src/globals.rs @@ -7,36 +7,42 @@ use crate::ifs::wl_seat::{WlSeatError, WlSeatGlobal}; use crate::ifs::wl_shm::WlShmError; use crate::ifs::wl_subcompositor::WlSubcompositorError; use crate::ifs::xdg_wm_base::XdgWmBaseError; +use crate::ifs::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Error; use crate::object::{Interface, ObjectId}; use crate::utils::copyhashmap::CopyHashMap; use crate::{ NumCell, State, WlCompositorGlobal, WlDataDeviceManagerGlobal, WlShmGlobal, - WlSubcompositorGlobal, XdgWmBaseGlobal, + WlSubcompositorGlobal, XdgWmBaseGlobal, ZwpLinuxDmabufV1Global, }; use std::fmt::{Display, Formatter}; use std::rc::Rc; use thiserror::Error; +use crate::ifs::wl_drm::{WlDrmError, WlDrmGlobal}; #[derive(Debug, Error)] pub enum GlobalError { #[error("The requested global {0} does not exist")] GlobalDoesNotExist(GlobalName), - #[error("An error occurred in a wl_compositor")] + #[error("An error occurred in a `wl_compositor` global")] WlCompositorError(#[source] Box), - #[error("An error occurred in a wl_shm")] + #[error("An error occurred in a `wl_shm` global")] WlShmError(#[source] Box), - #[error("An error occurred in a wl_subcompositor")] + #[error("An error occurred in a `wl_subcompositor` global")] WlSubcompositorError(#[source] Box), - #[error("An error occurred in a xdg_wm_base")] + #[error("An error occurred in a `xdg_wm_base` global")] XdgWmBaseError(#[source] Box), - #[error("An error occurred in a wl_output")] + #[error("An error occurred in a `wl_output` global")] WlOutputError(#[source] Box), - #[error("An error occurred in a wl_seat")] + #[error("An error occurred in a `wl_seat` global")] WlSeatError(#[source] Box), #[error("The output with id {0} does not exist")] OutputDoesNotExist(GlobalName), - #[error("An error occurred in a wl_data_device_manager")] + #[error("An error occurred in a `wl_data_device_manager` global")] WlDataDeviceManagerError(#[source] Box), + #[error("An error occurred in a `zwp_linux_dmabuf_v1` global")] + ZwpLinuxDmabufV1Error(#[source] Box), + #[error("An error occurred in a `wl_drm` global")] + WlDrmError(#[source] Box), } efrom!(GlobalError, WlCompositorError, WlCompositorError); @@ -45,6 +51,8 @@ efrom!(GlobalError, WlSubcompositorError, WlSubcompositorError); efrom!(GlobalError, XdgWmBaseError, XdgWmBaseError); efrom!(GlobalError, WlOutputError, WlOutputError); efrom!(GlobalError, WlSeatError, WlSeatError); +efrom!(GlobalError, ZwpLinuxDmabufV1Error, ZwpLinuxDmabufV1Error); +efrom!(GlobalError, WlDrmError, WlDrmError); efrom!( GlobalError, WlDataDeviceManagerError, @@ -211,6 +219,8 @@ simple_add_global!(WlShmGlobal); simple_add_global!(WlSubcompositorGlobal); simple_add_global!(XdgWmBaseGlobal); simple_add_global!(WlDataDeviceManagerGlobal); +simple_add_global!(ZwpLinuxDmabufV1Global); +simple_add_global!(WlDrmGlobal); macro_rules! dedicated_add_global { ($ty:ty, $field:ident) => { diff --git a/src/ifs/mod.rs b/src/ifs/mod.rs index ec8d0e17..14cf888b 100644 --- a/src/ifs/mod.rs +++ b/src/ifs/mod.rs @@ -6,6 +6,7 @@ pub mod wl_data_device_manager; pub mod wl_data_offer; pub mod wl_data_source; pub mod wl_display; +pub mod wl_drm; pub mod wl_output; pub mod wl_region; pub mod wl_registry; @@ -16,3 +17,5 @@ pub mod wl_subcompositor; pub mod wl_surface; pub mod xdg_positioner; pub mod xdg_wm_base; +pub mod zwp_linux_buffer_params_v1; +pub mod zwp_linux_dmabuf_v1; diff --git a/src/ifs/wl_buffer/mod.rs b/src/ifs/wl_buffer/mod.rs index b9b16044..d81ff5fe 100644 --- a/src/ifs/wl_buffer/mod.rs +++ b/src/ifs/wl_buffer/mod.rs @@ -6,7 +6,7 @@ use crate::format::Format; use crate::ifs::wl_surface::{WlSurface, WlSurfaceId}; use crate::object::{Interface, Object, ObjectId}; use crate::rect::Rect; -use crate::render::Texture; +use crate::render::{Image, Texture}; use crate::utils::buffd::MsgParser; use crate::utils::clonecell::CloneCell; use crate::utils::copyhashmap::CopyHashMap; @@ -19,14 +19,17 @@ const RELEASE: u32 = 0; id!(WlBufferId); +pub enum WlBufferStorage { + Shm { mem: ClientMemOffset, stride: i32 }, + Dmabuf(Rc), +} + pub struct WlBuffer { id: WlBufferId, pub client: Rc, - _offset: usize, pub rect: Rect, - stride: i32, format: &'static Format, - mem: ClientMemOffset, + storage: WlBufferStorage, pub texture: CloneCell>>, pub(super) surfaces: CopyHashMap>, width: i32, @@ -35,7 +38,29 @@ pub struct WlBuffer { impl WlBuffer { #[allow(clippy::too_many_arguments)] - pub fn new( + pub fn new_dmabuf( + id: WlBufferId, + client: &Rc, + format: &'static Format, + img: &Rc, + ) -> Self { + let width = img.width(); + let height = img.height(); + Self { + id, + client: client.clone(), + rect: Rect::new_sized(0, 0, width, height).unwrap(), + format, + width, + height, + texture: CloneCell::new(None), + surfaces: Default::default(), + storage: WlBufferStorage::Dmabuf(img.clone()), + } + } + + #[allow(clippy::too_many_arguments)] + pub fn new_shm( id: WlBufferId, client: &Rc, offset: usize, @@ -58,11 +83,9 @@ impl WlBuffer { Ok(Self { id, client: client.clone(), - _offset: offset, rect: Rect::new_sized(0, 0, width, height).unwrap(), - stride, format, - mem, + storage: WlBufferStorage::Shm { mem, stride }, width, height, texture: CloneCell::new(None), @@ -71,12 +94,21 @@ impl WlBuffer { } pub fn update_texture(&self) -> Result<(), WlBufferError> { - self.texture.set(None); - let ctx = self.client.state.render_ctx.get().unwrap(); - let tex = self.mem.access(|mem| { - ctx.shmem_texture(mem, self.format, self.width, self.height, self.stride) - })??; - self.texture.set(Some(tex)); + match &self.storage { + WlBufferStorage::Shm { mem, stride } => { + self.texture.set(None); + let ctx = self.client.state.render_ctx.get().unwrap(); + let tex = mem.access(|mem| { + ctx.shmem_texture(mem, self.format, self.width, self.height, *stride) + })??; + self.texture.set(Some(tex)); + } + WlBufferStorage::Dmabuf(img) => { + if self.texture.get().is_none() { + self.texture.set(Some(img.to_texture()?)); + } + } + } Ok(()) } diff --git a/src/ifs/wl_drm/mod.rs b/src/ifs/wl_drm/mod.rs new file mode 100644 index 00000000..11c7ff52 --- /dev/null +++ b/src/ifs/wl_drm/mod.rs @@ -0,0 +1,145 @@ +use std::ffi::CString; +use crate::client::{Client, DynEventFormatter}; +use crate::globals::{Global, GlobalName}; +use crate::object::{Interface, Object, ObjectId}; +use crate::utils::buffd::MsgParser; +use std::rc::Rc; +pub use types::*; + +mod types; + +id!(WlDrmId); + +const AUTHENTICATE: u32 = 0; +const CREATE_BUFFER: u32 = 1; +const CREATE_PLANAR_BUFFER: u32 = 2; + +const DEVICE: u32 = 0; +const FORMAT: u32 = 1; +const AUTHENTICATED: u32 = 2; +const CAPABILITIES: u32 = 3; + +const PRIME: u32 = 1; + +pub struct WlDrmGlobal { + name: GlobalName, +} + +impl WlDrmGlobal { + pub fn new(name: GlobalName) -> Self { + Self { name } + } + + fn bind_( + self: Rc, + id: WlDrmId, + client: &Rc, + version: u32, + ) -> Result<(), WlDrmError> { + let obj = Rc::new(WlDrmObj { + id, + client: client.clone(), + _version: version, + }); + client.add_client_obj(&obj)?; + if let Some(rc) = client.state.render_ctx.get() { + client.event(obj.device(&rc.render_node())); + client.event(obj.capabilities(PRIME)); + } + Ok(()) + } +} + +bind!(WlDrmGlobal); + +impl Global for WlDrmGlobal { + fn name(&self) -> GlobalName { + self.name + } + + fn singleton(&self) -> bool { + true + } + + fn interface(&self) -> Interface { + Interface::WlDrm + } + + fn version(&self) -> u32 { + 1 + } +} + +pub struct WlDrmObj { + id: WlDrmId, + pub client: Rc, + _version: u32, +} + +impl WlDrmObj { + fn device(self: &Rc, device: &Rc) -> DynEventFormatter { + Box::new(Device { + obj: self.clone(), + name: device.clone(), + }) + } + + fn authenticated(self: &Rc) -> DynEventFormatter { + Box::new(Authenticated { + obj: self.clone(), + }) + } + + fn capabilities(self: &Rc, value: u32) -> DynEventFormatter { + Box::new(Capabilities { + obj: self.clone(), + value, + }) + } + + fn authenticate(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), AuthenticateError> { + let _req: Authenticate = self.client.parse(&**self, parser)?; + self.client.event(self.authenticated()); + Ok(()) + } + + fn create_buffer(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), CreateBufferError> { + let _req: CreateBuffer = self.client.parse(&**self, parser)?; + Err(CreateBufferError::Unsupported) + } + + fn create_planar_buffer(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), CreatePlanarBufferError> { + let _req: CreatePlanarBuffer = self.client.parse(&**self, parser)?; + Err(CreatePlanarBufferError::Unsupported) + } + + fn handle_request_( + self: &Rc, + request: u32, + parser: MsgParser<'_, '_>, + ) -> Result<(), WlDrmError> { + match request { + AUTHENTICATE => self.authenticate(parser)?, + CREATE_BUFFER => self.create_buffer(parser)?, + CREATE_PLANAR_BUFFER => self.create_planar_buffer(parser)?, + _ => unreachable!(), + } + Ok(()) + } +} + +handle_request!(WlDrmObj); + +impl Object for WlDrmObj { + fn id(&self) -> ObjectId { + self.id.into() + } + + fn interface(&self) -> Interface { + Interface::WlDrm + } + + fn num_requests(&self) -> u32 { + CREATE_PLANAR_BUFFER + 1 + } +} diff --git a/src/ifs/wl_drm/types.rs b/src/ifs/wl_drm/types.rs new file mode 100644 index 00000000..9a58c70d --- /dev/null +++ b/src/ifs/wl_drm/types.rs @@ -0,0 +1,223 @@ +use std::ffi::CString; +use crate::client::{ClientError, EventFormatter, RequestParser}; +use crate::ifs::wl_buffer::WlBufferId; +use crate::object::Object; +use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; +use thiserror::Error; +use crate::ifs::wl_drm::{AUTHENTICATED, CAPABILITIES, DEVICE, FORMAT, WlDrmObj}; + +#[derive(Debug, Error)] +pub enum WlDrmError { + #[error("Could not process a `authenticate` request")] + AuthenticateError(#[from] AuthenticateError), + #[error("Could not process a `create_buffer` request")] + CreateBufferError(#[from] CreateBufferError), + #[error("Could not process a `create_planar_buffer` request")] + CreatePlanarBufferError(#[from] CreatePlanarBufferError), + #[error(transparent)] + ClientError(Box), +} +efrom!(WlDrmError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum AuthenticateError { + #[error("Parsing failed")] + ParseError(#[source] Box), +} +efrom!(AuthenticateError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum CreateBufferError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("This api is not supported")] + Unsupported, +} +efrom!(CreateBufferError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum CreatePlanarBufferError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("This api is not supported")] + Unsupported, +} +efrom!(CreatePlanarBufferError, ParseError, MsgParserError); + +pub(super) struct Authenticate { + id: u32, +} +impl RequestParser<'_> for Authenticate { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { id: parser.uint()? }) + } +} +impl Debug for Authenticate { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "authenticate(id: {})", self.id) + } +} + +pub(super) struct CreateBuffer { + pub id: WlBufferId, + pub name: u32, + pub width: i32, + pub height: i32, + pub stride: u32, + pub format: u32, +} +impl RequestParser<'_> for CreateBuffer { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + id: parser.object()?, + name: parser.uint()?, + width: parser.int()?, + height: parser.int()?, + stride: parser.uint()?, + format: parser.uint()?, + }) + } +} +impl Debug for CreateBuffer { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "create_buffer(id: {}, name: {}, width: {}, height: {}, stride: {}, format: {})", + self.id, self.name, self.width, self.height, self.stride, self.format, + ) + } +} + +pub(super) struct CreatePlanarBuffer { + id: WlBufferId, + name: u32, + width: i32, + height: i32, + format: u32, + offset0: i32, + stride0: i32, + offset1: i32, + stride1: i32, + offset2: i32, + stride2: i32, +} +impl RequestParser<'_> for CreatePlanarBuffer { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + id: parser.object()?, + name: parser.uint()?, + width: parser.int()?, + height: parser.int()?, + format: parser.uint()?, + offset0: parser.int()?, + stride0: parser.int()?, + offset1: parser.int()?, + stride1: parser.int()?, + offset2: parser.int()?, + stride2: parser.int()?, + }) + } +} +impl Debug for CreatePlanarBuffer { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "create_params(id: {}, name: {}, width: {}, height: {}, format: {}, offset0: {}, stride0: {}, offset1: {}, stride1: {}, offset2: {}, stride2: {})", + self.id, + self.name, + self.width, + self.height, + self.format, + self.offset0, + self.stride0, + self.offset1, + self.stride1, + self.offset2, + self.stride2, + ) + } +} + +pub(super) struct Device { + pub obj: Rc, + pub name: Rc, +} +impl EventFormatter for Device { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, DEVICE).string(self.name.as_bytes()); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Device { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "device(name: {:?})", self.name) + } +} + +pub(super) struct Format { + pub obj: Rc, + pub format: u32, +} +impl EventFormatter for Format { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, FORMAT) + .uint(self.format); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Format { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "format(format: {})", + self.format, + ) + } +} + +pub(super) struct Authenticated { + pub obj: Rc, +} +impl EventFormatter for Authenticated { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, AUTHENTICATED); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Authenticated { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "authenticated()", + ) + } +} + +pub(super) struct Capabilities { + pub obj: Rc, + pub value: u32, +} +impl EventFormatter for Capabilities { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, CAPABILITIES) + .uint(self.value); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Capabilities { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "capabilities(value: {})", + self.value, + ) + } +} diff --git a/src/ifs/wl_seat/mod.rs b/src/ifs/wl_seat/mod.rs index 26cf473b..70be1f1a 100644 --- a/src/ifs/wl_seat/mod.rs +++ b/src/ifs/wl_seat/mod.rs @@ -7,7 +7,7 @@ use crate::backend::{KeyState, OutputId, ScrollAxis, Seat, SeatEvent}; use crate::client::{Client, ClientId, DynEventFormatter}; use crate::fixed::Fixed; use crate::globals::{Global, GlobalName}; -use crate::ifs::wl_seat::wl_keyboard::{WlKeyboard, WlKeyboardId}; +use crate::ifs::wl_seat::wl_keyboard::{REPEAT_INFO_SINCE, WlKeyboard, WlKeyboardId}; use crate::ifs::wl_seat::wl_pointer::{WlPointer, WlPointerId, POINTER_FRAME_SINCE_VERSION}; use crate::ifs::wl_seat::wl_touch::WlTouch; use crate::ifs::wl_surface::xdg_surface::xdg_toplevel::{XdgToplevel, XdgToplevelId}; @@ -502,7 +502,9 @@ impl WlSeatObj { self.keyboards.set(req.id, p.clone()); self.client .event(p.keymap(wl_keyboard::XKB_V1, p.keymap_fd()?, self.global.layout_size)); - self.client.event(p.repeat_info(25, 250)); + if self.version >= REPEAT_INFO_SINCE { + self.client.event(p.repeat_info(25, 250)); + } Ok(()) } diff --git a/src/ifs/wl_seat/wl_keyboard/mod.rs b/src/ifs/wl_seat/wl_keyboard/mod.rs index 90decc17..c177ceea 100644 --- a/src/ifs/wl_seat/wl_keyboard/mod.rs +++ b/src/ifs/wl_seat/wl_keyboard/mod.rs @@ -18,6 +18,8 @@ const KEY: u32 = 3; const MODIFIERS: u32 = 4; const REPEAT_INFO: u32 = 5; +pub const REPEAT_INFO_SINCE: u32 = 4; + #[allow(dead_code)] const NO_KEYMAP: u32 = 0; pub(super) const XKB_V1: u32 = 1; diff --git a/src/ifs/wl_shm_pool/mod.rs b/src/ifs/wl_shm_pool/mod.rs index 597cdcdc..f7e4a116 100644 --- a/src/ifs/wl_shm_pool/mod.rs +++ b/src/ifs/wl_shm_pool/mod.rs @@ -49,7 +49,7 @@ impl WlShmPool { if req.height < 0 || req.width < 0 || req.stride < 0 || req.offset < 0 { return Err(CreateBufferError::NegativeParameters); } - let buffer = Rc::new(WlBuffer::new( + let buffer = Rc::new(WlBuffer::new_shm( req.id, &self.client, req.offset as usize, diff --git a/src/ifs/wl_surface/mod.rs b/src/ifs/wl_surface/mod.rs index 9fd10269..efc6c030 100644 --- a/src/ifs/wl_surface/mod.rs +++ b/src/ifs/wl_surface/mod.rs @@ -334,9 +334,7 @@ impl WlSurface { if let Some(buffer_change) = self.pending.buffer.take() { let mut old_size = None; let mut new_size = None; - log::info!("changing buffer"); if let Some(buffer) = self.buffer.take() { - log::info!("releasing buffer {}", buffer.id()); old_size = Some(buffer.rect); self.client.event(buffer.release()); buffer.surfaces.remove(&self.id); diff --git a/src/ifs/wl_surface/xdg_surface/mod.rs b/src/ifs/wl_surface/xdg_surface/mod.rs index 79acef79..d525a4b2 100644 --- a/src/ifs/wl_surface/xdg_surface/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/mod.rs @@ -53,6 +53,14 @@ struct PendingXdgSurfaceData { } trait XdgSurfaceExt { + fn initial_configure(self: Rc) { + // nothing + } + + fn pre_commit(self: Rc) { + // nothing + } + fn post_commit(self: Rc) { // nothing } @@ -243,6 +251,9 @@ impl SurfaceExt for XdgSurface { let rse = self.requested_serial.get(); if ase != Some(rse) { if ase.is_none() { + if let Some(ext) = self.ext.get() { + ext.initial_configure(); + } self.surface.client.event(self.configure(rse)); } // return CommitAction::AbortCommit; diff --git a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs index efb6fa90..4827d20f 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_popup/mod.rs @@ -25,37 +25,39 @@ id!(XdgPopupId); pub struct XdgPopup { id: XdgPopupId, node_id: PopupId, - pub(in super::super) surface: Rc, + pub(in super::super) xdg: Rc, pub(super) parent: CloneCell>>, } impl XdgPopup { - pub fn new(id: XdgPopupId, surface: &Rc, parent: Option<&Rc>) -> Self { + pub fn new(id: XdgPopupId, xdg: &Rc, parent: Option<&Rc>) -> Self { Self { id, - node_id: surface.surface.client.state.node_ids.next(), - surface: surface.clone(), + node_id: xdg.surface.client.state.node_ids.next(), + xdg: xdg.clone(), parent: CloneCell::new(parent.cloned()), } } fn destroy(&self, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { - let _req: Destroy = self.surface.surface.client.parse(self, parser)?; + let _req: Destroy = self.xdg.surface.client.parse(self, parser)?; { if let Some(parent) = self.parent.take() { parent.popups.remove(&self.id); } } + self.xdg.ext.set(None); + self.xdg.surface.client.remove_obj(self)?; Ok(()) } fn grab(&self, parser: MsgParser<'_, '_>) -> Result<(), GrabError> { - let _req: Grab = self.surface.surface.client.parse(self, parser)?; + let _req: Grab = self.xdg.surface.client.parse(self, parser)?; Ok(()) } fn reposition(&self, parser: MsgParser<'_, '_>) -> Result<(), RepositionError> { - let _req: Reposition = self.surface.surface.client.parse(self, parser)?; + let _req: Reposition = self.xdg.surface.client.parse(self, parser)?; Ok(()) } diff --git a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs index 9d1dd6b2..0e3b60a9 100644 --- a/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs +++ b/src/ifs/wl_surface/xdg_surface/xdg_toplevel/mod.rs @@ -387,6 +387,10 @@ impl Node for XdgToplevel { } impl XdgSurfaceExt for XdgToplevel { + fn initial_configure(self: Rc) { + self.xdg.surface.client.event(self.configure(0, 0)); + } + fn post_commit(self: Rc) { let surface = &self.xdg.surface; if let Some(parent) = self.parent_node.get() { diff --git a/src/ifs/zwp_linux_buffer_params_v1/mod.rs b/src/ifs/zwp_linux_buffer_params_v1/mod.rs new file mode 100644 index 00000000..ca22049f --- /dev/null +++ b/src/ifs/zwp_linux_buffer_params_v1/mod.rs @@ -0,0 +1,202 @@ +use crate::client::DynEventFormatter; +use crate::drm::dma::{DmaBuf, DmaBufPlane}; +use crate::drm::INVALID_MODIFIER; +use crate::ifs::wl_buffer::{WlBuffer, WlBufferId}; +use crate::ifs::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Obj; +use crate::object::{Interface, Object, ObjectId}; +use crate::utils::buffd::MsgParser; +use crate::ErrorFmt; +use ahash::AHashMap; +use std::cell::{Cell, RefCell}; +use std::rc::Rc; +pub use types::*; + +mod types; + +const DESTROY: u32 = 0; +const ADD: u32 = 1; +const CREATE: u32 = 2; +const CREATE_IMMED: u32 = 3; + +const CREATED: u32 = 0; +const FAILED: u32 = 1; + +#[allow(dead_code)] +const Y_INVERT: u32 = 1; +#[allow(dead_code)] +const INTERLACED: u32 = 2; +#[allow(dead_code)] +const BOTTOM_FIRST: u32 = 4; + +id!(ZwpLinuxBufferParamsV1Id); + +const MAX_PLANE: u32 = 3; + +pub struct ZwpLinuxBufferParamsV1 { + id: ZwpLinuxBufferParamsV1Id, + parent: Rc, + planes: RefCell>, + used: Cell, +} + +impl ZwpLinuxBufferParamsV1 { + pub fn new(id: ZwpLinuxBufferParamsV1Id, parent: &Rc) -> Self { + Self { + id, + parent: parent.clone(), + planes: RefCell::new(Default::default()), + used: Cell::new(false), + } + } + + fn created(self: &Rc, buffer_id: WlBufferId) -> DynEventFormatter { + Box::new(Created { + obj: self.clone(), + buffer: buffer_id, + }) + } + + fn failed(self: &Rc) -> DynEventFormatter { + Box::new(Failed { obj: self.clone() }) + } + + fn destroy(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.parent.client.parse(&**self, parser)?; + self.parent.client.remove_obj(&**self)?; + Ok(()) + } + + fn add(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), AddError> { + let req: Add = self.parent.client.parse(&**self, parser)?; + let modifier = ((req.modifier_hi as u64) << 32) | req.modifier_lo as u64; + if modifier != INVALID_MODIFIER { + return Err(AddError::InvalidModifier(modifier)); + } + let plane = req.plane_idx; + if plane > MAX_PLANE { + return Err(AddError::MaxPlane); + } + if self.planes.borrow_mut().insert(plane, req).is_some() { + return Err(AddError::AlreadySet(plane)); + } + Ok(()) + } + + fn do_create( + self: &Rc, + buffer_id: Option, + width: i32, + height: i32, + format: u32, + _flags: u32, + ) -> Result { + let ctx = match self.parent.client.state.render_ctx.get() { + Some(ctx) => ctx, + None => return Err(DoCreateError::NoRenderContext), + }; + let formats = ctx.formats(); + let format = match formats.get(&format) { + Some(f) => *f, + None => return Err(DoCreateError::InvalidFormat(format)), + }; + let mut dmabuf = DmaBuf { + width, + height, + format, + modifier: INVALID_MODIFIER, + planes: vec![], + }; + let mut planes: Vec<_> = self.planes.borrow_mut().drain().map(|v| v.1).collect(); + planes.sort_by_key(|a| a.plane_idx); + for (i, p) in planes.into_iter().enumerate() { + if p.plane_idx as usize != i { + return Err(DoCreateError::MissingPlane(i)); + } + dmabuf.planes.push(DmaBufPlane { + offset: p.offset, + stride: p.stride, + fd: p.fd, + }); + } + let img = ctx.dmabuf_img(&dmabuf)?; + let (is_client_id, buffer_id) = match buffer_id { + Some(i) => (true, i), + None => (false, self.parent.client.new_id()?), + }; + let buffer = Rc::new(WlBuffer::new_dmabuf( + buffer_id, + &self.parent.client, + format, + &img, + )); + if is_client_id { + self.parent.client.add_client_obj(&buffer)?; + } else { + self.parent.client.add_server_obj(&buffer); + } + Ok(buffer_id) + } + + fn create(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), CreateError> { + let req: Create = self.parent.client.parse(&**self, parser)?; + if self.used.replace(true) { + return Err(CreateError::AlreadyUsed); + } + match self.do_create(None, req.width, req.height, req.format, req.flags) { + Ok(id) => { + self.parent.client.event(self.created(id)); + } + Err(e) => { + log::debug!("Could not create a dmabuf buffer: {}", ErrorFmt(e)); + self.parent.client.event(self.failed()); + } + } + Ok(()) + } + + fn create_immed(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), CreateImmedError> { + let req: CreateImmed = self.parent.client.parse(&**self, parser)?; + if self.used.replace(true) { + return Err(CreateImmedError::AlreadyUsed); + } + self.do_create( + Some(req.buffer_id), + req.width, + req.height, + req.format, + req.flags, + )?; + Ok(()) + } + + fn handle_request_( + self: &Rc, + request: u32, + parser: MsgParser<'_, '_>, + ) -> Result<(), ZwpLinuxBufferParamsV1Error> { + match request { + DESTROY => self.destroy(parser)?, + ADD => self.add(parser)?, + CREATE => self.create(parser)?, + CREATE_IMMED => self.create_immed(parser)?, + _ => unreachable!(), + } + Ok(()) + } +} + +handle_request!(ZwpLinuxBufferParamsV1); + +impl Object for ZwpLinuxBufferParamsV1 { + fn id(&self) -> ObjectId { + self.id.into() + } + + fn interface(&self) -> Interface { + Interface::ZwpLinuxBufferParamsV1 + } + + fn num_requests(&self) -> u32 { + CREATE_IMMED + 1 + } +} diff --git a/src/ifs/zwp_linux_buffer_params_v1/types.rs b/src/ifs/zwp_linux_buffer_params_v1/types.rs new file mode 100644 index 00000000..0886e3af --- /dev/null +++ b/src/ifs/zwp_linux_buffer_params_v1/types.rs @@ -0,0 +1,227 @@ +use crate::client::{ClientError, EventFormatter, RequestParser}; +use crate::ifs::wl_buffer::WlBufferId; +use crate::ifs::zwp_linux_buffer_params_v1::{ZwpLinuxBufferParamsV1, CREATED, FAILED}; +use crate::object::Object; +use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; +use crate::RenderError; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; +use thiserror::Error; +use uapi::OwnedFd; + +#[derive(Debug, Error)] +pub enum ZwpLinuxBufferParamsV1Error { + #[error("Could not process a `destroy` request")] + DestroyError(#[from] DestroyError), + #[error("Could not process a `add` request")] + AddError(#[from] AddError), + #[error("Could not process a `create` request")] + Create(#[from] CreateError), + #[error("Could not process a `create_immed` request")] + CreateImmed(#[from] CreateImmedError), + #[error(transparent)] + ClientError(Box), +} +efrom!(ZwpLinuxBufferParamsV1Error, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ClientError, ClientError); +efrom!(DestroyError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum AddError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error("A buffer can contain at most 4 planes")] + MaxPlane, + #[error(transparent)] + ClientError(Box), + #[error("The modifier {0} is not supported")] + InvalidModifier(u64), + #[error("The plane {0} was already set")] + AlreadySet(u32), +} +efrom!(AddError, ClientError, ClientError); +efrom!(AddError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum DoCreateError { + #[error(transparent)] + ClientError(Box), + #[error("The compositor has no render context attached")] + NoRenderContext, + #[error("The format {0} is not supported")] + InvalidFormat(u32), + #[error("Plane {0} was not set")] + MissingPlane(usize), + #[error("Could not import the buffer")] + ImportError(#[from] RenderError), +} +efrom!(DoCreateError, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum CreateError { + #[error("The params object has already been used")] + AlreadyUsed, + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(CreateError, ClientError, ClientError); +efrom!(CreateError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum CreateImmedError { + #[error("The params object has already been used")] + AlreadyUsed, + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error(transparent)] + DoCreateError(#[from] DoCreateError), + #[error(transparent)] + ClientError(Box), +} +efrom!(CreateImmedError, ClientError, ClientError); +efrom!(CreateImmedError, ParseError, MsgParserError); + +pub(super) struct Destroy; +impl RequestParser<'_> for Destroy { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for Destroy { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "destroy()") + } +} + +pub(super) struct Add { + pub fd: OwnedFd, + pub plane_idx: u32, + pub offset: u32, + pub stride: u32, + pub modifier_hi: u32, + pub modifier_lo: u32, +} +impl RequestParser<'_> for Add { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + fd: parser.fd()?, + plane_idx: parser.uint()?, + offset: parser.uint()?, + stride: parser.uint()?, + modifier_hi: parser.uint()?, + modifier_lo: parser.uint()?, + }) + } +} +impl Debug for Add { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "add(fd: {}, plane_idx: {}, offset: {}, stride: {}, modifier: {})", + self.fd.raw(), + self.plane_idx, + self.offset, + self.stride, + (self.modifier_hi as u64) << 32 | self.modifier_lo as u64, + ) + } +} + +pub(super) struct Create { + pub width: i32, + pub height: i32, + pub format: u32, + pub flags: u32, +} +impl RequestParser<'_> for Create { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + width: parser.int()?, + height: parser.int()?, + format: parser.uint()?, + flags: parser.uint()?, + }) + } +} +impl Debug for Create { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "create(width: {}, height: {}, format: {}, flags: {})", + self.width, self.height, self.format, self.flags, + ) + } +} + +pub(super) struct CreateImmed { + pub buffer_id: WlBufferId, + pub width: i32, + pub height: i32, + pub format: u32, + pub flags: u32, +} +impl RequestParser<'_> for CreateImmed { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + buffer_id: parser.object()?, + width: parser.int()?, + height: parser.int()?, + format: parser.uint()?, + flags: parser.uint()?, + }) + } +} +impl Debug for CreateImmed { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "create_immed(buffer_id: {}, width: {}, height: {}, format: {}, flags: {})", + self.buffer_id, self.width, self.height, self.format, self.flags, + ) + } +} + +pub(super) struct Created { + pub obj: Rc, + pub buffer: WlBufferId, +} +impl EventFormatter for Created { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, CREATED).object(self.buffer); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Created { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "created(buffer: {})", self.buffer) + } +} + +pub(super) struct Failed { + pub obj: Rc, +} +impl EventFormatter for Failed { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, FAILED); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Failed { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "failed()") + } +} diff --git a/src/ifs/zwp_linux_dmabuf_v1/mod.rs b/src/ifs/zwp_linux_dmabuf_v1/mod.rs new file mode 100644 index 00000000..c5af831a --- /dev/null +++ b/src/ifs/zwp_linux_dmabuf_v1/mod.rs @@ -0,0 +1,139 @@ +use crate::client::{Client, DynEventFormatter}; +use crate::drm::INVALID_MODIFIER; +use crate::globals::{Global, GlobalName}; +use crate::ifs::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1; +use crate::object::{Interface, Object, ObjectId}; +use crate::utils::buffd::MsgParser; +use std::rc::Rc; +pub use types::*; + +mod types; + +id!(ZwpLinuxDmabufV1Id); + +const DESTROY: u32 = 0; +const CREATE_PARAMS: u32 = 1; + +const FORMAT: u32 = 0; +const MODIFIER: u32 = 1; + +pub struct ZwpLinuxDmabufV1Global { + name: GlobalName, +} + +impl ZwpLinuxDmabufV1Global { + pub fn new(name: GlobalName) -> Self { + Self { name } + } + + fn bind_( + self: Rc, + id: ZwpLinuxDmabufV1Id, + client: &Rc, + version: u32, + ) -> Result<(), ZwpLinuxDmabufV1Error> { + let obj = Rc::new(ZwpLinuxDmabufV1Obj { + id, + client: client.clone(), + _version: version, + }); + client.add_client_obj(&obj)?; + if let Some(ctx) = client.state.render_ctx.get() { + let formats = ctx.formats(); + for format in formats.values() { + client.event(obj.format(format.drm)); + if version >= MODIFIERS_SINCE_VERSION { + client.event(obj.modifier(format.drm, INVALID_MODIFIER)); + } + } + } + Ok(()) + } +} + +const MODIFIERS_SINCE_VERSION: u32 = 3; + +bind!(ZwpLinuxDmabufV1Global); + +impl Global for ZwpLinuxDmabufV1Global { + fn name(&self) -> GlobalName { + self.name + } + + fn singleton(&self) -> bool { + true + } + + fn interface(&self) -> Interface { + Interface::ZwpLinuxDmabufV1 + } + + fn version(&self) -> u32 { + 3 + } +} + +pub struct ZwpLinuxDmabufV1Obj { + id: ZwpLinuxDmabufV1Id, + pub client: Rc, + _version: u32, +} + +impl ZwpLinuxDmabufV1Obj { + fn format(self: &Rc, format: u32) -> DynEventFormatter { + Box::new(Format { + obj: self.clone(), + format, + }) + } + + fn modifier(self: &Rc, format: u32, modifier: u64) -> DynEventFormatter { + Box::new(Modifier { + obj: self.clone(), + format, + modifier, + }) + } + + fn destroy(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), DestroyError> { + let _req: Destroy = self.client.parse(&**self, parser)?; + self.client.remove_obj(&**self)?; + Ok(()) + } + + fn create_params(self: &Rc, parser: MsgParser<'_, '_>) -> Result<(), CreateParamsError> { + let req: CreateParams = self.client.parse(&**self, parser)?; + let params = Rc::new(ZwpLinuxBufferParamsV1::new(req.params_id, self)); + self.client.add_client_obj(¶ms)?; + Ok(()) + } + + fn handle_request_( + self: &Rc, + request: u32, + parser: MsgParser<'_, '_>, + ) -> Result<(), ZwpLinuxDmabufV1Error> { + match request { + DESTROY => self.destroy(parser)?, + CREATE_PARAMS => self.create_params(parser)?, + _ => unreachable!(), + } + Ok(()) + } +} + +handle_request!(ZwpLinuxDmabufV1Obj); + +impl Object for ZwpLinuxDmabufV1Obj { + fn id(&self) -> ObjectId { + self.id.into() + } + + fn interface(&self) -> Interface { + Interface::ZwpLinuxDmabufV1 + } + + fn num_requests(&self) -> u32 { + CREATE_PARAMS + 1 + } +} diff --git a/src/ifs/zwp_linux_dmabuf_v1/types.rs b/src/ifs/zwp_linux_dmabuf_v1/types.rs new file mode 100644 index 00000000..93d3e123 --- /dev/null +++ b/src/ifs/zwp_linux_dmabuf_v1/types.rs @@ -0,0 +1,111 @@ +use crate::client::{ClientError, EventFormatter, RequestParser}; +use crate::ifs::zwp_linux_buffer_params_v1::ZwpLinuxBufferParamsV1Id; +use crate::ifs::zwp_linux_dmabuf_v1::{ZwpLinuxDmabufV1Obj, FORMAT, MODIFIER}; +use crate::object::Object; +use crate::utils::buffd::{MsgFormatter, MsgParser, MsgParserError}; +use std::fmt::{Debug, Formatter}; +use std::rc::Rc; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum ZwpLinuxDmabufV1Error { + #[error("Could not process a `destroy` request")] + DestroyError(#[from] DestroyError), + #[error("Could not process a `create_params` request")] + CreateParamsError(#[from] CreateParamsError), + #[error(transparent)] + ClientError(Box), +} +efrom!(ZwpLinuxDmabufV1Error, ClientError, ClientError); + +#[derive(Debug, Error)] +pub enum DestroyError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(DestroyError, ClientError, ClientError); +efrom!(DestroyError, ParseError, MsgParserError); + +#[derive(Debug, Error)] +pub enum CreateParamsError { + #[error("Parsing failed")] + ParseError(#[source] Box), + #[error(transparent)] + ClientError(Box), +} +efrom!(CreateParamsError, ClientError, ClientError); +efrom!(CreateParamsError, ParseError, MsgParserError); + +pub(super) struct Destroy; +impl RequestParser<'_> for Destroy { + fn parse(_parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self) + } +} +impl Debug for Destroy { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "destroy()") + } +} + +pub(super) struct CreateParams { + pub params_id: ZwpLinuxBufferParamsV1Id, +} +impl RequestParser<'_> for CreateParams { + fn parse(parser: &mut MsgParser<'_, '_>) -> Result { + Ok(Self { + params_id: parser.object()?, + }) + } +} +impl Debug for CreateParams { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "create_params(params_id: {})", self.params_id) + } +} + +pub(super) struct Format { + pub obj: Rc, + pub format: u32, +} +impl EventFormatter for Format { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, FORMAT).uint(self.format); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Format { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "format(format: {})", self.format) + } +} + +pub(super) struct Modifier { + pub obj: Rc, + pub format: u32, + pub modifier: u64, +} +impl EventFormatter for Modifier { + fn format(self: Box, fmt: &mut MsgFormatter<'_>) { + fmt.header(self.obj.id, MODIFIER) + .uint(self.format) + .uint((self.modifier >> 32) as u32) + .uint(self.modifier as u32); + } + fn obj(&self) -> &dyn Object { + &*self.obj + } +} +impl Debug for Modifier { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!( + f, + "modifiers(format: {}, modifier: {})", + self.format, self.modifier + ) + } +} diff --git a/src/main.rs b/src/main.rs index 94ccf89e..55b182f0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,6 +26,7 @@ use crate::ifs::wl_shm::WlShmGlobal; use crate::ifs::wl_subcompositor::WlSubcompositorGlobal; use crate::ifs::wl_surface::NoneSurfaceExt; use crate::ifs::xdg_wm_base::XdgWmBaseGlobal; +use crate::ifs::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1Global; use crate::render::RenderError; use crate::sighand::SighandError; use crate::state::State; @@ -41,6 +42,7 @@ use log::LevelFilter; use std::rc::Rc; use thiserror::Error; use wheel::Wheel; +use crate::ifs::wl_drm::WlDrmGlobal; #[macro_use] mod macros; @@ -114,6 +116,8 @@ fn main_() -> Result<(), MainError> { globals.add_global_no_broadcast(&Rc::new(WlSubcompositorGlobal::new(globals.name()))); globals.add_global_no_broadcast(&Rc::new(XdgWmBaseGlobal::new(globals.name()))); globals.add_global_no_broadcast(&Rc::new(WlDataDeviceManagerGlobal::new(globals.name()))); + globals.add_global_no_broadcast(&Rc::new(ZwpLinuxDmabufV1Global::new(globals.name()))); + globals.add_global_no_broadcast(&Rc::new(WlDrmGlobal::new(globals.name()))); let node_ids = NodeIds::default(); let state = Rc::new(State { eng: engine.clone(), diff --git a/src/object.rs b/src/object.rs index c2aed6bd..62256f99 100644 --- a/src/object.rs +++ b/src/object.rs @@ -66,6 +66,9 @@ pub enum Interface { WlRegion, WlBuffer, WlSeat, + WlDrm, + ZwpLinuxDmabufV1, + ZwpLinuxBufferParamsV1, } impl Interface { @@ -96,6 +99,9 @@ impl Interface { Interface::WlDataDevice => "wl_data_device", Interface::WlDataSource => "wl_data_source", Interface::WlDataOffer => "wl_data_offer", + Interface::ZwpLinuxDmabufV1 => "zwp_linux_dmabuf_v1", + Interface::ZwpLinuxBufferParamsV1 => "zwp_linux_buffer_params_v1", + Interface::WlDrm => "wl_drm", } } } diff --git a/src/rect.rs b/src/rect.rs index b02a720e..e874694a 100644 --- a/src/rect.rs +++ b/src/rect.rs @@ -39,6 +39,7 @@ impl Rect { } } + #[allow(dead_code)] pub fn intersects(&self, other: &Self) -> bool { let x1 = self.x1.max(other.x1); let y1 = self.y1.max(other.y1); diff --git a/src/render/egl/device.rs b/src/render/egl/device.rs index 0dabd04d..9c0560a0 100644 --- a/src/render/egl/device.rs +++ b/src/render/egl/device.rs @@ -40,7 +40,7 @@ impl EglDevice { } let mut dpy = EglDisplay { exts: DisplayExt::empty(), - formats: AHashMap::new(), + formats: Rc::new(AHashMap::new()), dev: *self, dpy, }; @@ -68,7 +68,7 @@ impl EglDevice { if !dpy.exts.intersects(DisplayExt::KHR_SURFACELESS_CONTEXT) { return Err(RenderError::SurfacelessContext); } - dpy.formats = query_formats(dpy.dpy)?; + dpy.formats = Rc::new(query_formats(dpy.dpy)?); Ok(Rc::new(dpy)) } diff --git a/src/render/egl/display.rs b/src/render/egl/display.rs index ae4568fb..2ee30140 100644 --- a/src/render/egl/display.rs +++ b/src/render/egl/display.rs @@ -26,7 +26,7 @@ use std::rc::Rc; #[derive(Debug, Clone)] pub struct EglDisplay { pub exts: DisplayExt, - pub formats: AHashMap, + pub formats: Rc>, pub dev: EglDevice, pub dpy: EGLDisplay, } diff --git a/src/render/egl/mod.rs b/src/render/egl/mod.rs index 7811456c..deaa8bac 100644 --- a/src/render/egl/mod.rs +++ b/src/render/egl/mod.rs @@ -1,4 +1,4 @@ -use crate::drm::drm::Drm; +use crate::drm::drm::{DrmDevice}; use crate::render::egl::device::EglDevice; use crate::render::egl::sys::{ eglBindAPI, EGLAttrib, EGLLabelKHR, EGLenum, EGLint, EGL_DEBUG_MSG_CRITICAL_KHR, @@ -63,8 +63,7 @@ pub fn init() -> Result<(), RenderError> { Ok(()) } -pub fn find_drm_device(drm: &Drm) -> Result, RenderError> { - let drm_dev = drm.get_device()?; +pub fn find_drm_device(drm_dev: &DrmDevice) -> Result, RenderError> { for device in query_devices()? { if device.exts.contains(DeviceExt::EXT_DEVICE_DRM) { let device_file = device.query_string(EGL_DRM_DEVICE_FILE_EXT)?; diff --git a/src/render/egl/sys.rs b/src/render/egl/sys.rs index ee5e21bb..262b164d 100644 --- a/src/render/egl/sys.rs +++ b/src/render/egl/sys.rs @@ -3,6 +3,7 @@ use uapi::c; pub type EGLint = i32; pub type EGLenum = c::c_uint; pub type EGLBoolean = c::c_uint; +#[allow(dead_code)] pub type EGLuint64KHR = u64; pub type EGLAttrib = isize; diff --git a/src/render/gl/sys.rs b/src/render/gl/sys.rs index 7c10f777..0d9a3be8 100644 --- a/src/render/gl/sys.rs +++ b/src/render/gl/sys.rs @@ -7,6 +7,7 @@ pub type GLenum = c::c_uint; pub type GLfloat = f32; pub type GLint = c::c_int; pub type GLsizei = c::c_int; +#[allow(dead_code)] pub type GLubyte = u8; pub type GLuint = c::c_uint; @@ -29,6 +30,7 @@ pub const GL_RENDERBUFFER: GLenum = 0x8D41; pub const GL_SCISSOR_TEST: GLenum = 0x0C11; pub const GL_TEXTURE0: GLenum = 0x84C0; pub const GL_TEXTURE_2D: GLenum = 0x0DE1; +#[allow(dead_code)] pub const GL_TEXTURE_MAG_FILTER: GLenum = 0x2800; pub const GL_TEXTURE_MIN_FILTER: GLenum = 0x2801; pub const GL_TEXTURE_WRAP_S: GLenum = 0x2802; @@ -54,6 +56,7 @@ extern "C" { renderbuffertarget: GLenum, renderbuffer: GLuint, ); + #[allow(dead_code)] pub fn glFramebufferTexture2D( target: GLenum, attachment: GLenum, @@ -64,6 +67,7 @@ extern "C" { pub fn glCheckFramebufferStatus(target: GLenum) -> GLenum; pub fn glClear(mask: GLbitfield); pub fn glClearColor(red: GLfloat, green: GLfloat, blue: GLfloat, alpha: GLfloat); + #[allow(dead_code)] pub fn glFlush(); pub fn glGenTextures(n: GLsizei, textures: *mut GLuint); @@ -112,6 +116,7 @@ extern "C" { pub fn glGetUniformLocation(prog: GLuint, name: *const GLchar) -> GLint; pub fn glGetAttribLocation(prog: GLuint, name: *const GLchar) -> GLint; pub fn glUniform1i(location: GLint, v0: GLint); + #[allow(dead_code)] pub fn glUniform1f(location: GLint, v0: GLfloat); pub fn glUniform4f(location: GLint, v0: GLfloat, v1: GLfloat, v2: GLfloat, v3: GLfloat); pub fn glVertexAttribPointer( diff --git a/src/render/gl/texture.rs b/src/render/gl/texture.rs index fb2830df..03b68979 100644 --- a/src/render/gl/texture.rs +++ b/src/render/gl/texture.rs @@ -1,5 +1,7 @@ use crate::format::Format; use crate::render::egl::context::EglContext; +use crate::render::egl::image::EglImage; +use crate::render::egl::PROCS; use crate::render::gl::frame_buffer::GlFrameBuffer; use crate::render::gl::sys::{ glBindFramebuffer, glBindTexture, glCheckFramebufferStatus, glDeleteTextures, @@ -8,6 +10,7 @@ use crate::render::gl::sys::{ GL_FRAMEBUFFER_COMPLETE, GL_LINEAR, GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_TEXTURE_MIN_FILTER, GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T, GL_UNPACK_ROW_LENGTH_EXT, }; +use crate::render::sys::GLeglImageOES; use crate::render::RenderError; use std::cell::Cell; use std::ptr; @@ -15,12 +18,14 @@ use std::rc::Rc; pub struct GlTexture { pub(super) ctx: Rc, + pub img: Option>, pub tex: GLuint, pub width: i32, pub height: i32, } impl GlTexture { + #[allow(dead_code)] pub fn new( ctx: &Rc, format: &'static Format, @@ -49,12 +54,14 @@ impl GlTexture { })?; Ok(Rc::new(GlTexture { ctx: ctx.clone(), + img: None, tex, width, height, })) } + #[allow(dead_code)] pub unsafe fn to_framebuffer(self: &Rc) -> Result, RenderError> { self.ctx.with_current(|| unsafe { let mut fbo = 0; @@ -84,7 +91,27 @@ impl GlTexture { }) } - pub fn import_texture( + pub fn import_img(ctx: &Rc, img: &Rc) -> Result { + let tex = ctx.with_current(|| unsafe { + let mut tex = 0; + glGenTextures(1, &mut tex); + glBindTexture(GL_TEXTURE_2D, tex); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + PROCS.glEGLImageTargetTexture2DOES(GL_TEXTURE_2D, GLeglImageOES(img.img.0)); + glBindTexture(GL_TEXTURE_2D, 0); + Ok(tex) + })?; + Ok(GlTexture { + ctx: ctx.clone(), + img: Some(img.clone()), + tex, + width: img.width, + height: img.height, + }) + } + + pub fn import_shm( ctx: &Rc, data: &[Cell], format: &'static Format, @@ -119,6 +146,7 @@ impl GlTexture { })?; Ok(GlTexture { ctx: ctx.clone(), + img: None, tex, width, height, @@ -128,11 +156,9 @@ impl GlTexture { impl Drop for GlTexture { fn drop(&mut self) { - unsafe { - self.ctx.with_current(|| { - glDeleteTextures(1, &self.tex); - Ok(()) - }); - } + let _ = self.ctx.with_current(|| unsafe { + glDeleteTextures(1, &self.tex); + Ok(()) + }); } } diff --git a/src/render/mod.rs b/src/render/mod.rs index 0a317250..2b0a5a27 100644 --- a/src/render/mod.rs +++ b/src/render/mod.rs @@ -72,6 +72,7 @@ pub enum RenderError { #[error("EGL display does not support `EGL_EXT_image_dma_buf_import_modifiers`")] DmaBufImport, #[error("GLES driver does not support `GL_OES_EGL_image`")] + #[allow(dead_code)] OesEglImage, #[error("EGL display does not support `EGL_KHR_image_base`")] ImageBase, @@ -89,4 +90,6 @@ pub enum RenderError { UnknownDrmDevice, #[error("The GLES driver does not support the XRGB8888 format")] XRGB888, + #[error("The DRM device does not have a render node")] + NoRenderNode, } diff --git a/src/render/proc.rs b/src/render/proc.rs index 1929131c..7fefdc56 100644 --- a/src/render/proc.rs +++ b/src/render/proc.rs @@ -1,3 +1,3 @@ -#![allow(non_snake_case)] +#![allow(non_snake_case, dead_code)] include!(concat!(env!("OUT_DIR"), "/egl_procs.rs")); diff --git a/src/render/renderer/context.rs b/src/render/renderer/context.rs index 94756211..efad7259 100644 --- a/src/render/renderer/context.rs +++ b/src/render/renderer/context.rs @@ -1,5 +1,5 @@ use crate::drm::dma::DmaBuf; -use crate::drm::drm::Drm; +use crate::drm::drm::{Drm, DRM_NODE_RENDER}; use crate::format::{Format, XRGB8888}; use crate::render::egl::context::EglContext; use crate::render::egl::find_drm_device; @@ -8,16 +8,21 @@ use crate::render::gl::render_buffer::GlRenderBuffer; use crate::render::gl::sys::GLint; use crate::render::gl::texture::GlTexture; use crate::render::renderer::framebuffer::Framebuffer; +use crate::render::renderer::image::Image; use crate::render::renderer::RENDERDOC; use crate::render::{RenderError, Texture}; +use ahash::AHashMap; use renderdoc::{RenderDoc, V100}; use std::cell::{Cell, RefCell}; +use std::ffi::CString; use std::rc::Rc; use uapi::ustr; pub struct RenderContext { pub(super) ctx: Rc, + pub(super) render_node: Rc, + pub(super) renderdoc: Option>>, pub(super) tex_prog: GlProgram, @@ -32,7 +37,12 @@ pub struct RenderContext { impl RenderContext { pub fn from_drm_device(drm: &Drm) -> Result { - let egl_dev = match find_drm_device(&drm)? { + let drm_dev = drm.get_device()?; + let node = match drm_dev.nodes().find(|(ty, _)| *ty == DRM_NODE_RENDER) { + None => return Err(RenderError::NoRenderNode), + Some((_, n)) => Rc::new(n.to_owned()), + }; + let egl_dev = match find_drm_device(&drm_dev)? { Some(d) => d, None => return Err(RenderError::UnknownDrmDevice), }; @@ -41,10 +51,10 @@ impl RenderContext { return Err(RenderError::XRGB888); } let ctx = dpy.create_context()?; - ctx.with_current(|| unsafe { Self::new(&ctx) }) + ctx.with_current(|| unsafe { Self::new(&ctx, &node) }) } - unsafe fn new(ctx: &Rc) -> Result { + unsafe fn new(ctx: &Rc, node: &Rc) -> Result { let tex_prog = GlProgram::from_shaders( ctx, include_str!("../shaders/tex.vert.glsl"), @@ -58,6 +68,8 @@ impl RenderContext { Ok(Self { ctx: ctx.clone(), + render_node: node.clone(), + tex_prog_pos: tex_prog.get_attrib_location(ustr!("pos")), tex_prog_texcoord: tex_prog.get_attrib_location(ustr!("texcoord")), tex_prog_tex: tex_prog.get_uniform_location(ustr!("tex")), @@ -75,6 +87,14 @@ impl RenderContext { }) } + pub fn render_node(&self) -> Rc { + self.render_node.clone() + } + + pub fn formats(&self) -> Rc> { + self.ctx.dpy.formats.clone() + } + pub fn dmabuf_fb(self: &Rc, buf: &DmaBuf) -> Result, RenderError> { self.ctx.with_current(|| unsafe { let img = self.ctx.dpy.import_dmabuf(buf)?; @@ -87,6 +107,16 @@ impl RenderContext { }) } + pub fn dmabuf_img(self: &Rc, buf: &DmaBuf) -> Result, RenderError> { + self.ctx.with_current(|| { + let img = self.ctx.dpy.import_dmabuf(buf)?; + Ok(Rc::new(Image { + ctx: self.clone(), + gl: img, + })) + }) + } + pub fn shmem_texture( self: &Rc, data: &[Cell], @@ -95,7 +125,7 @@ impl RenderContext { height: i32, stride: i32, ) -> Result, RenderError> { - let gl = GlTexture::import_texture(&self.ctx, data, format, width, height, stride)?; + let gl = GlTexture::import_shm(&self.ctx, data, format, width, height, stride)?; Ok(Rc::new(Texture { ctx: self.clone(), gl, diff --git a/src/render/renderer/image.rs b/src/render/renderer/image.rs new file mode 100644 index 00000000..e76db41c --- /dev/null +++ b/src/render/renderer/image.rs @@ -0,0 +1,27 @@ +use crate::render::egl::image::EglImage; +use crate::render::gl::texture::GlTexture; +use crate::render::{RenderContext, Texture}; +use crate::RenderError; +use std::rc::Rc; + +pub struct Image { + pub(super) ctx: Rc, + pub(super) gl: Rc, +} + +impl Image { + pub fn width(&self) -> i32 { + self.gl.width + } + + pub fn height(&self) -> i32 { + self.gl.height + } + + pub fn to_texture(self: &Rc) -> Result, RenderError> { + Ok(Rc::new(Texture { + ctx: self.ctx.clone(), + gl: GlTexture::import_img(&self.ctx.ctx, &self.gl)?, + })) + } +} diff --git a/src/render/renderer/mod.rs b/src/render/renderer/mod.rs index b7fefd68..b77e7657 100644 --- a/src/render/renderer/mod.rs +++ b/src/render/renderer/mod.rs @@ -1,10 +1,12 @@ pub use context::*; pub use framebuffer::*; +pub use image::*; pub use renderer::*; pub use texture::*; mod context; mod framebuffer; +mod image; mod renderer; mod texture; diff --git a/src/servermem.rs b/src/servermem.rs index 3496b6be..a7b50150 100644 --- a/src/servermem.rs +++ b/src/servermem.rs @@ -1,3 +1,5 @@ +#![allow(dead_code)] + use std::cell::Cell; use std::ptr; use std::sync::atomic::AtomicUsize; diff --git a/src/utils/linkedlist.rs b/src/utils/linkedlist.rs index a90db89a..db404c60 100644 --- a/src/utils/linkedlist.rs +++ b/src/utils/linkedlist.rs @@ -49,6 +49,7 @@ impl LinkedList { unsafe { self.endpoint(self.root.data.as_ref().prev.get()) } } + #[allow(dead_code)] pub fn first(&self) -> Option> { unsafe { self.endpoint(self.root.data.as_ref().next.get()) } } diff --git a/src/wheel.rs b/src/wheel.rs index e9f1bba7..eadd2a47 100644 --- a/src/wheel.rs +++ b/src/wheel.rs @@ -120,6 +120,7 @@ impl Wheel { Ok(()) } + #[allow(dead_code)] pub fn periodic( &self, id: WheelId, diff --git a/src/xkbcommon/mod.rs b/src/xkbcommon/mod.rs index 04ae223b..9c0d7fb7 100644 --- a/src/xkbcommon/mod.rs +++ b/src/xkbcommon/mod.rs @@ -76,12 +76,15 @@ extern "C" { fn xkb_keymap_unref(keymap: *mut xkb_keymap); fn xkb_state_unref(state: *mut xkb_state); fn xkb_state_new(keymap: *mut xkb_keymap) -> *mut xkb_state; + #[allow(dead_code)] fn xkb_state_update_key( state: *mut xkb_state, key: u32, direction: xkb_key_direction, ) -> xkb_state_component; + #[allow(dead_code)] fn xkb_state_serialize_mods(state: *mut xkb_state, components: xkb_state_component) -> u32; + #[allow(dead_code)] fn xkb_state_serialize_layout(state: *mut xkb_state, components: xkb_state_component) -> u32; } @@ -198,6 +201,7 @@ impl XkbState { self.mods } + #[allow(dead_code)] pub fn update(&mut self, key: u32, direction: XkbKeyDirection) -> Option { unsafe { let changes = xkb_state_update_key(self.state, key + 8, direction.raw() as _);