compositor: fix finish_frame presentation feedback crash

This was brought up in issue 1063. The assertion in
weston_presentation_feedback_present_list() will trigger randomly during
repeated suspend/resume testing, presumably while a client is animating
and asking for presentation feedback.

drm_output_start_repaint_loop() has a path where drmWaitVBlank() is able
to pull a good timestamp for the last vblank. This results in a call to
weston_output_finish_frame() with a good timestamp and
WP_PRESENTATION_FEEDBACK_INVALID in the flags.

Previously it was assumed that in such case the presentation feedback
list cannot have any entries. This assumption is false. It is possible
that while the output is in idle state, a client will post an update to
a surface and ask for presentation feedback on it. This should trigger
drm_output_start_repaint_loop() with a non-empty feedback list.

It is unclear why this problem was not seen in the wild much more often.

Start-repaint-loop does not present anything by definition, it only acts
to synchronize the output repaint loop with the (hardware) scanout
cycle. Therefore no feedback must be sent there. As
WP_PRESENTATION_FEEDBACK_INVALID flag indicates no feedback must be
sent, use it to avoid calling
weston_presentation_feedback_present_list().

References: https://gitlab.freedesktop.org/wayland/weston/-/issues/1063
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
Pekka Paalanen 2025-11-13 11:38:34 +02:00
parent 1a868b7244
commit d69e816b54

View file

@ -4039,10 +4039,12 @@ weston_output_finish_frame(struct weston_output *output,
TLP_VBLANK(&vblank_monotonic), TLP_END); TLP_VBLANK(&vblank_monotonic), TLP_END);
refresh_nsec = millihz_to_nsec(output->current_mode->refresh); refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
weston_presentation_feedback_present_list(&output->feedback_list, if (!(presented_flags & WP_PRESENTATION_FEEDBACK_INVALID)) {
output, refresh_nsec, stamp, weston_presentation_feedback_present_list(&output->feedback_list,
output->msc, output, refresh_nsec, stamp,
presented_flags); output->msc,
presented_flags);
}
output->frame_time = *stamp; output->frame_time = *stamp;