backend: Support wl-dmabuf v6
This commit is contained in:
parent
81cd5fdbaa
commit
091583ac84
14 changed files with 298 additions and 210 deletions
30
Cargo.lock
generated
30
Cargo.lock
generated
|
|
@ -312,12 +312,6 @@ version = "1.1.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "atomic_float"
|
|
||||||
version = "1.1.0"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "628d228f918ac3b82fe590352cc719d30664a0c13ca3a60266fe02c7132d480a"
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "atomicwrites"
|
name = "atomicwrites"
|
||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
|
|
@ -1194,7 +1188,7 @@ dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"option-ext",
|
"option-ext",
|
||||||
"redox_users",
|
"redox_users",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -1508,7 +1502,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2695,7 +2689,7 @@ dependencies = [
|
||||||
"portable-atomic",
|
"portable-atomic",
|
||||||
"portable-atomic-util",
|
"portable-atomic-util",
|
||||||
"serde_core",
|
"serde_core",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -2818,7 +2812,7 @@ version = "1.4.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7a1886916523694cd6ea3d175f03a1e5010699a2a4cc13696d83d7bea1d80638"
|
checksum = "7a1886916523694cd6ea3d175f03a1e5010699a2a4cc13696d83d7bea1d80638"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -3428,7 +3422,7 @@ version = "0.50.3"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4524,7 +4518,7 @@ dependencies = [
|
||||||
"errno",
|
"errno",
|
||||||
"libc",
|
"libc",
|
||||||
"linux-raw-sys 0.12.1",
|
"linux-raw-sys 0.12.1",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -4819,12 +4813,11 @@ checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "smithay"
|
name = "smithay"
|
||||||
version = "0.7.0"
|
version = "0.7.0"
|
||||||
source = "git+https://github.com/smithay/smithay.git?rev=1ed69cb#1ed69cb55e9d0e9f38887c3b7d53d24365c4b14f"
|
source = "git+https://github.com/smithay/smithay.git?rev=cdc03f7#cdc03f73ce57d3352c0c57a69971e3e16544051c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aliasable",
|
"aliasable",
|
||||||
"appendlist",
|
"appendlist",
|
||||||
"ash",
|
"ash",
|
||||||
"atomic_float",
|
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.0",
|
||||||
"calloop",
|
"calloop",
|
||||||
"cc",
|
"cc",
|
||||||
|
|
@ -4846,6 +4839,7 @@ dependencies = [
|
||||||
"libseat",
|
"libseat",
|
||||||
"pixman",
|
"pixman",
|
||||||
"pkg-config",
|
"pkg-config",
|
||||||
|
"portable-atomic",
|
||||||
"profiling",
|
"profiling",
|
||||||
"rand 0.9.2",
|
"rand 0.9.2",
|
||||||
"reis",
|
"reis",
|
||||||
|
|
@ -5113,7 +5107,7 @@ dependencies = [
|
||||||
"getrandom 0.4.1",
|
"getrandom 0.4.1",
|
||||||
"once_cell",
|
"once_cell",
|
||||||
"rustix 1.1.4",
|
"rustix 1.1.4",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.52.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -5887,9 +5881,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "wayland-protocols"
|
name = "wayland-protocols"
|
||||||
version = "0.32.12"
|
version = "0.32.13"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "563a85523cade2429938e790815fd7319062103b9f4a2dc806e9b53b95982d8f"
|
checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.11.0",
|
"bitflags 2.11.0",
|
||||||
"wayland-backend",
|
"wayland-backend",
|
||||||
|
|
@ -6132,7 +6126,7 @@ version = "0.1.11"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.48.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -144,4 +144,4 @@ lto = "fat"
|
||||||
cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" }
|
cosmic-protocols = { git = "https://github.com/pop-os//cosmic-protocols", branch = "main" }
|
||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
smithay = { git = "https://github.com/smithay/smithay.git", rev = "1ed69cb" }
|
smithay = { git = "https://github.com/smithay/smithay.git", rev = "cdc03f7" }
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@ use std::{
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{drm_helpers, socket::Socket, surface::Surface};
|
use super::{drm_helpers, surface::Surface};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct EGLInternals {
|
pub struct EGLInternals {
|
||||||
|
|
@ -98,14 +98,12 @@ pub struct Device {
|
||||||
|
|
||||||
pub texture_formats: FormatSet,
|
pub texture_formats: FormatSet,
|
||||||
event_token: Option<RegistrationToken>,
|
event_token: Option<RegistrationToken>,
|
||||||
pub socket: Option<Socket>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
struct ReusableDevice {
|
struct ReusableDevice {
|
||||||
leasing_global: Option<DrmLeaseState>,
|
leasing_global: Option<DrmLeaseState>,
|
||||||
active_clients: HashSet<ClientId>,
|
active_clients: HashSet<ClientId>,
|
||||||
socket: Option<Socket>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -593,7 +591,7 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn device_removed(&mut self, dev: dev_t, dh: &DisplayHandle) -> Result<()> {
|
pub fn device_removed(&mut self, dev: dev_t, _dh: &DisplayHandle) -> Result<()> {
|
||||||
let backend = self.backend.kms();
|
let backend = self.backend.kms();
|
||||||
// we can't use DrmNode::from_node_id, because that assumes the node is still on sysfs
|
// we can't use DrmNode::from_node_id, because that assumes the node is still on sysfs
|
||||||
let drm_node = backend
|
let drm_node = backend
|
||||||
|
|
@ -616,13 +614,6 @@ impl State {
|
||||||
if let Some(token) = device.event_token.take() {
|
if let Some(token) = device.event_token.take() {
|
||||||
self.common.event_loop_handle.remove(token);
|
self.common.event_loop_handle.remove(token);
|
||||||
}
|
}
|
||||||
if let Some(socket) = device.socket.take() {
|
|
||||||
self.common.event_loop_handle.remove(socket.token);
|
|
||||||
self.common
|
|
||||||
.dmabuf_state
|
|
||||||
.destroy_global::<State>(dh, socket.dmabuf_global);
|
|
||||||
dh.remove_global::<State>(socket.drm_global);
|
|
||||||
}
|
|
||||||
backend.api.as_mut().remove_node(&device.inner.render_node);
|
backend.api.as_mut().remove_node(&device.inner.render_node);
|
||||||
backend
|
backend
|
||||||
.primary_node
|
.primary_node
|
||||||
|
|
@ -755,23 +746,7 @@ impl Device {
|
||||||
let ReusableDevice {
|
let ReusableDevice {
|
||||||
leasing_global,
|
leasing_global,
|
||||||
active_clients,
|
active_clients,
|
||||||
socket,
|
|
||||||
} = reuse.unwrap_or_else(|| {
|
} = reuse.unwrap_or_else(|| {
|
||||||
let socket = match (!is_software)
|
|
||||||
.then(|| common.create_socket(dh, render_node, texture_formats.clone()))
|
|
||||||
.transpose()
|
|
||||||
{
|
|
||||||
Ok(socket) => socket,
|
|
||||||
Err(err) => {
|
|
||||||
warn!(
|
|
||||||
?err,
|
|
||||||
"Failed to initialize hardware-acceleration for clients on {}.",
|
|
||||||
render_node,
|
|
||||||
);
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let leasing_global = match (!is_software)
|
let leasing_global = match (!is_software)
|
||||||
.then(|| DrmLeaseState::new::<State>(dh, &dev_node))
|
.then(|| DrmLeaseState::new::<State>(dh, &dev_node))
|
||||||
.transpose()
|
.transpose()
|
||||||
|
|
@ -790,7 +765,6 @@ impl Device {
|
||||||
ReusableDevice {
|
ReusableDevice {
|
||||||
leasing_global,
|
leasing_global,
|
||||||
active_clients: HashSet::new(),
|
active_clients: HashSet::new(),
|
||||||
socket,
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -831,7 +805,6 @@ impl Device {
|
||||||
|
|
||||||
texture_formats,
|
texture_formats,
|
||||||
event_token: Some(token),
|
event_token: Some(token),
|
||||||
socket,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -892,7 +865,6 @@ impl Device {
|
||||||
let device = ReusableDevice {
|
let device = ReusableDevice {
|
||||||
leasing_global: self.inner.leasing_global,
|
leasing_global: self.inner.leasing_global,
|
||||||
active_clients: self.inner.active_clients,
|
active_clients: self.inner.active_clients,
|
||||||
socket: self.socket,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let state = OldDeviceState {
|
let state = OldDeviceState {
|
||||||
|
|
|
||||||
|
|
@ -4,12 +4,15 @@ use crate::{
|
||||||
config::{CompOutputConfig, ScreenFilter},
|
config::{CompOutputConfig, ScreenFilter},
|
||||||
shell::Shell,
|
shell::Shell,
|
||||||
state::BackendData,
|
state::BackendData,
|
||||||
utils::{env::dev_var, prelude::*},
|
utils::{env::dev_var, global::remove_global_with_timer, prelude::*},
|
||||||
wayland::protocols::output_power::OutputPowerState,
|
wayland::protocols::{drm::WlDrmState, output_power::OutputPowerState},
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{self, Context, Result};
|
||||||
use calloop::LoopSignal;
|
use calloop::{
|
||||||
|
LoopSignal,
|
||||||
|
timer::{TimeoutAction, Timer},
|
||||||
|
};
|
||||||
use cosmic_comp_config::output::comp::{AdaptiveSync, OutputState};
|
use cosmic_comp_config::output::comp::{AdaptiveSync, OutputState};
|
||||||
use indexmap::IndexMap;
|
use indexmap::IndexMap;
|
||||||
use render::gles::GbmGlowBackend;
|
use render::gles::GbmGlowBackend;
|
||||||
|
|
@ -32,11 +35,12 @@ use smithay::{
|
||||||
control::{Device as _, connector::Interface, crtc},
|
control::{Device as _, connector::Interface, crtc},
|
||||||
},
|
},
|
||||||
input::{self, Libinput},
|
input::{self, Libinput},
|
||||||
|
wayland_protocols::wp::linux_dmabuf::zv1::server::zwp_linux_dmabuf_feedback_v1::TrancheFlags,
|
||||||
wayland_server::{Client, DisplayHandle},
|
wayland_server::{Client, DisplayHandle},
|
||||||
},
|
},
|
||||||
utils::{Clock, DevPath, Monotonic, Size},
|
utils::{Clock, DevPath, Monotonic, Size},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::DmabufGlobal,
|
dmabuf::{DmabufFeedbackBuilder, DmabufGlobal},
|
||||||
drm_syncobj::{DrmSyncobjState, supports_syncobj_eventfd},
|
drm_syncobj::{DrmSyncobjState, supports_syncobj_eventfd},
|
||||||
relative_pointer::RelativePointerManagerState,
|
relative_pointer::RelativePointerManagerState,
|
||||||
},
|
},
|
||||||
|
|
@ -48,12 +52,12 @@ use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
path::Path,
|
path::Path,
|
||||||
sync::{Arc, RwLock, atomic::AtomicBool},
|
sync::{Arc, RwLock, atomic::AtomicBool},
|
||||||
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod device;
|
mod device;
|
||||||
mod drm_helpers;
|
mod drm_helpers;
|
||||||
pub mod render;
|
pub mod render;
|
||||||
mod socket;
|
|
||||||
mod surface;
|
mod surface;
|
||||||
use device::*;
|
use device::*;
|
||||||
pub(crate) use surface::Surface;
|
pub(crate) use surface::Surface;
|
||||||
|
|
@ -74,6 +78,7 @@ pub struct KmsState {
|
||||||
libinput: Libinput,
|
libinput: Libinput,
|
||||||
|
|
||||||
pub syncobj_state: Option<DrmSyncobjState>,
|
pub syncobj_state: Option<DrmSyncobjState>,
|
||||||
|
pub dmabuf_global: Option<DmabufGlobal>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct KmsGuard<'a> {
|
pub struct KmsGuard<'a> {
|
||||||
|
|
@ -131,6 +136,7 @@ pub fn init_backend(
|
||||||
libinput: libinput_context,
|
libinput: libinput_context,
|
||||||
|
|
||||||
syncobj_state: None,
|
syncobj_state: None,
|
||||||
|
dmabuf_global: None,
|
||||||
});
|
});
|
||||||
|
|
||||||
// manually add already present gpus
|
// manually add already present gpus
|
||||||
|
|
@ -142,9 +148,10 @@ pub fn init_backend(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(err) = state.backend.kms().select_primary_gpu(dh) {
|
if let Err(err) = state.select_primary_gpu(dh) {
|
||||||
warn!("Failed to determine primary gpu: {}", err);
|
warn!("Failed to determine primary gpu: {}", err);
|
||||||
}
|
}
|
||||||
|
state.update_default_feedback();
|
||||||
|
|
||||||
if let Err(err) = state.refresh_output_config() {
|
if let Err(err) = state.refresh_output_config() {
|
||||||
info!(
|
info!(
|
||||||
|
|
@ -317,11 +324,13 @@ fn init_udev(
|
||||||
|
|
||||||
{
|
{
|
||||||
let backend = state.backend.kms();
|
let backend = state.backend.kms();
|
||||||
if matches!(event, UdevEvent::Added { .. } | UdevEvent::Removed { .. })
|
if matches!(event, UdevEvent::Added { .. } | UdevEvent::Removed { .. }) {
|
||||||
&& backend.primary_node.read().unwrap().is_none()
|
if backend.primary_node.read().unwrap().is_none()
|
||||||
&& let Err(err) = state.backend.kms().select_primary_gpu(&dh)
|
&& let Err(err) = state.select_primary_gpu(&dh)
|
||||||
{
|
{
|
||||||
warn!("Failed to determine a new primary gpu: {}", err);
|
warn!("Failed to determine a new primary gpu: {}", err);
|
||||||
|
}
|
||||||
|
state.update_default_feedback();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -465,50 +474,118 @@ impl State {
|
||||||
device.drm.pause();
|
device.drm.pause();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl KmsState {
|
|
||||||
fn select_primary_gpu(&mut self, dh: &DisplayHandle) -> Result<()> {
|
fn select_primary_gpu(&mut self, dh: &DisplayHandle) -> Result<()> {
|
||||||
// We don't have to check the allow/blocklist here,
|
// We don't have to check the allow/blocklist here,
|
||||||
// as any disallowed devices won't be in `self.drm_devices`.
|
// as any disallowed devices won't be in `self.drm_devices`.
|
||||||
|
|
||||||
let mut primary_node = self.primary_node.write().unwrap();
|
let kms = self.backend.kms();
|
||||||
|
let mut primary_node = kms.primary_node.write().unwrap();
|
||||||
let _ = primary_node.take(); // if we error don't leave an old node in place
|
let _ = primary_node.take(); // if we error don't leave an old node in place
|
||||||
*primary_node = determine_primary_gpu(&self.drm_devices, self.session.seat())?;
|
*primary_node = determine_primary_gpu(&kms.drm_devices, kms.session.seat())?;
|
||||||
|
|
||||||
if let Some(node) = *primary_node {
|
if let Some(node) = *primary_node {
|
||||||
info!("Using {} as primary gpu for rendering.", node);
|
info!("Using {} as primary gpu for rendering.", node);
|
||||||
self.software_renderer.take();
|
kms.software_renderer.take();
|
||||||
} else if self.software_renderer.is_none() {
|
|
||||||
|
// setup minimal feedback. We will update it in `update_default_feedback`
|
||||||
|
let primary_formats = kms
|
||||||
|
.drm_devices
|
||||||
|
.values()
|
||||||
|
.find(|dev| dev.inner.render_node == node)
|
||||||
|
.unwrap()
|
||||||
|
.texture_formats
|
||||||
|
.clone();
|
||||||
|
let feedback = DmabufFeedbackBuilder::new(node.dev_id(), primary_formats.clone())
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
if let Some(global) = kms.dmabuf_global.as_ref() {
|
||||||
|
self.common
|
||||||
|
.dmabuf_state
|
||||||
|
.set_default_feedback(global, &feedback);
|
||||||
|
} else {
|
||||||
|
let dmabuf_global = self
|
||||||
|
.common
|
||||||
|
.dmabuf_state
|
||||||
|
.create_global_with_default_feedback::<State>(dh, &feedback);
|
||||||
|
kms.dmabuf_global = Some(dmabuf_global);
|
||||||
|
};
|
||||||
|
|
||||||
|
let device_path = node
|
||||||
|
.dev_path_with_type(NodeType::Render)
|
||||||
|
.or_else(|| node.dev_path())
|
||||||
|
.ok_or(anyhow::anyhow!(
|
||||||
|
"Could not determine path for gpu node: {}",
|
||||||
|
node
|
||||||
|
))?;
|
||||||
|
|
||||||
|
if let Some(drm) = self.common.wl_drm_state.as_mut() {
|
||||||
|
drm.update_device(device_path, primary_formats);
|
||||||
|
} else {
|
||||||
|
self.common.wl_drm_state = Some(WlDrmState::new::<State>(
|
||||||
|
dh,
|
||||||
|
device_path,
|
||||||
|
primary_formats,
|
||||||
|
kms.dmabuf_global.as_ref().unwrap(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
} else if kms.software_renderer.is_none() {
|
||||||
info!("Failed to find a suitable gpu, using software renderingr");
|
info!("Failed to find a suitable gpu, using software renderingr");
|
||||||
self.software_renderer = match software_renderer() {
|
kms.software_renderer = match software_renderer() {
|
||||||
Ok(renderer) => Some(renderer),
|
Ok(renderer) => Some(renderer),
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
error!(?err, "Failed to initialize software EGL renderer.");
|
error!(?err, "Failed to initialize software EGL renderer.");
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if let Some(drm) = self.common.wl_drm_state.take() {
|
||||||
|
remove_global_with_timer(dh, &self.common.event_loop_handle, drm.global().clone());
|
||||||
|
}
|
||||||
|
if let Some(global) = kms.dmabuf_global.take() {
|
||||||
|
self.common
|
||||||
|
.dmabuf_state
|
||||||
|
.disable_global::<State>(dh, &global);
|
||||||
|
let source = Timer::from_duration(Duration::from_secs(5));
|
||||||
|
let res =
|
||||||
|
self.common
|
||||||
|
.event_loop_handle
|
||||||
|
.insert_source(source, move |_, _, state| {
|
||||||
|
state
|
||||||
|
.common
|
||||||
|
.dmabuf_state
|
||||||
|
.destroy_global::<State>(&state.common.display_handle, global);
|
||||||
|
TimeoutAction::Drop
|
||||||
|
});
|
||||||
|
if let Err(err) = res {
|
||||||
|
tracing::error!(
|
||||||
|
"failed to insert timer source to destroy output global: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !crate::utils::env::bool_var("COSMIC_DISABLE_SYNCOBJ").unwrap_or(false) {
|
if !crate::utils::env::bool_var("COSMIC_DISABLE_SYNCOBJ").unwrap_or(false) {
|
||||||
if let Some(primary_node) = primary_node
|
if let Some(primary_node) = primary_node
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|node| node.node_with_type(NodeType::Primary).and_then(|x| x.ok()))
|
.and_then(|node| node.node_with_type(NodeType::Primary).and_then(|x| x.ok()))
|
||||||
&& let Some(device) = self.drm_devices.get(&primary_node)
|
&& let Some(device) = kms.drm_devices.get(&primary_node)
|
||||||
{
|
{
|
||||||
let import_device = device.drm.device().device_fd().clone();
|
let import_device = device.drm.device().device_fd().clone();
|
||||||
if supports_syncobj_eventfd(&import_device) {
|
if supports_syncobj_eventfd(&import_device) {
|
||||||
if let Some(state) = self.syncobj_state.as_mut() {
|
if let Some(state) = kms.syncobj_state.as_mut() {
|
||||||
state.update_device(import_device);
|
state.update_device(import_device);
|
||||||
} else {
|
} else {
|
||||||
let syncobj_state = DrmSyncobjState::new::<State>(dh, import_device);
|
let syncobj_state = DrmSyncobjState::new::<State>(dh, import_device);
|
||||||
self.syncobj_state = Some(syncobj_state);
|
kms.syncobj_state = Some(syncobj_state);
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(old_state) = self.syncobj_state.take() {
|
if let Some(old_state) = kms.syncobj_state.take() {
|
||||||
dh.remove_global::<State>(old_state.into_global());
|
dh.remove_global::<State>(old_state.into_global());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -516,6 +593,45 @@ impl KmsState {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn update_default_feedback(&mut self) {
|
||||||
|
let kms = self.backend.kms();
|
||||||
|
let primary_node = kms.primary_node.read().unwrap();
|
||||||
|
if let Some(primary_node) = *primary_node {
|
||||||
|
let primary_formats = kms
|
||||||
|
.drm_devices
|
||||||
|
.values()
|
||||||
|
.find(|dev| dev.inner.render_node == primary_node)
|
||||||
|
.unwrap()
|
||||||
|
.texture_formats
|
||||||
|
.clone();
|
||||||
|
|
||||||
|
let mut feedback =
|
||||||
|
DmabufFeedbackBuilder::new(primary_node.dev_id(), primary_formats.clone());
|
||||||
|
for dev in kms
|
||||||
|
.drm_devices
|
||||||
|
.values()
|
||||||
|
.filter(|dev| dev.inner.render_node != primary_node)
|
||||||
|
{
|
||||||
|
feedback = feedback.add_preference_tranche(
|
||||||
|
dev.inner.render_node.dev_id(),
|
||||||
|
TrancheFlags::Sampling,
|
||||||
|
dev.texture_formats.iter().cloned(),
|
||||||
|
6..=6,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let default_feedback = feedback.build().unwrap();
|
||||||
|
self.common.dmabuf_state.set_default_feedback(
|
||||||
|
kms.dmabuf_global
|
||||||
|
.as_ref()
|
||||||
|
.expect("Primary node but no dmabuf global?"),
|
||||||
|
&default_feedback,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl KmsState {
|
||||||
pub fn switch_vt(&mut self, num: i32) -> Result<(), anyhow::Error> {
|
pub fn switch_vt(&mut self, num: i32) -> Result<(), anyhow::Error> {
|
||||||
self.session.change_vt(num).map_err(Into::into)
|
self.session.change_vt(num).map_err(Into::into)
|
||||||
}
|
}
|
||||||
|
|
@ -523,29 +639,25 @@ impl KmsState {
|
||||||
pub fn dmabuf_imported(
|
pub fn dmabuf_imported(
|
||||||
&mut self,
|
&mut self,
|
||||||
client: Option<Client>,
|
client: Option<Client>,
|
||||||
global: &DmabufGlobal,
|
_global: &DmabufGlobal,
|
||||||
dmabuf: Dmabuf,
|
dmabuf: Dmabuf,
|
||||||
) -> Result<DrmNode> {
|
) -> Result<DrmNode> {
|
||||||
|
let device_node = dmabuf
|
||||||
|
.node()
|
||||||
|
.unwrap_or_else(|| self.primary_node.read().unwrap().unwrap());
|
||||||
let mut device = self
|
let mut device = self
|
||||||
.drm_devices
|
.drm_devices
|
||||||
.values_mut()
|
.values_mut()
|
||||||
.find(|device| {
|
.find(|dev| dev.inner.render_node == device_node)
|
||||||
device
|
.ok_or(anyhow::anyhow!(
|
||||||
.socket
|
"Unable to find device for node: {}",
|
||||||
.as_ref()
|
device_node
|
||||||
.map(|s| &s.dmabuf_global == global)
|
))?;
|
||||||
.unwrap_or(false)
|
|
||||||
})
|
|
||||||
.context("Couldn't find gpu for dmabuf global")?;
|
|
||||||
|
|
||||||
// If device advertised to client doesn't support format/modifier, select
|
// If device advertised to client doesn't support format/modifier, select
|
||||||
// first device that does. This is needed for image-copy from
|
// first device that does. This is needed for image-copy from
|
||||||
// output/toplevel on a different node.
|
// output/toplevel on a different node.
|
||||||
//
|
if dmabuf.node().is_none() && !device.texture_formats.contains(&dmabuf.format()) {
|
||||||
// TODO: After
|
|
||||||
// https://gitlab.freedesktop.org/wayland/wayland-protocols/-/merge_requests/268,
|
|
||||||
// only try the device specified explicitly by the client, if set.
|
|
||||||
if !device.texture_formats.contains(&dmabuf.format()) {
|
|
||||||
device = self
|
device = self
|
||||||
.drm_devices
|
.drm_devices
|
||||||
.values_mut()
|
.values_mut()
|
||||||
|
|
|
||||||
|
|
@ -1529,7 +1529,7 @@ fn get_surface_dmabuf_feedback(
|
||||||
render_node: DrmNode,
|
render_node: DrmNode,
|
||||||
target_node: DrmNode,
|
target_node: DrmNode,
|
||||||
render_formats: FormatSet,
|
render_formats: FormatSet,
|
||||||
_target_formats: FormatSet,
|
target_formats: FormatSet,
|
||||||
primary_plane_formats: FormatSet,
|
primary_plane_formats: FormatSet,
|
||||||
overlay_plane_formats: Option<FormatSet>,
|
overlay_plane_formats: Option<FormatSet>,
|
||||||
) -> SurfaceDmabufFeedback {
|
) -> SurfaceDmabufFeedback {
|
||||||
|
|
@ -1547,60 +1547,40 @@ fn get_surface_dmabuf_feedback(
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect::<FormatSet>()
|
.collect::<FormatSet>()
|
||||||
});
|
});
|
||||||
let builder = DmabufFeedbackBuilder::new(render_node.dev_id(), render_formats);
|
|
||||||
|
|
||||||
/*
|
let mut builder = DmabufFeedbackBuilder::new(render_node.dev_id(), render_formats.clone());
|
||||||
// Sadly no implementation would pick this up as a preferred render tranche,
|
|
||||||
// where the combined formats would increase our chances of doing a dmabuf copy.
|
|
||||||
// .. So we should probably not advertise this on the off-chance it actually triggers bugs.
|
|
||||||
//
|
|
||||||
|
|
||||||
let combined_formats = render_formats.intersection(&target_formats).cloned().collect::<FormatSet>();
|
if target_node != render_node {
|
||||||
if target_node != render_node.dev_id() && !combined_formats.is_empty() {
|
|
||||||
builder = builder.add_preference_tranche(
|
|
||||||
render_node.dev_id(),
|
|
||||||
None,
|
|
||||||
combined_formats,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
// We also can't advertise scan out tranches for the actual display device,
|
|
||||||
// as e.g. the nvidia driver might then send us dmabufs, that makes e.g. the iris hangs on import...
|
|
||||||
if target_node != render_node.dev_id() && !combined_formats.is_empty() {
|
|
||||||
builder = builder.add_preference_tranche(
|
builder = builder.add_preference_tranche(
|
||||||
target_node.dev_id(),
|
target_node.dev_id(),
|
||||||
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
|
zwp_linux_dmabuf_feedback_v1::TrancheFlags::Sampling,
|
||||||
combined_formats,
|
target_formats,
|
||||||
|
6..=6,
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// So no fun combinations, we gotta wait for dmabuf-v6
|
|
||||||
*/
|
|
||||||
|
|
||||||
let render_feedback = builder.clone().build().unwrap();
|
let render_feedback = builder.clone().build().unwrap();
|
||||||
let primary_scanout_feedback = (target_node == render_node).then(|| {
|
|
||||||
|
let primary_scanout_feedback = builder
|
||||||
|
.clone()
|
||||||
|
.add_preference_tranche(
|
||||||
|
target_node.dev_id(),
|
||||||
|
zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout,
|
||||||
|
primary_plane_formats,
|
||||||
|
4..=6,
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
let overlay_scanout_feedback = overlay_plane_formats.map(|formats| {
|
||||||
builder
|
builder
|
||||||
.clone()
|
|
||||||
.add_preference_tranche(
|
.add_preference_tranche(
|
||||||
render_node.dev_id(),
|
target_node.dev_id(),
|
||||||
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
|
zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout,
|
||||||
primary_plane_formats,
|
formats,
|
||||||
|
4..=6,
|
||||||
)
|
)
|
||||||
.build()
|
.build()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
});
|
});
|
||||||
let overlay_scanout_feedback = overlay_plane_formats
|
|
||||||
.filter(|_| target_node == render_node)
|
|
||||||
.map(|formats| {
|
|
||||||
builder
|
|
||||||
.add_preference_tranche(
|
|
||||||
render_node.dev_id(),
|
|
||||||
Some(zwp_linux_dmabuf_feedback_v1::TrancheFlags::Scanout),
|
|
||||||
formats,
|
|
||||||
)
|
|
||||||
.build()
|
|
||||||
.unwrap()
|
|
||||||
});
|
|
||||||
|
|
||||||
SurfaceDmabufFeedback {
|
SurfaceDmabufFeedback {
|
||||||
render_feedback,
|
render_feedback,
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
shell::{Devices, SeatExt},
|
shell::{Devices, SeatExt},
|
||||||
state::{BackendData, Common},
|
state::{BackendData, Common},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
|
wayland::protocols::drm::WlDrmState,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result, anyhow};
|
use anyhow::{Context, Result, anyhow};
|
||||||
use cosmic_comp_config::output::comp::{OutputConfig, TransformDef};
|
use cosmic_comp_config::output::comp::{OutputConfig, TransformDef};
|
||||||
|
|
@ -273,7 +274,7 @@ fn init_egl_client_side(
|
||||||
.create_global_with_default_feedback::<State>(dh, &feedback);
|
.create_global_with_default_feedback::<State>(dh, &feedback);
|
||||||
|
|
||||||
let render_node = render_node.unwrap().unwrap();
|
let render_node = render_node.unwrap().unwrap();
|
||||||
let _drm_global_id = state.common.wl_drm_state.create_global::<State>(
|
state.common.wl_drm_state = Some(WlDrmState::new::<State>(
|
||||||
dh,
|
dh,
|
||||||
render_node
|
render_node
|
||||||
.dev_path_with_type(NodeType::Render)
|
.dev_path_with_type(NodeType::Render)
|
||||||
|
|
@ -284,7 +285,7 @@ fn init_egl_client_side(
|
||||||
))?,
|
))?,
|
||||||
dmabuf_formats,
|
dmabuf_formats,
|
||||||
&dmabuf_global,
|
&dmabuf_global,
|
||||||
);
|
));
|
||||||
|
|
||||||
info!("EGL hardware-acceleration enabled.");
|
info!("EGL hardware-acceleration enabled.");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
shell::{Devices, SeatExt},
|
shell::{Devices, SeatExt},
|
||||||
state::{BackendData, Common},
|
state::{BackendData, Common},
|
||||||
utils::prelude::*,
|
utils::prelude::*,
|
||||||
|
wayland::protocols::drm::WlDrmState,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result, anyhow};
|
use anyhow::{Context, Result, anyhow};
|
||||||
use cosmic_comp_config::output::comp::OutputConfig;
|
use cosmic_comp_config::output::comp::OutputConfig;
|
||||||
|
|
@ -497,7 +498,7 @@ where
|
||||||
.common
|
.common
|
||||||
.dmabuf_state
|
.dmabuf_state
|
||||||
.create_global_with_default_feedback::<State>(dh, &default_feedback);
|
.create_global_with_default_feedback::<State>(dh, &default_feedback);
|
||||||
let _drm_global_id = state.common.wl_drm_state.create_global::<State>(
|
state.common.wl_drm_state = Some(WlDrmState::new::<State>(
|
||||||
dh,
|
dh,
|
||||||
render_node
|
render_node
|
||||||
.dev_path_with_type(NodeType::Render)
|
.dev_path_with_type(NodeType::Render)
|
||||||
|
|
@ -508,7 +509,7 @@ where
|
||||||
))?,
|
))?,
|
||||||
renderer.dmabuf_formats(),
|
renderer.dmabuf_formats(),
|
||||||
&dmabuf_global,
|
&dmabuf_global,
|
||||||
);
|
));
|
||||||
|
|
||||||
info!("EGL hardware-acceleration enabled.");
|
info!("EGL hardware-acceleration enabled.");
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -838,10 +838,7 @@ impl CosmicSurface {
|
||||||
self.0
|
self.0
|
||||||
.send_dmabuf_feedback(output, primary_scan_out_output, |_, data| {
|
.send_dmabuf_feedback(output, primary_scan_out_output, |_, data| {
|
||||||
if is_fullscreen {
|
if is_fullscreen {
|
||||||
feedback
|
&feedback.primary_scanout_feedback
|
||||||
.primary_scanout_feedback
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&feedback.render_feedback)
|
|
||||||
} else if frame_time_filter_fn(data) == Kind::ScanoutCandidate {
|
} else if frame_time_filter_fn(data) == Kind::ScanoutCandidate {
|
||||||
feedback
|
feedback
|
||||||
.overlay_scanout_feedback
|
.overlay_scanout_feedback
|
||||||
|
|
|
||||||
11
src/state.rs
11
src/state.rs
|
|
@ -276,7 +276,7 @@ pub struct Common {
|
||||||
pub idle_inhibiting_surfaces: HashSet<WlSurface>,
|
pub idle_inhibiting_surfaces: HashSet<WlSurface>,
|
||||||
pub shm_state: ShmState,
|
pub shm_state: ShmState,
|
||||||
pub cursor_shape_manager_state: CursorShapeManagerState,
|
pub cursor_shape_manager_state: CursorShapeManagerState,
|
||||||
pub wl_drm_state: WlDrmState<Option<DrmNode>>,
|
pub wl_drm_state: Option<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,
|
||||||
|
|
@ -326,7 +326,7 @@ pub enum LockedBackend<'a> {
|
||||||
pub struct SurfaceDmabufFeedback {
|
pub struct SurfaceDmabufFeedback {
|
||||||
pub render_feedback: DmabufFeedback,
|
pub render_feedback: DmabufFeedback,
|
||||||
pub overlay_scanout_feedback: Option<DmabufFeedback>,
|
pub overlay_scanout_feedback: Option<DmabufFeedback>,
|
||||||
pub primary_scanout_feedback: Option<DmabufFeedback>,
|
pub primary_scanout_feedback: DmabufFeedback,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
|
@ -671,7 +671,7 @@ impl State {
|
||||||
let cursor_shape_manager_state = CursorShapeManagerState::new::<State>(dh);
|
let cursor_shape_manager_state = CursorShapeManagerState::new::<State>(dh);
|
||||||
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::<Option<DrmNode>>::default();
|
let wl_drm_state = None;
|
||||||
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 =
|
||||||
|
|
@ -1066,10 +1066,7 @@ impl Common {
|
||||||
surface,
|
surface,
|
||||||
render_element_states,
|
render_element_states,
|
||||||
&feedback.render_feedback,
|
&feedback.render_feedback,
|
||||||
feedback
|
&feedback.primary_scanout_feedback,
|
||||||
.primary_scanout_feedback
|
|
||||||
.as_ref()
|
|
||||||
.unwrap_or(&feedback.render_feedback),
|
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
|
||||||
28
src/utils/global.rs
Normal file
28
src/utils/global.rs
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
use calloop::{
|
||||||
|
LoopHandle,
|
||||||
|
timer::{TimeoutAction, Timer},
|
||||||
|
};
|
||||||
|
use smithay::reexports::wayland_server::DisplayHandle;
|
||||||
|
use wayland_backend::server::GlobalId;
|
||||||
|
|
||||||
|
pub fn remove_global_with_timer<D: 'static>(
|
||||||
|
dh: &DisplayHandle,
|
||||||
|
event_loop_handle: &LoopHandle<D>,
|
||||||
|
id: GlobalId,
|
||||||
|
) {
|
||||||
|
dh.disable_global::<D>(id.clone());
|
||||||
|
let source = Timer::from_duration(Duration::from_secs(5));
|
||||||
|
let dh = dh.clone();
|
||||||
|
let res = event_loop_handle.insert_source(source, move |_, _, _state| {
|
||||||
|
dh.remove_global::<D>(id.clone());
|
||||||
|
TimeoutAction::Drop
|
||||||
|
});
|
||||||
|
if let Err(err) = res {
|
||||||
|
tracing::error!(
|
||||||
|
"failed to insert timer source to destroy output global: {}",
|
||||||
|
err
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -4,6 +4,7 @@ pub mod env;
|
||||||
mod ids;
|
mod ids;
|
||||||
pub(crate) use self::ids::id_gen;
|
pub(crate) use self::ids::id_gen;
|
||||||
pub mod geometry;
|
pub mod geometry;
|
||||||
|
pub mod global;
|
||||||
pub mod iced;
|
pub mod iced;
|
||||||
pub mod prelude;
|
pub mod prelude;
|
||||||
pub mod quirks;
|
pub mod quirks;
|
||||||
|
|
|
||||||
|
|
@ -40,7 +40,7 @@ impl DmabufHandler for State {
|
||||||
fn new_surface_feedback(
|
fn new_surface_feedback(
|
||||||
&mut self,
|
&mut self,
|
||||||
surface: &WlSurface,
|
surface: &WlSurface,
|
||||||
global: &DmabufGlobal,
|
_global: &DmabufGlobal,
|
||||||
) -> Option<DmabufFeedback> {
|
) -> Option<DmabufFeedback> {
|
||||||
let BackendData::Kms(kms) = &self.backend else {
|
let BackendData::Kms(kms) = &self.backend else {
|
||||||
return None;
|
return None;
|
||||||
|
|
@ -57,18 +57,7 @@ impl DmabufHandler for State {
|
||||||
f.ended_at.is_none() && f.surface.has_surface(surface, WindowSurfaceType::all())
|
f.ended_at.is_none() && f.surface.has_surface(surface, WindowSurfaceType::all())
|
||||||
});
|
});
|
||||||
|
|
||||||
let node = kms
|
let node = kms.primary_node.read().unwrap().unwrap();
|
||||||
.drm_devices
|
|
||||||
.values()
|
|
||||||
.find(|device| {
|
|
||||||
device
|
|
||||||
.socket
|
|
||||||
.as_ref()
|
|
||||||
.map(|s| &s.dmabuf_global == global)
|
|
||||||
.unwrap_or(false)
|
|
||||||
})?
|
|
||||||
.inner
|
|
||||||
.render_node;
|
|
||||||
let kms_surface = kms
|
let kms_surface = kms
|
||||||
.drm_devices
|
.drm_devices
|
||||||
.values()
|
.values()
|
||||||
|
|
@ -77,9 +66,7 @@ impl DmabufHandler for State {
|
||||||
|
|
||||||
Some(with_states(surface, |data| {
|
Some(with_states(surface, |data| {
|
||||||
if is_fullscreen {
|
if is_fullscreen {
|
||||||
feedback
|
feedback.primary_scanout_feedback
|
||||||
.primary_scanout_feedback
|
|
||||||
.unwrap_or(feedback.render_feedback)
|
|
||||||
} else if frame_time_filter_fn(data) == Kind::ScanoutCandidate {
|
} else if frame_time_filter_fn(data) == Kind::ScanoutCandidate {
|
||||||
feedback
|
feedback
|
||||||
.overlay_scanout_feedback
|
.overlay_scanout_feedback
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,11 @@ use smithay::{
|
||||||
};
|
};
|
||||||
use tracing::trace;
|
use tracing::trace;
|
||||||
|
|
||||||
use std::{convert::TryFrom, path::PathBuf, sync::Arc};
|
use std::{
|
||||||
|
convert::TryFrom,
|
||||||
|
path::PathBuf,
|
||||||
|
sync::{Arc, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
pub enum ImportError {
|
pub enum ImportError {
|
||||||
Failed,
|
Failed,
|
||||||
|
|
@ -52,19 +56,28 @@ pub trait DrmHandler<R: 'static> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug)]
|
||||||
pub struct WlDrmState<R>(std::marker::PhantomData<R>);
|
pub struct WlDrmState<R> {
|
||||||
|
device: Arc<Mutex<DrmGlobalDeviceData>>,
|
||||||
|
global: GlobalId,
|
||||||
|
_marker: std::marker::PhantomData<R>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct DrmGlobalDeviceData {
|
||||||
|
formats: Vec<Fourcc>,
|
||||||
|
path: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
/// Data associated with a drm global.
|
/// Data associated with a drm global.
|
||||||
pub struct DrmGlobalData {
|
pub struct DrmGlobalData {
|
||||||
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
|
filter: Box<dyn for<'a> Fn(&'a Client) -> bool + Send + Sync>,
|
||||||
formats: Arc<Vec<Fourcc>>,
|
|
||||||
device_path: PathBuf,
|
|
||||||
dmabuf_global: DmabufGlobal,
|
dmabuf_global: DmabufGlobal,
|
||||||
|
device: Arc<Mutex<DrmGlobalDeviceData>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DrmInstanceData {
|
pub struct DrmInstanceData {
|
||||||
formats: Arc<Vec<Fourcc>>,
|
device: Arc<Mutex<DrmGlobalDeviceData>>,
|
||||||
dmabuf_global: DmabufGlobal,
|
dmabuf_global: DmabufGlobal,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -86,16 +99,24 @@ where
|
||||||
data_init: &mut DataInit<'_, D>,
|
data_init: &mut DataInit<'_, D>,
|
||||||
) {
|
) {
|
||||||
let data = DrmInstanceData {
|
let data = DrmInstanceData {
|
||||||
formats: global_data.formats.clone(),
|
device: global_data.device.clone(),
|
||||||
dmabuf_global: global_data.dmabuf_global,
|
dmabuf_global: global_data.dmabuf_global,
|
||||||
};
|
};
|
||||||
let drm_instance = data_init.init(resource, data);
|
let drm_instance = data_init.init(resource, data);
|
||||||
|
|
||||||
drm_instance.device(global_data.device_path.to_string_lossy().into_owned());
|
drm_instance.device(
|
||||||
|
global_data
|
||||||
|
.device
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.path
|
||||||
|
.to_string_lossy()
|
||||||
|
.into_owned(),
|
||||||
|
);
|
||||||
if drm_instance.version() >= 2 {
|
if drm_instance.version() >= 2 {
|
||||||
drm_instance.capabilities(wl_drm::Capability::Prime as u32);
|
drm_instance.capabilities(wl_drm::Capability::Prime as u32);
|
||||||
}
|
}
|
||||||
for format in global_data.formats.iter() {
|
for format in global_data.device.lock().unwrap().formats.iter() {
|
||||||
if let Ok(converted) = wl_drm::Format::try_from(*format as u32) {
|
if let Ok(converted) = wl_drm::Format::try_from(*format as u32) {
|
||||||
drm_instance.format(converted as u32);
|
drm_instance.format(converted as u32);
|
||||||
}
|
}
|
||||||
|
|
@ -148,7 +169,7 @@ where
|
||||||
} => {
|
} => {
|
||||||
let format = match Fourcc::try_from(format) {
|
let format = match Fourcc::try_from(format) {
|
||||||
Ok(format) => {
|
Ok(format) => {
|
||||||
if !data.formats.contains(&format) {
|
if !data.device.lock().unwrap().formats.contains(&format) {
|
||||||
drm.post_error(
|
drm.post_error(
|
||||||
wl_drm::Error::InvalidFormat,
|
wl_drm::Error::InvalidFormat,
|
||||||
String::from("Format not advertised by wl_drm"),
|
String::from("Format not advertised by wl_drm"),
|
||||||
|
|
@ -220,13 +241,12 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: 'static> WlDrmState<R> {
|
impl<R: 'static> WlDrmState<R> {
|
||||||
pub fn create_global<D>(
|
pub fn new<D>(
|
||||||
&mut self,
|
|
||||||
display: &DisplayHandle,
|
display: &DisplayHandle,
|
||||||
device_path: PathBuf,
|
device_path: PathBuf,
|
||||||
formats: FormatSet,
|
formats: FormatSet,
|
||||||
dmabuf_global: &DmabufGlobal,
|
dmabuf_global: &DmabufGlobal,
|
||||||
) -> GlobalId
|
) -> Self
|
||||||
where
|
where
|
||||||
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
||||||
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
||||||
|
|
@ -234,19 +254,16 @@ impl<R: 'static> WlDrmState<R> {
|
||||||
+ DmabufHandler
|
+ DmabufHandler
|
||||||
+ 'static,
|
+ 'static,
|
||||||
{
|
{
|
||||||
self.create_global_with_filter::<D, _>(display, device_path, formats, dmabuf_global, |_| {
|
Self::new_with_filter::<D, _>(display, device_path, formats, dmabuf_global, |_| true)
|
||||||
true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create_global_with_filter<D, F>(
|
pub fn new_with_filter<D, F>(
|
||||||
&mut self,
|
|
||||||
display: &DisplayHandle,
|
display: &DisplayHandle,
|
||||||
device_path: PathBuf,
|
device_path: PathBuf,
|
||||||
formats: FormatSet,
|
formats: FormatSet,
|
||||||
dmabuf_global: &DmabufGlobal,
|
dmabuf_global: &DmabufGlobal,
|
||||||
client_filter: F,
|
client_filter: F,
|
||||||
) -> GlobalId
|
) -> Self
|
||||||
where
|
where
|
||||||
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
D: GlobalDispatch<wl_drm::WlDrm, DrmGlobalData>
|
||||||
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
+ Dispatch<wl_drm::WlDrm, DrmInstanceData>
|
||||||
|
|
@ -255,21 +272,45 @@ impl<R: 'static> WlDrmState<R> {
|
||||||
+ 'static,
|
+ 'static,
|
||||||
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
|
||||||
{
|
{
|
||||||
let formats = Arc::new(
|
let device = Arc::new(Mutex::new(DrmGlobalDeviceData {
|
||||||
formats
|
formats: formats
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|f| f.modifier == Modifier::Invalid)
|
.filter(|f| f.modifier == Modifier::Invalid)
|
||||||
.map(|f| f.code)
|
.map(|f| f.code)
|
||||||
.collect(),
|
.collect(),
|
||||||
);
|
path: device_path,
|
||||||
|
}));
|
||||||
|
|
||||||
let data = DrmGlobalData {
|
let data = DrmGlobalData {
|
||||||
filter: Box::new(client_filter),
|
filter: Box::new(client_filter),
|
||||||
formats,
|
device: device.clone(),
|
||||||
device_path,
|
|
||||||
dmabuf_global: *dmabuf_global,
|
dmabuf_global: *dmabuf_global,
|
||||||
};
|
};
|
||||||
|
|
||||||
display.create_global::<D, wl_drm::WlDrm, _>(2, data)
|
let global = display.create_global::<D, wl_drm::WlDrm, _>(2, data);
|
||||||
|
|
||||||
|
WlDrmState {
|
||||||
|
device,
|
||||||
|
global,
|
||||||
|
_marker: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn update_device(&mut self, device_path: PathBuf, formats: FormatSet) {
|
||||||
|
let new_device = DrmGlobalDeviceData {
|
||||||
|
formats: formats
|
||||||
|
.into_iter()
|
||||||
|
.filter(|f| f.modifier == Modifier::Invalid)
|
||||||
|
.map(|f| f.code)
|
||||||
|
.collect(),
|
||||||
|
path: device_path,
|
||||||
|
};
|
||||||
|
|
||||||
|
*self.device.lock().unwrap() = new_device;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn global(&self) -> &GlobalId {
|
||||||
|
&self.global
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use calloop::{
|
use calloop::LoopHandle;
|
||||||
LoopHandle,
|
|
||||||
timer::{TimeoutAction, Timer},
|
|
||||||
};
|
|
||||||
use cosmic_comp_config::output::comp::AdaptiveSync;
|
use cosmic_comp_config::output::comp::AdaptiveSync;
|
||||||
use cosmic_protocols::output_management::v1::server::{
|
use cosmic_protocols::output_management::v1::server::{
|
||||||
zcosmic_output_configuration_head_v1::ZcosmicOutputConfigurationHeadV1,
|
zcosmic_output_configuration_head_v1::ZcosmicOutputConfigurationHeadV1,
|
||||||
|
|
@ -30,7 +27,7 @@ use smithay::{
|
||||||
utils::{Logical, Physical, Point, Size, Transform},
|
utils::{Logical, Physical, Point, Size, Transform},
|
||||||
wayland::output::WlOutputData,
|
wayland::output::WlOutputData,
|
||||||
};
|
};
|
||||||
use std::{convert::TryFrom, sync::Mutex, time::Duration};
|
use std::{convert::TryFrom, sync::Mutex};
|
||||||
|
|
||||||
mod handlers;
|
mod handlers;
|
||||||
|
|
||||||
|
|
@ -519,26 +516,6 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn remove_global_with_timer<D: 'static>(
|
|
||||||
dh: &DisplayHandle,
|
|
||||||
event_loop_handle: &LoopHandle<D>,
|
|
||||||
id: GlobalId,
|
|
||||||
) {
|
|
||||||
dh.disable_global::<D>(id.clone());
|
|
||||||
let source = Timer::from_duration(Duration::from_secs(5));
|
|
||||||
let dh = dh.clone();
|
|
||||||
let res = event_loop_handle.insert_source(source, move |_, _, _state| {
|
|
||||||
dh.remove_global::<D>(id.clone());
|
|
||||||
TimeoutAction::Drop
|
|
||||||
});
|
|
||||||
if let Err(err) = res {
|
|
||||||
tracing::error!(
|
|
||||||
"failed to insert timer source to destroy output global: {}",
|
|
||||||
err
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! delegate_output_configuration {
|
macro_rules! delegate_output_configuration {
|
||||||
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
|
($(@<$( $lt:tt $( : $clt:tt $(+ $dlt:tt )* )? ),+>)? $ty: ty) => {
|
||||||
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
smithay::reexports::wayland_server::delegate_global_dispatch!($(@< $( $lt $( : $clt $(+ $dlt )* )? ),+ >)? $ty: [
|
||||||
|
|
@ -578,4 +555,4 @@ macro_rules! delegate_output_configuration {
|
||||||
}
|
}
|
||||||
pub(crate) use delegate_output_configuration;
|
pub(crate) use delegate_output_configuration;
|
||||||
|
|
||||||
use crate::utils::prelude::OutputExt;
|
use crate::utils::{global::remove_global_with_timer, prelude::OutputExt};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue