kms: Change awkward new trait to InnerDevice

This commit is contained in:
Victoria Brekenfeld 2025-07-23 17:25:16 +02:00 • committed by Victoria Brekenfeld
parent 87742c1e0c
commit 6492629f90
8 changed files with 274 additions and 251 deletions

View file

@ -88,62 +88,54 @@ pub type GbmDrmOutputManager = DrmOutputManager<
DrmDeviceFd, DrmDeviceFd,
>; >;
#[derive(Debug)]
pub struct Device { pub struct Device {
pub inner: InnerDevice,
pub drm: GbmDrmOutputManager,
supports_atomic: bool,
event_token: Option<RegistrationToken>,
pub socket: Option<Socket>,
}
#[derive(Debug)]
pub struct LockedDevice<'a> {
pub inner: &'a mut InnerDevice,
pub drm: LockedGbmDrmOutputManager<'a>,
}
pub struct InnerDevice {
pub dev_node: DrmNode, pub dev_node: DrmNode,
pub render_node: DrmNode, pub render_node: DrmNode,
pub egl: Option<EGLInternals>, pub egl: Option<EGLInternals>,
pub outputs: HashMap<connector::Handle, Output>, pub outputs: HashMap<connector::Handle, Output>,
pub surfaces: HashMap<crtc::Handle, Surface>, pub surfaces: HashMap<crtc::Handle, Surface>,
pub drm: GbmDrmOutputManager,
pub gbm: GbmDevice<DrmDeviceFd>, pub gbm: GbmDevice<DrmDeviceFd>,
supports_atomic: bool,
pub leased_connectors: Vec<(connector::Handle, crtc::Handle)>, pub leased_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>>, pub active_buffers: HashSet<Weak<WlBuffer>>,
event_token: Option<RegistrationToken>,
pub socket: Option<Socket>,
} }
impl fmt::Debug for Device { impl fmt::Debug for InnerDevice {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Device") f.debug_struct("Device")
.field("dev_node", &self.render_node) .field("dev_node", &self.dev_node)
.field("render_node", &self.render_node) .field("render_node", &self.render_node)
.field("egl", &self.egl)
.field("outputs", &self.outputs) .field("outputs", &self.outputs)
.field("surfaces", &self.surfaces) .field("surfaces", &self.surfaces)
.field("drm", &"..") .field("gbm", &"..")
.field("egl", &self.egl)
.field("supports_atomic", &self.supports_atomic)
.field("leased_connectors", &self.leased_connectors) .field("leased_connectors", &self.leased_connectors)
.field("leasing_global", &self.leasing_global) .field("leasing_global", &self.leasing_global)
.field("active_leases", &self.active_leases) .field("active_leases", &self.active_leases)
.field("event_token", &self.event_token) .field("active_buffers", &self.active_buffers.len())
.field("socket", &self.socket)
.finish() .finish()
} }
} }
pub struct LockedDevice<'a> {
pub dev_node: &'a DrmNode,
pub render_node: &'a DrmNode,
pub egl: &'a mut Option<EGLInternals>,
pub outputs: &'a HashMap<connector::Handle, Output>,
pub surfaces: &'a mut HashMap<crtc::Handle, Surface>,
pub drm: LockedGbmDrmOutputManager<'a>,
pub gbm: &'a GbmDevice<DrmDeviceFd>,
pub leased_connectors: &'a mut Vec<(connector::Handle, crtc::Handle)>,
pub leasing_global: &'a mut Option<DrmLeaseState>,
pub active_leases: &'a mut Vec<DrmLease>,
pub active_buffers: &'a HashSet<Weak<WlBuffer>>,
}
pub fn init_egl(gbm: &GbmDevice<DrmDeviceFd>) -> Result<EGLInternals> { pub fn init_egl(gbm: &GbmDevice<DrmDeviceFd>) -> Result<EGLInternals> {
let path = gbm.dev_path(); let path = gbm.dev_path();
@ -268,7 +260,7 @@ impl State {
move |event, metadata, state: &mut State| match event { move |event, metadata, state: &mut State| match event {
DrmEvent::VBlank(crtc) => { DrmEvent::VBlank(crtc) => {
if let Some(device) = state.backend.kms().drm_devices.get_mut(&drm_node) { if let Some(device) = state.backend.kms().drm_devices.get_mut(&drm_node) {
if let Some(surface) = device.surfaces.get_mut(&crtc) { if let Some(surface) = device.inner.surfaces.get_mut(&crtc) {
surface.on_vblank(metadata.take()); surface.on_vblank(metadata.take());
} }
} }
@ -309,31 +301,32 @@ impl State {
); );
let mut device = Device { let mut device = Device {
dev_node: drm_node,
render_node,
egl: None,
outputs: HashMap::new(),
surfaces: HashMap::new(),
drm, drm,
gbm, inner: InnerDevice {
dev_node: drm_node,
render_node,
egl: None,
outputs: HashMap::new(),
surfaces: HashMap::new(),
gbm,
leased_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(),
active_buffers: HashSet::new(),
},
supports_atomic, supports_atomic,
leased_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(),
active_buffers: HashSet::new(),
event_token: Some(token), event_token: Some(token),
socket, socket,
}; };
@ -344,7 +337,8 @@ impl State {
{ {
for (conn, maybe_crtc) in connectors { for (conn, maybe_crtc) in connectors {
match device.connector_added( match device.inner.connector_added(
device.drm.device_mut(),
self.backend.kms().primary_node.clone(), self.backend.kms().primary_node.clone(),
conn, conn,
maybe_crtc, maybe_crtc,
@ -359,7 +353,7 @@ impl State {
w += output.geometry().size.w as u32; w += output.geometry().size.w as u32;
wl_outputs.push(output.clone()); wl_outputs.push(output.clone());
} }
device.outputs.insert(conn, output); device.inner.outputs.insert(conn, output);
} }
Err(err) => { Err(err) => {
warn!(?err, "Failed to initialize output, skipping"); warn!(?err, "Failed to initialize output, skipping");
@ -411,26 +405,29 @@ impl State {
for conn in changes.removed { for conn in changes.removed {
// contains conns with updated crtcs, just drop the surface and re-create // contains conns with updated crtcs, just drop the surface and re-create
if let Some(pos) = device if let Some(pos) = device
.inner
.leased_connectors .leased_connectors
.iter() .iter()
.position(|(handle, _)| *handle == conn) .position(|(handle, _)| *handle == conn)
{ {
let _ = device.leased_connectors.remove(pos); let _ = device.inner.leased_connectors.remove(pos);
if let Some(leasing_state) = device.leasing_global.as_mut() { if let Some(leasing_state) = device.inner.leasing_global.as_mut() {
leasing_state.withdraw_connector(conn); leasing_state.withdraw_connector(conn);
} }
} else if let Some(crtc) = device } else if let Some(crtc) = device
.inner
.surfaces .surfaces
.iter() .iter()
.find_map(|(crtc, surface)| (surface.connector == conn).then_some(crtc)) .find_map(|(crtc, surface)| (surface.connector == conn).then_some(crtc))
.cloned() .cloned()
{ {
device.surfaces.remove(&crtc).unwrap(); device.inner.surfaces.remove(&crtc).unwrap();
} }
if !changes.added.iter().any(|(c, _)| c == &conn) { if !changes.added.iter().any(|(c, _)| c == &conn) {
outputs_removed.push( outputs_removed.push(
device device
.inner
.outputs .outputs
.remove(&conn) .remove(&conn)
.expect("Connector without output?"), .expect("Connector without output?"),
@ -439,7 +436,8 @@ impl State {
} }
for (conn, maybe_crtc) in changes.added { for (conn, maybe_crtc) in changes.added {
match device.connector_added( match device.inner.connector_added(
device.drm.device_mut(),
backend.primary_node.clone(), backend.primary_node.clone(),
conn, conn,
maybe_crtc, maybe_crtc,
@ -455,7 +453,7 @@ impl State {
outputs_added.push(output.clone()); outputs_added.push(output.clone());
} }
device.outputs.insert(conn, output); device.inner.outputs.insert(conn, output);
} }
Err(err) => { Err(err) => {
warn!(?err, "Failed to initialize output, skipping"); warn!(?err, "Failed to initialize output, skipping");
@ -502,15 +500,17 @@ impl State {
let drm_node = backend let drm_node = backend
.drm_devices .drm_devices
.values() .values()
.find_map(|device| (device.dev_node.dev_id() == dev).then_some(device.dev_node)) .find_map(|device| {
(device.inner.dev_node.dev_id() == dev).then_some(device.inner.dev_node)
})
.with_context(|| format!("Couldn't find drm node for {}", dev))?; .with_context(|| format!("Couldn't find drm node for {}", dev))?;
let mut outputs_removed = Vec::new(); let mut outputs_removed = Vec::new();
if let Some(mut device) = backend.drm_devices.shift_remove(&drm_node) { if let Some(mut device) = backend.drm_devices.shift_remove(&drm_node) {
if let Some(mut leasing_global) = device.leasing_global.take() { if let Some(mut leasing_global) = device.inner.leasing_global.take() {
leasing_global.disable_global::<State>(); leasing_global.disable_global::<State>();
} }
for surface in device.surfaces.values_mut() { for surface in device.inner.surfaces.values_mut() {
outputs_removed.push(surface.output.clone()); outputs_removed.push(surface.output.clone());
} }
if let Some(token) = device.event_token.take() { if let Some(token) = device.event_token.take() {
@ -523,12 +523,12 @@ impl State {
.destroy_global::<State>(dh, socket.dmabuf_global); .destroy_global::<State>(dh, socket.dmabuf_global);
dh.remove_global::<State>(socket.drm_global); dh.remove_global::<State>(socket.drm_global);
} }
backend.api.as_mut().remove_node(&device.render_node); backend.api.as_mut().remove_node(&device.inner.render_node);
backend backend
.primary_node .primary_node
.write() .write()
.unwrap() .unwrap()
.take_if(|node| node == &device.render_node); .take_if(|node| node == &device.inner.render_node);
}; };
self.common self.common
.output_configuration_state .output_configuration_state
@ -570,11 +570,13 @@ impl Device {
drm_helpers::display_configuration(self.drm.device_mut(), self.supports_atomic)?; drm_helpers::display_configuration(self.drm.device_mut(), self.supports_atomic)?;
let surfaces = self let surfaces = self
.inner
.surfaces .surfaces
.iter() .iter()
.map(|(c, s)| (s.connector, *c)) .map(|(c, s)| (s.connector, *c))
.chain( .chain(
self.leased_connectors self.inner
.leased_connectors
.iter() .iter()
.map(|(conn, crtc)| (*conn, *crtc)), .map(|(conn, crtc)| (*conn, *crtc)),
) )
@ -591,6 +593,7 @@ impl Device {
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let removed = self let removed = self
.inner
.outputs .outputs
.iter() .iter()
.filter(|(conn, _)| match config.get(conn) { .filter(|(conn, _)| match config.get(conn) {
@ -605,17 +608,8 @@ impl Device {
pub fn lock(&mut self) -> LockedDevice<'_> { pub fn lock(&mut self) -> LockedDevice<'_> {
LockedDevice { LockedDevice {
dev_node: &self.dev_node, inner: &mut self.inner,
render_node: &self.render_node,
egl: &mut self.egl,
outputs: &self.outputs,
surfaces: &mut self.surfaces,
drm: self.drm.lock(), drm: self.drm.lock(),
gbm: &self.gbm,
leased_connectors: &mut self.leased_connectors,
leasing_global: &mut self.leasing_global,
active_leases: &mut self.active_leases,
active_buffers: &mut self.active_buffers,
} }
} }
} }
@ -629,13 +623,14 @@ impl<'a> LockedDevice<'a> {
clock: &Clock<Monotonic>, clock: &Clock<Monotonic>,
shell: &Arc<parking_lot::RwLock<Shell>>, shell: &Arc<parking_lot::RwLock<Shell>>,
) -> Result<()> { ) -> Result<()> {
for surface in self.surfaces.values_mut() { for surface in self.inner.surfaces.values_mut() {
surface.allow_frame_flags(flag, flags); surface.allow_frame_flags(flag, flags);
} }
if !flag { if !flag {
let now = clock.now(); let now = clock.now();
let output_map = self let output_map = self
.inner
.surfaces .surfaces
.iter() .iter()
.filter(|(_, s)| s.is_active()) .filter(|(_, s)| s.is_active())
@ -645,7 +640,7 @@ impl<'a> LockedDevice<'a> {
for (crtc, compositor) in self.drm.compositors().iter() { for (crtc, compositor) in self.drm.compositors().iter() {
let elements = match output_map.get(crtc) { let elements = match output_map.get(crtc) {
Some(output) => output_elements( Some(output) => output_elements(
Some(&self.render_node), Some(&self.inner.render_node),
renderer, renderer,
shell, shell,
now, now,
@ -702,7 +697,7 @@ impl<'a> LockedDevice<'a> {
)?; )?;
for (crtc, comp) in self.drm.compositors() { for (crtc, comp) in self.drm.compositors() {
let Some(surface) = self.surfaces.get_mut(crtc) else { let Some(surface) = self.inner.surfaces.get_mut(crtc) else {
continue; continue;
}; };
let comp = comp.lock().unwrap(); let comp = comp.lock().unwrap();
@ -725,25 +720,16 @@ impl<'a> LockedDevice<'a> {
} }
} }
pub trait MaybeLockedDevice { impl InnerDevice {
fn dev_node(&self) -> DrmNode; pub fn in_use(&self, primary: Option<&DrmNode>) -> bool {
fn render_node(&self) -> DrmNode; Some(&self.render_node) == primary
fn output(&self, conn: &connector::Handle) -> Option<&Output>; || !self.surfaces.is_empty()
fn drm_device_mut(&mut self) -> &mut DrmDevice; || !self.active_buffers.is_empty()
fn gbm(&self) -> &GbmDevice<DrmDeviceFd>; }
fn egl(&mut self) -> &mut Option<EGLInternals>;
fn insert_surface(&mut self, crtc: crtc::Handle, surface: Surface);
fn in_use(&self, primary: Option<&DrmNode>) -> bool; pub fn connector_added(
fn add_leased_connector(
&mut self,
crtc: crtc::Handle,
conn: connector::Handle,
output: &Output,
);
fn connector_added(
&mut self, &mut self,
drm: &mut DrmDevice,
primary_node: Arc<RwLock<Option<DrmNode>>>, primary_node: Arc<RwLock<Option<DrmNode>>>,
conn: connector::Handle, conn: connector::Handle,
maybe_crtc: Option<crtc::Handle>, maybe_crtc: Option<crtc::Handle>,
@ -754,27 +740,39 @@ pub trait MaybeLockedDevice {
startup_done: Arc<AtomicBool>, startup_done: Arc<AtomicBool>,
) -> Result<(Output, bool)> { ) -> Result<(Output, bool)> {
let output = self let output = self
.output(&conn) .outputs
.get(&conn)
.cloned() .cloned()
.map(|output| Ok(output)) .map(|output| Ok(output))
.unwrap_or_else(|| create_output_for_conn(self.drm_device_mut(), conn)) .unwrap_or_else(|| create_output_for_conn(drm, conn))
.context("Failed to create `Output`")?; .context("Failed to create `Output`")?;
let non_desktop = let non_desktop = match drm_helpers::get_property_val(drm, conn, "non-desktop") {
match drm_helpers::get_property_val(self.drm_device_mut(), conn, "non-desktop") { Ok((val_type, value)) => val_type.convert_value(value).as_boolean().unwrap(),
Ok((val_type, value)) => val_type.convert_value(value).as_boolean().unwrap(), Err(err) => {
Err(err) => { warn!(
warn!( ?err,
?err, "Failed to determine if connector is meant desktop usage, assuming so."
"Failed to determine if connector is meant desktop usage, assuming so." );
); false
false }
} };
};
if non_desktop { if non_desktop {
if let Some(crtc) = maybe_crtc { if let Some(crtc) = maybe_crtc {
self.add_leased_connector(crtc, conn, &output); self.leased_connectors.push((conn, crtc));
info!(
"Connector {} is non-desktop, setting up for leasing",
output.name()
);
if let Some(lease_state) = self.leasing_global.as_mut() {
let physical = output.physical_properties();
lease_state.add_connector::<State>(
conn,
output.name(),
format!("{} {}", physical.make, physical.model),
);
}
} else { } else {
warn!( warn!(
"Connector {} is non-desktop, but we don't have a free crtc: not leasing", "Connector {} is non-desktop, but we don't have a free crtc: not leasing",
@ -788,7 +786,7 @@ pub trait MaybeLockedDevice {
.user_data() .user_data()
.insert_if_missing(|| RefCell::new(OutputConfig::default())); .insert_if_missing(|| RefCell::new(OutputConfig::default()));
populate_modes(self.drm_device_mut(), &output, conn, position) populate_modes(drm, &output, conn, position)
.with_context(|| "Failed to enumerate connector modes")?; .with_context(|| "Failed to enumerate connector modes")?;
let has_surface = if let Some(crtc) = maybe_crtc { let has_surface = if let Some(crtc) = maybe_crtc {
@ -797,15 +795,15 @@ pub trait MaybeLockedDevice {
crtc, crtc,
conn, conn,
primary_node, primary_node,
self.dev_node(), self.dev_node,
self.render_node(), self.render_node,
evlh, evlh,
screen_filter, screen_filter,
shell, shell,
startup_done, startup_done,
) { ) {
Ok(data) => { Ok(data) => {
self.insert_surface(crtc, data); self.surfaces.insert(crtc, data);
true true
} }
Err(err) => { Err(err) => {
@ -830,14 +828,14 @@ pub trait MaybeLockedDevice {
} }
} }
fn update_egl( pub fn update_egl(
&mut self, &mut self,
primary_node: Option<&DrmNode>, primary_node: Option<&DrmNode>,
api: &mut GbmGlowBackend<DrmDeviceFd>, api: &mut GbmGlowBackend<DrmDeviceFd>,
) -> Result<bool> { ) -> Result<bool> {
if self.in_use(primary_node) { if self.in_use(primary_node) {
if self.egl().is_none() { if self.egl.is_none() {
let egl = init_egl(self.gbm()).context("Failed to create EGL context")?; let egl = init_egl(&self.gbm).context("Failed to create EGL context")?;
let mut renderer = unsafe { let mut renderer = unsafe {
GlowRenderer::new( GlowRenderer::new(
EGLContext::new_shared_with_priority( EGLContext::new_shared_with_priority(
@ -851,96 +849,34 @@ pub trait MaybeLockedDevice {
}; };
init_shaders(renderer.borrow_mut()).context("Failed to compile shaders")?; init_shaders(renderer.borrow_mut()).context("Failed to compile shaders")?;
api.add_node( api.add_node(
self.render_node(), self.render_node,
GbmAllocator::new( GbmAllocator::new(
self.gbm().clone(), self.gbm.clone(),
// SCANOUT because stride bugs // SCANOUT because stride bugs
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT, GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
), ),
renderer, renderer,
); );
*self.egl() = Some(egl); self.egl = Some(egl);
} }
Ok(true) Ok(true)
} else { } else {
if self.egl().is_some() { if self.egl.is_some() {
let _ = self.egl().take(); let _ = self.egl.take();
api.remove_node(&self.render_node()); api.remove_node(&self.render_node);
} }
Ok(false) Ok(false)
} }
} }
fn update_surface_nodes<'b>( pub fn update_surface_nodes<'b>(
&mut self, &mut self,
used_devices: &HashSet<DrmNode>, used_devices: &HashSet<DrmNode>,
others: impl Iterator<Item = &'b Self>, mut others: impl Iterator<Item = &'b Self>,
) -> Result<()> ) -> Result<()>
where where
Self: 'b; Self: 'b,
} {
impl MaybeLockedDevice for Device {
fn dev_node(&self) -> DrmNode {
self.dev_node
}
fn render_node(&self) -> DrmNode {
self.render_node
}
fn output(&self, conn: &connector::Handle) -> Option<&Output> {
self.outputs.get(conn)
}
fn drm_device_mut(&mut self) -> &mut DrmDevice {
self.drm.device_mut()
}
fn gbm(&self) -> &GbmDevice<DrmDeviceFd> {
&self.gbm
}
fn egl(&mut self) -> &mut Option<EGLInternals> {
&mut self.egl
}
fn insert_surface(&mut self, crtc: crtc::Handle, surface: Surface) {
self.surfaces.insert(crtc, surface);
}
fn in_use(&self, primary: Option<&DrmNode>) -> bool {
Some(&self.render_node) == primary
|| !self.surfaces.is_empty()
|| !self.active_buffers.is_empty()
}
fn add_leased_connector(
&mut self,
crtc: crtc::Handle,
conn: connector::Handle,
output: &Output,
) {
self.leased_connectors.push((conn, crtc));
info!(
"Connector {} is non-desktop, setting up for leasing",
output.name()
);
if let Some(lease_state) = self.leasing_global.as_mut() {
let physical = output.physical_properties();
lease_state.add_connector::<State>(
conn,
output.name(),
format!("{} {}", physical.make, physical.model),
);
}
}
fn update_surface_nodes<'b>(
&mut self,
used_devices: &HashSet<DrmNode>,
mut others: impl Iterator<Item = &'b Device>,
) -> Result<()> {
for surface in self.surfaces.values_mut() { for surface in self.surfaces.values_mut() {
let known_nodes = surface.known_nodes().clone(); let known_nodes = surface.known_nodes().clone();
for gone_device in known_nodes.difference(&used_devices) { for gone_device in known_nodes.difference(&used_devices) {
@ -980,7 +916,59 @@ impl MaybeLockedDevice for Device {
} }
} }
impl<'a> MaybeLockedDevice for LockedDevice<'a> { impl Device {
/*
fn dev_node(&self) -> DrmNode {
self.dev_node
}
fn render_node(&self) -> DrmNode {
self.render_node
}
fn output(&self, conn: &connector::Handle) -> Option<&Output> {
self.outputs.get(conn)
}
fn drm_device_mut(&mut self) -> &mut DrmDevice {
self.drm.device_mut()
}
fn gbm(&self) -> &GbmDevice<DrmDeviceFd> {
&self.gbm
}
fn egl(&mut self) -> &mut Option<EGLInternals> {
&mut self.egl
}
fn insert_surface(&mut self, crtc: crtc::Handle, surface: Surface) {
}
fn in_use(&self, primary: Option<&DrmNode>) -> bool {
}
fn add_leased_connector(
&mut self,
crtc: crtc::Handle,
conn: connector::Handle,
output: &Output,
) {
}
fn update_surface_nodes<'b>(
&mut self,
used_devices: &HashSet<DrmNode>,
mut others: impl Iterator<Item = &'b Device>,
) -> Result<()> {
}
*/
}
impl<'a> LockedDevice<'a> {
/*
fn dev_node(&self) -> DrmNode { fn dev_node(&self) -> DrmNode {
*self.dev_node *self.dev_node
} }
@ -1081,6 +1069,7 @@ impl<'a> MaybeLockedDevice for LockedDevice<'a> {
Ok(()) Ok(())
} }
*/
} }
fn create_output_for_conn(drm: &mut DrmDevice, conn: connector::Handle) -> Result<Output> { fn create_output_for_conn(drm: &mut DrmDevice, conn: connector::Handle) -> Result<Output> {

View file

@ -53,12 +53,10 @@ mod drm_helpers;
pub mod render; pub mod render;
mod socket; mod socket;
mod surface; mod surface;
use device::*;
pub(crate) use surface::Surface; pub(crate) use surface::Surface;
pub use surface::Timings; pub use surface::Timings;
pub use device::MaybeLockedDevice;
use device::*;
use super::render::{output_elements, CursorMode, CLEAR_COLOR}; use super::render::{output_elements, CursorMode, CLEAR_COLOR};
#[derive(Debug)] #[derive(Debug)]
@ -203,17 +201,18 @@ fn determine_primary_gpu(
seat: String, seat: String,
) -> Result<Option<DrmNode>> { ) -> Result<Option<DrmNode>> {
if let Some(device) = dev_var("COSMIC_RENDER_DEVICE") { if let Some(device) = dev_var("COSMIC_RENDER_DEVICE") {
if let Some(node) = drm_devices if let Some(node) = drm_devices.values().find_map(|dev| {
.values() device
.find_map(|dev| device.matches(&dev.render_node).then_some(dev.render_node)) .matches(&dev.inner.render_node)
{ .then_some(dev.inner.render_node)
}) {
return Ok(Some(node)); return Ok(Some(node));
} }
} }
// try to find builtin display // try to find builtin display
for dev in drm_devices.values() { for dev in drm_devices.values() {
if dev.surfaces.values().any(|s| { if dev.inner.surfaces.values().any(|s| {
if let Some(conn_info) = dev.drm.device().get_connector(s.connector, false).ok() { if let Some(conn_info) = dev.drm.device().get_connector(s.connector, false).ok() {
let i = conn_info.interface(); let i = conn_info.interface();
i == Interface::EmbeddedDisplayPort || i == Interface::LVDS || i == Interface::DSI i == Interface::EmbeddedDisplayPort || i == Interface::LVDS || i == Interface::DSI
@ -221,20 +220,23 @@ fn determine_primary_gpu(
false false
} }
}) { }) {
return Ok(Some(dev.render_node)); return Ok(Some(dev.inner.render_node));
} }
} }
// else try to find the boot gpu // else try to find the boot gpu
let boot = determine_boot_gpu(seat); let boot = determine_boot_gpu(seat);
if let Some(boot) = boot { if let Some(boot) = boot {
if drm_devices.values().any(|dev| dev.render_node == boot) { if drm_devices
.values()
.any(|dev| dev.inner.render_node == boot)
{
return Ok(Some(boot)); return Ok(Some(boot));
} }
} }
// else just take the first // else just take the first
Ok(drm_devices.values().next().map(|dev| dev.render_node)) Ok(drm_devices.values().next().map(|dev| dev.inner.render_node))
} }
/// Create `GlowRenderer` for `EGL_MESA_device_software` device, if present /// Create `GlowRenderer` for `EGL_MESA_device_software` device, if present
@ -316,7 +318,7 @@ impl State {
if let Err(err) = device.drm.lock().activate(true) { if let Err(err) = device.drm.lock().activate(true) {
error!(?err, "Failed to resume drm device"); error!(?err, "Failed to resume drm device");
} }
if let Some(lease_state) = device.leasing_global.as_mut() { if let Some(lease_state) = device.inner.leasing_global.as_mut() {
lease_state.resume::<State>(); lease_state.resume::<State>();
} }
} }
@ -367,10 +369,10 @@ impl State {
backend.libinput.suspend(); backend.libinput.suspend();
for device in backend.drm_devices.values_mut() { for device in backend.drm_devices.values_mut() {
device.drm.pause(); device.drm.pause();
if let Some(lease_state) = device.leasing_global.as_mut() { if let Some(lease_state) = device.inner.leasing_global.as_mut() {
lease_state.suspend(); lease_state.suspend();
} }
for surface in device.surfaces.values_mut() { for surface in device.inner.surfaces.values_mut() {
surface.suspend(); surface.suspend();
} }
} }
@ -451,12 +453,16 @@ impl KmsState {
let mut last_err = anyhow::anyhow!("Dmabuf cannot be imported on any gpu"); let mut last_err = anyhow::anyhow!("Dmabuf cannot be imported on any gpu");
for device in expected_node.into_iter().chain(other_nodes.into_iter()) { for device in expected_node.into_iter().chain(other_nodes.into_iter()) {
let mut _egl = None; let mut _egl = None;
let egl_display = if let Some(egl_display) = let egl_display = if let Some(egl_display) = device
device.egl.as_ref().map(|internals| &internals.display) .inner
.egl
.as_ref()
.map(|internals| &internals.display)
{ {
egl_display egl_display
} else { } else {
_egl = Some(init_egl(&device.gbm).context("Failed to initialize egl context")?); _egl =
Some(init_egl(&device.inner.gbm).context("Failed to initialize egl context")?);
&_egl.as_ref().unwrap().display &_egl.as_ref().unwrap().display
}; };
@ -466,7 +472,7 @@ impl KmsState {
{ {
trace!( trace!(
"Skipping import of dmabuf on {:?}: unsupported format", "Skipping import of dmabuf on {:?}: unsupported format",
device.render_node device.inner.render_node
); );
continue; continue;
} }
@ -480,7 +486,7 @@ impl KmsState {
image, image,
); );
}; };
device.render_node device.inner.render_node
}) })
.map_err(Into::into); .map_err(Into::into);
@ -490,7 +496,11 @@ impl KmsState {
return Ok(node); return Ok(node);
} }
Err(err) => { Err(err) => {
trace!(?err, "Failed to import dmabuf on {:?}", device.render_node); trace!(
?err,
"Failed to import dmabuf on {:?}",
device.inner.render_node
);
last_err = err; last_err = err;
} }
} }
@ -503,7 +513,7 @@ impl KmsState {
for surface in self for surface in self
.drm_devices .drm_devices
.values() .values()
.flat_map(|d| d.surfaces.values()) .flat_map(|d| d.inner.surfaces.values())
.filter(|s| s.output == *output || s.output.mirroring().is_some_and(|o| &o == output)) .filter(|s| s.output == *output || s.output.mirroring().is_some_and(|o| &o == output))
{ {
surface.schedule_render(); surface.schedule_render();
@ -513,14 +523,14 @@ impl KmsState {
pub fn target_node_for_output(&self, output: &Output) -> Option<DrmNode> { pub fn target_node_for_output(&self, output: &Output) -> Option<DrmNode> {
self.drm_devices self.drm_devices
.values() .values()
.find(|dev| dev.surfaces.values().any(|s| s.output == *output)) .find(|dev| dev.inner.surfaces.values().any(|s| s.output == *output))
.map(|dev| &dev.render_node) .map(|dev| &dev.inner.render_node)
.copied() .copied()
} }
pub fn update_screen_filter(&mut self, screen_filter: &ScreenFilter) -> Result<()> { pub fn update_screen_filter(&mut self, screen_filter: &ScreenFilter) -> Result<()> {
for device in self.drm_devices.values_mut() { for device in self.drm_devices.values_mut() {
for surface in device.surfaces.values_mut() { for surface in device.inner.surfaces.values_mut() {
surface.set_screen_filter(screen_filter.clone()); surface.set_screen_filter(screen_filter.clone());
} }
} }
@ -538,8 +548,11 @@ impl KmsState {
let mut used_devices = HashSet::new(); let mut used_devices = HashSet::new();
for device in self.drm_devices.values_mut() { for device in self.drm_devices.values_mut() {
if device.update_egl(primary_node.as_ref(), self.api.as_mut())? { if device
used_devices.insert(device.render_node()); .inner
.update_egl(primary_node.as_ref(), self.api.as_mut())?
{
used_devices.insert(device.inner.render_node);
} }
} }
@ -552,14 +565,16 @@ impl KmsState {
let all_devices = self let all_devices = self
.drm_devices .drm_devices
.values() .values()
.map(|d| d.render_node) .map(|d| d.inner.render_node)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for node in all_devices { for node in all_devices {
let (mut device, others) = self let (mut device, others) = self
.drm_devices .drm_devices
.values_mut() .values_mut()
.partition::<Vec<_>, _>(|d| d.render_node == node); .partition::<Vec<_>, _>(|d| d.inner.render_node == node);
device[0].update_surface_nodes(&used_devices, others.iter().map(|device| &**device))?; device[0]
.inner
.update_surface_nodes(&used_devices, others.iter().map(|device| &device.inner))?;
} }
Ok(()) Ok(())
@ -584,7 +599,7 @@ impl<'a> KmsGuard<'a> {
for surface in self for surface in self
.drm_devices .drm_devices
.values() .values()
.flat_map(|d| d.surfaces.values()) .flat_map(|d| d.inner.surfaces.values())
.filter(|s| s.output == *output || s.output.mirroring().is_some_and(|o| &o == output)) .filter(|s| s.output == *output || s.output.mirroring().is_some_and(|o| &o == output))
{ {
surface.schedule_render(); surface.schedule_render();
@ -596,8 +611,11 @@ impl<'a> KmsGuard<'a> {
let mut used_devices = HashSet::new(); let mut used_devices = HashSet::new();
for device in self.drm_devices.values_mut() { for device in self.drm_devices.values_mut() {
if device.update_egl(primary_node.as_ref(), self.api.as_mut())? { if device
used_devices.insert(device.render_node()); .inner
.update_egl(primary_node.as_ref(), self.api.as_mut())?
{
used_devices.insert(device.inner.render_node);
} }
} }
@ -610,14 +628,16 @@ impl<'a> KmsGuard<'a> {
let all_devices = self let all_devices = self
.drm_devices .drm_devices
.values() .values()
.map(|d| d.render_node) .map(|d| d.inner.render_node)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
for node in all_devices { for node in all_devices {
let (mut device, others) = self let (mut device, others) = self
.drm_devices .drm_devices
.values_mut() .values_mut()
.partition::<Vec<_>, _>(|d| d.render_node == node); .partition::<Vec<_>, _>(|d| d.inner.render_node == node);
device[0].update_surface_nodes(&used_devices, others.iter().map(|device| &**device))?; device[0]
.inner
.update_surface_nodes(&used_devices, others.iter().map(|device| &*device.inner))?;
} }
Ok(()) Ok(())
@ -628,10 +648,12 @@ impl<'a> KmsGuard<'a> {
.values() .values()
.flat_map(|device| { .flat_map(|device| {
device device
.inner
.outputs .outputs
.iter() .iter()
.filter(|(conn, _)| { .filter(|(conn, _)| {
!device !device
.inner
.leased_connectors .leased_connectors
.iter() .iter()
.any(|(leased_conn, _)| *conn == leased_conn) .any(|(leased_conn, _)| *conn == leased_conn)
@ -658,10 +680,12 @@ impl<'a> KmsGuard<'a> {
// we only want outputs exposed to wayland - not leased ones // we only want outputs exposed to wayland - not leased ones
// but that is also not all surface, because that doesn't contain all detected, but unmapped outputs // but that is also not all surface, because that doesn't contain all detected, but unmapped outputs
let outputs = device let outputs = device
.inner
.outputs .outputs
.iter() .iter()
.filter(|(conn, _)| { .filter(|(conn, _)| {
!device !device
.inner
.leased_connectors .leased_connectors
.iter() .iter()
.any(|(leased_conn, _)| *conn == leased_conn) .any(|(leased_conn, _)| *conn == leased_conn)
@ -681,6 +705,7 @@ impl<'a> KmsGuard<'a> {
.iter() .iter()
.filter(|crtc| { .filter(|crtc| {
!device !device
.inner
.surfaces .surfaces
.get(crtc) .get(crtc)
.is_some_and(|surface| surface.output.is_enabled()) .is_some_and(|surface| surface.output.is_enabled())
@ -690,10 +715,12 @@ impl<'a> KmsGuard<'a> {
let open_conns = outputs let open_conns = outputs
.iter() .iter()
.filter(|output| { .filter(|output| {
output.is_enabled() && !device.surfaces.values().any(|s| &s.output == *output) output.is_enabled()
&& !device.inner.surfaces.values().any(|s| &s.output == *output)
}) })
.flat_map(|output| { .flat_map(|output| {
device device
.inner
.outputs .outputs
.iter() .iter()
.find_map(|(conn, o)| (output == o).then_some(*conn)) .find_map(|(conn, o)| (output == o).then_some(*conn))
@ -731,6 +758,7 @@ impl<'a> KmsGuard<'a> {
if !test_only { if !test_only {
for output in outputs.iter().filter(|o| !o.is_enabled()) { for output in outputs.iter().filter(|o| !o.is_enabled()) {
device device
.inner
.surfaces .surfaces
.retain(|_, surface| surface.output != *output); .retain(|_, surface| surface.output != *output);
} }
@ -740,7 +768,8 @@ impl<'a> KmsGuard<'a> {
let mut w = shell.read().global_space().size.w as u32; let mut w = shell.read().global_space().size.w as u32;
if !test_only { if !test_only {
for (conn, crtc) in new_pairings { for (conn, crtc) in new_pairings {
let (output, _) = device.connector_added( let (output, _) = device.inner.connector_added(
device.drm.device_mut(),
self.primary_node.clone(), self.primary_node.clone(),
conn, conn,
Some(crtc), Some(crtc),
@ -765,6 +794,7 @@ impl<'a> KmsGuard<'a> {
for device in self.drm_devices.values_mut() { for device in self.drm_devices.values_mut() {
let now = clock.now(); let now = clock.now();
let output_map = device let output_map = device
.inner
.surfaces .surfaces
.iter() .iter()
.filter(|(_, s)| s.is_active()) .filter(|(_, s)| s.is_active())
@ -772,7 +802,7 @@ impl<'a> KmsGuard<'a> {
.collect::<HashMap<_, _>>(); .collect::<HashMap<_, _>>();
// reconfigure existing // reconfigure existing
for (crtc, surface) in device.surfaces.iter_mut() { for (crtc, surface) in device.inner.surfaces.iter_mut() {
let output_config = surface.output.config(); let output_config = surface.output.config();
let drm = &mut device.drm; let drm = &mut device.drm;
@ -815,13 +845,13 @@ impl<'a> KmsGuard<'a> {
let mut renderer = self let mut renderer = self
.api .api
.single_renderer(&device.render_node) .single_renderer(&device.inner.render_node)
.with_context(|| "Failed to create renderer")?; .with_context(|| "Failed to create renderer")?;
let mut elements = DrmOutputRenderElements::default(); let mut elements = DrmOutputRenderElements::default();
for (crtc, output) in output_map.iter() { for (crtc, output) in output_map.iter() {
let output_elements = output_elements( let output_elements = output_elements(
Some(&device.render_node), Some(&device.inner.render_node),
&mut renderer, &mut renderer,
&shell, &shell,
now, now,
@ -924,13 +954,13 @@ impl<'a> KmsGuard<'a> {
let mut renderer = self let mut renderer = self
.api .api
.single_renderer(&device.render_node) .single_renderer(&device.inner.render_node)
.with_context(|| "Failed to create renderer")?; .with_context(|| "Failed to create renderer")?;
let mut elements = DrmOutputRenderElements::default(); let mut elements = DrmOutputRenderElements::default();
for (crtc, output) in output_map.iter() { for (crtc, output) in output_map.iter() {
let output_elements = output_elements( let output_elements = output_elements(
Some(&device.render_node), Some(&device.inner.render_node),
&mut renderer, &mut renderer,
&shell, &shell,
now, now,
@ -950,15 +980,16 @@ impl<'a> KmsGuard<'a> {
} }
// configure primary scanout allowance // configure primary scanout allowance
if !device.surfaces.is_empty() { if !device.inner.surfaces.is_empty() {
let mut renderer = self let mut renderer = self
.api .api
.single_renderer(&device.render_node) .single_renderer(&device.inner.render_node)
.with_context(|| "Failed to create renderer")?; .with_context(|| "Failed to create renderer")?;
device device
.allow_primary_scanout_any( .allow_primary_scanout_any(
device device
.inner
.surfaces .surfaces
.values() .values()
.filter(|s| s.output.is_enabled() && s.output.mirroring().is_none()) .filter(|s| s.output.is_enabled() && s.output.mirroring().is_none())
@ -973,7 +1004,7 @@ impl<'a> KmsGuard<'a> {
let mut elements = DrmOutputRenderElements::default(); let mut elements = DrmOutputRenderElements::default();
for (crtc, output) in output_map.iter() { for (crtc, output) in output_map.iter() {
let output_elements = output_elements( let output_elements = output_elements(
Some(&device.render_node), Some(&device.inner.render_node),
&mut renderer, &mut renderer,
&shell, &shell,
now, now,
@ -998,7 +1029,7 @@ impl<'a> KmsGuard<'a> {
// we need to handle mirroring, after all outputs have been enabled // we need to handle mirroring, after all outputs have been enabled
let all_outputs = self.all_outputs(); let all_outputs = self.all_outputs();
for device in self.drm_devices.values_mut() { for device in self.drm_devices.values_mut() {
for surface in device.surfaces.values_mut() { for surface in device.inner.surfaces.values_mut() {
let mirrored_output = let mirrored_output =
if let OutputState::Mirroring(conn) = &surface.output.config().enabled { if let OutputState::Mirroring(conn) = &surface.output.config().enabled {
Some( Some(

View file

@ -296,6 +296,7 @@ impl Surface {
.drm_devices .drm_devices
.get_mut(&dev_node) .get_mut(&dev_node)
.unwrap() .unwrap()
.inner
.surfaces .surfaces
.get_mut(&crtc) .get_mut(&crtc)
.unwrap(); .unwrap();

View file

@ -1,9 +1,6 @@
// SPDX-License-Identifier: GPL-3.0-only // SPDX-License-Identifier: GPL-3.0-only
use crate::{ use crate::state::{BackendData, State};
backend::kms::MaybeLockedDevice,
state::{BackendData, State},
};
use smithay::{ use smithay::{
reexports::wayland_server::{protocol::wl_buffer::WlBuffer, Resource}, reexports::wayland_server::{protocol::wl_buffer::WlBuffer, Resource},
wayland::buffer::BufferHandler, wayland::buffer::BufferHandler,
@ -14,8 +11,11 @@ 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 { if let BackendData::Kms(kms_state) = &mut self.backend {
for device in kms_state.drm_devices.values_mut() { for device in kms_state.drm_devices.values_mut() {
if device.active_buffers.remove(&buffer.downgrade()) { if device.inner.active_buffers.remove(&buffer.downgrade()) {
if !device.in_use(kms_state.primary_node.read().unwrap().as_ref()) { if !device
.inner
.in_use(kms_state.primary_node.read().unwrap().as_ref())
{
if let Err(err) = kms_state.refresh_used_devices() { if let Err(err) = kms_state.refresh_used_devices() {
warn!(?err, "Failed to init devices."); warn!(?err, "Failed to init devices.");
}; };

View file

@ -38,9 +38,9 @@ impl DmabufHandler for State {
if let Some(device) = kms_state if let Some(device) = kms_state
.drm_devices .drm_devices
.values_mut() .values_mut()
.find(|dev| dev.render_node == node) .find(|dev| dev.inner.render_node == node)
{ {
device.active_buffers.insert(buffer.downgrade()); device.inner.active_buffers.insert(buffer.downgrade());
} }
if let Err(err) = kms_state.refresh_used_devices() { if let Err(err) = kms_state.refresh_used_devices() {
warn!(?err, "Failed to init devices."); warn!(?err, "Failed to init devices.");

View file

@ -29,9 +29,9 @@ impl DrmHandler<Option<DrmNode>> for State {
if let Some(device) = kms_state if let Some(device) = kms_state
.drm_devices .drm_devices
.values_mut() .values_mut()
.find(|device| device.render_node == node) .find(|device| device.inner.render_node == node)
{ {
device.active_buffers.insert(buffer.downgrade()); device.inner.active_buffers.insert(buffer.downgrade());
} }
if let Err(err) = kms_state.refresh_used_devices() { if let Err(err) = kms_state.refresh_used_devices() {

View file

@ -16,6 +16,7 @@ impl DrmLeaseHandler for State {
.drm_devices .drm_devices
.get_mut(&node) .get_mut(&node)
.unwrap() .unwrap()
.inner
.leasing_global .leasing_global
.as_mut() .as_mut()
.unwrap() .unwrap()
@ -32,7 +33,7 @@ impl DrmLeaseHandler for State {
.get_mut(&node) .get_mut(&node)
.ok_or(LeaseRejected::default())? .ok_or(LeaseRejected::default())?
.lock(); .lock();
let mut renderer = match kms.api.single_renderer(&backend.render_node) { let mut renderer = match kms.api.single_renderer(&backend.inner.render_node) {
Ok(renderer) => renderer, Ok(renderer) => renderer,
Err(err) => { Err(err) => {
tracing::warn!( tracing::warn!(
@ -55,6 +56,7 @@ impl DrmLeaseHandler for State {
let mut builder = DrmLeaseBuilder::new(backend.drm.device()); let mut builder = DrmLeaseBuilder::new(backend.drm.device());
for conn in request.connectors { for conn in request.connectors {
if let Some((_, crtc)) = backend if let Some((_, crtc)) = backend
.inner
.leased_connectors .leased_connectors
.iter() .iter()
.find(|(handle, _)| *handle == conn) .find(|(handle, _)| *handle == conn)
@ -101,7 +103,7 @@ impl DrmLeaseHandler for State {
fn new_active_lease(&mut self, node: DrmNode, lease: DrmLease) { fn new_active_lease(&mut self, node: DrmNode, lease: DrmLease) {
if let Some(backend) = self.backend.kms().drm_devices.get_mut(&node) { if let Some(backend) = self.backend.kms().drm_devices.get_mut(&node) {
backend.active_leases.push(lease); backend.inner.active_leases.push(lease);
} }
// else the backend is gone, drop the lease // else the backend is gone, drop the lease
} }
@ -110,10 +112,10 @@ impl DrmLeaseHandler for State {
let kms = self.backend.kms(); let kms = self.backend.kms();
if let Some(backend) = kms.drm_devices.get_mut(&node) { if let Some(backend) = kms.drm_devices.get_mut(&node) {
let mut backend = backend.lock(); let mut backend = backend.lock();
backend.active_leases.retain(|l| l.id() != lease); backend.inner.active_leases.retain(|l| l.id() != lease);
if backend.active_leases.is_empty() { if backend.inner.active_leases.is_empty() {
let mut renderer = match kms.api.single_renderer(&backend.render_node) { let mut renderer = match kms.api.single_renderer(&backend.inner.render_node) {
Ok(renderer) => renderer, Ok(renderer) => renderer,
Err(err) => { Err(err) => {
tracing::warn!(?err, "Failed to create renderer to enable direct scanout."); tracing::warn!(?err, "Failed to create renderer to enable direct scanout.");

View file

@ -31,7 +31,7 @@ fn kms_surfaces(state: &mut State) -> impl Iterator<Item = &mut Surface> {
kms_state kms_state
.drm_devices .drm_devices
.values_mut() .values_mut()
.flat_map(|device| device.surfaces.values_mut()), .flat_map(|device| device.inner.surfaces.values_mut()),
) )
} else { } else {
None None