fix(wayland): support all dmabuf protocol versions

This commit is contained in:
Nova
2025-07-15 00:44:23 -07:00
parent 12a3dc26af
commit 72d1173d2e
3 changed files with 93 additions and 59 deletions

View File

@@ -133,8 +133,9 @@ impl WlRegistry for Registry {
}
RegistryGlobals::DMABUF => {
tracing::info!("Binding dmabuf");
let dmabuf = client.insert(new_id.object_id, Dmabuf::new());
dmabuf.send_modifiers(client, new_id.object_id).await?;
let dmabuf = Dmabuf::new(client, new_id.object_id, new_id.version).await?;
client.insert(new_id.object_id, dmabuf);
}
id => {
tracing::error!(id, "Wayland: failed to bind to registry global");

View File

@@ -1,12 +1,11 @@
use bevy_dmabuf::{
format_mapping::{drm_fourcc_to_vk_format, vk_format_to_drm_fourcc},
wgpu_init::vulkan_to_wgpu,
};
use super::Dmabuf;
use crate::wayland::vulkano_data::VULKANO_CONTEXT;
use drm_fourcc::DrmFourcc;
use memfd::MemfdOptions;
use std::{
io::Write,
os::fd::{FromRawFd, IntoRawFd, OwnedFd},
sync::Arc,
};
use waynest::{
server::{
@@ -18,42 +17,17 @@ use waynest::{
wire::ObjectId,
};
use crate::wayland::vulkano_data::{DMA_CAPABLE_FORMATS, VULKANO_CONTEXT};
#[derive(Debug, Dispatcher)]
pub struct DmabufFeedback;
pub struct DmabufFeedback(pub Arc<Dmabuf>);
impl DmabufFeedback {
pub async fn send_params(&self, client: &mut Client, sender_id: ObjectId) -> Result<()> {
let vk = VULKANO_CONTEXT.wait();
let formats = DMA_CAPABLE_FORMATS
.iter()
.filter(|f| {
vk_format_to_drm_fourcc((**f).into())
.and_then(drm_fourcc_to_vk_format)
.and_then(vulkan_to_wgpu)
.is_some()
})
.filter_map(|f| {
Some((
vk_format_to_drm_fourcc((*f).into())?,
vk.phys_dev
.format_properties(*f)
.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::<Vec<_>>();
let num_formats = formats.len();
let num_formats = self.0.formats.len();
// Send format table first
self.send_format_table(client, sender_id, formats).await?;
self.send_format_table(client, sender_id, &self.0.formats)
.await?;
// Get the device information from Vulkan properties
let props = vk.phys_dev.properties();
let props = VULKANO_CONTEXT.get().unwrap().phys_dev.properties();
// Create dev_t from the primary node major/minor numbers
let primary_dev_id = {
@@ -92,7 +66,7 @@ impl DmabufFeedback {
&self,
client: &mut Client,
sender_id: ObjectId,
formats: Vec<(DrmFourcc, u64)>,
formats: &[(DrmFourcc, u64)],
) -> Result<()> {
// Format + modifier pair (16 bytes):
// - format: u32
@@ -107,7 +81,7 @@ impl DmabufFeedback {
mfd.as_file().set_len(size as u64)?;
for (format, modifier) in formats {
let format = format as u32;
let format = format.clone() as u32;
// Write the format+modifier pair
mfd.as_file().write_all(&format.to_ne_bytes())?;
mfd.as_file().write_all(&0_u32.to_ne_bytes())?;

View File

@@ -2,19 +2,31 @@ pub mod buffer_backing;
pub mod buffer_params;
pub mod feedback;
use bevy_dmabuf::{
format_mapping::{drm_fourcc_to_vk_format, vk_format_to_drm_fourcc},
wgpu_init::vulkan_to_wgpu,
};
use buffer_params::BufferParams;
use drm_fourcc::DrmFourcc;
use feedback::DmabufFeedback;
use waynest::{
server::{
Client, Dispatcher, Result,
protocol::stable::linux_dmabuf_v1::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
Client, Dispatcher, Error, Result,
protocol::{
core::wayland::wl_display::WlDisplay,
stable::linux_dmabuf_v1::zwp_linux_dmabuf_v1::ZwpLinuxDmabufV1,
},
},
wire::ObjectId,
};
use crate::core::registry::Registry;
use super::{
util::ClientExt,
vulkano_data::{DMA_CAPABLE_FORMATS, VULKANO_CONTEXT},
};
/// Main DMA-BUF interface implementation
///
/// This interface allows clients to create wl_buffers from DMA-BUFs.
@@ -27,32 +39,68 @@ use crate::core::registry::Registry;
/// - Coherency for read access in dmabuf data
/// - Proper lifetime management of dmabuf file descriptors
/// - Safe handling of buffer attachments
#[derive(Dispatcher)]
#[derive(Debug, Dispatcher)]
pub struct Dmabuf {
// Track supported formats and modifiers
// formats: Mutex<FxHashSet<DrmFormat>>,
// Track active buffer parameters objects by their ID
active_params: Registry<BufferParams>,
pub(self) version: u32,
pub(self) formats: Vec<(DrmFourcc, u64)>,
}
impl Dmabuf {
/// Create a new DMA-BUF interface instance
pub fn new() -> Self {
// let mut formats = FxHashSet::default();
pub async fn new(client: &mut Client, id: ObjectId, version: u32) -> Result<Self> {
let vk = VULKANO_CONTEXT.wait();
let formats = DMA_CAPABLE_FORMATS
.iter()
.filter(|f| {
vk_format_to_drm_fourcc((**f).into())
.and_then(drm_fourcc_to_vk_format)
.and_then(vulkan_to_wgpu)
.is_some()
})
.filter_map(|f| {
Some((
vk_format_to_drm_fourcc((*f).into())?,
vk.phys_dev
.format_properties(*f)
.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();
Self {
let dmabuf = Self {
// formats: Mutex::new(formats),
active_params: Registry::new(),
}
}
version,
formats,
};
pub async fn send_modifiers(&self, client: &mut Client, sender_id: ObjectId) -> Result<()> {
let format = DrmFourcc::Xrgb8888 as u32;
let modifier_hi = 0u32; // Linear modifier high 32 bits
let modifier_lo = 0u32; // Linear modifier low 32 bits
self.modifier(client, sender_id, format, modifier_hi, modifier_lo)
.await?;
Ok(())
if version > 3 {
for (format, _) in &dmabuf.formats {
dmabuf.format(client, id, *format as u32).await?;
}
}
// `modifier` is deprecated in version 4
if version == 3 {
for (format, modifier) in &dmabuf.formats {
let format = *format as u32;
let modifier_hi = (*modifier >> 32) as u32;
let modifier_lo = *modifier as u32;
dmabuf
.modifier(client, id, format, modifier_hi, modifier_lo)
.await?;
}
}
Ok(dmabuf)
}
/// Remove a buffer parameters object from tracking
@@ -82,11 +130,24 @@ impl ZwpLinuxDmabufV1 for Dmabuf {
async fn get_default_feedback(
&self,
client: &mut Client,
_sender_id: ObjectId,
sender_id: ObjectId,
id: ObjectId,
) -> Result<()> {
if self.version < 3 {
client
.display()
.error(
client,
sender_id,
id,
71,
"Can't call get_default_feedback on version < 4 of dmabuf".into(),
)
.await?;
return Err(Error::Custom("Protocol error".into()));
}
// Create feedback object for default (non-surface-specific) settings
let feedback = client.insert(id, DmabufFeedback);
let feedback = client.insert(id, DmabufFeedback(client.get::<Dmabuf>(sender_id).unwrap()));
feedback.send_params(client, id).await?;
Ok(())
}
@@ -94,15 +155,13 @@ impl ZwpLinuxDmabufV1 for Dmabuf {
async fn get_surface_feedback(
&self,
client: &mut Client,
_sender_id: ObjectId,
sender_id: ObjectId,
id: ObjectId,
_surface: ObjectId,
) -> Result<()> {
// Create feedback object for surface-specific settings
// Note: Surface-specific feedback could be optimized based on the surface's
// requirements, but for now we use the same feedback as default
let feedback = client.insert(id, DmabufFeedback);
feedback.send_params(client, id).await?;
Ok(())
self.get_default_feedback(client, sender_id, id).await
}
}