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 <alexandros.frantzis@collabora.com>
This commit is contained in:
Alexandros Frantzis 2021-06-14 13:09:44 +03:00 committed by Pekka Paalanen
parent f0c6104444
commit 10937feef8
4 changed files with 45 additions and 4 deletions

View file

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

View file

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

View file

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

View file

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