From 10937feef842ee2656c27caba45c6426e74bcdad Mon Sep 17 00:00:00 2001 From: Alexandros Frantzis Date: Mon, 14 Jun 2021 13:09:44 +0300 Subject: [PATCH] backend-drm: Clear drm_output cursor_view when view is destroyed The DRM backend uses changes in the cursor view memory address and surface damage to detect when it needs to re-upload to a cursor plane framebuffer. However, when a cursor view is destroyed and then recreated, e.g., when the pointer cursor surface is updated, the newly created view may have the same memory address as the just destroyed one. If no new cursor buffer is provided (because it was attached, committed and used previously) when this address reuse occurs, then there also isn't any updated surface damage and the backend doesn't update the cursor plane framebuffer at all. To fix this issue utilize the destroy signal to track when the cursor view is destroyed, and clear the cached cursor_view value in drm_output. After clearing the cached value, the next cursor view is always considered new and thus uploaded to the plane properly. Signed-off-by: Alexandros Frantzis --- libweston/backend-drm/drm-internal.h | 4 +++ libweston/backend-drm/drm.c | 2 ++ libweston/backend-drm/kms.c | 4 +-- libweston/backend-drm/state-propose.c | 39 +++++++++++++++++++++++++-- 4 files changed, 45 insertions(+), 4 deletions(-) diff --git a/libweston/backend-drm/drm-internal.h b/libweston/backend-drm/drm-internal.h index a47dc09b..86c25105 100644 --- a/libweston/backend-drm/drm-internal.h +++ b/libweston/backend-drm/drm-internal.h @@ -511,6 +511,7 @@ struct drm_output { struct drm_fb *gbm_cursor_fb[2]; struct drm_plane *cursor_plane; struct weston_view *cursor_view; + struct wl_listener cursor_view_destroy_listener; int current_cursor; struct gbm_surface *gbm_surface; @@ -688,6 +689,9 @@ struct drm_fb * drm_fb_get_from_bo(struct gbm_bo *bo, struct drm_backend *backend, bool is_opaque, enum drm_fb_type type); +void +drm_output_set_cursor_view(struct drm_output *output, struct weston_view *ev); + #ifdef BUILD_DRM_GBM extern struct drm_fb * drm_fb_get_from_view(struct drm_output_state *state, struct weston_view *ev); diff --git a/libweston/backend-drm/drm.c b/libweston/backend-drm/drm.c index 08aee4f1..e7fd788d 100644 --- a/libweston/backend-drm/drm.c +++ b/libweston/backend-drm/drm.c @@ -1793,6 +1793,8 @@ drm_output_destroy(struct weston_output *base) return; } + drm_output_set_cursor_view(output, NULL); + if (output->base.enabled) drm_output_deinit(&output->base); diff --git a/libweston/backend-drm/kms.c b/libweston/backend-drm/kms.c index c8196d88..2a6b0d12 100644 --- a/libweston/backend-drm/kms.c +++ b/libweston/backend-drm/kms.c @@ -669,7 +669,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state) * cursor plane set up. */ if (output->base.disable_planes) { - output->cursor_view = NULL; + drm_output_set_cursor_view(output, NULL); if (output->cursor_plane) { output->cursor_plane->base.x = INT32_MIN; output->cursor_plane->base.y = INT32_MIN; @@ -777,7 +777,7 @@ drm_output_apply_state_legacy(struct drm_output_state *state) return 0; err: - output->cursor_view = NULL; + drm_output_set_cursor_view(output, NULL); drm_output_state_free(state); return -1; } diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c index a6a7a316..78deb928 100644 --- a/libweston/backend-drm/state-propose.c +++ b/libweston/backend-drm/state-propose.c @@ -381,7 +381,7 @@ drm_output_prepare_cursor_view(struct drm_output_state *output_state, needs_update = true; } - output->cursor_view = ev; + drm_output_set_cursor_view(output, ev); plane_state->ev = ev; plane_state->fb = @@ -1156,6 +1156,41 @@ drm_assign_planes(struct weston_output *output_base, void *repaint_data) drm_output_state_get_existing_plane(state, output->cursor_plane); if (!plane_state || !plane_state->fb) - output->cursor_view = NULL; + drm_output_set_cursor_view(output, NULL); + } +} + +static void +drm_output_handle_cursor_view_destroy(struct wl_listener *listener, void *data) +{ + struct drm_output *output = + container_of(listener, struct drm_output, + cursor_view_destroy_listener); + + drm_output_set_cursor_view(output, NULL); +} + +/** Set the current cursor view used for an output. + * + * Ensure the stored value will be properly cleared if the view is destroyed. + * The stored cursor view helps avoid unnecessary uploads of cursor data to + * cursor plane buffer objects (see drm_output_prepare_cursor_view). + */ +void +drm_output_set_cursor_view(struct drm_output *output, struct weston_view *ev) +{ + if (output->cursor_view == ev) + return; + + if (output->cursor_view) + wl_list_remove(&output->cursor_view_destroy_listener.link); + + output->cursor_view = ev; + + if (ev) { + output->cursor_view_destroy_listener.notify = + drm_output_handle_cursor_view_destroy; + wl_signal_add(&ev->destroy_signal, + &output->cursor_view_destroy_listener); } }