diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 279cacb7..03eab9a1 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -325,13 +325,13 @@ impl State { let backend = self.backend.kms(); backend.libinput.suspend(); for device in backend.drm_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.suspend(); + let _ = surface.suspend(); } + device.drm.pause(); } } } diff --git a/src/backend/kms/surface/mod.rs b/src/backend/kms/surface/mod.rs index 8b866dad..b03403a2 100644 --- a/src/backend/kms/surface/mod.rs +++ b/src/backend/kms/surface/mod.rs @@ -217,7 +217,9 @@ impl Default for QueueState { #[derive(Debug)] pub enum ThreadCommand { - Suspend, + Suspend { + result: SyncSender>, + }, Resume { surface: DrmSurface, gbm: GbmDevice, @@ -389,8 +391,12 @@ impl Surface { rx.recv().context("Surface thread died")? } - pub fn suspend(&mut self) { - let _ = self.thread_command.send(ThreadCommand::Suspend); + pub fn suspend(&mut self) -> Result<()> { + let (tx, rx) = std::sync::mpsc::sync_channel(1); + let _ = self + .thread_command + .send(ThreadCommand::Suspend { result: tx }); + rx.recv().context("Surface thread died")? } pub fn resume( @@ -496,7 +502,9 @@ fn surface_thread( event_loop .handle() .insert_source(thread_receiver, move |command, _, state| match command { - Event::Msg(ThreadCommand::Suspend) => state.suspend(), + Event::Msg(ThreadCommand::Suspend { result }) => { + let _ = result.send(state.suspend()); + } Event::Msg(ThreadCommand::Resume { surface, gbm, @@ -546,7 +554,7 @@ fn surface_thread( } impl SurfaceThreadState { - fn suspend(&mut self) { + fn suspend(&mut self) -> Result<()> { self.active.store(false, Ordering::SeqCst); let _ = self.compositor.take(); @@ -564,6 +572,8 @@ impl SurfaceThreadState { self.loop_handle.remove(queued_render); } }; + + Ok(()) } fn resume( @@ -673,8 +683,27 @@ impl SurfaceThreadState { let Some(compositor) = self.compositor.as_mut() else { return; }; + + // handle edge-cases right after resume + if !matches!( + self.state, + QueueState::WaitingForVBlank { .. } | QueueState::Idle + ) { + match mem::replace(&mut self.state, QueueState::Idle) { + QueueState::WaitingForVBlank { .. } | QueueState::Idle => unreachable!(), + QueueState::Queued(token) | QueueState::WaitingForEstimatedVBlank(token) => { + self.loop_handle.remove(token); + } + QueueState::WaitingForEstimatedVBlankAndQueued { + estimated_vblank, + queued_render, + } => { + self.loop_handle.remove(estimated_vblank); + self.loop_handle.remove(queued_render); + } + } + } if matches!(self.state, QueueState::Idle) { - // can happen right after resume return; }