diff --git a/src/wayland/core/registry.rs b/src/wayland/core/registry.rs index 4c14d46..173c8e4 100644 --- a/src/wayland/core/registry.rs +++ b/src/wayland/core/registry.rs @@ -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"); diff --git a/src/wayland/dmabuf/feedback.rs b/src/wayland/dmabuf/feedback.rs index 1ce6603..c1f99cb 100644 --- a/src/wayland/dmabuf/feedback.rs +++ b/src/wayland/dmabuf/feedback.rs @@ -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); 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::>(), - )) - }) - .flat_map(|(f, mods)| mods.into_iter().map(move |modifier| (f, modifier))) - .collect::>(); - - 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())?; diff --git a/src/wayland/dmabuf/mod.rs b/src/wayland/dmabuf/mod.rs index cb84b46..4af6d55 100644 --- a/src/wayland/dmabuf/mod.rs +++ b/src/wayland/dmabuf/mod.rs @@ -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>, // Track active buffer parameters objects by their ID active_params: Registry, + 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 { + 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::>(), + )) + }) + .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::(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 } }