diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 40d1f673..20e67883 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -39,6 +39,7 @@ use smithay::{ glow::GlowRenderer, multigpu::{gbm::GbmGlesBackend, Error as MultiError, GpuManager}, sync::SyncPoint, + utils::with_renderer_surface_state, Bind, ImportDma, Offscreen, }, session::{libseat::LibSeatSession, Event as SessionEvent, Session}, @@ -62,7 +63,10 @@ use smithay::{ linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1, presentation_time::server::wp_presentation_feedback, }, - wayland_server::{protocol::wl_surface::WlSurface, DisplayHandle, Resource}, + wayland_server::{ + protocol::{wl_buffer::WlBuffer, wl_surface::WlSurface}, + Client, DisplayHandle, Resource, Weak, + }, }, utils::{DeviceFd, Size, Transform}, wayland::{ @@ -97,13 +101,14 @@ pub struct KmsState { pub devices: HashMap, pub input_devices: HashMap, pub api: GpuManager>, - pub primary: DrmNode, + pub primary_node: DrmNode, session: LibSeatSession, + pub auto_assign: bool, _tokens: Vec, } pub struct Device { - render_node: DrmNode, + pub render_node: DrmNode, surfaces: HashMap, pub drm: DrmDevice, gbm: GbmDevice, @@ -113,6 +118,7 @@ pub struct Device { pub non_desktop_connectors: Vec<(connector::Handle, crtc::Handle)>, pub leasing_global: Option, pub active_leases: Vec, + pub active_buffers: HashSet>, event_token: Option, socket: Option, } @@ -367,6 +373,11 @@ pub fn init_backend( .map_err(|err| err.error) .context("Failed to initialize session event source")?; + let auto_assign = matches!( + std::env::var("COSMIC_RENDER_AUTO_ASSIGN").map(|val| val.to_lowercase()), + Ok(val) if val == "y" || val == "yes" || val == "true" + ); + state.backend = BackendData::Kms(KmsState { api, _tokens: vec![ @@ -374,8 +385,9 @@ pub fn init_backend( session_event_source, udev_event_source, ], - primary, + primary_node: primary, session, + auto_assign, devices: HashMap::new(), input_devices: HashMap::new(), }); @@ -598,6 +610,7 @@ impl State { }) .ok(), active_leases: Vec::new(), + active_buffers: HashSet::new(), event_token: Some(token), socket, }; @@ -621,9 +634,13 @@ impl State { let mut renderer = match backend.api.single_renderer(&render_node) { Ok(renderer) => renderer, Err(err) => { - warn!(?err, "Failed to initialize output."); backend.api.as_mut().remove_node(&render_node); - return Ok(()); + return Err(err).with_context(|| { + format!( + "Failed to initialize renderer for device: {}, skipping", + render_node + ) + }); } }; init_shaders(&mut renderer).expect("Failed to initialize renderer"); @@ -686,6 +703,11 @@ impl State { }; } } + + if !device.in_use(&backend.primary_node) { + backend.api.as_mut().remove_node(&render_node); + } + backend.devices.insert(drm_node, device); } @@ -735,6 +757,31 @@ impl State { outputs_removed.push(surface.output.clone()); } } + backend + .api + .as_mut() + .add_node(device.render_node, device.gbm.clone()) + .with_context(|| { + format!( + "Failed to initialize renderer for device: {}, skipping", + device.render_node + ) + })?; + + let mut renderer = match backend.api.single_renderer(&device.render_node) { + Ok(renderer) => renderer, + Err(err) => { + backend.api.as_mut().remove_node(&device.render_node); + return Err(err).with_context(|| { + format!( + "Failed to initialize renderer for device: {}, skipping", + device.render_node + ) + }); + } + }; + init_shaders(&mut renderer).expect("Failed to initialize renderer"); + for (crtc, conn) in changes.added { let non_desktop = match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") { @@ -778,13 +825,6 @@ impl State { ); } } else { - let mut renderer = match backend.api.single_renderer(&device.render_node) { - Ok(renderer) => renderer, - Err(err) => { - warn!(?err, "Failed to initialize output."); - continue; - } - }; match device.setup_surface(crtc, conn, (w, 0), &mut renderer) { Ok(output) => { w += output @@ -827,6 +867,15 @@ impl State { .remove_output(&output, seats.iter().cloned()); } + { + let backend = self.backend.kms(); + if let Some(device) = backend.devices.get_mut(&drm_node) { + if !device.in_use(&backend.primary_node) { + backend.api.as_mut().remove_node(&device.render_node); + } + } + } + Ok(()) } @@ -1012,49 +1061,58 @@ impl Device { Ok(output) } + + pub fn in_use(&self, primary: &DrmNode) -> bool { + &self.render_node == primary || !self.surfaces.is_empty() || !self.active_buffers.is_empty() + } } -pub fn source_node_for_surface(w: &WlSurface, dh: &DisplayHandle) -> Option { - // Lets check the global drm-node the client got either through default-feedback or wl_drm - let client = dh.get_client(w.id()).ok()?; - if let Some(normal_client) = client.get_data::() { - return normal_client.drm_node.clone(); - } - // last but not least all xwayland-surfaces should also share a single node - if let Some(xwayland_client) = client.get_data::() { - return xwayland_client.user_data().get::().cloned(); - } - None +fn source_node_for_surface<'a>( + w: &WlSurface, + mut devices: impl Iterator, +) -> Option { + with_renderer_surface_state(w, |state| { + state.buffer().and_then(|buffer| { + devices.find_map(|dev| { + dev.active_buffers + .contains(&buffer.downgrade()) + .then_some(dev.render_node) + }) + }) + }) } fn render_node_for_output( - dh: &DisplayHandle, output: &Output, + primary_node: DrmNode, target_node: DrmNode, shell: &Shell, + non_target_devices: &Vec<(&DrmNode, &mut Device)>, ) -> DrmNode { + if target_node == primary_node { + return target_node; + } + let workspace = shell.active_space(output); let nodes = workspace .get_fullscreen() .map(|w| vec![w.clone()]) .unwrap_or_else(|| workspace.windows().collect::>()) .into_iter() - .flat_map(|w| w.wl_surface().and_then(|s| source_node_for_surface(&s, dh))) + .flat_map(|w| { + w.wl_surface().and_then(|s| { + source_node_for_surface(&s, non_target_devices.iter().map(|(_, dev)| &**dev)) + }) + }) .collect::>(); - if nodes.contains(&target_node) || nodes.is_empty() { + + if nodes.is_empty() { + // we don't want to force needlessly expensive imports, + // so we only choose the target node if it is save and use the main_device otherwise. + // (possibly fixable, once we have kernel API to test for migrations or dmabuf-v5) target_node } else { - nodes - .iter() - .fold(HashMap::new(), |mut count_map, node| { - let count = count_map.entry(node).or_insert(0); - *count += 1; - count_map - }) - .into_iter() - .reduce(|a, b| if a.1 > b.1 { a } else { b }) - .map(|(node, _)| *node) - .unwrap_or(target_node) + primary_node } } @@ -1494,11 +1552,17 @@ impl KmsState { target: DrmNode, shell: &Shell, ) { - let render = render_node_for_output(dh, &output, target, &shell); + let render = render_node_for_output( + &output, + self.primary_node, + target, + &shell, + &self.devices.iter_mut().collect(), + ); if let Err(err) = self.api.early_import( if let Some(client) = dh.get_client(surface.id()).ok() { if let Some(normal_client) = client.get_data::() { - normal_client.drm_node.clone() + normal_client.advertised_drm_node.clone() } else if let Some(xwayland_client) = client.get_data::() { xwayland_client.user_data().get::().cloned() } else { @@ -1514,19 +1578,42 @@ impl KmsState { } } - pub fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<()> { - for device in self.devices.values() { + pub fn dmabuf_imported( + &mut self, + _client: Option, + global: &DmabufGlobal, + dmabuf: Dmabuf, + ) -> Result { + for device in self.devices.values_mut() { if device .socket .as_ref() .map(|s| &s.dmabuf_global == global) .unwrap_or(false) { + if device.render_node != self.primary_node { + if !device.in_use(&self.primary_node) { + self.api + .as_mut() + .add_node(device.render_node, device.gbm.clone()) + .context("Failed to initialize device")?; + + let mut renderer = match self.api.single_renderer(&device.render_node) { + Ok(renderer) => renderer, + Err(err) => { + self.api.as_mut().remove_node(&device.render_node); + return Err(err).context("Failed to initialize renderer"); + } + }; + init_shaders(&mut renderer).context("Failed to initialize shaders")?; + } + } + return self .api .single_renderer(&device.render_node)? .import_dmabuf(&dmabuf, None) - .map(|_| ()) + .map(|_| device.render_node) .map_err(Into::into); } } @@ -1582,13 +1669,14 @@ impl KmsState { if let Some(surface) = target_device.surfaces.get_mut(&crtc) { let target_node = target_device.render_node; let render_node = render_node_for_output( - &state.common.display_handle, &surface.output, + backend.primary_node, target_node, &state.common.shell, + &other, ); - let common = &mut state.common; + let common = &mut state.common; let result = if render_node != target_node { let render_device = &mut other .iter_mut() diff --git a/src/backend/kms/socket.rs b/src/backend/kms/socket.rs index 414c2dae..abde22c3 100644 --- a/src/backend/kms/socket.rs +++ b/src/backend/kms/socket.rs @@ -50,7 +50,7 @@ impl State { // initialize globals let filter = move |client: &Client| { if let Some(normal_client) = client.get_data::() { - let dev_id = normal_client.drm_node.unwrap(); + let dev_id = normal_client.advertised_drm_node.unwrap(); return dev_id == render_node; } if let Some(xwayland_client) = client.get_data::() { diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 6c53dee8..38348877 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -331,6 +331,15 @@ pub fn init_shaders(renderer: &mut R) -> Result<(), GlesError let glow_renderer = renderer.glow_renderer_mut(); let gles_renderer: &mut GlesRenderer = glow_renderer.borrow_mut(); + { + let egl_context = gles_renderer.egl_context(); + if egl_context.user_data().get::().is_some() + && egl_context.user_data().get::().is_some() + { + return Ok(()); + } + } + let outline_shader = gles_renderer.compile_custom_pixel_shader( OUTLINE_SHADER, &[ diff --git a/src/main.rs b/src/main.rs index 435094bd..a32ad7d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,10 @@ use anyhow::{Context, Result}; use std::{env, ffi::OsString, process, sync::Arc}; use tracing::{error, info, warn}; -use crate::wayland::handlers::compositor::client_compositor_state; +use crate::{ + state::BackendData, utils::prelude::SeatExt, + wayland::handlers::compositor::client_compositor_state, +}; pub mod backend; pub mod config; @@ -145,15 +148,23 @@ fn init_wayland_display( event_loop .handle() .insert_source(source, |client_stream, _, state| { + let node = match &state.backend { + BackendData::Kms(kms_state) if kms_state.auto_assign => kms_state + .target_node_for_output(&state.common.last_active_seat().active_output()), + _ => None, + }; + if let Err(err) = state.common.display_handle.insert_client( client_stream, Arc::new(if cfg!(debug_assertions) { state.new_privileged_client_state() + } else if let Some(node) = node { + state.new_client_state_with_node(node) } else { state.new_client_state() }), ) { - warn!(?err, "Error adding wayland client"); + warn!(?err, "Error adding wayland client") }; }) .with_context(|| "Failed to init the wayland socket source.")?; diff --git a/src/state.rs b/src/state.rs index 1deb9eb2..94f9f00c 100644 --- a/src/state.rs +++ b/src/state.rs @@ -1,11 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - backend::{ - kms::{source_node_for_surface, KmsState}, - winit::WinitState, - x11::X11State, - }, + backend::{kms::KmsState, winit::WinitState, x11::X11State}, config::{Config, OutputConfig}, input::Devices, shell::{grabs::SeatMoveGrabState, Shell}, @@ -54,8 +50,8 @@ use smithay::{ wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode, wayland_server::{ backend::{ClientData, ClientId, DisconnectReason}, - protocol::wl_shm, - Client, DisplayHandle, + protocol::{wl_shm, wl_surface::WlSurface}, + Client, DisplayHandle, Resource, }, }, utils::{Clock, IsAlive, Monotonic}, @@ -84,6 +80,7 @@ use smithay::{ virtual_keyboard::VirtualKeyboardManagerState, xwayland_keyboard_grab::XWaylandKeyboardGrabState, }, + xwayland::XWaylandClientData, }; use time::UtcOffset; use tracing::error; @@ -111,7 +108,7 @@ macro_rules! fl { pub struct ClientState { pub compositor_client_state: CompositorClientState, pub workspace_client_state: WorkspaceClientState, - pub drm_node: Option, + pub advertised_drm_node: Option, pub privileged: bool, pub evls: LoopSignal, pub security_context: Option, @@ -123,6 +120,19 @@ impl ClientData for ClientState { } } +pub fn advertised_node_for_surface(w: &WlSurface, dh: &DisplayHandle) -> Option { + // Lets check the global drm-node the client got either through default-feedback or wl_drm + let client = dh.get_client(w.id()).ok()?; + if let Some(normal_client) = client.get_data::() { + return normal_client.advertised_drm_node.clone(); + } + // last but not least all xwayland-surfaces should also share a single node + if let Some(xwayland_client) = client.get_data::() { + return xwayland_client.user_data().get::().cloned(); + } + None +} + #[derive(Debug)] pub struct State { pub backend: BackendData, @@ -168,7 +178,7 @@ pub struct Common { pub seat_state: SeatState, pub session_lock_manager_state: SessionLockManagerState, pub shm_state: ShmState, - pub wl_drm_state: WlDrmState, + pub wl_drm_state: WlDrmState>, pub viewporter_state: ViewporterState, pub kde_decoration_state: KdeDecorationState, pub xdg_decoration_state: XdgDecorationState, @@ -278,11 +288,16 @@ impl BackendData { pub fn dmabuf_imported( &mut self, + client: Option, global: &DmabufGlobal, dmabuf: Dmabuf, - ) -> Result<(), anyhow::Error> { + ) -> Result, anyhow::Error> { match self { - BackendData::Kms(ref mut state) => state.dmabuf_imported(global, dmabuf)?, + BackendData::Kms(ref mut state) => { + return state + .dmabuf_imported(client, global, dmabuf) + .map(|node| Some(node)) + } BackendData::Winit(ref mut state) => { state.backend.renderer().import_dmabuf(&dmabuf, None)?; } @@ -290,8 +305,8 @@ impl BackendData { state.renderer.import_dmabuf(&dmabuf, None)?; } _ => unreachable!("No backend set when importing dmabuf"), - } - Ok(()) + }; + Ok(None) } } @@ -357,7 +372,7 @@ impl State { ShmState::new::(dh, vec![wl_shm::Format::Xbgr8888, wl_shm::Format::Abgr8888]); let seat_state = SeatState::::new(); let viewporter_state = ViewporterState::new::(dh); - let wl_drm_state = WlDrmState; + let wl_drm_state = WlDrmState::>::default(); let kde_decoration_state = KdeDecorationState::new::(&dh, Mode::Client); let xdg_decoration_state = XdgDecorationState::new::(&dh); let session_lock_manager_state = @@ -432,19 +447,8 @@ impl State { ClientState { compositor_client_state: CompositorClientState::default(), workspace_client_state: WorkspaceClientState::default(), - drm_node: match &self.backend { - BackendData::Kms(kms_state) => { - match std::env::var("COSMIC_RENDER_AUTO_ASSIGN").map(|val| val.to_lowercase()) { - Ok(val) if val == "y" || val == "yes" || val == "true" => Some( - kms_state - .target_node_for_output( - &self.common.last_active_seat().active_output(), - ) - .unwrap_or(kms_state.primary), - ), - _ => Some(kms_state.primary), - } - } + advertised_drm_node: match &self.backend { + BackendData::Kms(kms_state) => Some(kms_state.primary_node), _ => None, }, privileged: false, @@ -457,7 +461,7 @@ impl State { ClientState { compositor_client_state: CompositorClientState::default(), workspace_client_state: WorkspaceClientState::default(), - drm_node: Some(drm_node), + advertised_drm_node: Some(drm_node), privileged: false, evls: self.common.event_loop_signal.clone(), security_context: None, @@ -468,8 +472,8 @@ impl State { ClientState { compositor_client_state: CompositorClientState::default(), workspace_client_state: WorkspaceClientState::default(), - drm_node: match &self.backend { - BackendData::Kms(kms_state) => Some(kms_state.primary), + advertised_drm_node: match &self.backend { + BackendData::Kms(kms_state) => Some(kms_state.primary_node), _ => None, }, privileged: true, @@ -537,7 +541,7 @@ impl Common { surface_primary_scanout_output, ); if let Some(feedback) = - source_node_for_surface(lock_surface.wl_surface(), &self.display_handle) + advertised_node_for_surface(lock_surface.wl_surface(), &self.display_handle) .and_then(|source| dmabuf_feedback(source)) { send_dmabuf_feedback_surface_tree( @@ -599,7 +603,7 @@ impl Common { if let Some(feedback) = window .wl_surface() .and_then(|wl_surface| { - source_node_for_surface(&wl_surface, &self.display_handle) + advertised_node_for_surface(&wl_surface, &self.display_handle) }) .and_then(|source| dmabuf_feedback(source)) { @@ -644,7 +648,7 @@ impl Common { if let Some(feedback) = window .wl_surface() .and_then(|wl_surface| { - source_node_for_surface(&wl_surface, &self.display_handle) + advertised_node_for_surface(&wl_surface, &self.display_handle) }) .and_then(|source| dmabuf_feedback(source)) { @@ -693,7 +697,9 @@ impl Common { window.send_frame(output, time, throttle, surface_primary_scanout_output); if let Some(feedback) = window .wl_surface() - .and_then(|wl_surface| source_node_for_surface(&wl_surface, &self.display_handle)) + .and_then(|wl_surface| { + advertised_node_for_surface(&wl_surface, &self.display_handle) + }) .and_then(|source| dmabuf_feedback(source)) { window.send_dmabuf_feedback( @@ -741,8 +747,9 @@ impl Common { throttle, surface_primary_scanout_output, ); - if let Some(feedback) = source_node_for_surface(&wl_surface, &self.display_handle) - .and_then(|source| dmabuf_feedback(source)) + if let Some(feedback) = + advertised_node_for_surface(&wl_surface, &self.display_handle) + .and_then(|source| dmabuf_feedback(source)) { send_dmabuf_feedback_surface_tree( &wl_surface, @@ -780,7 +787,7 @@ impl Common { }); layer_surface.send_frame(output, time, throttle, surface_primary_scanout_output); if let Some(feedback) = - source_node_for_surface(layer_surface.wl_surface(), &self.display_handle) + advertised_node_for_surface(layer_surface.wl_surface(), &self.display_handle) .and_then(|source| dmabuf_feedback(source)) { layer_surface.send_dmabuf_feedback( diff --git a/src/utils/screenshot.rs b/src/utils/screenshot.rs index 9038bbe1..f0df8d43 100644 --- a/src/utils/screenshot.rs +++ b/src/utils/screenshot.rs @@ -16,9 +16,8 @@ use smithay::{ use tracing::warn; use crate::{ - backend::kms::source_node_for_surface, shell::element::CosmicSurface, - state::{BackendData, State}, + state::{advertised_node_for_surface, BackendData, State}, }; pub fn screenshot_window(state: &mut State, surface: &CosmicSurface) { @@ -99,8 +98,8 @@ pub fn screenshot_window(state: &mut State, surface: &CosmicSurface) { if let Some(wl_surface) = surface.wl_surface() { let res = match &mut state.backend { BackendData::Kms(kms) => { - let node = source_node_for_surface(&wl_surface, &state.common.display_handle) - .unwrap_or(kms.primary); + let node = advertised_node_for_surface(&wl_surface, &state.common.display_handle) + .unwrap_or(kms.primary_node); kms.api .single_renderer(&node) .with_context(|| "Failed to get renderer for screenshot") diff --git a/src/wayland/handlers/buffer.rs b/src/wayland/handlers/buffer.rs index eb21f57f..a3d0604c 100644 --- a/src/wayland/handlers/buffer.rs +++ b/src/wayland/handlers/buffer.rs @@ -1,10 +1,22 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::utils::prelude::*; +use crate::{state::BackendData, utils::prelude::*}; use smithay::{ - reexports::wayland_server::protocol::wl_buffer::WlBuffer, wayland::buffer::BufferHandler, + reexports::wayland_server::{protocol::wl_buffer::WlBuffer, Resource}, + wayland::buffer::BufferHandler, }; impl BufferHandler for State { - fn buffer_destroyed(&mut self, _buffer: &WlBuffer) {} + fn buffer_destroyed(&mut self, buffer: &WlBuffer) { + if let BackendData::Kms(kms_state) = &mut self.backend { + for device in kms_state.devices.values_mut() { + if device.active_buffers.remove(&buffer.downgrade()) { + if !device.in_use(&kms_state.primary_node) { + kms_state.api.as_mut().remove_node(&device.render_node); + } + break; + } + } + } + } } diff --git a/src/wayland/handlers/dmabuf.rs b/src/wayland/handlers/dmabuf.rs index 7637ccd7..fd48d355 100644 --- a/src/wayland/handlers/dmabuf.rs +++ b/src/wayland/handlers/dmabuf.rs @@ -1,9 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-only -use crate::state::State; +use crate::state::{BackendData, State}; use smithay::{ backend::allocator::dmabuf::Dmabuf, delegate_dmabuf, + reexports::wayland_server::Resource, wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier}, }; @@ -18,10 +19,33 @@ impl DmabufHandler for State { dmabuf: Dmabuf, import_notifier: ImportNotifier, ) { - if self.backend.dmabuf_imported(global, dmabuf).is_err() { - import_notifier.failed(); - } else { - let _ = import_notifier.successful::(); + match self + .backend + .dmabuf_imported(import_notifier.client(), global, dmabuf) + { + Err(err) => { + tracing::debug!(?err, "dmabuf import failed"); + import_notifier.failed() + } + Ok(Some(node)) => { + // kms backend + let Ok(buffer) = import_notifier.successful::() else { + return + }; + + if let BackendData::Kms(kms_state) = &mut self.backend { + if let Some(device) = kms_state + .devices + .values_mut() + .find(|dev| dev.render_node == node) + { + device.active_buffers.insert(buffer.downgrade()); + } + } + } + Ok(None) => { + let _ = import_notifier.successful::(); + } } } } diff --git a/src/wayland/handlers/drm.rs b/src/wayland/handlers/drm.rs index 90c5596d..adb5ce6c 100644 --- a/src/wayland/handlers/drm.rs +++ b/src/wayland/handlers/drm.rs @@ -1,19 +1,40 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - state::State, - wayland::protocols::drm::{DrmHandler, ImportError}, + state::{BackendData, State}, + wayland::protocols::drm::{delegate_wl_drm, DrmHandler, ImportError}, +}; +use smithay::{ + backend::{allocator::dmabuf::Dmabuf, drm::DrmNode}, + reexports::wayland_server::{protocol::wl_buffer::WlBuffer, Resource}, + wayland::dmabuf::DmabufGlobal, }; -use smithay::{backend::allocator::dmabuf::Dmabuf, wayland::dmabuf::DmabufGlobal}; -impl DrmHandler for State { +impl DrmHandler> for State { fn dmabuf_imported( &mut self, global: &DmabufGlobal, dmabuf: Dmabuf, - ) -> Result<(), ImportError> { + ) -> Result, ImportError> { self.backend - .dmabuf_imported(global, dmabuf) + .dmabuf_imported(None, global, dmabuf) .map_err(|_| ImportError::Failed) } + + fn buffer_created(&mut self, buffer: WlBuffer, result: Option) { + if let Some(node) = result { + // kms backend + if let BackendData::Kms(kms_state) = &mut self.backend { + if let Some(device) = kms_state + .devices + .values_mut() + .find(|device| device.render_node == node) + { + device.active_buffers.insert(buffer.downgrade()); + } + } + } + } } + +delegate_wl_drm!(State; Option); diff --git a/src/wayland/handlers/mod.rs b/src/wayland/handlers/mod.rs index 5dae5d80..cf1c4ab5 100644 --- a/src/wayland/handlers/mod.rs +++ b/src/wayland/handlers/mod.rs @@ -31,7 +31,6 @@ pub mod toplevel_info; pub mod toplevel_management; pub mod viewporter; pub mod virtual_keyboard; -pub mod wl_drm; pub mod workspace; pub mod xdg_activation; pub mod xdg_shell; diff --git a/src/wayland/handlers/screencopy.rs b/src/wayland/handlers/screencopy.rs index 714bd0aa..b2ee3248 100644 --- a/src/wayland/handlers/screencopy.rs +++ b/src/wayland/handlers/screencopy.rs @@ -180,7 +180,7 @@ impl ScreencopyHandler for State { .and_then(|client| { // Lets check the global drm-node the client got either through default-feedback or wl_drm if let Some(normal_client) = client.get_data::() { - return normal_client.drm_node.clone(); + return normal_client.advertised_drm_node.clone(); } // last but not least all xwayland-surfaces should also share a single node if let Some(xwayland_client) = client.get_data::() { @@ -188,7 +188,7 @@ impl ScreencopyHandler for State { } None }) - .unwrap_or(kms.primary.clone()); + .unwrap_or(kms.primary_node.clone()); _kms_renderer = Some(kms.api.single_renderer(&node).unwrap()); _kms_renderer.as_mut().unwrap().as_mut() } @@ -456,7 +456,9 @@ fn formats_for_output( let mut _kms_renderer = None; let renderer = match backend { BackendData::Kms(ref mut kms) => { - let node = kms.target_node_for_output(&output).unwrap_or(kms.primary); + let node = kms + .target_node_for_output(&output) + .unwrap_or(kms.primary_node); _kms_renderer = Some(kms.api.single_renderer(&node).unwrap()); _kms_renderer.as_mut().unwrap().as_mut() } @@ -530,7 +532,7 @@ fn node_from_params( BackendData::Kms(kms) => Some( output .and_then(|output| kms.target_node_for_output(output)) - .unwrap_or(kms.primary), + .unwrap_or(kms.primary_node), ), _ => None, }, diff --git a/src/wayland/handlers/security_context.rs b/src/wayland/handlers/security_context.rs index 666e18eb..e564f1bf 100644 --- a/src/wayland/handlers/security_context.rs +++ b/src/wayland/handlers/security_context.rs @@ -37,14 +37,14 @@ impl SecurityContextHandler for State { let drm_node = client_data .as_ref() .and_then(|data| data.downcast_ref::()) - .and_then(|data| data.drm_node.clone()) + .and_then(|data| data.advertised_drm_node.clone()) .or_else(|| { client_data .as_ref() .and_then(|data| data.downcast_ref::()) .and_then(|data| data.user_data().get::().cloned()) }) - .or_else(|| new_state.drm_node.clone()); + .or_else(|| new_state.advertised_drm_node.clone()); if let Err(err) = state.common.display_handle.insert_client( client_stream, @@ -53,7 +53,7 @@ impl SecurityContextHandler for State { privileged: privileged && security_context.sandbox_engine.as_deref() == Some("com.system76.CosmicPanel"), - drm_node, + advertised_drm_node: drm_node, ..new_state }), ) { diff --git a/src/wayland/handlers/wl_drm.rs b/src/wayland/handlers/wl_drm.rs deleted file mode 100644 index 2bfdafbf..00000000 --- a/src/wayland/handlers/wl_drm.rs +++ /dev/null @@ -1,5 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-only - -use crate::{state::State, wayland::protocols::drm::delegate_wl_drm}; - -delegate_wl_drm!(State); diff --git a/src/wayland/protocols/drm.rs b/src/wayland/protocols/drm.rs index 19555a26..dba123ca 100644 --- a/src/wayland/protocols/drm.rs +++ b/src/wayland/protocols/drm.rs @@ -7,6 +7,7 @@ // You can use all the types from my_protocol as if they went from `wayland_client::protocol`. pub use generated::wl_drm; +#[allow(non_snake_case, non_upper_case_globals, non_camel_case_types)] mod generated { use smithay::reexports::wayland_server::{self, protocol::*}; @@ -43,13 +44,15 @@ pub enum ImportError { InvalidFormat, } -pub trait DrmHandler { - fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) - -> Result<(), ImportError>; +pub trait DrmHandler { + fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result; + fn buffer_created(&mut self, buffer: WlBuffer, result: R) { + let _ = (buffer, result); + } } -#[derive(Debug)] -pub struct WlDrmState; +#[derive(Debug, Default)] +pub struct WlDrmState(std::marker::PhantomData); /// Data associated with a drm global. pub struct DrmGlobalData { @@ -64,13 +67,14 @@ pub struct DrmInstanceData { dmabuf_global: DmabufGlobal, } -impl GlobalDispatch for WlDrmState +impl GlobalDispatch for WlDrmState where D: GlobalDispatch + Dispatch + BufferHandler + DmabufHandler + 'static, + R: 'static, { fn bind( _state: &mut D, @@ -102,14 +106,15 @@ where } } -impl Dispatch for WlDrmState +impl Dispatch for WlDrmState where D: GlobalDispatch + Dispatch + Dispatch + BufferHandler - + DrmHandler + + DrmHandler + 'static, + R: 'static, { fn request( state: &mut D, @@ -178,10 +183,11 @@ where match dma.build() { Some(dmabuf) => { match state.dmabuf_imported(&data.dmabuf_global, dmabuf.clone()) { - Ok(()) => { + Ok(result) => { // import was successful - data_init.init(id, dmabuf); + let buffer = data_init.init(id, dmabuf); trace!("Created a new validated dma wl_buffer via wl_drm."); + state.buffer_created(buffer, result); } Err(ImportError::InvalidFormat) => { @@ -212,7 +218,7 @@ where } } -impl WlDrmState { +impl WlDrmState { pub fn create_global( &mut self, display: &DisplayHandle, @@ -267,13 +273,13 @@ impl WlDrmState { } macro_rules! delegate_wl_drm { - ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => { + ($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty; $r: ty) => { smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::wayland::protocols::drm::wl_drm::WlDrm: $crate::wayland::protocols::drm::DrmGlobalData - ] => $crate::wayland::protocols::drm::WlDrmState); + ] => $crate::wayland::protocols::drm::WlDrmState<$r>); smithay::reexports::wayland_server::delegate_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [ $crate::wayland::protocols::drm::wl_drm::WlDrm: $crate::wayland::protocols::drm::DrmInstanceData - ] => $crate::wayland::protocols::drm::WlDrmState); + ] => $crate::wayland::protocols::drm::WlDrmState<$r>); }; } pub(crate) use delegate_wl_drm;