From c2bdc9e6ce32aa30a6eeb1ebd716b21c3a37b79c Mon Sep 17 00:00:00 2001 From: Christian Meissl Date: Sun, 21 Jan 2024 12:38:03 +0100 Subject: [PATCH] anvil: reset drm state on test failure this changes session resume to an optimistic path, we first assume our state is good after a session resume and only reset the whole state if we hit a test failure on commit. --- anvil/src/udev.rs | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/anvil/src/udev.rs b/anvil/src/udev.rs index 95c86ea2dc..297cfe13ad 100644 --- a/anvil/src/udev.rs +++ b/anvil/src/udev.rs @@ -313,17 +313,24 @@ pub fn run_udev() { .iter_mut() .map(|(handle, backend)| (*handle, backend)) { - // disable all connectors and reset the internal state of - // the device and all known surfaces to prevent issues with - // conflicting requirements after a tty switch where we can't be - // sure another drm master left the state in a usable way + // if we do not care about flicking (caused by modesetting) we could just + // pass true for disable connectors here. this would make sure our drm + // device is in a known state (all connectors and planes disabled). + // but for demonstration we choose a more optimistic path by leaving the + // state as is and assume it will just work. If this assumption fails + // we will try to reset the state when trying to queue a frame. backend .drm - .activate(true) + .activate(false) .expect("failed to activate drm backend"); if let Some(lease_global) = backend.leasing_global.as_mut() { lease_global.resume::>(); } + for surface in backend.surfaces.values_mut() { + if let Err(err) = surface.compositor.surface().reset_state() { + warn!("Failed to reset drm surface state: {}", err); + } + } handle.insert_idle(move |data| data.state.render(node, None)); } } @@ -1488,7 +1495,16 @@ impl AnvilState { } _ => false, }, - SwapBuffersError::ContextLost(err) => panic!("Rendering loop lost: {}", err), + SwapBuffersError::ContextLost(err) => match err.downcast_ref::() { + Some(DrmError::TestFailed(_)) => { + // reset the complete state, disabling all connectors and planes in case we hit a test failed + // most likely we hit this after a tty switch when a foreign master changed CRTC <-> connector bindings + // and we run in a mismatch + device.drm.reset_state().expect("failed to reset drm device"); + true + } + _ => panic!("Rendering loop lost: {}", err), + }, } } };