summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Olbrich <m.olbrich@pengutronix.de>2022-06-22 08:22:06 +0200
committerMichael Olbrich <m.olbrich@pengutronix.de>2022-08-03 17:35:26 +0200
commit3b3fdc52c31f828ff0fb71d2c6ce7bdcc64f20a1 (patch)
treef4286180246ac1baed73258e80a4c6d43b170b82
parentd4eafbaa980a7698e4c0c8170ab29f9fd929754c (diff)
downloadweston-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.c6
-rw-r--r--libweston/compositor.c26
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);
}