Merge pull request #191 from pop-os/drm-lease_jammy
wayland/kms: Add drm_lease implementation
This commit is contained in:
commit
806e10fcd9
3 changed files with 243 additions and 35 deletions
|
|
@ -68,6 +68,7 @@ use smithay::{
|
||||||
utils::{DeviceFd, Size, Transform},
|
utils::{DeviceFd, Size, Transform},
|
||||||
wayland::{
|
wayland::{
|
||||||
dmabuf::{get_dmabuf, DmabufFeedbackBuilder, DmabufGlobal},
|
dmabuf::{get_dmabuf, DmabufFeedbackBuilder, DmabufGlobal},
|
||||||
|
drm_lease::{DrmLease, DrmLeaseState},
|
||||||
relative_pointer::RelativePointerManagerState,
|
relative_pointer::RelativePointerManagerState,
|
||||||
seat::WaylandFocus,
|
seat::WaylandFocus,
|
||||||
shm::{shm_format_to_fourcc, with_buffer_contents},
|
shm::{shm_format_to_fourcc, with_buffer_contents},
|
||||||
|
|
@ -96,7 +97,7 @@ const MIN_RENDER_TIME: Duration = Duration::from_millis(3);
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct KmsState {
|
pub struct KmsState {
|
||||||
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: DrmNode,
|
||||||
|
|
@ -107,11 +108,14 @@ pub struct KmsState {
|
||||||
pub struct Device {
|
pub struct Device {
|
||||||
render_node: DrmNode,
|
render_node: DrmNode,
|
||||||
surfaces: HashMap<crtc::Handle, Surface>,
|
surfaces: HashMap<crtc::Handle, Surface>,
|
||||||
drm: DrmDevice,
|
pub drm: DrmDevice,
|
||||||
gbm: GbmDevice<DrmDeviceFd>,
|
gbm: GbmDevice<DrmDeviceFd>,
|
||||||
allocator: Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>,
|
allocator: Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>,
|
||||||
formats: HashSet<Format>,
|
formats: HashSet<Format>,
|
||||||
supports_atomic: bool,
|
supports_atomic: bool,
|
||||||
|
pub non_desktop_connectors: Vec<(connector::Handle, crtc::Handle)>,
|
||||||
|
pub leasing_global: Option<DrmLeaseState>,
|
||||||
|
pub active_leases: Vec<DrmLease>,
|
||||||
event_token: Option<RegistrationToken>,
|
event_token: Option<RegistrationToken>,
|
||||||
socket: Option<Socket>,
|
socket: Option<Socket>,
|
||||||
}
|
}
|
||||||
|
|
@ -126,6 +130,9 @@ impl fmt::Debug for Device {
|
||||||
.field("allocator", &"...")
|
.field("allocator", &"...")
|
||||||
.field("formats", &self.formats)
|
.field("formats", &self.formats)
|
||||||
.field("supports_atomic", &self.supports_atomic)
|
.field("supports_atomic", &self.supports_atomic)
|
||||||
|
.field("non_desktop_connectors", &self.non_desktop_connectors)
|
||||||
|
.field("leasing_global", &self.leasing_global)
|
||||||
|
.field("active_leases", &self.active_leases)
|
||||||
.field("event_token", &self.event_token)
|
.field("event_token", &self.event_token)
|
||||||
.field("socket", &self.socket)
|
.field("socket", &self.socket)
|
||||||
.finish()
|
.finish()
|
||||||
|
|
@ -272,8 +279,11 @@ pub fn init_backend(
|
||||||
if let Err(err) = libinput_context.resume() {
|
if let Err(err) = libinput_context.resume() {
|
||||||
error!(?err, "Failed to resume libinput context.");
|
error!(?err, "Failed to resume libinput context.");
|
||||||
}
|
}
|
||||||
for device in state.backend.kms().devices.values() {
|
for device in state.backend.kms().devices.values_mut() {
|
||||||
device.drm.activate();
|
device.drm.activate();
|
||||||
|
if let Some(lease_state) = device.leasing_global.as_mut() {
|
||||||
|
lease_state.resume::<State>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let dispatcher = dispatcher.clone();
|
let dispatcher = dispatcher.clone();
|
||||||
handle.insert_idle(move |state| {
|
handle.insert_idle(move |state| {
|
||||||
|
|
@ -341,6 +351,9 @@ pub fn init_backend(
|
||||||
libinput_context.suspend();
|
libinput_context.suspend();
|
||||||
for device in state.backend.kms().devices.values_mut() {
|
for device in state.backend.kms().devices.values_mut() {
|
||||||
device.drm.pause();
|
device.drm.pause();
|
||||||
|
if let Some(lease_state) = device.leasing_global.as_mut() {
|
||||||
|
lease_state.suspend();
|
||||||
|
}
|
||||||
for surface in device.surfaces.values_mut() {
|
for surface in device.surfaces.values_mut() {
|
||||||
surface.surface = None;
|
surface.surface = None;
|
||||||
if let Some(token) = surface.render_timer_token.take() {
|
if let Some(token) = surface.render_timer_token.take() {
|
||||||
|
|
@ -593,6 +606,18 @@ impl State {
|
||||||
drm,
|
drm,
|
||||||
formats,
|
formats,
|
||||||
supports_atomic,
|
supports_atomic,
|
||||||
|
non_desktop_connectors: Vec::new(),
|
||||||
|
leasing_global: DrmLeaseState::new::<State>(dh, &drm_node)
|
||||||
|
.map_err(|err| {
|
||||||
|
// TODO: replace with inspect_err, once stable
|
||||||
|
warn!(
|
||||||
|
?err,
|
||||||
|
"Failed to initialize drm lease global for: {}", drm_node
|
||||||
|
);
|
||||||
|
err
|
||||||
|
})
|
||||||
|
.ok(),
|
||||||
|
active_leases: Vec::new(),
|
||||||
event_token: Some(token),
|
event_token: Some(token),
|
||||||
socket,
|
socket,
|
||||||
};
|
};
|
||||||
|
|
@ -624,19 +649,62 @@ impl State {
|
||||||
init_shaders(&mut renderer).expect("Failed to initialize renderer");
|
init_shaders(&mut renderer).expect("Failed to initialize renderer");
|
||||||
|
|
||||||
for (crtc, conn) in outputs {
|
for (crtc, conn) in outputs {
|
||||||
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
|
let non_desktop =
|
||||||
Ok(output) => {
|
match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") {
|
||||||
w += output
|
Ok((val_type, value)) => {
|
||||||
.user_data()
|
val_type.convert_value(value).as_boolean().unwrap()
|
||||||
.get::<RefCell<OutputConfig>>()
|
}
|
||||||
.unwrap()
|
Err(err) => {
|
||||||
.borrow()
|
warn!(
|
||||||
.mode_size()
|
?err,
|
||||||
.w;
|
"Failed to determine if connector is meant desktop usage, assuming so."
|
||||||
wl_outputs.push(output);
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if non_desktop {
|
||||||
|
let Ok(output_name) = drm_helpers::interface_name(&device.drm, conn) else {
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
let drm_helpers::EdidInfo {
|
||||||
|
model,
|
||||||
|
manufacturer,
|
||||||
|
} = match drm_helpers::edid_info(&device.drm, conn) {
|
||||||
|
Ok(info) => info,
|
||||||
|
Err(_) => drm_helpers::EdidInfo {
|
||||||
|
model: "Unknown".into(),
|
||||||
|
manufacturer: "Unknown".into(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
device.non_desktop_connectors.push((conn, crtc));
|
||||||
|
info!(
|
||||||
|
"Connector {} is non-desktop, setting up for leasing",
|
||||||
|
output_name
|
||||||
|
);
|
||||||
|
if let Some(lease_state) = device.leasing_global.as_mut() {
|
||||||
|
lease_state.add_connector::<State>(
|
||||||
|
conn,
|
||||||
|
output_name,
|
||||||
|
format!("{} {}", manufacturer, model),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
Err(err) => warn!(?err, "Failed to initialize output."),
|
} else {
|
||||||
};
|
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
|
||||||
|
Ok(output) => {
|
||||||
|
w += output
|
||||||
|
.user_data()
|
||||||
|
.get::<RefCell<OutputConfig>>()
|
||||||
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.mode_size()
|
||||||
|
.w;
|
||||||
|
wl_outputs.push(output);
|
||||||
|
}
|
||||||
|
Err(err) => warn!(?err, "Failed to initialize output."),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
backend.devices.insert(drm_node, device);
|
backend.devices.insert(drm_node, device);
|
||||||
}
|
}
|
||||||
|
|
@ -714,7 +782,16 @@ impl State {
|
||||||
let changes = device.enumerate_surfaces()?;
|
let changes = device.enumerate_surfaces()?;
|
||||||
let mut w = self.common.shell.global_space().size.w;
|
let mut w = self.common.shell.global_space().size.w;
|
||||||
for crtc in changes.removed {
|
for crtc in changes.removed {
|
||||||
if let Some(surface) = device.surfaces.remove(&crtc) {
|
if let Some(pos) = device
|
||||||
|
.non_desktop_connectors
|
||||||
|
.iter()
|
||||||
|
.position(|(_, handle)| *handle == crtc)
|
||||||
|
{
|
||||||
|
let (conn, _) = device.non_desktop_connectors.remove(pos);
|
||||||
|
if let Some(leasing_state) = device.leasing_global.as_mut() {
|
||||||
|
leasing_state.withdraw_connector(conn);
|
||||||
|
}
|
||||||
|
} else if let Some(surface) = device.surfaces.remove(&crtc) {
|
||||||
if let Some(token) = surface.render_timer_token {
|
if let Some(token) = surface.render_timer_token {
|
||||||
self.common.event_loop_handle.remove(token);
|
self.common.event_loop_handle.remove(token);
|
||||||
}
|
}
|
||||||
|
|
@ -723,26 +800,69 @@ impl State {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (crtc, conn) in changes.added {
|
for (crtc, conn) in changes.added {
|
||||||
let mut renderer = match backend.api.single_renderer(&device.render_node) {
|
let non_desktop =
|
||||||
Ok(renderer) => renderer,
|
match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") {
|
||||||
Err(err) => {
|
Ok((val_type, value)) => {
|
||||||
warn!(?err, "Failed to initialize output.");
|
val_type.convert_value(value).as_boolean().unwrap()
|
||||||
continue;
|
}
|
||||||
|
Err(err) => {
|
||||||
|
warn!(
|
||||||
|
?err,
|
||||||
|
"Failed to determine if connector is meant desktop usage, assuming so."
|
||||||
|
);
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if non_desktop {
|
||||||
|
let Ok(output_name) = drm_helpers::interface_name(&device.drm, conn) else {
|
||||||
|
continue
|
||||||
|
};
|
||||||
|
let drm_helpers::EdidInfo {
|
||||||
|
model,
|
||||||
|
manufacturer,
|
||||||
|
} = match drm_helpers::edid_info(&device.drm, conn) {
|
||||||
|
Ok(info) => info,
|
||||||
|
Err(_) => drm_helpers::EdidInfo {
|
||||||
|
model: "Unknown".into(),
|
||||||
|
manufacturer: "Unknown".into(),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
device.non_desktop_connectors.push((conn, crtc));
|
||||||
|
info!(
|
||||||
|
"Connector {} is non-desktop, setting up for leasing",
|
||||||
|
output_name
|
||||||
|
);
|
||||||
|
if let Some(lease_state) = device.leasing_global.as_mut() {
|
||||||
|
lease_state.add_connector::<State>(
|
||||||
|
conn,
|
||||||
|
output_name,
|
||||||
|
format!("{} {}", manufacturer, model),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
};
|
} else {
|
||||||
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
|
let mut renderer = match backend.api.single_renderer(&device.render_node) {
|
||||||
Ok(output) => {
|
Ok(renderer) => renderer,
|
||||||
w += output
|
Err(err) => {
|
||||||
.user_data()
|
warn!(?err, "Failed to initialize output.");
|
||||||
.get::<RefCell<OutputConfig>>()
|
continue;
|
||||||
.unwrap()
|
}
|
||||||
.borrow()
|
};
|
||||||
.mode_size()
|
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
|
||||||
.w;
|
Ok(output) => {
|
||||||
outputs_added.push(output);
|
w += output
|
||||||
}
|
.user_data()
|
||||||
Err(err) => warn!(?err, "Failed to initialize output."),
|
.get::<RefCell<OutputConfig>>()
|
||||||
};
|
.unwrap()
|
||||||
|
.borrow()
|
||||||
|
.mode_size()
|
||||||
|
.w;
|
||||||
|
outputs_added.push(output);
|
||||||
|
}
|
||||||
|
Err(err) => warn!(?err, "Failed to initialize output."),
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -779,6 +899,9 @@ impl State {
|
||||||
let mut outputs_removed = Vec::new();
|
let mut outputs_removed = Vec::new();
|
||||||
let backend = self.backend.kms();
|
let backend = self.backend.kms();
|
||||||
if let Some(mut device) = backend.devices.remove(&drm_node) {
|
if let Some(mut device) = backend.devices.remove(&drm_node) {
|
||||||
|
if let Some(mut leasing_global) = device.leasing_global.take() {
|
||||||
|
leasing_global.disable_global::<State>();
|
||||||
|
}
|
||||||
backend.api.as_mut().remove_node(&device.render_node);
|
backend.api.as_mut().remove_node(&device.render_node);
|
||||||
for surface in device.surfaces.values_mut() {
|
for surface in device.surfaces.values_mut() {
|
||||||
if let Some(token) = surface.render_timer_token.take() {
|
if let Some(token) = surface.render_timer_token.take() {
|
||||||
|
|
@ -837,6 +960,11 @@ impl Device {
|
||||||
.surfaces
|
.surfaces
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(c, s)| (*c, s.connector))
|
.map(|(c, s)| (*c, s.connector))
|
||||||
|
.chain(
|
||||||
|
self.non_desktop_connectors
|
||||||
|
.iter()
|
||||||
|
.map(|(conn, crtc)| (*crtc, *conn)),
|
||||||
|
)
|
||||||
.collect::<HashMap<crtc::Handle, connector::Handle>>();
|
.collect::<HashMap<crtc::Handle, connector::Handle>>();
|
||||||
|
|
||||||
let added = config
|
let added = config
|
||||||
|
|
|
||||||
79
src/wayland/handlers/drm_lease.rs
Normal file
79
src/wayland/handlers/drm_lease.rs
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use crate::state::State;
|
||||||
|
use smithay::{
|
||||||
|
backend::drm::DrmNode,
|
||||||
|
delegate_drm_lease,
|
||||||
|
wayland::drm_lease::{
|
||||||
|
DrmLease, DrmLeaseBuilder, DrmLeaseHandler, DrmLeaseRequest, DrmLeaseState, LeaseRejected,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
impl DrmLeaseHandler for State {
|
||||||
|
fn drm_lease_state(&mut self, node: DrmNode) -> &mut DrmLeaseState {
|
||||||
|
self.backend
|
||||||
|
.kms()
|
||||||
|
.devices
|
||||||
|
.get_mut(&node)
|
||||||
|
.unwrap()
|
||||||
|
.leasing_global
|
||||||
|
.as_mut()
|
||||||
|
.unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lease_request(
|
||||||
|
&mut self,
|
||||||
|
node: DrmNode,
|
||||||
|
request: DrmLeaseRequest,
|
||||||
|
) -> Result<DrmLeaseBuilder, LeaseRejected> {
|
||||||
|
let backend = self
|
||||||
|
.backend
|
||||||
|
.kms()
|
||||||
|
.devices
|
||||||
|
.get_mut(&node)
|
||||||
|
.ok_or(LeaseRejected::default())?;
|
||||||
|
|
||||||
|
let mut builder = DrmLeaseBuilder::new(&backend.drm);
|
||||||
|
for conn in request.connectors {
|
||||||
|
if let Some((_, crtc)) = backend
|
||||||
|
.non_desktop_connectors
|
||||||
|
.iter()
|
||||||
|
.find(|(handle, _)| *handle == conn)
|
||||||
|
{
|
||||||
|
builder.add_connector(conn);
|
||||||
|
builder.add_crtc(*crtc);
|
||||||
|
let planes = backend
|
||||||
|
.drm
|
||||||
|
.planes(crtc)
|
||||||
|
.map_err(LeaseRejected::with_cause)?;
|
||||||
|
builder.add_plane(planes.primary.handle);
|
||||||
|
if let Some(cursor) = planes.cursor {
|
||||||
|
builder.add_plane(cursor.handle);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tracing::warn!(
|
||||||
|
?conn,
|
||||||
|
"Lease requested for desktop connector, denying request"
|
||||||
|
);
|
||||||
|
return Err(LeaseRejected::default());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(builder)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_active_lease(&mut self, node: DrmNode, lease: DrmLease) {
|
||||||
|
if let Some(backend) = self.backend.kms().devices.get_mut(&node) {
|
||||||
|
backend.active_leases.push(lease);
|
||||||
|
}
|
||||||
|
// else the backend is gone, drop the lease
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lease_destroyed(&mut self, node: DrmNode, lease: u32) {
|
||||||
|
if let Some(backend) = self.backend.kms().devices.get_mut(&node) {
|
||||||
|
backend.active_leases.retain(|l| l.id() != lease);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate_drm_lease!(State);
|
||||||
|
|
@ -5,6 +5,7 @@ pub mod compositor;
|
||||||
pub mod data_device;
|
pub mod data_device;
|
||||||
pub mod decoration;
|
pub mod decoration;
|
||||||
pub mod dmabuf;
|
pub mod dmabuf;
|
||||||
|
pub mod drm_lease;
|
||||||
pub mod fractional_scale;
|
pub mod fractional_scale;
|
||||||
pub mod keyboard_shortcuts_inhibit;
|
pub mod keyboard_shortcuts_inhibit;
|
||||||
pub mod layer_shell;
|
pub mod layer_shell;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue