diff options
author | Michael Olbrich <m.olbrich@pengutronix.de> | 2022-06-22 08:22:06 +0200 |
---|---|---|
committer | Michael Olbrich <m.olbrich@pengutronix.de> | 2022-08-03 17:35:26 +0200 |
commit | 3b3fdc52c31f828ff0fb71d2c6ce7bdcc64f20a1 (patch) | |
tree | f4286180246ac1baed73258e80a4c6d43b170b82 | |
parent | d4eafbaa980a7698e4c0c8170ab29f9fd929754c (diff) | |
download | weston-3b3fdc52c31f828ff0fb71d2c6ce7bdcc64f20a1.tar.gz |
backend-drm: improve atomic commit failure handling
When an atomic commit fails then the output will be stuck in
REPAINT_AWAITING_COMPLETION state. It is waiting for a vblank event that was
never scheduled.
If the error is EBUSY then it can be expected to be a transient error. So
propagate the error and schedule a new repaint in the core compositor.
This is necessary because there are some circumstances when the commit can fail
unexpectedly:
- With 'state_invalid == true' one commit will disable all planes. If another
commit for a different output is triggered immediately afterwards, then this
commit can temporarily fail with EBUSY because it tries to use the same
planes.
- At least with i915, if one commit enables an output then a second commit for a
different output immediately afterwards can temporarily fail with EBUSY. This
is probably caused by some hardware interdependency.
Signed-off-by: Michael Olbrich <m.olbrich@pengutronix.de>
-rw-r--r-- | libweston/backend-drm/drm.c | 6 | ||||
-rw-r--r-- | libweston/compositor.c | 26 |
2 files changed, 26 insertions, 6 deletions
diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index c8bec7e4..79ab239d 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -593,8 +593,8 @@ drm_output_start_repaint_loop(struct weston_output *output_base) if (ret != 0) { weston_log("applying repaint-start state failed: %s\n", strerror(errno)); - if (ret == -EACCES) - return -1; + if (ret == -EACCES || ret == -EBUSY) + return ret; goto finish_frame; } @@ -657,7 +657,7 @@ drm_repaint_flush(struct weston_compositor *compositor) drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state); device->repaint_data = NULL; - return (ret == -EACCES) ? -1 : 0; + return (ret == -EACCES || ret == -EBUSY) ? ret : 0; } /** diff --git a/libweston/compositor.c b/libweston/compositor.c index 89fe410e..9c1768d2 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -3405,6 +3405,20 @@ output_repaint_timer_arm(struct weston_compositor *compositor) wl_event_source_timer_update(compositor->repaint_timer, msec_to_next); } +static void +weston_output_schedule_repaint_restart(struct weston_output *output) +{ + assert(output->repaint_status == REPAINT_AWAITING_COMPLETION); + /* The device was busy so try again one frame later */ + timespec_add_nsec(&output->next_repaint, &output->next_repaint, + millihz_to_nsec(output->current_mode->refresh)); + output->repaint_status = REPAINT_SCHEDULED; + TL_POINT(output->compositor, "core_repaint_restart", + TLP_OUTPUT(output), TLP_END); + output_repaint_timer_arm(output->compositor); + weston_output_damage(output); +} + static int output_repaint_timer_handler(void *data) { @@ -3435,8 +3449,12 @@ output_repaint_timer_handler(void *data) if (ret != 0) { wl_list_for_each(output, &compositor->output_list, link) { - if (output->repainted) - weston_output_schedule_repaint_reset(output); + if (output->repainted) { + if (ret == -EBUSY) + weston_output_schedule_repaint_restart(output); + else + weston_output_schedule_repaint_reset(output); + } } } @@ -3583,7 +3601,9 @@ idle_repaint(void *data) output->repaint_status = REPAINT_AWAITING_COMPLETION; output->idle_repaint_source = NULL; ret = output->start_repaint_loop(output); - if (ret != 0) + if (ret == -EBUSY) + weston_output_schedule_repaint_restart(output); + else if (ret != 0) weston_output_schedule_repaint_reset(output); } |