kms: Track used devices and free resources
This commit is contained in:
parent
e74b0dfaaa
commit
ef3486f7e0
14 changed files with 303 additions and 130 deletions
|
|
@ -39,6 +39,7 @@ use smithay::{
|
||||||
glow::GlowRenderer,
|
glow::GlowRenderer,
|
||||||
multigpu::{gbm::GbmGlesBackend, Error as MultiError, GpuManager},
|
multigpu::{gbm::GbmGlesBackend, Error as MultiError, GpuManager},
|
||||||
sync::SyncPoint,
|
sync::SyncPoint,
|
||||||
|
utils::with_renderer_surface_state,
|
||||||
Bind, ImportDma, Offscreen,
|
Bind, ImportDma, Offscreen,
|
||||||
},
|
},
|
||||||
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
session::{libseat::LibSeatSession, Event as SessionEvent, Session},
|
||||||
|
|
@ -62,7 +63,10 @@ use smithay::{
|
||||||
linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1,
|
linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1,
|
||||||
presentation_time::server::wp_presentation_feedback,
|
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},
|
utils::{DeviceFd, Size, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
|
|
@ -97,13 +101,14 @@ pub struct KmsState {
|
||||||
pub devices: HashMap<DrmNode, Device>,
|
pub devices: HashMap<DrmNode, Device>,
|
||||||
pub input_devices: HashMap<String, input::Device>,
|
pub input_devices: HashMap<String, input::Device>,
|
||||||
pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
|
pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
|
||||||
pub primary: DrmNode,
|
pub primary_node: DrmNode,
|
||||||
session: LibSeatSession,
|
session: LibSeatSession,
|
||||||
|
pub auto_assign: bool,
|
||||||
_tokens: Vec<RegistrationToken>,
|
_tokens: Vec<RegistrationToken>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
render_node: DrmNode,
|
pub render_node: DrmNode,
|
||||||
surfaces: HashMap<crtc::Handle, Surface>,
|
surfaces: HashMap<crtc::Handle, Surface>,
|
||||||
pub drm: DrmDevice,
|
pub drm: DrmDevice,
|
||||||
gbm: GbmDevice<DrmDeviceFd>,
|
gbm: GbmDevice<DrmDeviceFd>,
|
||||||
|
|
@ -113,6 +118,7 @@ pub struct Device {
|
||||||
pub non_desktop_connectors: Vec<(connector::Handle, crtc::Handle)>,
|
pub non_desktop_connectors: Vec<(connector::Handle, crtc::Handle)>,
|
||||||
pub leasing_global: Option<DrmLeaseState>,
|
pub leasing_global: Option<DrmLeaseState>,
|
||||||
pub active_leases: Vec<DrmLease>,
|
pub active_leases: Vec<DrmLease>,
|
||||||
|
pub active_buffers: HashSet<Weak<WlBuffer>>,
|
||||||
event_token: Option<RegistrationToken>,
|
event_token: Option<RegistrationToken>,
|
||||||
socket: Option<Socket>,
|
socket: Option<Socket>,
|
||||||
}
|
}
|
||||||
|
|
@ -367,6 +373,11 @@ pub fn init_backend(
|
||||||
.map_err(|err| err.error)
|
.map_err(|err| err.error)
|
||||||
.context("Failed to initialize session event source")?;
|
.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 {
|
state.backend = BackendData::Kms(KmsState {
|
||||||
api,
|
api,
|
||||||
_tokens: vec![
|
_tokens: vec![
|
||||||
|
|
@ -374,8 +385,9 @@ pub fn init_backend(
|
||||||
session_event_source,
|
session_event_source,
|
||||||
udev_event_source,
|
udev_event_source,
|
||||||
],
|
],
|
||||||
primary,
|
primary_node: primary,
|
||||||
session,
|
session,
|
||||||
|
auto_assign,
|
||||||
devices: HashMap::new(),
|
devices: HashMap::new(),
|
||||||
input_devices: HashMap::new(),
|
input_devices: HashMap::new(),
|
||||||
});
|
});
|
||||||
|
|
@ -598,6 +610,7 @@ impl State {
|
||||||
})
|
})
|
||||||
.ok(),
|
.ok(),
|
||||||
active_leases: Vec::new(),
|
active_leases: Vec::new(),
|
||||||
|
active_buffers: HashSet::new(),
|
||||||
event_token: Some(token),
|
event_token: Some(token),
|
||||||
socket,
|
socket,
|
||||||
};
|
};
|
||||||
|
|
@ -621,9 +634,13 @@ impl State {
|
||||||
let mut renderer = match backend.api.single_renderer(&render_node) {
|
let mut renderer = match backend.api.single_renderer(&render_node) {
|
||||||
Ok(renderer) => renderer,
|
Ok(renderer) => renderer,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(?err, "Failed to initialize output.");
|
|
||||||
backend.api.as_mut().remove_node(&render_node);
|
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");
|
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);
|
backend.devices.insert(drm_node, device);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -735,6 +757,31 @@ impl State {
|
||||||
outputs_removed.push(surface.output.clone());
|
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 {
|
for (crtc, conn) in changes.added {
|
||||||
let non_desktop =
|
let non_desktop =
|
||||||
match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") {
|
match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") {
|
||||||
|
|
@ -778,13 +825,6 @@ impl State {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} 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) {
|
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
|
||||||
Ok(output) => {
|
Ok(output) => {
|
||||||
w += output
|
w += output
|
||||||
|
|
@ -827,6 +867,15 @@ impl State {
|
||||||
.remove_output(&output, seats.iter().cloned());
|
.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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1012,49 +1061,58 @@ impl Device {
|
||||||
|
|
||||||
Ok(output)
|
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<DrmNode> {
|
fn source_node_for_surface<'a>(
|
||||||
// Lets check the global drm-node the client got either through default-feedback or wl_drm
|
w: &WlSurface,
|
||||||
let client = dh.get_client(w.id()).ok()?;
|
mut devices: impl Iterator<Item = &'a Device>,
|
||||||
if let Some(normal_client) = client.get_data::<ClientState>() {
|
) -> Option<DrmNode> {
|
||||||
return normal_client.drm_node.clone();
|
with_renderer_surface_state(w, |state| {
|
||||||
}
|
state.buffer().and_then(|buffer| {
|
||||||
// last but not least all xwayland-surfaces should also share a single node
|
devices.find_map(|dev| {
|
||||||
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
dev.active_buffers
|
||||||
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
.contains(&buffer.downgrade())
|
||||||
}
|
.then_some(dev.render_node)
|
||||||
None
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_node_for_output(
|
fn render_node_for_output(
|
||||||
dh: &DisplayHandle,
|
|
||||||
output: &Output,
|
output: &Output,
|
||||||
|
primary_node: DrmNode,
|
||||||
target_node: DrmNode,
|
target_node: DrmNode,
|
||||||
shell: &Shell,
|
shell: &Shell,
|
||||||
|
non_target_devices: &Vec<(&DrmNode, &mut Device)>,
|
||||||
) -> DrmNode {
|
) -> DrmNode {
|
||||||
|
if target_node == primary_node {
|
||||||
|
return target_node;
|
||||||
|
}
|
||||||
|
|
||||||
let workspace = shell.active_space(output);
|
let workspace = shell.active_space(output);
|
||||||
let nodes = workspace
|
let nodes = workspace
|
||||||
.get_fullscreen()
|
.get_fullscreen()
|
||||||
.map(|w| vec![w.clone()])
|
.map(|w| vec![w.clone()])
|
||||||
.unwrap_or_else(|| workspace.windows().collect::<Vec<_>>())
|
.unwrap_or_else(|| workspace.windows().collect::<Vec<_>>())
|
||||||
.into_iter()
|
.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::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
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
|
target_node
|
||||||
} else {
|
} else {
|
||||||
nodes
|
primary_node
|
||||||
.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)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1494,11 +1552,17 @@ impl KmsState {
|
||||||
target: DrmNode,
|
target: DrmNode,
|
||||||
shell: &Shell,
|
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 Err(err) = self.api.early_import(
|
||||||
if let Some(client) = dh.get_client(surface.id()).ok() {
|
if let Some(client) = dh.get_client(surface.id()).ok() {
|
||||||
if let Some(normal_client) = client.get_data::<ClientState>() {
|
if let Some(normal_client) = client.get_data::<ClientState>() {
|
||||||
normal_client.drm_node.clone()
|
normal_client.advertised_drm_node.clone()
|
||||||
} else if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
} else if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
||||||
xwayland_client.user_data().get::<DrmNode>().cloned()
|
xwayland_client.user_data().get::<DrmNode>().cloned()
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -1514,19 +1578,42 @@ impl KmsState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<()> {
|
pub fn dmabuf_imported(
|
||||||
for device in self.devices.values() {
|
&mut self,
|
||||||
|
_client: Option<Client>,
|
||||||
|
global: &DmabufGlobal,
|
||||||
|
dmabuf: Dmabuf,
|
||||||
|
) -> Result<DrmNode> {
|
||||||
|
for device in self.devices.values_mut() {
|
||||||
if device
|
if device
|
||||||
.socket
|
.socket
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.map(|s| &s.dmabuf_global == global)
|
.map(|s| &s.dmabuf_global == global)
|
||||||
.unwrap_or(false)
|
.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
|
return self
|
||||||
.api
|
.api
|
||||||
.single_renderer(&device.render_node)?
|
.single_renderer(&device.render_node)?
|
||||||
.import_dmabuf(&dmabuf, None)
|
.import_dmabuf(&dmabuf, None)
|
||||||
.map(|_| ())
|
.map(|_| device.render_node)
|
||||||
.map_err(Into::into);
|
.map_err(Into::into);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1582,13 +1669,14 @@ impl KmsState {
|
||||||
if let Some(surface) = target_device.surfaces.get_mut(&crtc) {
|
if let Some(surface) = target_device.surfaces.get_mut(&crtc) {
|
||||||
let target_node = target_device.render_node;
|
let target_node = target_device.render_node;
|
||||||
let render_node = render_node_for_output(
|
let render_node = render_node_for_output(
|
||||||
&state.common.display_handle,
|
|
||||||
&surface.output,
|
&surface.output,
|
||||||
|
backend.primary_node,
|
||||||
target_node,
|
target_node,
|
||||||
&state.common.shell,
|
&state.common.shell,
|
||||||
|
&other,
|
||||||
);
|
);
|
||||||
let common = &mut state.common;
|
|
||||||
|
|
||||||
|
let common = &mut state.common;
|
||||||
let result = if render_node != target_node {
|
let result = if render_node != target_node {
|
||||||
let render_device = &mut other
|
let render_device = &mut other
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ impl State {
|
||||||
// initialize globals
|
// initialize globals
|
||||||
let filter = move |client: &Client| {
|
let filter = move |client: &Client| {
|
||||||
if let Some(normal_client) = client.get_data::<ClientState>() {
|
if let Some(normal_client) = client.get_data::<ClientState>() {
|
||||||
let dev_id = normal_client.drm_node.unwrap();
|
let dev_id = normal_client.advertised_drm_node.unwrap();
|
||||||
return dev_id == render_node;
|
return dev_id == render_node;
|
||||||
}
|
}
|
||||||
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
||||||
|
|
|
||||||
|
|
@ -331,6 +331,15 @@ pub fn init_shaders<R: AsGlowRenderer>(renderer: &mut R) -> Result<(), GlesError
|
||||||
let glow_renderer = renderer.glow_renderer_mut();
|
let glow_renderer = renderer.glow_renderer_mut();
|
||||||
let gles_renderer: &mut GlesRenderer = glow_renderer.borrow_mut();
|
let gles_renderer: &mut GlesRenderer = glow_renderer.borrow_mut();
|
||||||
|
|
||||||
|
{
|
||||||
|
let egl_context = gles_renderer.egl_context();
|
||||||
|
if egl_context.user_data().get::<IndicatorShader>().is_some()
|
||||||
|
&& egl_context.user_data().get::<BackdropShader>().is_some()
|
||||||
|
{
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let outline_shader = gles_renderer.compile_custom_pixel_shader(
|
let outline_shader = gles_renderer.compile_custom_pixel_shader(
|
||||||
OUTLINE_SHADER,
|
OUTLINE_SHADER,
|
||||||
&[
|
&[
|
||||||
|
|
|
||||||
15
src/main.rs
15
src/main.rs
|
|
@ -12,7 +12,10 @@ use anyhow::{Context, Result};
|
||||||
use std::{env, ffi::OsString, process, sync::Arc};
|
use std::{env, ffi::OsString, process, sync::Arc};
|
||||||
use tracing::{error, info, warn};
|
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 backend;
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
|
@ -145,15 +148,23 @@ fn init_wayland_display(
|
||||||
event_loop
|
event_loop
|
||||||
.handle()
|
.handle()
|
||||||
.insert_source(source, |client_stream, _, state| {
|
.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(
|
if let Err(err) = state.common.display_handle.insert_client(
|
||||||
client_stream,
|
client_stream,
|
||||||
Arc::new(if cfg!(debug_assertions) {
|
Arc::new(if cfg!(debug_assertions) {
|
||||||
state.new_privileged_client_state()
|
state.new_privileged_client_state()
|
||||||
|
} else if let Some(node) = node {
|
||||||
|
state.new_client_state_with_node(node)
|
||||||
} else {
|
} else {
|
||||||
state.new_client_state()
|
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.")?;
|
.with_context(|| "Failed to init the wayland socket source.")?;
|
||||||
|
|
|
||||||
81
src/state.rs
81
src/state.rs
|
|
@ -1,11 +1,7 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::{
|
backend::{kms::KmsState, winit::WinitState, x11::X11State},
|
||||||
kms::{source_node_for_surface, KmsState},
|
|
||||||
winit::WinitState,
|
|
||||||
x11::X11State,
|
|
||||||
},
|
|
||||||
config::{Config, OutputConfig},
|
config::{Config, OutputConfig},
|
||||||
input::Devices,
|
input::Devices,
|
||||||
shell::{grabs::SeatMoveGrabState, Shell},
|
shell::{grabs::SeatMoveGrabState, Shell},
|
||||||
|
|
@ -54,8 +50,8 @@ use smithay::{
|
||||||
wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode,
|
wayland_protocols_misc::server_decoration::server::org_kde_kwin_server_decoration_manager::Mode,
|
||||||
wayland_server::{
|
wayland_server::{
|
||||||
backend::{ClientData, ClientId, DisconnectReason},
|
backend::{ClientData, ClientId, DisconnectReason},
|
||||||
protocol::wl_shm,
|
protocol::{wl_shm, wl_surface::WlSurface},
|
||||||
Client, DisplayHandle,
|
Client, DisplayHandle, Resource,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
utils::{Clock, IsAlive, Monotonic},
|
utils::{Clock, IsAlive, Monotonic},
|
||||||
|
|
@ -84,6 +80,7 @@ use smithay::{
|
||||||
virtual_keyboard::VirtualKeyboardManagerState,
|
virtual_keyboard::VirtualKeyboardManagerState,
|
||||||
xwayland_keyboard_grab::XWaylandKeyboardGrabState,
|
xwayland_keyboard_grab::XWaylandKeyboardGrabState,
|
||||||
},
|
},
|
||||||
|
xwayland::XWaylandClientData,
|
||||||
};
|
};
|
||||||
use time::UtcOffset;
|
use time::UtcOffset;
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
|
|
@ -111,7 +108,7 @@ macro_rules! fl {
|
||||||
pub struct ClientState {
|
pub struct ClientState {
|
||||||
pub compositor_client_state: CompositorClientState,
|
pub compositor_client_state: CompositorClientState,
|
||||||
pub workspace_client_state: WorkspaceClientState,
|
pub workspace_client_state: WorkspaceClientState,
|
||||||
pub drm_node: Option<DrmNode>,
|
pub advertised_drm_node: Option<DrmNode>,
|
||||||
pub privileged: bool,
|
pub privileged: bool,
|
||||||
pub evls: LoopSignal,
|
pub evls: LoopSignal,
|
||||||
pub security_context: Option<SecurityContext>,
|
pub security_context: Option<SecurityContext>,
|
||||||
|
|
@ -123,6 +120,19 @@ impl ClientData for ClientState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn advertised_node_for_surface(w: &WlSurface, dh: &DisplayHandle) -> Option<DrmNode> {
|
||||||
|
// 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::<ClientState>() {
|
||||||
|
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::<XWaylandClientData>() {
|
||||||
|
return xwayland_client.user_data().get::<DrmNode>().cloned();
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
pub backend: BackendData,
|
pub backend: BackendData,
|
||||||
|
|
@ -168,7 +178,7 @@ pub struct Common {
|
||||||
pub seat_state: SeatState<State>,
|
pub seat_state: SeatState<State>,
|
||||||
pub session_lock_manager_state: SessionLockManagerState,
|
pub session_lock_manager_state: SessionLockManagerState,
|
||||||
pub shm_state: ShmState,
|
pub shm_state: ShmState,
|
||||||
pub wl_drm_state: WlDrmState,
|
pub wl_drm_state: WlDrmState<Option<DrmNode>>,
|
||||||
pub viewporter_state: ViewporterState,
|
pub viewporter_state: ViewporterState,
|
||||||
pub kde_decoration_state: KdeDecorationState,
|
pub kde_decoration_state: KdeDecorationState,
|
||||||
pub xdg_decoration_state: XdgDecorationState,
|
pub xdg_decoration_state: XdgDecorationState,
|
||||||
|
|
@ -278,11 +288,16 @@ impl BackendData {
|
||||||
|
|
||||||
pub fn dmabuf_imported(
|
pub fn dmabuf_imported(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
client: Option<Client>,
|
||||||
global: &DmabufGlobal,
|
global: &DmabufGlobal,
|
||||||
dmabuf: Dmabuf,
|
dmabuf: Dmabuf,
|
||||||
) -> Result<(), anyhow::Error> {
|
) -> Result<Option<DrmNode>, anyhow::Error> {
|
||||||
match self {
|
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) => {
|
BackendData::Winit(ref mut state) => {
|
||||||
state.backend.renderer().import_dmabuf(&dmabuf, None)?;
|
state.backend.renderer().import_dmabuf(&dmabuf, None)?;
|
||||||
}
|
}
|
||||||
|
|
@ -290,8 +305,8 @@ impl BackendData {
|
||||||
state.renderer.import_dmabuf(&dmabuf, None)?;
|
state.renderer.import_dmabuf(&dmabuf, None)?;
|
||||||
}
|
}
|
||||||
_ => unreachable!("No backend set when importing dmabuf"),
|
_ => unreachable!("No backend set when importing dmabuf"),
|
||||||
}
|
};
|
||||||
Ok(())
|
Ok(None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -357,7 +372,7 @@ impl State {
|
||||||
ShmState::new::<Self>(dh, vec![wl_shm::Format::Xbgr8888, wl_shm::Format::Abgr8888]);
|
ShmState::new::<Self>(dh, vec![wl_shm::Format::Xbgr8888, wl_shm::Format::Abgr8888]);
|
||||||
let seat_state = SeatState::<Self>::new();
|
let seat_state = SeatState::<Self>::new();
|
||||||
let viewporter_state = ViewporterState::new::<Self>(dh);
|
let viewporter_state = ViewporterState::new::<Self>(dh);
|
||||||
let wl_drm_state = WlDrmState;
|
let wl_drm_state = WlDrmState::<Option<DrmNode>>::default();
|
||||||
let kde_decoration_state = KdeDecorationState::new::<Self>(&dh, Mode::Client);
|
let kde_decoration_state = KdeDecorationState::new::<Self>(&dh, Mode::Client);
|
||||||
let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
|
let xdg_decoration_state = XdgDecorationState::new::<Self>(&dh);
|
||||||
let session_lock_manager_state =
|
let session_lock_manager_state =
|
||||||
|
|
@ -432,19 +447,8 @@ impl State {
|
||||||
ClientState {
|
ClientState {
|
||||||
compositor_client_state: CompositorClientState::default(),
|
compositor_client_state: CompositorClientState::default(),
|
||||||
workspace_client_state: WorkspaceClientState::default(),
|
workspace_client_state: WorkspaceClientState::default(),
|
||||||
drm_node: match &self.backend {
|
advertised_drm_node: match &self.backend {
|
||||||
BackendData::Kms(kms_state) => {
|
BackendData::Kms(kms_state) => Some(kms_state.primary_node),
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
privileged: false,
|
privileged: false,
|
||||||
|
|
@ -457,7 +461,7 @@ impl State {
|
||||||
ClientState {
|
ClientState {
|
||||||
compositor_client_state: CompositorClientState::default(),
|
compositor_client_state: CompositorClientState::default(),
|
||||||
workspace_client_state: WorkspaceClientState::default(),
|
workspace_client_state: WorkspaceClientState::default(),
|
||||||
drm_node: Some(drm_node),
|
advertised_drm_node: Some(drm_node),
|
||||||
privileged: false,
|
privileged: false,
|
||||||
evls: self.common.event_loop_signal.clone(),
|
evls: self.common.event_loop_signal.clone(),
|
||||||
security_context: None,
|
security_context: None,
|
||||||
|
|
@ -468,8 +472,8 @@ impl State {
|
||||||
ClientState {
|
ClientState {
|
||||||
compositor_client_state: CompositorClientState::default(),
|
compositor_client_state: CompositorClientState::default(),
|
||||||
workspace_client_state: WorkspaceClientState::default(),
|
workspace_client_state: WorkspaceClientState::default(),
|
||||||
drm_node: match &self.backend {
|
advertised_drm_node: match &self.backend {
|
||||||
BackendData::Kms(kms_state) => Some(kms_state.primary),
|
BackendData::Kms(kms_state) => Some(kms_state.primary_node),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
privileged: true,
|
privileged: true,
|
||||||
|
|
@ -537,7 +541,7 @@ impl Common {
|
||||||
surface_primary_scanout_output,
|
surface_primary_scanout_output,
|
||||||
);
|
);
|
||||||
if let Some(feedback) =
|
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))
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
{
|
{
|
||||||
send_dmabuf_feedback_surface_tree(
|
send_dmabuf_feedback_surface_tree(
|
||||||
|
|
@ -599,7 +603,7 @@ impl Common {
|
||||||
if let Some(feedback) = window
|
if let Some(feedback) = window
|
||||||
.wl_surface()
|
.wl_surface()
|
||||||
.and_then(|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))
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
{
|
{
|
||||||
|
|
@ -644,7 +648,7 @@ impl Common {
|
||||||
if let Some(feedback) = window
|
if let Some(feedback) = window
|
||||||
.wl_surface()
|
.wl_surface()
|
||||||
.and_then(|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))
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
{
|
{
|
||||||
|
|
@ -693,7 +697,9 @@ impl Common {
|
||||||
window.send_frame(output, time, throttle, surface_primary_scanout_output);
|
window.send_frame(output, time, throttle, surface_primary_scanout_output);
|
||||||
if let Some(feedback) = window
|
if let Some(feedback) = window
|
||||||
.wl_surface()
|
.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))
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
{
|
{
|
||||||
window.send_dmabuf_feedback(
|
window.send_dmabuf_feedback(
|
||||||
|
|
@ -741,8 +747,9 @@ impl Common {
|
||||||
throttle,
|
throttle,
|
||||||
surface_primary_scanout_output,
|
surface_primary_scanout_output,
|
||||||
);
|
);
|
||||||
if let Some(feedback) = source_node_for_surface(&wl_surface, &self.display_handle)
|
if let Some(feedback) =
|
||||||
.and_then(|source| dmabuf_feedback(source))
|
advertised_node_for_surface(&wl_surface, &self.display_handle)
|
||||||
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
{
|
{
|
||||||
send_dmabuf_feedback_surface_tree(
|
send_dmabuf_feedback_surface_tree(
|
||||||
&wl_surface,
|
&wl_surface,
|
||||||
|
|
@ -780,7 +787,7 @@ impl Common {
|
||||||
});
|
});
|
||||||
layer_surface.send_frame(output, time, throttle, surface_primary_scanout_output);
|
layer_surface.send_frame(output, time, throttle, surface_primary_scanout_output);
|
||||||
if let Some(feedback) =
|
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))
|
.and_then(|source| dmabuf_feedback(source))
|
||||||
{
|
{
|
||||||
layer_surface.send_dmabuf_feedback(
|
layer_surface.send_dmabuf_feedback(
|
||||||
|
|
|
||||||
|
|
@ -16,9 +16,8 @@ use smithay::{
|
||||||
use tracing::warn;
|
use tracing::warn;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backend::kms::source_node_for_surface,
|
|
||||||
shell::element::CosmicSurface,
|
shell::element::CosmicSurface,
|
||||||
state::{BackendData, State},
|
state::{advertised_node_for_surface, BackendData, State},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub fn screenshot_window(state: &mut State, surface: &CosmicSurface) {
|
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() {
|
if let Some(wl_surface) = surface.wl_surface() {
|
||||||
let res = match &mut state.backend {
|
let res = match &mut state.backend {
|
||||||
BackendData::Kms(kms) => {
|
BackendData::Kms(kms) => {
|
||||||
let node = source_node_for_surface(&wl_surface, &state.common.display_handle)
|
let node = advertised_node_for_surface(&wl_surface, &state.common.display_handle)
|
||||||
.unwrap_or(kms.primary);
|
.unwrap_or(kms.primary_node);
|
||||||
kms.api
|
kms.api
|
||||||
.single_renderer(&node)
|
.single_renderer(&node)
|
||||||
.with_context(|| "Failed to get renderer for screenshot")
|
.with_context(|| "Failed to get renderer for screenshot")
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,22 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::utils::prelude::*;
|
use crate::{state::BackendData, utils::prelude::*};
|
||||||
use smithay::{
|
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 {
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::state::State;
|
use crate::state::{BackendData, State};
|
||||||
use smithay::{
|
use smithay::{
|
||||||
backend::allocator::dmabuf::Dmabuf,
|
backend::allocator::dmabuf::Dmabuf,
|
||||||
delegate_dmabuf,
|
delegate_dmabuf,
|
||||||
|
reexports::wayland_server::Resource,
|
||||||
wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
|
wayland::dmabuf::{DmabufGlobal, DmabufHandler, DmabufState, ImportNotifier},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -18,10 +19,33 @@ impl DmabufHandler for State {
|
||||||
dmabuf: Dmabuf,
|
dmabuf: Dmabuf,
|
||||||
import_notifier: ImportNotifier,
|
import_notifier: ImportNotifier,
|
||||||
) {
|
) {
|
||||||
if self.backend.dmabuf_imported(global, dmabuf).is_err() {
|
match self
|
||||||
import_notifier.failed();
|
.backend
|
||||||
} else {
|
.dmabuf_imported(import_notifier.client(), global, dmabuf)
|
||||||
let _ = import_notifier.successful::<State>();
|
{
|
||||||
|
Err(err) => {
|
||||||
|
tracing::debug!(?err, "dmabuf import failed");
|
||||||
|
import_notifier.failed()
|
||||||
|
}
|
||||||
|
Ok(Some(node)) => {
|
||||||
|
// kms backend
|
||||||
|
let Ok(buffer) = import_notifier.successful::<State>() 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::<State>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,40 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
state::State,
|
state::{BackendData, State},
|
||||||
wayland::protocols::drm::{DrmHandler, ImportError},
|
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<Option<DrmNode>> for State {
|
||||||
fn dmabuf_imported(
|
fn dmabuf_imported(
|
||||||
&mut self,
|
&mut self,
|
||||||
global: &DmabufGlobal,
|
global: &DmabufGlobal,
|
||||||
dmabuf: Dmabuf,
|
dmabuf: Dmabuf,
|
||||||
) -> Result<(), ImportError> {
|
) -> Result<Option<DrmNode>, ImportError> {
|
||||||
self.backend
|
self.backend
|
||||||
.dmabuf_imported(global, dmabuf)
|
.dmabuf_imported(None, global, dmabuf)
|
||||||
.map_err(|_| ImportError::Failed)
|
.map_err(|_| ImportError::Failed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn buffer_created(&mut self, buffer: WlBuffer, result: Option<DrmNode>) {
|
||||||
|
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<DrmNode>);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,6 @@ pub mod toplevel_info;
|
||||||
pub mod toplevel_management;
|
pub mod toplevel_management;
|
||||||
pub mod viewporter;
|
pub mod viewporter;
|
||||||
pub mod virtual_keyboard;
|
pub mod virtual_keyboard;
|
||||||
pub mod wl_drm;
|
|
||||||
pub mod workspace;
|
pub mod workspace;
|
||||||
pub mod xdg_activation;
|
pub mod xdg_activation;
|
||||||
pub mod xdg_shell;
|
pub mod xdg_shell;
|
||||||
|
|
|
||||||
|
|
@ -180,7 +180,7 @@ impl ScreencopyHandler for State {
|
||||||
.and_then(|client| {
|
.and_then(|client| {
|
||||||
// Lets check the global drm-node the client got either through default-feedback or wl_drm
|
// Lets check the global drm-node the client got either through default-feedback or wl_drm
|
||||||
if let Some(normal_client) = client.get_data::<ClientState>() {
|
if let Some(normal_client) = client.get_data::<ClientState>() {
|
||||||
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
|
// last but not least all xwayland-surfaces should also share a single node
|
||||||
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
if let Some(xwayland_client) = client.get_data::<XWaylandClientData>() {
|
||||||
|
|
@ -188,7 +188,7 @@ impl ScreencopyHandler for State {
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
.unwrap_or(kms.primary.clone());
|
.unwrap_or(kms.primary_node.clone());
|
||||||
_kms_renderer = Some(kms.api.single_renderer(&node).unwrap());
|
_kms_renderer = Some(kms.api.single_renderer(&node).unwrap());
|
||||||
_kms_renderer.as_mut().unwrap().as_mut()
|
_kms_renderer.as_mut().unwrap().as_mut()
|
||||||
}
|
}
|
||||||
|
|
@ -456,7 +456,9 @@ fn formats_for_output(
|
||||||
let mut _kms_renderer = None;
|
let mut _kms_renderer = None;
|
||||||
let renderer = match backend {
|
let renderer = match backend {
|
||||||
BackendData::Kms(ref mut kms) => {
|
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 = Some(kms.api.single_renderer(&node).unwrap());
|
||||||
_kms_renderer.as_mut().unwrap().as_mut()
|
_kms_renderer.as_mut().unwrap().as_mut()
|
||||||
}
|
}
|
||||||
|
|
@ -530,7 +532,7 @@ fn node_from_params(
|
||||||
BackendData::Kms(kms) => Some(
|
BackendData::Kms(kms) => Some(
|
||||||
output
|
output
|
||||||
.and_then(|output| kms.target_node_for_output(output))
|
.and_then(|output| kms.target_node_for_output(output))
|
||||||
.unwrap_or(kms.primary),
|
.unwrap_or(kms.primary_node),
|
||||||
),
|
),
|
||||||
_ => None,
|
_ => None,
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -37,14 +37,14 @@ impl SecurityContextHandler for State {
|
||||||
let drm_node = client_data
|
let drm_node = client_data
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|data| data.downcast_ref::<ClientState>())
|
.and_then(|data| data.downcast_ref::<ClientState>())
|
||||||
.and_then(|data| data.drm_node.clone())
|
.and_then(|data| data.advertised_drm_node.clone())
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
client_data
|
client_data
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|data| data.downcast_ref::<XWaylandClientData>())
|
.and_then(|data| data.downcast_ref::<XWaylandClientData>())
|
||||||
.and_then(|data| data.user_data().get::<DrmNode>().cloned())
|
.and_then(|data| data.user_data().get::<DrmNode>().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(
|
if let Err(err) = state.common.display_handle.insert_client(
|
||||||
client_stream,
|
client_stream,
|
||||||
|
|
@ -53,7 +53,7 @@ impl SecurityContextHandler for State {
|
||||||
privileged: privileged
|
privileged: privileged
|
||||||
&& security_context.sandbox_engine.as_deref()
|
&& security_context.sandbox_engine.as_deref()
|
||||||
== Some("com.system76.CosmicPanel"),
|
== Some("com.system76.CosmicPanel"),
|
||||||
drm_node,
|
advertised_drm_node: drm_node,
|
||||||
..new_state
|
..new_state
|
||||||
}),
|
}),
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -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);
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
// You can use all the types from my_protocol as if they went from `wayland_client::protocol`.
|
// You can use all the types from my_protocol as if they went from `wayland_client::protocol`.
|
||||||
pub use generated::wl_drm;
|
pub use generated::wl_drm;
|
||||||
|
|
||||||
|
#[allow(non_snake_case, non_upper_case_globals, non_camel_case_types)]
|
||||||
mod generated {
|
mod generated {
|
||||||
use smithay::reexports::wayland_server::{self, protocol::*};
|
use smithay::reexports::wayland_server::{self, protocol::*};
|
||||||
|
|
||||||
|
|
@ -43,13 +44,15 @@ pub enum ImportError {
|
||||||
InvalidFormat,
|
InvalidFormat,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait DrmHandler {
|
pub trait DrmHandler<R: 'static> {
|
||||||
fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf)
|
fn dmabuf_imported(&mut self, global: &DmabufGlobal, dmabuf: Dmabuf) -> Result<R, ImportError>;
|
||||||
-> Result<(), ImportError>;
|
fn buffer_created(&mut self, buffer: WlBuffer, result: R) {
|
||||||
|
let _ = (buffer, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct WlDrmState;
|
pub struct WlDrmState<R>(std::marker::PhantomData<R>);
|
||||||
|
|
||||||
/// Data associated with a drm global.
|
/// Data associated with a drm global.
|
||||||
pub struct DrmGlobalData {
|
pub struct DrmGlobalData {
|
||||||
|
|
@ -64,13 +67,14 @@ pub struct DrmInstanceData {
|
||||||
dmabuf_global: DmabufGlobal,
|
dmabuf_global: DmabufGlobal,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> GlobalDispatch<wl_drm::WlDrm, DrmGlobalData, D> for WlDrmState
|
impl<D, R> GlobalDispatch<wl_drm::WlDrm, DrmGlobalData, D> for WlDrmState<R>
|
||||||
where
|
where
|
||||||
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
||||||
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
||||||
+ BufferHandler
|
+ BufferHandler
|
||||||
+ DmabufHandler
|
+ DmabufHandler
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
R: 'static,
|
||||||
{
|
{
|
||||||
fn bind(
|
fn bind(
|
||||||
_state: &mut D,
|
_state: &mut D,
|
||||||
|
|
@ -102,14 +106,15 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<D> Dispatch<wl_drm::WlDrm, DrmInstanceData, D> for WlDrmState
|
impl<D, R> Dispatch<wl_drm::WlDrm, DrmInstanceData, D> for WlDrmState<R>
|
||||||
where
|
where
|
||||||
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
||||||
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
||||||
+ Dispatch<WlBuffer, Dmabuf>
|
+ Dispatch<WlBuffer, Dmabuf>
|
||||||
+ BufferHandler
|
+ BufferHandler
|
||||||
+ DrmHandler
|
+ DrmHandler<R>
|
||||||
+ 'static,
|
+ 'static,
|
||||||
|
R: 'static,
|
||||||
{
|
{
|
||||||
fn request(
|
fn request(
|
||||||
state: &mut D,
|
state: &mut D,
|
||||||
|
|
@ -178,10 +183,11 @@ where
|
||||||
match dma.build() {
|
match dma.build() {
|
||||||
Some(dmabuf) => {
|
Some(dmabuf) => {
|
||||||
match state.dmabuf_imported(&data.dmabuf_global, dmabuf.clone()) {
|
match state.dmabuf_imported(&data.dmabuf_global, dmabuf.clone()) {
|
||||||
Ok(()) => {
|
Ok(result) => {
|
||||||
// import was successful
|
// 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.");
|
trace!("Created a new validated dma wl_buffer via wl_drm.");
|
||||||
|
state.buffer_created(buffer, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(ImportError::InvalidFormat) => {
|
Err(ImportError::InvalidFormat) => {
|
||||||
|
|
@ -212,7 +218,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WlDrmState {
|
impl<R: 'static> WlDrmState<R> {
|
||||||
pub fn create_global<D>(
|
pub fn create_global<D>(
|
||||||
&mut self,
|
&mut self,
|
||||||
display: &DisplayHandle,
|
display: &DisplayHandle,
|
||||||
|
|
@ -267,13 +273,13 @@ impl WlDrmState {
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! delegate_wl_drm {
|
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: [
|
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::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: [
|
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::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;
|
pub(crate) use delegate_wl_drm;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue