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>
diff --git a/libweston/backend-drm/state-propose.c b/libweston/backend-drm/state-propose.c
index a6a7a31..78deb92 100644
--- a/libweston/backend-drm/state-propose.c
+++ b/libweston/backend-drm/state-propose.c
@@ -381,7 +381,7 @@
 		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_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);
 	}
 }