From ef175c8ed43112685e36b24951cd21d97cebfd1e Mon Sep 17 00:00:00 2001 From: Michael Olbrich Date: Tue, 2 Jan 2024 16:39:31 +0100 Subject: [PATCH] backend-drm: handle commit failures correctly Currently only the return value of the last backend that implements repaint_flush() is actually used. That only works because the drm backend is the only backend that implements repaint_flush(). In the drm backend only the return value of the last device is used. And if a failure is actually detected, then all repainted outputs of all backends are reset. This can trigger asserts: weston_output_schedule_repaint_reset() (or _restart()) will change the state of the output but the backend that did not cause the failure will still call weston_output_finish_frame(). The same thing can happen with multiple devices in the drm backend. Or outputs get stuck if an error is dropped. Since the drm backend is the only one that implements repaint_flush() anyways, move the failure handling into the backend and make it device specific. This way only the outputs that need it are reset. Signed-off-by: Michael Olbrich --- include/libweston/libweston.h | 4 ++++ libweston/backend-drm/drm.c | 28 +++++++++++++++++++--------- libweston/backend.h | 2 +- libweston/compositor.c | 14 +++++--------- 4 files changed, 29 insertions(+), 19 deletions(-) diff --git a/include/libweston/libweston.h b/include/libweston/libweston.h index 4f44cd6fc..2593e894d 100644 --- a/include/libweston/libweston.h +++ b/include/libweston/libweston.h @@ -2199,6 +2199,10 @@ weston_layer_mask_is_infinite(struct weston_layer *layer); void weston_output_schedule_repaint(struct weston_output *output); void +weston_output_schedule_repaint_reset(struct weston_output *output); +void +weston_output_schedule_repaint_restart(struct weston_output *output); +void weston_compositor_schedule_repaint(struct weston_compositor *compositor); void weston_compositor_damage_all(struct weston_compositor *compositor); diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index bd8881b5d..1e693839a 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -941,16 +941,17 @@ drm_repaint_begin(struct weston_backend *backend) } } -static int +static void drm_repaint_flush_device(struct drm_device *device) { struct drm_backend *b = device->backend; struct drm_pending_state *pending_state; + struct weston_output *base; int ret; pending_state = device->repaint_data; if (!pending_state) - return 0; + return; ret = drm_pending_state_apply(pending_state); if (ret != 0) @@ -960,7 +961,19 @@ drm_repaint_flush_device(struct drm_device *device) device->drm.filename, pending_state); device->repaint_data = NULL; - return (ret == -EACCES || ret == -EBUSY) ? ret : 0; + if (ret == 0) + return; + + wl_list_for_each(base, &b->compositor->output_list, link) { + struct drm_output *tmp = to_drm_output(base); + if (!tmp || tmp->device != device) + continue; + + if (ret == -EBUSY) + weston_output_schedule_repaint_restart(base); + else + weston_output_schedule_repaint_reset(base); + } } /** @@ -972,19 +985,16 @@ drm_repaint_flush_device(struct drm_device *device) * the update completes (see drm_output_update_complete), the output * state will be freed. */ -static int +static void drm_repaint_flush(struct weston_backend *backend) { struct drm_backend *b = container_of(backend, struct drm_backend, base); struct drm_device *device; - int ret; - ret= drm_repaint_flush_device(b->drm); + drm_repaint_flush_device(b->drm); wl_list_for_each(device, &b->kms_list, link) - ret = drm_repaint_flush_device(device); - - return ret; + drm_repaint_flush_device(device); } static void diff --git a/libweston/backend.h b/libweston/backend.h index a9f3c2adb..8b7e4e600 100644 --- a/libweston/backend.h +++ b/libweston/backend.h @@ -89,7 +89,7 @@ struct weston_backend { * Called on successful completion of a repaint sequence; see * repaint_begin. */ - int (*repaint_flush)(struct weston_backend *backend); + void (*repaint_flush)(struct weston_backend *backend); /** Allocate a new output * diff --git a/libweston/compositor.c b/libweston/compositor.c index fdf1d0003..da00de96d 100644 --- a/libweston/compositor.c +++ b/libweston/compositor.c @@ -3606,7 +3606,7 @@ weston_output_flush_damage_for_primary_plane(struct weston_output *output, } } -static void +WL_EXPORT void weston_output_schedule_repaint_reset(struct weston_output *output) { output->repaint_status = REPAINT_NOT_SCHEDULED; @@ -3819,7 +3819,7 @@ output_repaint_timer_arm(struct weston_compositor *compositor) wl_event_source_timer_update(compositor->repaint_timer, msec_to_next); } -static void +WL_EXPORT void weston_output_schedule_repaint_restart(struct weston_output *output) { assert(output->repaint_status == REPAINT_AWAITING_COMPLETION); @@ -3879,7 +3879,7 @@ output_repaint_timer_handler(void *data) } if (ret == 0) { if (backend->repaint_flush) - ret = backend->repaint_flush(backend); + backend->repaint_flush(backend); } else { if (backend->repaint_cancel) backend->repaint_cancel(backend); @@ -3888,12 +3888,8 @@ output_repaint_timer_handler(void *data) if (output->backend != backend) continue; - if (output->repainted) { - if (ret == -EBUSY) - weston_output_schedule_repaint_restart(output); - else - weston_output_schedule_repaint_reset(output); - } + if (output->repainted) + weston_output_schedule_repaint_reset(output); } } }