feat: wl_drm

This commit is contained in:
Nova
2025-07-30 23:24:39 -07:00
parent 72c5312c5e
commit f4c75c5705
12 changed files with 251 additions and 97 deletions

8
Cargo.lock generated
View File

@@ -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",

View File

@@ -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 }

View File

@@ -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;

View File

@@ -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::{

View File

@@ -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<BufferParams>,
size: Vector2<u32>,
format: DrmFourcc,
_flags: Flags,
tex: OnceLock<Handle<Image>>,
pending_imported_dmatex: Mutex<Option<ImportedTexture>>,
}
@@ -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<Self, ImportError> {
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<BufferParams>,
size: Vector2<u32>,
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)]

View File

@@ -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>(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>(self.id).unwrap(),
[width as u32, height as u32].into(),
DrmFourcc::try_from(format).unwrap(),

View File

@@ -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<FxHashSet<(DrmFourcc, u64)>> = 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::<Vec<_>>(),
))
})
.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<Self> {
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::<Vec<_>>(),
))
})
.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 {

126
src/wayland/mesa_drm.rs Normal file
View File

@@ -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<MesaDrm> {
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::<FxHashSet<_>>();
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(())
}
}

View File

@@ -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::{

View File

@@ -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) }));

View File

@@ -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};

View File

@@ -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::*;