kms/surface: Fix thread crash on error return of redraw

If `redraw()` returned early, before updating `self.state`, but after
calling `queue_frame`, `on_vblank` would later be called, and reach
`unreachable` since state isn't set to `WaitinfForVBlank`.

In particular, this was happening when the dmabuf from the image copy
frame failed to `bind`.

To avoid this, make sure to update `self.state` immediately after
calling `queue_frame`, before any early return from an error.
This commit is contained in:
Ian Douglas Scott 2025-05-12 12:32:39 -07:00 committed by Victoria Brekenfeld
parent a57f4a8466
commit e1a817bc06

View file

@ -1431,6 +1431,25 @@ impl SurfaceThreadState {
x @ Ok(()) | x @ Err(FrameError::EmptyFrame) => {
self.timings.submitted_for_presentation(&self.clock);
// Update `state` after `queue_frame`, before any early return from errors
if x.is_ok() {
let new_state = QueueState::WaitingForVBlank {
redraw_needed: false,
};
match mem::replace(&mut self.state, new_state) {
QueueState::Idle => unreachable!(),
QueueState::Queued(_) => (),
QueueState::WaitingForVBlank { .. } => unreachable!(),
QueueState::WaitingForEstimatedVBlank(estimated_vblank)
| QueueState::WaitingForEstimatedVBlankAndQueued {
estimated_vblank,
..
} => {
self.loop_handle.remove(estimated_vblank);
}
};
}
for (session, frame, res) in frames {
let damage = match res {
Ok((damage, _)) => damage,
@ -1691,22 +1710,6 @@ impl SurfaceThreadState {
}
if x.is_ok() {
let new_state = QueueState::WaitingForVBlank {
redraw_needed: false,
};
match mem::replace(&mut self.state, new_state) {
QueueState::Idle => unreachable!(),
QueueState::Queued(_) => (),
QueueState::WaitingForVBlank { .. } => unreachable!(),
QueueState::WaitingForEstimatedVBlank(estimated_vblank)
| QueueState::WaitingForEstimatedVBlankAndQueued {
estimated_vblank,
..
} => {
self.loop_handle.remove(estimated_vblank);
}
};
if self.mirroring.is_none() {
self.frame_callback_seq = self.frame_callback_seq.wrapping_add(1);
self.send_frame_callbacks();