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) {
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+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);
|
||||
}
|
||||
|
||||
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,10 +3449,14 @@ output_repaint_timer_handler(void *data)
|
||||
|
||||
if (ret != 0) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wl_list_for_each(output, &compositor->output_list, link)
|
||||
output->repainted = false;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user