libweston: add initial dma-buf feedback implementation

This adds the initial dma-buf feedback implementation, following the
changes in the dma-buf protocol extension.

The initial dma-buf feedback implementation gives support to send
default feedback and per-surface feedback. For now the per-surface
feedback support is very basic and is still not implemented in the
DRM-backend, what basically means that KMS plane's formats/modifiers are
not being exposed to clients. In the next commits of this series we add
the DRM-backend implementation.

This patch is based on previous work of Scott Anderson (@ascent).

Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
Signed-off-by: Scott Anderson <scott.anderson@collabora.com>
Reviewed-by: Daniel Stone <daniels@collabora.com>
diff --git a/libweston/compositor.c b/libweston/compositor.c
index 42984f9..bcdcb09 100644
--- a/libweston/compositor.c
+++ b/libweston/compositor.c
@@ -2313,6 +2313,9 @@
 	assert(wl_list_empty(&surface->subsurface_list_pending));
 	assert(wl_list_empty(&surface->subsurface_list));
 
+	if (surface->dmabuf_feedback)
+		weston_dmabuf_feedback_destroy(surface->dmabuf_feedback);
+
 	wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
 		weston_view_destroy(ev);
 
@@ -4038,31 +4041,65 @@
 	surface_damage_buffer
 };
 
+static int
+create_surface_dmabuf_feedback(struct weston_compositor *ec,
+			       struct weston_surface *surface)
+{
+	struct weston_dmabuf_feedback_tranche *tranche;
+	dev_t main_device = ec->default_dmabuf_feedback->main_device;
+	uint32_t flags = 0;
+
+	surface->dmabuf_feedback = weston_dmabuf_feedback_create(main_device);
+	if (!surface->dmabuf_feedback)
+		return -1;
+
+	tranche = weston_dmabuf_feedback_tranche_create(surface->dmabuf_feedback,
+							ec->dmabuf_feedback_format_table,
+							main_device, flags,
+							RENDERER_PREF);
+	if (!tranche) {
+		weston_dmabuf_feedback_destroy(surface->dmabuf_feedback);
+		surface->dmabuf_feedback = NULL;
+		return -1;
+	}
+
+	return 0;
+}
+
 static void
 compositor_create_surface(struct wl_client *client,
 			  struct wl_resource *resource, uint32_t id)
 {
 	struct weston_compositor *ec = wl_resource_get_user_data(resource);
 	struct weston_surface *surface;
+	int ret;
 
 	surface = weston_surface_create(ec);
-	if (surface == NULL) {
-		wl_resource_post_no_memory(resource);
-		return;
+	if (surface == NULL)
+		goto err;
+
+	if (ec->default_dmabuf_feedback) {
+		ret = create_surface_dmabuf_feedback(ec, surface);
+		if (ret < 0)
+			goto err_dmabuf_feedback;
 	}
 
 	surface->resource =
 		wl_resource_create(client, &wl_surface_interface,
 				   wl_resource_get_version(resource), id);
-	if (surface->resource == NULL) {
-		weston_surface_destroy(surface);
-		wl_resource_post_no_memory(resource);
-		return;
-	}
+	if (surface->resource == NULL)
+		goto err_dmabuf_feedback;
 	wl_resource_set_implementation(surface->resource, &surface_interface,
 				       surface, destroy_surface);
 
 	wl_signal_emit(&ec->create_surface_signal, surface);
+
+	return;
+
+err_dmabuf_feedback:
+	weston_surface_destroy(surface);
+err:
+	wl_resource_post_no_memory(resource);
 }
 
 static void
@@ -8191,6 +8228,11 @@
 	weston_log_scope_destroy(compositor->timeline);
 	compositor->timeline = NULL;
 
+	if (compositor->default_dmabuf_feedback) {
+		weston_dmabuf_feedback_destroy(compositor->default_dmabuf_feedback);
+		weston_dmabuf_feedback_format_table_destroy(compositor->dmabuf_feedback_format_table);
+	}
+
 	free(compositor);
 }