From f4c75c570591f0cad088f436e7d8546809eaa301 Mon Sep 17 00:00:00 2001 From: Nova Date: Wed, 30 Jul 2025 23:24:39 -0700 Subject: [PATCH] feat: wl_drm --- Cargo.lock | 8 +- Cargo.toml | 71 +++++++-------- src/wayland/core/mod.rs | 2 - src/wayland/{core => }/display.rs | 2 +- src/wayland/dmabuf/buffer_backing.rs | 33 +++---- src/wayland/dmabuf/buffer_params.rs | 4 +- src/wayland/dmabuf/mod.rs | 49 ++++++----- src/wayland/mesa_drm.rs | 126 +++++++++++++++++++++++++++ src/wayland/mod.rs | 16 ++-- src/wayland/{core => }/registry.rs | 30 +++++-- src/wayland/util.rs | 2 +- src/wayland/xdg/surface.rs | 5 +- 12 files changed, 251 insertions(+), 97 deletions(-) rename src/wayland/{core => }/display.rs (98%) create mode 100644 src/wayland/mesa_drm.rs rename src/wayland/{core => }/registry.rs (83%) diff --git a/Cargo.lock b/Cargo.lock index 6cee3df..35f9e36 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3490,7 +3490,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667" dependencies = [ "cfg-if", - "windows-targets 0.53.2", + "windows-targets 0.48.5", ] [[package]] @@ -6115,7 +6115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69fff37da548239c3bf9e64a12193d261e8b22b660991c6fd2df057c168f435f" dependencies = [ "cc", - "windows-targets 0.52.6", + "windows-targets 0.48.5", ] [[package]] @@ -6539,7 +6539,7 @@ dependencies = [ [[package]] name = "waynest" version = "0.0.25" -source = "git+https://github.com/technobaboo/waynest.git?branch=fix%2Ffd_clear#0b2e3e5b5383c1f7011599849e2baf1c9afeb9bb" +source = "git+https://github.com/technobaboo/waynest.git?branch=fix%2Fwayland-drm#3d9a49a454d5e9ce4c2633ea71e413150b8c2943" dependencies = [ "async-trait", "bitflags 2.9.1", @@ -6557,7 +6557,7 @@ dependencies = [ [[package]] name = "waynest-macros" version = "0.0.25" -source = "git+https://github.com/technobaboo/waynest.git?branch=fix%2Ffd_clear#0b2e3e5b5383c1f7011599849e2baf1c9afeb9bb" +source = "git+https://github.com/technobaboo/waynest.git?branch=fix%2Fwayland-drm#3d9a49a454d5e9ce4c2633ea71e413150b8c2943" dependencies = [ "quote", "syn 2.0.104", diff --git a/Cargo.toml b/Cargo.toml index 02d4f1b..09dc92d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,15 +23,15 @@ path = "src/main.rs" [features] default = ["wayland"] wayland = [ - "dep:cluFlock", - "dep:waynest", - "dep:tokio-stream", - "dep:memmap2", - "dep:drm-fourcc", - "dep:memfd", - "dep:vulkano", - "dep:wgpu-hal", - "dep:ash", + "dep:cluFlock", + "dep:waynest", + "dep:tokio-stream", + "dep:memmap2", + "dep:drm-fourcc", + "dep:memfd", + "dep:vulkano", + "dep:wgpu-hal", + "dep:ash", ] profile_tokio = ["dep:console-subscriber", "tokio/tracing"] profile_app = ["dep:tracing-tracy", "bevy/trace_tracy", "bevy/trace"] @@ -88,28 +88,28 @@ tokio = { version = "1.39.2", features = ["rt-multi-thread", "signal", "time"] } # bevy bevy = { version = "0.16", default-features = false, features = [ - "bevy_asset", - "bevy_audio", - "bevy_color", - "bevy_core_pipeline", - "bevy_gizmos", - "bevy_gltf", - "bevy_log", - "bevy_pbr", - "bevy_render", - "bevy_window", - "bevy_winit", - "std", - "x11", - "wayland", - "mp3", - "wav", - "qoi", - "png", - "hdr", - "jpeg", - "tonemapping_luts", - "multi_threaded", + "bevy_asset", + "bevy_audio", + "bevy_color", + "bevy_core_pipeline", + "bevy_gizmos", + "bevy_gltf", + "bevy_log", + "bevy_pbr", + "bevy_render", + "bevy_window", + "bevy_winit", + "std", + "x11", + "wayland", + "mp3", + "wav", + "qoi", + "png", + "hdr", + "jpeg", + "tonemapping_luts", + "multi_threaded", ] } bevy_mod_xr = "0.3" bevy_mod_openxr = "0.3" @@ -138,10 +138,11 @@ cluFlock = { version = "1.2.7", optional = true } # for the lockfile checking # "stable", # "tracing", # ], default-features = false, optional = true } -waynest = { git = "https://github.com/technobaboo/waynest.git", branch = "fix/fd_clear", features = [ - "server", - "stable", - "tracing", +waynest = { git = "https://github.com/technobaboo/waynest.git", branch = "fix/wayland-drm", features = [ + "server", + "stable", + "external", + "tracing", ], default-features = false, optional = true } tokio-stream = { version = "0.1.17", optional = true } memmap2 = { version = "0.9.5", optional = true } diff --git a/src/wayland/core/mod.rs b/src/wayland/core/mod.rs index e724bce..6e73d01 100644 --- a/src/wayland/core/mod.rs +++ b/src/wayland/core/mod.rs @@ -1,11 +1,9 @@ pub mod buffer; pub mod callback; pub mod compositor; -pub mod display; pub mod keyboard; pub mod output; pub mod pointer; -pub mod registry; pub mod seat; pub mod shm; pub mod shm_buffer_backing; diff --git a/src/wayland/core/display.rs b/src/wayland/display.rs similarity index 98% rename from src/wayland/core/display.rs rename to src/wayland/display.rs index 0707783..df4a0d9 100644 --- a/src/wayland/core/display.rs +++ b/src/wayland/display.rs @@ -4,9 +4,9 @@ use crate::wayland::{ MessageSink, core::{ callback::{Callback, WlCallback}, - registry::Registry, seat::Seat, }, + registry::Registry, }; use global_counter::primitive::exact::CounterU32; use std::{ diff --git a/src/wayland/dmabuf/buffer_backing.rs b/src/wayland/dmabuf/buffer_backing.rs index eb7ea1a..0e411e2 100644 --- a/src/wayland/dmabuf/buffer_backing.rs +++ b/src/wayland/dmabuf/buffer_backing.rs @@ -17,10 +17,8 @@ use waynest::server::protocol::stable::linux_dmabuf_v1::zwp_linux_buffer_params_ /// Parameters for a shared memory buffer pub struct DmabufBacking { - params: Arc, size: Vector2, format: DrmFourcc, - _flags: Flags, tex: OnceLock>, pending_imported_dmatex: Mutex>, } @@ -28,10 +26,8 @@ pub struct DmabufBacking { impl std::fmt::Debug for DmabufBacking { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("DmabufBacking") - .field("params", &self.params) .field("size", &self.size) .field("format", &self.format) - .field("_flags", &self._flags) .field("tex", &self.tex) .finish() } @@ -39,7 +35,23 @@ impl std::fmt::Debug for DmabufBacking { impl DmabufBacking { #[tracing::instrument(level = "debug", skip_all)] - pub fn new( + pub fn new(dmatex: Dmatex) -> Result { + let dev = RENDER_DEVICE.wait(); + + Ok(Self { + size: [dmatex.res.x, dmatex.res.y].into(), + format: DrmFourcc::try_from(dmatex.format).unwrap(), + tex: OnceLock::new(), + pending_imported_dmatex: Mutex::new(Some(import_texture( + dev, + dmatex, + DropCallback(None), + )?)), + }) + } + + #[tracing::instrument(level = "debug", skip_all)] + pub fn from_params( params: Arc, size: Vector2, format: DrmFourcc, @@ -60,17 +72,8 @@ impl DmabufBacking { flip_y: flags.contains(Flags::YInvert), srgb: true, }; - let dev = RENDER_DEVICE.wait(); - let imported_tex = import_texture(dev, dmatex, DropCallback(None))?; - Ok(Self { - params, - size, - format, - _flags: flags, - tex: OnceLock::new(), - pending_imported_dmatex: Mutex::new(Some(imported_tex)), - }) + DmabufBacking::new(dmatex) } #[tracing::instrument(level = "debug", skip_all)] diff --git a/src/wayland/dmabuf/buffer_params.rs b/src/wayland/dmabuf/buffer_params.rs index d035ac0..f6628bb 100644 --- a/src/wayland/dmabuf/buffer_params.rs +++ b/src/wayland/dmabuf/buffer_params.rs @@ -104,7 +104,7 @@ impl ZwpLinuxBufferParamsV1 for BufferParams { tracing::info!("Creating buffer from BufferParams {:?}", self.id); // Create the buffer with DMA-BUF backing using self as the backing let size = [width as u32, height as u32].into(); - let buffer = DmabufBacking::new( + let buffer = DmabufBacking::from_params( client.get::(self.id).unwrap(), size, DrmFourcc::try_from(format).unwrap(), @@ -138,7 +138,7 @@ impl ZwpLinuxBufferParamsV1 for BufferParams { ) -> Result<()> { // TODO: terminate client on fail, or send a fail event or something // Create the buffer with DMA-BUF backing using self as the backing - _ = DmabufBacking::new( + _ = DmabufBacking::from_params( client.get::(self.id).unwrap(), [width as u32, height as u32].into(), DrmFourcc::try_from(format).unwrap(), diff --git a/src/wayland/dmabuf/mod.rs b/src/wayland/dmabuf/mod.rs index c51b168..6ab28a7 100644 --- a/src/wayland/dmabuf/mod.rs +++ b/src/wayland/dmabuf/mod.rs @@ -2,6 +2,8 @@ pub mod buffer_backing; pub mod buffer_params; pub mod feedback; +use std::sync::LazyLock; + use super::{util::ClientExt, vulkano_data::VULKANO_CONTEXT}; use crate::core::registry::Registry; use bevy_dmabuf::{format_mapping::drm_fourcc_to_vk_format, wgpu_init::vulkan_to_wgpu}; @@ -20,6 +22,30 @@ use waynest::{ wire::ObjectId, }; +pub static DMABUF_FORMATS: LazyLock> = LazyLock::new(|| { + let vk = VULKANO_CONTEXT.wait(); + + ALL_DRM_FOURCCS + .iter() + .copied() + .filter_map(|f| Some((f, drm_fourcc_to_vk_format(f)?))) + .filter(|(_, vk_format)| vulkan_to_wgpu(*vk_format).is_some()) + .filter_map(|(f, vk_format)| { + Some(( + f, + vk.phys_dev + .format_properties(vk_format.try_into().unwrap()) + .ok()? + .drm_format_modifier_properties + .into_iter() + .map(|v| v.drm_format_modifier) + .collect::>(), + )) + }) + .flat_map(|(f, mods)| mods.into_iter().map(move |modifier| (f, modifier))) + .collect() +}); + /// Main DMA-BUF interface implementation /// /// This interface allows clients to create wl_buffers from DMA-BUFs. @@ -45,31 +71,10 @@ pub struct Dmabuf { impl Dmabuf { /// Create a new DMA-BUF interface instance pub async fn new(client: &mut Client, id: ObjectId, version: u32) -> Result { - let vk = VULKANO_CONTEXT.wait(); - let formats: FxHashSet<(DrmFourcc, u64)> = ALL_DRM_FOURCCS - .iter() - .copied() - .filter_map(|f| Some((f, drm_fourcc_to_vk_format(f)?))) - .filter(|(_, vk_format)| vulkan_to_wgpu(*vk_format).is_some()) - .filter_map(|(f, vk_format)| { - Some(( - f, - vk.phys_dev - .format_properties(vk_format.try_into().unwrap()) - .ok()? - .drm_format_modifier_properties - .into_iter() - .map(|v| v.drm_format_modifier) - .collect::>(), - )) - }) - .flat_map(|(f, mods)| mods.into_iter().map(move |modifier| (f, modifier))) - .collect(); - let dmabuf = Self { active_params: Registry::new(), version, - formats, + formats: DMABUF_FORMATS.clone(), }; if version < 3 { diff --git a/src/wayland/mesa_drm.rs b/src/wayland/mesa_drm.rs new file mode 100644 index 0000000..570df30 --- /dev/null +++ b/src/wayland/mesa_drm.rs @@ -0,0 +1,126 @@ +use crate::wayland::{ + core::buffer::{Buffer, BufferBacking}, + dmabuf::{DMABUF_FORMATS, buffer_backing::DmabufBacking}, + vulkano_data::VULKANO_CONTEXT, +}; +use bevy_dmabuf::dmatex::{Dmatex, DmatexPlane, Resolution}; +use rustc_hash::FxHashSet; +use std::os::fd::OwnedFd; +use waynest::{ + server::{Client, Dispatcher, Result, protocol::external::drm::wl_drm::*}, + wire::ObjectId, +}; + +#[derive(Debug, Dispatcher, Default)] +pub struct MesaDrm { + version: u32, +} +impl MesaDrm { + pub async fn new(client: &mut Client, id: ObjectId, version: u32) -> Result { + let drm = MesaDrm { version }; + + let path = { + // Get the device information from Vulkan properties + let props = VULKANO_CONTEXT.get().unwrap().phys_dev.properties(); + let minor_version = props.render_minor.unwrap(); + format!("/dev/dri/render{minor_version}") + }; + drm.device(client, id, path).await?; + + // this is basically just enabling ancient dmabufs lel + if drm.version >= 2 { + drm.capabilities(client, id, Capability::Prime as u32) + .await?; + } + + // DRM fomrats check + let formats = DMABUF_FORMATS + .iter() + .map(|(fourcc, _)| fourcc) + .collect::>(); + for format in formats { + drm.format(client, id, *format as u32).await?; + } + + Ok(drm) + } +} +impl WlDrm for MesaDrm { + async fn authenticate(&self, client: &mut Client, sender_id: ObjectId, _id: u32) -> Result<()> { + self.authenticated(client, sender_id).await + } + + async fn create_buffer( + &self, + _client: &mut Client, + _sender_id: ObjectId, + _id: ObjectId, + _name: u32, + _width: i32, + _height: i32, + _stride: u32, + _format: u32, + ) -> Result<()> { + tracing::error!("Tried to create non-prime wl_drm buffer!"); + Ok(()) + } + + async fn create_planar_buffer( + &self, + _client: &mut Client, + _sender_id: ObjectId, + _id: ObjectId, + _name: u32, + _width: i32, + _height: i32, + _format: u32, + _offset0: i32, + _stride0: i32, + _offset1: i32, + _stride1: i32, + _offset2: i32, + _stride2: i32, + ) -> Result<()> { + tracing::error!("Tried to create non-prime wl_drm buffer!"); + Ok(()) + } + + async fn create_prime_buffer( + &self, + client: &mut Client, + _sender_id: ObjectId, + buffer_id: ObjectId, + name: OwnedFd, + width: i32, + height: i32, + format: u32, + offset0: i32, + stride0: i32, + _offset1: i32, + _stride1: i32, + _offset2: i32, + _stride2: i32, + ) -> Result<()> { + // TODO: actual error checking + + let _ = DmabufBacking::new(Dmatex { + planes: vec![DmatexPlane { + dmabuf_fd: name.into(), + modifier: 72057594037927935, // because drmfourcc is so broken it doesn't actually export this, this is Invalid btw + offset: offset0 as u32, + stride: stride0, + }], + res: Resolution { + x: width as u32, + y: height as u32, + }, + format, + flip_y: false, + srgb: true, + }) + .inspect_err(|e| tracing::error!("Failed to import dmabuf because {e}")) + .map(|backing| Buffer::new(client, buffer_id, BufferBacking::Dmabuf(backing))); + + Ok(()) + } +} diff --git a/src/wayland/mod.rs b/src/wayland/mod.rs index a49fda6..dc935c8 100644 --- a/src/wayland/mod.rs +++ b/src/wayland/mod.rs @@ -1,8 +1,11 @@ -pub mod core; -pub mod dmabuf; -pub mod util; -pub mod vulkano_data; -pub mod xdg; +mod core; +mod display; +mod dmabuf; +mod mesa_drm; +mod registry; +mod util; +mod vulkano_data; +mod xdg; use crate::core::registry::OwnedRegistry; use crate::nodes::drawable::model::ModelNodeSystemSet; @@ -25,7 +28,8 @@ use bevy_dmabuf::import::ImportedDmatexs; use bevy_mod_xr::session::XrRenderSet; use cluFlock::{FlockLock, ToFlock}; use core::buffer::BufferUsage; -use core::{buffer::Buffer, callback::Callback, display::Display, surface::WL_SURFACE_REGISTRY}; +use core::{buffer::Buffer, callback::Callback, surface::WL_SURFACE_REGISTRY}; +use display::Display; use mint::Vector2; use std::fs::File; use std::{ diff --git a/src/wayland/core/registry.rs b/src/wayland/registry.rs similarity index 83% rename from src/wayland/core/registry.rs rename to src/wayland/registry.rs index 173c8e4..8dd9590 100644 --- a/src/wayland/core/registry.rs +++ b/src/wayland/registry.rs @@ -1,19 +1,23 @@ use crate::wayland::{ core::{ compositor::{Compositor, WlCompositor}, - display::Display, output::{Output, WlOutput}, seat::{Seat, WlSeat}, shm::{Shm, WlShm}, }, + display::Display, dmabuf::Dmabuf, + mesa_drm::MesaDrm, xdg::wm_base::{WmBase, XdgWmBase}, }; -pub use waynest::server::protocol::core::wayland::wl_registry::*; - -use waynest::server::protocol::stable::linux_dmabuf_v1::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1; use waynest::{ - server::{Client, Dispatcher, Error, Result}, + server::{ + Client, Dispatcher, Error, Result, + protocol::{ + core::wayland::wl_registry::*, external::drm::wl_drm::WlDrm, + stable::linux_dmabuf_v1::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1, + }, + }, wire::{NewId, ObjectId}, }; @@ -25,6 +29,7 @@ impl RegistryGlobals { pub const SEAT: u32 = 3; pub const OUTPUT: u32 = 4; pub const DMABUF: u32 = 5; + pub const WL_DRM: u32 = 6; } #[derive(Debug, Dispatcher, Default)] @@ -86,6 +91,15 @@ impl Registry { ) .await?; + self.global( + client, + sender_id, + RegistryGlobals::WL_DRM, + crate::wayland::mesa_drm::MesaDrm::INTERFACE.to_string(), + MesaDrm::VERSION, + ) + .await?; + Ok(()) } } @@ -137,6 +151,12 @@ impl WlRegistry for Registry { let dmabuf = Dmabuf::new(client, new_id.object_id, new_id.version).await?; client.insert(new_id.object_id, dmabuf); } + RegistryGlobals::WL_DRM => { + tracing::info!("Binding wl_drm"); + + let drm = MesaDrm::new(client, new_id.object_id, new_id.version).await?; + client.insert(new_id.object_id, drm); + } id => { tracing::error!(id, "Wayland: failed to bind to registry global"); return Err(Error::MissingObject(unsafe { ObjectId::from_raw(name) })); diff --git a/src/wayland/util.rs b/src/wayland/util.rs index c666b34..c971697 100644 --- a/src/wayland/util.rs +++ b/src/wayland/util.rs @@ -1,6 +1,6 @@ #![allow(unused)] -use super::{MessageSink, core::display::Display}; +use super::{MessageSink, display::Display}; use std::{fmt::Debug, sync::Arc}; use waynest::{server::Client, wire::ObjectId}; diff --git a/src/wayland/xdg/surface.rs b/src/wayland/xdg/surface.rs index 54bfc29..9934058 100644 --- a/src/wayland/xdg/surface.rs +++ b/src/wayland/xdg/surface.rs @@ -1,8 +1,5 @@ use super::{popup::Popup, positioner::Positioner, toplevel::Mapped}; -use crate::wayland::{ - core::{display::Display, surface::SurfaceRole}, - xdg::toplevel::Toplevel, -}; +use crate::wayland::{core::surface::SurfaceRole, display::Display, xdg::toplevel::Toplevel}; use std::sync::Arc; use std::sync::Weak; pub use waynest::server::protocol::stable::xdg_shell::xdg_surface::*;