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); } }