diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index af989815..912f75a8 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -331,7 +331,6 @@ pub fn init_backend( // Create relative pointer global RelativePointerManagerState::new::(&dh); - // TODO: Do multiple Xwaylands for better multigpu state.launch_xwayland(Some(primary)); for (dev, path) in udev_dispatcher.as_source_ref().device_list() { diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 166036e3..8f3e5336 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -298,7 +298,7 @@ where renderer, output, &state.shell.override_redirect_windows, - state.xwayland_state.values_mut(), + state.xwayland_state.as_mut(), (!move_active && active_output).then_some(&last_active_seat), exclude_workspace_overview, ) diff --git a/src/backend/winit.rs b/src/backend/winit.rs index a75384ee..49244ac2 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -11,6 +11,7 @@ use crate::{ use anyhow::{anyhow, Context, Result}; use smithay::{ backend::{ + egl::EGLDevice, renderer::{ damage::DamageTrackedRenderer, gles2::Gles2Renderbuffer, glow::GlowRenderer, ImportDma, ImportEgl, @@ -25,6 +26,7 @@ use smithay::{ wayland_server::DisplayHandle, }, utils::Transform, + wayland::dmabuf::DmabufFeedbackBuilder, }; use std::cell::RefCell; use tracing::{error, info, warn}; @@ -257,7 +259,6 @@ pub fn init_backend( seats.iter().cloned(), &state.common.event_loop_handle, ); - state.launch_xwayland(None); Ok(()) @@ -269,21 +270,56 @@ fn init_egl_client_side( renderer: &mut WinitGraphicsBackend, ) -> Result<()> { let bind_result = renderer.renderer().bind_wl_display(dh); - match bind_result { - Ok(_) => { + let render_node = EGLDevice::device_for_display(renderer.renderer().egl_context().display()) + .and_then(|device| device.try_get_render_node()); + + let dmabuf_formats = renderer + .renderer() + .dmabuf_formats() + .cloned() + .collect::>(); + let dmabuf_default_feedback = match render_node { + Ok(Some(node)) => { + let dmabuf_default_feedback = + DmabufFeedbackBuilder::new(node.dev_id(), dmabuf_formats.clone()) + .build() + .unwrap(); + Some(dmabuf_default_feedback) + } + Ok(None) => { + warn!("Failed to query render node, dmabuf protocol will only advertise v3"); + None + } + Err(err) => { + warn!( + ?err, + "Failed to egl device for display, dmabuf protocol will only advertise v3" + ); + None + } + }; + + match dmabuf_default_feedback { + Some(feedback) => { + state + .common + .dmabuf_state + .create_global_with_default_feedback::(dh, &feedback); + info!("EGL hardware-acceleration enabled."); - let dmabuf_formats = renderer - .renderer() - .dmabuf_formats() - .cloned() - .collect::>(); + } + None if bind_result.is_ok() => { state .common .dmabuf_state .create_global::(dh, dmabuf_formats); + info!("EGL hardware-acceleration enabled."); } - Err(err) => warn!(?err, "Unable to initialize bind display to EGL."), - }; + None => { + let err = bind_result.unwrap_err(); + warn!(?err, "Unable to initialize bind display to EGL.") + } + } Ok(()) } diff --git a/src/backend/x11.rs b/src/backend/x11.rs index 66cd06fc..73b3c72e 100644 --- a/src/backend/x11.rs +++ b/src/backend/x11.rs @@ -35,6 +35,7 @@ use smithay::{ wayland_server::DisplayHandle, }, utils::{DeviceFd, Transform}, + wayland::dmabuf::DmabufFeedbackBuilder, }; use std::{cell::RefCell, os::unix::io::OwnedFd}; use tracing::{debug, error, info, warn}; @@ -351,7 +352,7 @@ pub fn init_backend( unsafe { GlowRenderer::new(context) }.with_context(|| "Failed to initialize renderer")?; init_shaders(&mut renderer).expect("Failed to initialize renderer"); - init_egl_client_side(dh, state, &mut renderer)?; + init_egl_client_side(dh, state, &drm_node, &mut renderer)?; state.backend = BackendData::X11(X11State { handle, @@ -381,7 +382,6 @@ pub fn init_backend( seats.iter().cloned(), &state.common.event_loop_handle, ); - state.launch_xwayland(None); event_loop @@ -475,22 +475,32 @@ pub fn init_backend( Ok(()) } -fn init_egl_client_side(dh: &DisplayHandle, state: &mut State, renderer: &mut R) -> Result<()> +fn init_egl_client_side( + dh: &DisplayHandle, + state: &mut State, + render_node: &DrmNode, + renderer: &mut R, +) -> Result<()> where R: ImportEgl + ImportDma, { - let bind_result = renderer.bind_wl_display(dh); - match bind_result { - Ok(_) => { - info!("EGL hardware-acceleration enabled."); - let dmabuf_formats = renderer.dmabuf_formats().cloned().collect::>(); - state - .common - .dmabuf_state - .create_global::(dh, dmabuf_formats); - } - Err(err) => warn!(?err, "Unable to initialize bind display to EGL."), - }; + if let Err(err) = renderer.bind_wl_display(dh) { + warn!( + ?err, + "Unable to initialize bind display to EGL. Some older clients may not work correctly." + ) + } + let dmabuf_formats = renderer.dmabuf_formats().cloned().collect::>(); + + let default_feedback = DmabufFeedbackBuilder::new(render_node.dev_id(), dmabuf_formats.clone()) + .build() + .unwrap(); + state + .common + .dmabuf_state + .create_global_with_default_feedback::(dh, &default_feedback); + + info!("EGL hardware-acceleration enabled."); Ok(()) } diff --git a/src/input/mod.rs b/src/input/mod.rs index fe9bd894..cc171df1 100644 --- a/src/input/mod.rs +++ b/src/input/mod.rs @@ -1017,8 +1017,7 @@ impl State { &self .common .xwayland_state - .values() - .next() + .as_ref() .map(|s| format!(":{}", s.display)) .unwrap_or(String::new()), ) diff --git a/src/session.rs b/src/session.rs index db1795fe..3dba3ccf 100644 --- a/src/session.rs +++ b/src/session.rs @@ -78,13 +78,7 @@ pub fn setup_socket(handle: LoopHandle, state: &State) -> Result<()> { .into_string() .map_err(|_| anyhow!("wayland socket is no valid utf-8 string?"))?, ); - if let Some(display) = state - .common - .xwayland_state - .values() - .next() - .map(|s| s.display) - { + if let Some(display) = state.common.xwayland_state.as_ref().map(|s| s.display) { env.insert(String::from("DISPLAY"), format!(":{}", display)); } let message = serde_json::to_string(&Message::SetEnv { variables: env }) diff --git a/src/shell/focus/mod.rs b/src/shell/focus/mod.rs index 52c632ed..d4b30a03 100644 --- a/src/shell/focus/mod.rs +++ b/src/shell/focus/mod.rs @@ -131,7 +131,7 @@ impl Shell { fn update_active<'a, 'b>( &mut self, seats: impl Iterator>, - xwms: impl Iterator, + mut xwm: Option<&'b mut XWaylandState>, ) { // update activate status let focused_windows = seats @@ -144,16 +144,13 @@ impl Shell { }) .collect::>(); - let mut xwms = xwms.collect::>(); for output in self.outputs.iter() { let workspace = self.workspaces.active_mut(output); for focused in focused_windows.iter() { if workspace.floating_layer.mapped().any(|m| m == focused) { if let CosmicSurface::X11(window) = focused.active_window() { - for xwm in xwms.iter_mut().flat_map(|state| state.xwm.as_mut()) { - if Some(xwm.id()) == window.xwm_id() { - let _ = xwm.raise_window(&window); - } + if let Some(xwm) = xwm.as_mut().and_then(|state| state.xwm.as_mut()) { + let _ = xwm.raise_window(&window); } } workspace.floating_layer.space.raise_element(focused, true); @@ -179,7 +176,7 @@ impl Common { state .common .shell - .update_active(seats.iter(), state.common.xwayland_state.values_mut()); + .update_active(seats.iter(), state.common.xwayland_state.as_mut()); } pub fn refresh_focus(state: &mut State) { @@ -274,6 +271,6 @@ impl Common { state .common .shell - .update_active(seats.iter(), state.common.xwayland_state.values_mut()) + .update_active(seats.iter(), state.common.xwayland_state.as_mut()) } } diff --git a/src/shell/mod.rs b/src/shell/mod.rs index 7e50a175..44321fa7 100644 --- a/src/shell/mod.rs +++ b/src/shell/mod.rs @@ -1085,13 +1085,12 @@ impl Shell { .map(mapped.clone(), &seat, focus_stack.iter()); } - if let CosmicSurface::X11(surface) = window { + if let CosmicSurface::X11(_) = window { if let Some(xwm) = state .common .xwayland_state - .values_mut() - .flat_map(|state| state.xwm.as_mut()) - .find(|xwm| Some(xwm.id()) == surface.xwm_id()) + .as_mut() + .and_then(|state| state.xwm.as_mut()) { if let Err(err) = xwm.update_stacking_order_downwards(workspace.mapped()) { warn!(?err, "Failed to update Xwayland stacking order."); diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index 1f292136..e49c5883 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -437,7 +437,7 @@ impl Workspace { renderer: &mut R, output: &Output, override_redirect_windows: &[X11Surface], - xwm_state: impl Iterator, + xwm_state: Option<&'a mut XWaylandState>, draw_focus_indicator: Option<&Seat>, exclude_workspace_overview: bool, ) -> Result>, OutputNotMapped> @@ -502,7 +502,7 @@ impl Workspace { fullscreen, renderer, (0, 0).into(), output_scale.into() )); - for xwm in xwm_state.flat_map(|state| state.xwm.as_mut()) { + if let Some(xwm) = xwm_state.and_then(|state| state.xwm.as_mut()) { if let Err(err) = xwm.update_stacking_order_upwards(render_elements.iter().rev().map(|e| e.id())) { @@ -584,7 +584,7 @@ impl Workspace { .map(WorkspaceRenderElement::from), ); - for xwm in xwm_state.flat_map(|state| state.xwm.as_mut()) { + if let Some(xwm) = xwm_state.and_then(|state| state.xwm.as_mut()) { if let Err(err) = xwm.update_stacking_order_upwards(render_elements.iter().rev().map(|e| e.id())) { diff --git a/src/state.rs b/src/state.rs index 02187149..d3b202e5 100644 --- a/src/state.rs +++ b/src/state.rs @@ -57,7 +57,7 @@ use smithay::{ }; use tracing::error; -use std::{cell::RefCell, collections::HashMap, ffi::OsString, time::Duration}; +use std::{cell::RefCell, ffi::OsString, time::Duration}; use std::{collections::VecDeque, time::Instant}; pub struct ClientState { @@ -118,7 +118,7 @@ pub struct Common { pub xdg_decoration_state: XdgDecorationState, // xwayland state - pub xwayland_state: HashMap, XWaylandState>, + pub xwayland_state: Option, } pub enum BackendData { @@ -290,7 +290,7 @@ impl State { kde_decoration_state, xdg_decoration_state, - xwayland_state: HashMap::new(), + xwayland_state: None, }, backend: BackendData::Unset, } diff --git a/src/systemd.rs b/src/systemd.rs index f7ae5b99..d75f3f82 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -15,8 +15,7 @@ pub fn ready(state: &State) { &state .common .xwayland_state - .values() - .next() + .as_ref() .map(|s| format!(":{}", s.display)) .unwrap_or(String::new()), ) diff --git a/src/wayland/handlers/data_device.rs b/src/wayland/handlers/data_device.rs index bab3a71f..91519f02 100644 --- a/src/wayland/handlers/data_device.rs +++ b/src/wayland/handlers/data_device.rs @@ -58,8 +58,8 @@ impl DataDeviceHandler for State { } fn new_selection(&mut self, source: Option) { - for xstate in self.common.xwayland_state.values_mut() { - if let Some(xwm) = xstate.xwm.as_mut() { + if let Some(state) = self.common.xwayland_state.as_mut() { + if let Some(xwm) = state.xwm.as_mut() { if let Some(source) = &source { if let Ok(Err(err)) = with_source_metadata(source, |metadata| { xwm.new_selection( @@ -80,14 +80,13 @@ impl DataDeviceHandler for State { &mut self, mime_type: String, fd: OwnedFd, - user_data: &Self::SelectionUserData, + _user_data: &Self::SelectionUserData, ) { if let Some(xwm) = self .common .xwayland_state - .values_mut() - .flat_map(|xstate| xstate.xwm.as_mut()) - .find(|xwm| &xwm.id() == user_data) + .as_mut() + .and_then(|xstate| xstate.xwm.as_mut()) { if let Err(err) = xwm.send_selection( SelectionType::Clipboard, diff --git a/src/wayland/handlers/primary_selection.rs b/src/wayland/handlers/primary_selection.rs index bfa485cc..51a7d23e 100644 --- a/src/wayland/handlers/primary_selection.rs +++ b/src/wayland/handlers/primary_selection.rs @@ -17,8 +17,8 @@ impl PrimarySelectionHandler for State { } fn new_selection(&mut self, source: Option) { - for xstate in self.common.xwayland_state.values_mut() { - if let Some(xwm) = xstate.xwm.as_mut() { + if let Some(state) = self.common.xwayland_state.as_mut() { + if let Some(xwm) = state.xwm.as_mut() { if let Some(source) = &source { if let Ok(Err(err)) = with_source_metadata(source, |metadata| { xwm.new_selection(SelectionType::Primary, Some(metadata.mime_types.clone())) @@ -36,14 +36,13 @@ impl PrimarySelectionHandler for State { &mut self, mime_type: String, fd: OwnedFd, - user_data: &Self::SelectionUserData, + _user_data: &Self::SelectionUserData, ) { if let Some(xwm) = self .common .xwayland_state - .values_mut() - .flat_map(|xstate| xstate.xwm.as_mut()) - .find(|xwm| &xwm.id() == user_data) + .as_mut() + .and_then(|xstate| xstate.xwm.as_mut()) { if let Err(err) = xwm.send_selection( SelectionType::Primary, diff --git a/src/xwayland.rs b/src/xwayland.rs index a2357c06..5627ba4f 100644 --- a/src/xwayland.rs +++ b/src/xwayland.rs @@ -37,8 +37,8 @@ pub struct XWaylandState { } impl State { - pub fn launch_xwayland(&mut self, drm_node: Option) { - if self.common.xwayland_state.contains_key(&drm_node) { + pub fn launch_xwayland(&mut self, render_node: Option) { + if self.common.xwayland_state.is_some() { return; } @@ -81,14 +81,11 @@ impl State { ); } - let mut xwayland_state = - data.state.common.xwayland_state.get_mut(&drm_node).unwrap(); + let mut xwayland_state = data.state.common.xwayland_state.as_mut().unwrap(); xwayland_state.xwm = Some(wm); } XWaylandEvent::Exited => { - if let Some(mut xwayland_state) = - data.state.common.xwayland_state.remove(&drm_node) - { + if let Some(mut xwayland_state) = data.state.common.xwayland_state.take() { xwayland_state.xwm = None; } } @@ -105,21 +102,18 @@ impl State { None, std::iter::empty::<(OsString, OsString)>(), //vec![("WAYLAND_DEBUG", "client")].into_iter(), - |map| { - if let Some(node) = drm_node { - map.insert_if_missing(|| node); + |user_data| { + if let Some(node) = render_node { + user_data.insert_if_missing(|| node); } }, ) { Ok(display) => { - self.common.xwayland_state.insert( - drm_node, - XWaylandState { - xwayland, - xwm: None, - display, - }, - ); + self.common.xwayland_state = Some(XWaylandState { + xwayland, + xwm: None, + display, + }); } Err(err) => { error!(?err, "Failed to start Xwayland."); @@ -130,13 +124,12 @@ impl State { } impl XwmHandler for Data { - fn xwm_state(&mut self, xwm: XwmId) -> &mut X11Wm { + fn xwm_state(&mut self, _xwm: XwmId) -> &mut X11Wm { self.state .common .xwayland_state - .values_mut() - .flat_map(|state| &mut state.xwm) - .find(|wm| wm.id() == xwm) + .as_mut() + .and_then(|state| state.xwm.as_mut()) .unwrap() }