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>
This commit is contained in:
@@ -593,8 +593,8 @@ drm_output_start_repaint_loop(struct weston_output *output_base)
|
|||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
weston_log("applying repaint-start state failed: %s\n",
|
weston_log("applying repaint-start state failed: %s\n",
|
||||||
strerror(errno));
|
strerror(errno));
|
||||||
if (ret == -EACCES)
|
if (ret == -EACCES || ret == -EBUSY)
|
||||||
return -1;
|
return ret;
|
||||||
goto finish_frame;
|
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);
|
drm_debug(b, "[repaint] flushed pending_state %p\n", pending_state);
|
||||||
device->repaint_data = NULL;
|
device->repaint_data = NULL;
|
||||||
|
|
||||||
return (ret == -EACCES) ? -1 : 0;
|
return (ret == -EACCES || ret == -EBUSY) ? ret : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
+22
-2
@@ -3405,6 +3405,20 @@ output_repaint_timer_arm(struct weston_compositor *compositor)
|
|||||||
wl_event_source_timer_update(compositor->repaint_timer, msec_to_next);
|
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
|
static int
|
||||||
output_repaint_timer_handler(void *data)
|
output_repaint_timer_handler(void *data)
|
||||||
{
|
{
|
||||||
@@ -3435,10 +3449,14 @@ output_repaint_timer_handler(void *data)
|
|||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
wl_list_for_each(output, &compositor->output_list, link) {
|
wl_list_for_each(output, &compositor->output_list, link) {
|
||||||
if (output->repainted)
|
if (output->repainted) {
|
||||||
|
if (ret == -EBUSY)
|
||||||
|
weston_output_schedule_repaint_restart(output);
|
||||||
|
else
|
||||||
weston_output_schedule_repaint_reset(output);
|
weston_output_schedule_repaint_reset(output);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wl_list_for_each(output, &compositor->output_list, link)
|
wl_list_for_each(output, &compositor->output_list, link)
|
||||||
output->repainted = false;
|
output->repainted = false;
|
||||||
@@ -3583,7 +3601,9 @@ idle_repaint(void *data)
|
|||||||
output->repaint_status = REPAINT_AWAITING_COMPLETION;
|
output->repaint_status = REPAINT_AWAITING_COMPLETION;
|
||||||
output->idle_repaint_source = NULL;
|
output->idle_repaint_source = NULL;
|
||||||
ret = output->start_repaint_loop(output);
|
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);
|
weston_output_schedule_repaint_reset(output);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user