Skip to content

Commit e34a289

Browse files
committed
kms: lock during screen conf changes
1 parent bb7a6a7 commit e34a289

File tree

10 files changed

+743
-378
lines changed

10 files changed

+743
-378
lines changed

src/backend/kms/device.rs

Lines changed: 407 additions & 109 deletions
Large diffs are not rendered by default.

src/backend/kms/mod.rs

Lines changed: 157 additions & 119 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,9 @@ use indexmap::IndexMap;
1313
use render::gles::GbmGlowBackend;
1414
use smithay::{
1515
backend::{
16-
allocator::{
17-
dmabuf::Dmabuf,
18-
gbm::{GbmAllocator, GbmBufferFlags},
19-
Buffer,
20-
},
21-
drm::{output::DrmOutputRenderElements, DrmDeviceFd, DrmNode, NodeType},
22-
egl::{context::ContextPriority, EGLContext, EGLDevice, EGLDisplay},
16+
allocator::{dmabuf::Dmabuf, format::FormatSet, Buffer},
17+
drm::{output::DrmOutputRenderElements, DrmDeviceFd, DrmNode, NodeType, VrrSupport},
18+
egl::{EGLContext, EGLDevice, EGLDisplay},
2319
input::InputEvent,
2420
libinput::{LibinputInputBackend, LibinputSessionInterface},
2521
renderer::{glow::GlowRenderer, multigpu::GpuManager},
@@ -47,7 +43,6 @@ use surface::GbmDrmOutput;
4743
use tracing::{error, info, trace, warn};
4844

4945
use std::{
50-
borrow::BorrowMut,
5146
collections::{HashMap, HashSet},
5247
path::Path,
5348
sync::{atomic::AtomicBool, Arc, RwLock},
@@ -59,11 +54,12 @@ pub mod render;
5954
mod socket;
6055
mod surface;
6156
pub(crate) use surface::Surface;
57+
pub use surface::Timings;
6258

59+
pub use device::MaybeLockedDevice;
6360
use device::*;
64-
pub use surface::Timings;
6561

66-
use super::render::{init_shaders, output_elements, CursorMode, CLEAR_COLOR};
62+
use super::render::{output_elements, CursorMode, CLEAR_COLOR};
6763

6864
#[derive(Debug)]
6965
pub struct KmsState {
@@ -80,6 +76,13 @@ pub struct KmsState {
8076
pub syncobj_state: Option<DrmSyncobjState>,
8177
}
8278

79+
pub struct KmsGuard<'a> {
80+
pub drm_devices: IndexMap<DrmNode, LockedDevice<'a>>,
81+
pub primary_node: Arc<RwLock<Option<DrmNode>>>,
82+
api: &'a mut GpuManager<GbmGlowBackend<DrmDeviceFd>>,
83+
session: &'a LibSeatSession,
84+
}
85+
8386
pub fn init_backend(
8487
dh: &DisplayHandle,
8588
event_loop: &mut EventLoop<'static, State>,
@@ -515,47 +518,33 @@ impl KmsState {
515518
.copied()
516519
}
517520

521+
pub fn update_screen_filter(&mut self, screen_filter: &ScreenFilter) -> Result<()> {
522+
for device in self.drm_devices.values_mut() {
523+
for surface in device.surfaces.values_mut() {
524+
surface.set_screen_filter(screen_filter.clone());
525+
}
526+
}
527+
528+
// We don't expect this to fail in a meaningful way.
529+
// The shader is already compiled at this point and we don't rely on any features,
530+
// that might not be available for any filters we currently expose.
531+
//
532+
// But we might conditionally fail here in the future.
533+
Ok(())
534+
}
535+
518536
pub fn refresh_used_devices(&mut self) -> Result<()> {
537+
let primary_node = self.primary_node.read().unwrap();
519538
let mut used_devices = HashSet::new();
520539

521540
for device in self.drm_devices.values_mut() {
522-
if device.in_use(self.primary_node.read().unwrap().as_ref()) {
523-
if device.egl.is_none() {
524-
let egl = init_egl(&device.gbm).context("Failed to create EGL context")?;
525-
let mut renderer = unsafe {
526-
GlowRenderer::new(
527-
EGLContext::new_shared_with_priority(
528-
&egl.display,
529-
&egl.context,
530-
ContextPriority::High,
531-
)
532-
.context("Failed to create shared EGL context")?,
533-
)
534-
.context("Failed to create GL renderer")?
535-
};
536-
init_shaders(renderer.borrow_mut()).context("Failed to compile shaders")?;
537-
self.api.as_mut().add_node(
538-
device.render_node,
539-
GbmAllocator::new(
540-
device.gbm.clone(),
541-
// SCANOUT because stride bugs
542-
GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT,
543-
),
544-
renderer,
545-
);
546-
device.egl = Some(egl);
547-
}
548-
used_devices.insert(device.render_node);
549-
} else {
550-
if device.egl.is_some() {
551-
let _ = device.egl.take();
552-
self.api.as_mut().remove_node(&device.render_node);
553-
}
541+
if device.update_egl(primary_node.as_ref(), self.api.as_mut())? {
542+
used_devices.insert(device.render_node());
554543
}
555544
}
556545

557546
// trigger re-evaluation... urgh
558-
if let Some(primary_node) = self.primary_node.read().unwrap().as_ref() {
547+
if let Some(primary_node) = primary_node.as_ref() {
559548
let _ = self.api.single_renderer(primary_node);
560549
}
561550

@@ -566,54 +555,92 @@ impl KmsState {
566555
.map(|d| d.render_node)
567556
.collect::<Vec<_>>();
568557
for node in all_devices {
569-
let (mut device, mut others) = self
558+
let (mut device, others) = self
570559
.drm_devices
571560
.values_mut()
572561
.partition::<Vec<_>, _>(|d| d.render_node == node);
573-
let device = &mut device[0];
562+
device[0].update_surface_nodes(&used_devices, others.iter().map(|device| &**device))?;
563+
}
574564

575-
for surface in device.surfaces.values_mut() {
576-
let known_nodes = surface.known_nodes().clone();
577-
for gone_device in known_nodes.difference(&used_devices) {
578-
surface.remove_node(*gone_device);
579-
}
580-
for new_device in used_devices.difference(&known_nodes) {
581-
let (render_node, egl, gbm) = if node == *new_device {
582-
// we need to make sure to do partial borrows here, as device.surfaces is borrowed mutable
583-
(
584-
device.render_node,
585-
device.egl.as_ref().unwrap(),
586-
device.gbm.clone(),
587-
)
588-
} else {
589-
let device = others
590-
.iter_mut()
591-
.find(|d| d.render_node == *new_device)
592-
.unwrap();
593-
(
594-
device.render_node,
595-
device.egl.as_ref().unwrap(),
596-
device.gbm.clone(),
597-
)
598-
};
565+
Ok(())
566+
}
599567

600-
surface.add_node(
601-
render_node,
602-
GbmAllocator::new(gbm, GbmBufferFlags::RENDERING | GbmBufferFlags::SCANOUT),
603-
EGLContext::new_shared_with_priority(
604-
&egl.display,
605-
&egl.context,
606-
ContextPriority::High,
607-
)
608-
.context("Failed to create shared EGL context")?,
609-
);
610-
}
568+
pub fn lock_devices(&mut self) -> KmsGuard<'_> {
569+
KmsGuard {
570+
drm_devices: self
571+
.drm_devices
572+
.iter_mut()
573+
.map(|(node, device)| (*node, device.lock()))
574+
.collect(),
575+
primary_node: self.primary_node.clone(),
576+
api: &mut self.api,
577+
session: &self.session,
578+
}
579+
}
580+
}
581+
582+
impl<'a> KmsGuard<'a> {
583+
pub fn schedule_render(&mut self, output: &Output) {
584+
for surface in self
585+
.drm_devices
586+
.values()
587+
.flat_map(|d| d.surfaces.values())
588+
.filter(|s| s.output == *output || s.output.mirroring().is_some_and(|o| &o == output))
589+
{
590+
surface.schedule_render();
591+
}
592+
}
593+
594+
pub fn refresh_used_devices(&mut self) -> Result<()> {
595+
let primary_node = self.primary_node.read().unwrap();
596+
let mut used_devices = HashSet::new();
597+
598+
for device in self.drm_devices.values_mut() {
599+
if device.update_egl(primary_node.as_ref(), self.api.as_mut())? {
600+
used_devices.insert(device.render_node());
611601
}
612602
}
613603

604+
// trigger re-evaluation... urgh
605+
if let Some(primary_node) = primary_node.as_ref() {
606+
let _ = self.api.single_renderer(primary_node);
607+
}
608+
609+
// I hate this. I want partial borrows of hashmap values
610+
let all_devices = self
611+
.drm_devices
612+
.values()
613+
.map(|d| d.render_node)
614+
.collect::<Vec<_>>();
615+
for node in all_devices {
616+
let (mut device, others) = self
617+
.drm_devices
618+
.values_mut()
619+
.partition::<Vec<_>, _>(|d| d.render_node == node);
620+
device[0].update_surface_nodes(&used_devices, others.iter().map(|device| &**device))?;
621+
}
622+
614623
Ok(())
615624
}
616625

626+
pub fn all_outputs(&self) -> Vec<Output> {
627+
self.drm_devices
628+
.values()
629+
.flat_map(|device| {
630+
device
631+
.outputs
632+
.iter()
633+
.filter(|(conn, _)| {
634+
!device
635+
.leased_connectors
636+
.iter()
637+
.any(|(leased_conn, _)| *conn == leased_conn)
638+
})
639+
.map(|(_, output)| output.clone())
640+
})
641+
.collect()
642+
}
643+
617644
pub fn apply_config_for_outputs(
618645
&mut self,
619646
test_only: bool,
@@ -622,9 +649,9 @@ impl KmsState {
622649
shell: Arc<parking_lot::RwLock<Shell>>,
623650
startup_done: Arc<AtomicBool>,
624651
clock: &Clock<Monotonic>,
625-
) -> Result<Vec<Output>, anyhow::Error> {
652+
) -> Result<(), anyhow::Error> {
626653
if !self.session.is_active() {
627-
return Ok(Vec::new());
654+
return Ok(());
628655
}
629656

630657
for device in self.drm_devices.values_mut() {
@@ -771,7 +798,7 @@ impl KmsState {
771798
for (crtc, surface) in device.surfaces.iter_mut() {
772799
let output_config = surface.output.config();
773800

774-
let drm = &mut device.drm.lock();
801+
let drm = &mut device.drm;
775802
let conn = surface.connector;
776803
let conn_info = drm.device().get_connector(conn, false)?;
777804
let mode = conn_info
@@ -861,34 +888,61 @@ impl KmsState {
861888
let vrr = output_config.vrr;
862889
std::mem::drop(output_config);
863890

864-
match surface.resume(compositor) {
865-
Ok(_) => {
866-
surface.output.set_adaptive_sync_support(
867-
surface.adaptive_sync_support().ok(),
868-
);
869-
if surface.use_adaptive_sync(vrr)? {
870-
surface.output.set_adaptive_sync(vrr);
871-
} else {
872-
surface.output.config_mut().vrr = AdaptiveSync::Disabled;
873-
surface.output.set_adaptive_sync(AdaptiveSync::Disabled);
874-
}
875-
}
876-
Err(err) => {
877-
surface.output.config_mut().enabled = OutputState::Disabled;
878-
return Err(err).context("Failed to create surface");
891+
let compositor_ref = drm.compositors().get(crtc).unwrap().lock().unwrap();
892+
let vrr_support = compositor_ref
893+
.vrr_supported(
894+
compositor_ref
895+
.pending_connectors()
896+
.into_iter()
897+
.next()
898+
.unwrap(),
899+
)
900+
.ok();
901+
surface.resume(
902+
compositor,
903+
compositor_ref.surface().plane_info().formats.clone(),
904+
compositor_ref
905+
.surface()
906+
.planes()
907+
.overlay
908+
.iter()
909+
.flat_map(|p| p.formats.iter().cloned())
910+
.collect::<FormatSet>(),
911+
);
912+
913+
surface.output.set_adaptive_sync_support(vrr_support);
914+
if match vrr_support {
915+
Some(VrrSupport::RequiresModeset) if vrr == AdaptiveSync::Enabled => {
916+
false
879917
}
918+
Some(VrrSupport::NotSupported) => false,
919+
_ => true,
920+
} {
921+
surface.use_adaptive_sync(vrr);
922+
surface.output.set_adaptive_sync(vrr);
923+
} else {
924+
surface.use_adaptive_sync(AdaptiveSync::Disabled);
925+
surface.output.config_mut().vrr = AdaptiveSync::Disabled;
926+
surface.output.set_adaptive_sync(AdaptiveSync::Disabled);
880927
}
881928
} else {
882929
let vrr = output_config.vrr;
883930
std::mem::drop(output_config);
884931
if vrr != surface.output.adaptive_sync() {
885-
if surface.use_adaptive_sync(vrr)? {
886-
surface.output.set_adaptive_sync(vrr);
887-
} else if vrr != AdaptiveSync::Disabled {
932+
if match surface.output.adaptive_sync_support() {
933+
Some(VrrSupport::RequiresModeset)
934+
if vrr == AdaptiveSync::Enabled =>
935+
{
936+
true
937+
}
938+
Some(VrrSupport::NotSupported) => true,
939+
_ => false,
940+
} {
888941
anyhow::bail!("Requested VRR mode unsupported");
889-
} else {
890-
surface.output.set_adaptive_sync(AdaptiveSync::Disabled);
891942
}
943+
944+
surface.use_adaptive_sync(vrr);
945+
surface.output.set_adaptive_sync(vrr);
892946
}
893947

894948
let mut renderer = self
@@ -956,7 +1010,6 @@ impl KmsState {
9561010

9571011
if let Err(err) = device
9581012
.drm
959-
.lock()
9601013
.try_to_restore_modifiers(&mut renderer, &elements)
9611014
{
9621015
warn!(?err, "Failed to restore modifiers");
@@ -988,21 +1041,6 @@ impl KmsState {
9881041
}
9891042
}
9901043

991-
Ok(all_outputs)
992-
}
993-
994-
pub fn update_screen_filter(&mut self, screen_filter: &ScreenFilter) -> Result<()> {
995-
for device in self.drm_devices.values_mut() {
996-
for surface in device.surfaces.values_mut() {
997-
surface.set_screen_filter(screen_filter.clone());
998-
}
999-
}
1000-
1001-
// We don't expect this to fail in a meaningful way.
1002-
// The shader is already compiled at this point and we don't rely on any features,
1003-
// that might not be available for any filters we currently expose.
1004-
//
1005-
// But we might conditionally fail here in the future.
10061044
Ok(())
10071045
}
10081046
}

0 commit comments

Comments
 (0)