Skip to content

Commit

Permalink
wayland/kms: Add drm_lease implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
Drakulix committed Oct 6, 2023
1 parent 6a92030 commit 7ecc970
Show file tree
Hide file tree
Showing 3 changed files with 243 additions and 35 deletions.
198 changes: 163 additions & 35 deletions src/backend/kms/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ use smithay::{
utils::{DeviceFd, Size, Transform},
wayland::{
dmabuf::{get_dmabuf, DmabufFeedbackBuilder, DmabufGlobal},
drm_lease::{DrmLease, DrmLeaseState},
relative_pointer::RelativePointerManagerState,
seat::WaylandFocus,
shm::{shm_format_to_fourcc, with_buffer_contents},
Expand Down Expand Up @@ -96,7 +97,7 @@ const MIN_RENDER_TIME: Duration = Duration::from_millis(3);

#[derive(Debug)]
pub struct KmsState {
devices: HashMap<DrmNode, Device>,
pub devices: HashMap<DrmNode, Device>,
pub input_devices: HashMap<String, input::Device>,
pub api: GpuManager<GbmGlesBackend<GlowRenderer>>,
pub primary: DrmNode,
Expand All @@ -107,11 +108,14 @@ pub struct KmsState {
pub struct Device {
render_node: DrmNode,
surfaces: HashMap<crtc::Handle, Surface>,
drm: DrmDevice,
pub drm: DrmDevice,
gbm: GbmDevice<DrmDeviceFd>,
allocator: Box<dyn Allocator<Buffer = Dmabuf, Error = AnyError>>,
formats: HashSet<Format>,
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>,
socket: Option<Socket>,
}
Expand All @@ -126,6 +130,9 @@ impl fmt::Debug for Device {
.field("allocator", &"...")
.field("formats", &self.formats)
.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("socket", &self.socket)
.finish()
Expand Down Expand Up @@ -272,8 +279,11 @@ pub fn init_backend(
if let Err(err) = libinput_context.resume() {
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();
if let Some(lease_state) = device.leasing_global.as_mut() {
lease_state.resume::<State>();
}
}
let dispatcher = dispatcher.clone();
handle.insert_idle(move |state| {
Expand Down Expand Up @@ -341,6 +351,9 @@ pub fn init_backend(
libinput_context.suspend();
for device in state.backend.kms().devices.values_mut() {
device.drm.pause();
if let Some(lease_state) = device.leasing_global.as_mut() {
lease_state.suspend();
}
for surface in device.surfaces.values_mut() {
surface.surface = None;
if let Some(token) = surface.render_timer_token.take() {
Expand Down Expand Up @@ -593,6 +606,18 @@ impl State {
drm,
formats,
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),
socket,
};
Expand Down Expand Up @@ -624,19 +649,62 @@ impl State {
init_shaders(&mut renderer).expect("Failed to initialize renderer");

for (crtc, conn) in outputs {
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);
let non_desktop =
match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") {
Ok((val_type, value)) => {
val_type.convert_value(value).as_boolean().unwrap()
}
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),
);
}
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);
}
Expand Down Expand Up @@ -714,7 +782,16 @@ impl State {
let changes = device.enumerate_surfaces()?;
let mut w = self.common.shell.global_space().size.w;
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 {
self.common.event_loop_handle.remove(token);
}
Expand All @@ -723,26 +800,69 @@ impl State {
}
}
for (crtc, conn) in changes.added {
let mut renderer = match backend.api.single_renderer(&device.render_node) {
Ok(renderer) => renderer,
Err(err) => {
warn!(?err, "Failed to initialize output.");
continue;
}
};
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
Ok(output) => {
w += output
.user_data()
.get::<RefCell<OutputConfig>>()
.unwrap()
.borrow()
.mode_size()
.w;
outputs_added.push(output);
let non_desktop =
match drm_helpers::get_property_val(&device.drm, conn, "non-desktop") {
Ok((val_type, value)) => {
val_type.convert_value(value).as_boolean().unwrap()
}
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),
);
}
Err(err) => warn!(?err, "Failed to initialize output."),
};
} else {
let mut renderer = match backend.api.single_renderer(&device.render_node) {
Ok(renderer) => renderer,
Err(err) => {
warn!(?err, "Failed to initialize output.");
continue;
}
};
match device.setup_surface(crtc, conn, (w, 0), &mut renderer) {
Ok(output) => {
w += output
.user_data()
.get::<RefCell<OutputConfig>>()
.unwrap()
.borrow()
.mode_size()
.w;
outputs_added.push(output);
}
Err(err) => warn!(?err, "Failed to initialize output."),
};
}
}
}
}
Expand Down Expand Up @@ -779,6 +899,9 @@ impl State {
let mut outputs_removed = Vec::new();
let backend = self.backend.kms();
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);
for surface in device.surfaces.values_mut() {
if let Some(token) = surface.render_timer_token.take() {
Expand Down Expand Up @@ -837,6 +960,11 @@ impl Device {
.surfaces
.iter()
.map(|(c, s)| (*c, s.connector))
.chain(
self.non_desktop_connectors
.iter()
.map(|(conn, crtc)| (*crtc, *conn)),
)
.collect::<HashMap<crtc::Handle, connector::Handle>>();

let added = config
Expand Down
79 changes: 79 additions & 0 deletions src/wayland/handlers/drm_lease.rs
Original file line number Diff line number Diff line change
@@ -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);
1 change: 1 addition & 0 deletions src/wayland/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ pub mod compositor;
pub mod data_device;
pub mod decoration;
pub mod dmabuf;
pub mod drm_lease;
pub mod fractional_scale;
pub mod keyboard_shortcuts_inhibit;
pub mod layer_shell;
Expand Down

0 comments on commit 7ecc970

Please sign in to comment.