diff --git a/src/ifs/wl_drm.rs b/src/ifs/wl_drm.rs index cd23f39f..16185832 100644 --- a/src/ifs/wl_drm.rs +++ b/src/ifs/wl_drm.rs @@ -121,7 +121,7 @@ impl WlDrm { }; let formats = ctx.formats(); let format = match formats.get(&req.format) { - Some(f) => *f, + Some(f) => f.format, None => return Err(CreatePrimeBufferError::InvalidFormat(req.format)), }; let mut dmabuf = DmaBuf { diff --git a/src/ifs/wl_surface/xwindow.rs b/src/ifs/wl_surface/xwindow.rs index 1f8af5ad..0f05b6fd 100644 --- a/src/ifs/wl_surface/xwindow.rs +++ b/src/ifs/wl_surface/xwindow.rs @@ -11,8 +11,9 @@ use { render::Renderer, state::State, tree::{ - FindTreeResult, FoundNode, Node, NodeId, NodeVisitor, SizedNode, SizedToplevelNode, - ToplevelData, ToplevelNode, WorkspaceNode, + FindTreeResult, FoundNode, FullscreenData, Node, NodeId, NodeVisitor, + SizedFullscreenNode, SizedNode, SizedToplevelNode, ToplevelData, ToplevelNode, + WorkspaceNode, }, utils::{ clonecell::CloneCell, copyhashmap::CopyHashMap, linkedlist::LinkedNode, @@ -31,7 +32,6 @@ use { }, thiserror::Error, }; -use crate::tree::{FullscreenData, SizedFullscreenNode}; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum XInputModel { @@ -508,10 +508,15 @@ impl SizedToplevelNode for Xwindow { fn set_fullscreen(self: &Rc, fullscreen: bool) { if fullscreen { if let Some(ws) = self.workspace.get() { - self.fullscreen_data.set_fullscreen(&self.data.state, self.clone(), &ws.output.get()); + self.fullscreen_data.set_fullscreen( + &self.data.state, + self.clone(), + &ws.output.get(), + ); } } else { - self.fullscreen_data.unset_fullscreen(&self.data.state, self.clone()); + self.fullscreen_data + .unset_fullscreen(&self.data.state, self.clone()); } } @@ -538,7 +543,12 @@ impl SizedFullscreenNode for Xwindow { } fn title(&self) -> String { - self.data.info.title.borrow_mut().clone().unwrap_or_default() + self.data + .info + .title + .borrow_mut() + .clone() + .unwrap_or_default() } } diff --git a/src/ifs/zwp_linux_buffer_params_v1.rs b/src/ifs/zwp_linux_buffer_params_v1.rs index 38c73a7f..51f3c7ea 100644 --- a/src/ifs/zwp_linux_buffer_params_v1.rs +++ b/src/ifs/zwp_linux_buffer_params_v1.rs @@ -11,7 +11,6 @@ use { }, video::{ dmabuf::{DmaBuf, DmaBufPlane}, - INVALID_MODIFIER, }, wire::{zwp_linux_buffer_params_v1::*, WlBufferId, ZwpLinuxBufferParamsV1Id}, }, @@ -37,6 +36,7 @@ pub struct ZwpLinuxBufferParamsV1 { pub parent: Rc, planes: RefCell>, used: Cell, + modifier: Cell>, pub tracker: Tracker, } @@ -47,6 +47,7 @@ impl ZwpLinuxBufferParamsV1 { parent: parent.clone(), planes: RefCell::new(Default::default()), used: Cell::new(false), + modifier: Cell::new(None), tracker: Default::default(), } } @@ -71,8 +72,9 @@ impl ZwpLinuxBufferParamsV1 { 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)); + match self.modifier.get() { + Some(m) if m != modifier => return Err(AddError::MixedModifiers(modifier, m)), + _ => self.modifier.set(Some(modifier)), } let plane = req.plane_idx; if plane > MAX_PLANE { @@ -98,14 +100,21 @@ impl ZwpLinuxBufferParamsV1 { }; let formats = ctx.formats(); let format = match formats.get(&format) { - Some(f) => *f, + Some(f) => f, None => return Err(DoCreateError::InvalidFormat(format)), }; + let modifier = match self.modifier.get() { + Some(m) => m, + _ => return Err(DoCreateError::NoPlanes), + }; + if !format.modifiers.contains_key(&modifier) { + return Err(DoCreateError::InvalidModifier(modifier)); + } let mut dmabuf = DmaBuf { width, height, - format, - modifier: INVALID_MODIFIER, + format: format.format, + modifier, planes: vec![], }; let mut planes: Vec<_> = self.planes.borrow_mut().drain().map(|v| v.1).collect(); @@ -128,7 +137,7 @@ impl ZwpLinuxBufferParamsV1 { let buffer = Rc::new(WlBuffer::new_dmabuf( buffer_id, &self.parent.client, - format, + format.format, &img, )); track!(self.parent.client, buffer); @@ -223,8 +232,8 @@ pub enum AddError { MaxPlane, #[error(transparent)] ClientError(Box), - #[error("The modifier {0} is not supported")] - InvalidModifier(u64), + #[error("Tried to add a plane with modifier {0} that differs from a previous modifier {1}")] + MixedModifiers(u64, u64), #[error("The plane {0} was already set")] AlreadySet(u32), } @@ -239,6 +248,10 @@ pub enum DoCreateError { NoRenderContext, #[error("The format {0} is not supported")] InvalidFormat(u32), + #[error("No planes were added")] + NoPlanes, + #[error("The modifier {0} is not supported")] + InvalidModifier(u64), #[error("Plane {0} was not set")] MissingPlane(usize), #[error("Could not import the buffer")] diff --git a/src/ifs/zwp_linux_dmabuf_v1.rs b/src/ifs/zwp_linux_dmabuf_v1.rs index b35684b3..ffaf142c 100644 --- a/src/ifs/zwp_linux_dmabuf_v1.rs +++ b/src/ifs/zwp_linux_dmabuf_v1.rs @@ -6,7 +6,6 @@ use { leaks::Tracker, object::Object, utils::buffd::{MsgParser, MsgParserError}, - video::INVALID_MODIFIER, wire::{zwp_linux_dmabuf_v1::*, ZwpLinuxDmabufV1Id}, }, std::rc::Rc, @@ -39,9 +38,11 @@ impl ZwpLinuxDmabufV1Global { if let Some(ctx) = client.state.render_ctx.get() { let formats = ctx.formats(); for format in formats.values() { - obj.send_format(format.drm); + obj.send_format(format.format.drm); if version >= MODIFIERS_SINCE_VERSION { - obj.send_modifier(format.drm, INVALID_MODIFIER); + for modifier in format.modifiers.values() { + obj.send_modifier(format.format.drm, modifier.modifier); + } } } } diff --git a/src/render.rs b/src/render.rs index 58df24e4..2514c651 100644 --- a/src/render.rs +++ b/src/render.rs @@ -80,6 +80,8 @@ pub enum RenderError { SurfacelessContext, #[error("`eglQueryDmaBufFormatsEXT` failed")] QueryDmaBufFormats, + #[error("`eglQueryDmaBufModifiersEXT` failed")] + QueryDmaBufModifiers, #[error(transparent)] DrmError(#[from] DrmError), #[error("The GLES driver does not support the XRGB8888 format")] diff --git a/src/render/egl/display.rs b/src/render/egl/display.rs index a09e0bea..16079cc4 100644 --- a/src/render/egl/display.rs +++ b/src/render/egl/display.rs @@ -26,16 +26,28 @@ use { sys::{eglInitialize, EGL_PLATFORM_GBM_KHR}, RenderError, }, - video::{dmabuf::DmaBuf, drm::Drm, gbm::GbmDevice, INVALID_MODIFIER}, + video::{dmabuf::DmaBuf, drm::Drm, gbm::GbmDevice, INVALID_MODIFIER, LINEAR_MODIFIER}, }, - ahash::AHashMap, + ahash::{AHashMap}, std::{ptr, rc::Rc}, }; +#[derive(Debug)] +pub struct EglFormat { + pub format: &'static Format, + pub modifiers: AHashMap, +} + +#[derive(Debug)] +pub struct EglModifier { + pub modifier: u64, + pub external_only: bool, +} + #[derive(Debug)] pub struct EglDisplay { pub exts: DisplayExt, - pub formats: Rc>, + pub formats: Rc>, pub gbm: Rc, pub dpy: EGLDisplay, } @@ -201,7 +213,7 @@ impl Drop for EglDisplay { } } -unsafe fn query_formats(dpy: EGLDisplay) -> Result, RenderError> { +unsafe fn query_formats(dpy: EGLDisplay) -> Result, RenderError> { let mut vec = vec![]; let mut num = 0; let res = PROCS.eglQueryDmaBufFormatsEXT(dpy, num, ptr::null_mut(), &mut num); @@ -218,8 +230,73 @@ unsafe fn query_formats(dpy: EGLDisplay) -> Result Result, RenderError> { + let mut mods = vec![]; + let mut ext_only = vec![]; + let mut num = 0; + let res = PROCS.eglQueryDmaBufModifiersEXT( + dpy, + format, + num, + ptr::null_mut(), + ptr::null_mut(), + &mut num, + ); + if res != EGL_TRUE { + return Err(RenderError::QueryDmaBufModifiers); + } + mods.reserve_exact(num as usize); + ext_only.reserve_exact(num as usize); + let res = PROCS.eglQueryDmaBufModifiersEXT( + dpy, + format, + num, + mods.as_mut_ptr(), + ext_only.as_mut_ptr(), + &mut num, + ); + if res != EGL_TRUE { + return Err(RenderError::QueryDmaBufModifiers); + } + mods.set_len(num as usize); + ext_only.set_len(num as usize); + let mut res = AHashMap::new(); + res.insert( + INVALID_MODIFIER, + EglModifier { + modifier: INVALID_MODIFIER, + external_only: false, + }, + ); + if mods.is_empty() { + res.insert( + LINEAR_MODIFIER, + EglModifier { + modifier: LINEAR_MODIFIER, + external_only: false, + }, + ); + } + for (modifier, ext_only) in mods.iter().copied().zip(ext_only.iter().copied()) { + res.insert( + modifier as _, + EglModifier { + modifier: modifier as _, + external_only: ext_only == EGL_TRUE, + }, + ); + } + Ok(res) +} diff --git a/src/render/renderer/context.rs b/src/render/renderer/context.rs index d9cdc360..56b98562 100644 --- a/src/render/renderer/context.rs +++ b/src/render/renderer/context.rs @@ -24,6 +24,7 @@ use { }, uapi::ustr, }; +use crate::render::egl::display::EglFormat; pub(super) struct TexProg { pub(super) prog: GlProgram, @@ -116,7 +117,7 @@ impl RenderContext { self.render_node.clone() } - pub fn formats(&self) -> Rc> { + pub fn formats(&self) -> Rc> { self.ctx.dpy.formats.clone() } diff --git a/src/xwayland/xwm.rs b/src/xwayland/xwm.rs index e887d405..3b705004 100644 --- a/src/xwayland/xwm.rs +++ b/src/xwayland/xwm.rs @@ -7,7 +7,7 @@ use { }, rect::Rect, state::State, - tree::{Node, SizedNode}, + tree::{Node, SizedNode, ToplevelNode}, utils::{bitflags::BitflagsExt, errorfmt::ErrorFmt, linkedlist::LinkedList}, wire::WlSurfaceId, wire_xcon::{ @@ -47,7 +47,6 @@ use { }, uapi::OwnedFd, }; -use crate::tree::{ToplevelNode}; atoms! { Atoms; @@ -369,7 +368,9 @@ impl Wm { XWaylandEvent::Activate(window) => self.activate_window(Some(&window)).await, XWaylandEvent::ActivateRoot => self.activate_window(None).await, XWaylandEvent::Close(window) => self.close_window(&window).await, - XWaylandEvent::SetFullscreen(window, fullscreen) => self.set_fullscreen(&window, fullscreen).await, + XWaylandEvent::SetFullscreen(window, fullscreen) => { + self.set_fullscreen(&window, fullscreen).await + } } }