compositor-drm: cache gem handle in dmabuf object

cache gem handle in dmabuf object to avoid re-import
dmabuf fd every time

Upstream-Status: Inappropriate [i.MX-specific]

Signed-off-by: Haihua Hu <jared.hu@nxp.com>
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
index 8c1fd34..78b5b2a 100644
--- a/libweston/compositor-drm.c
+++ b/libweston/compositor-drm.c
@@ -1089,6 +1089,21 @@
 	drm_fb_destroy(fb);
 }
 
+static void
+drm_close_gem_handle(struct linux_dmabuf_buffer *dmabuf)
+{
+	struct drm_backend *b = to_drm_backend(dmabuf->compositor);
+	int i;
+
+	if (dmabuf->gem_handles[0] != 0) {
+		for (i = 0; i < dmabuf->attributes.n_planes; i++) {
+			struct drm_gem_close arg = { dmabuf->gem_handles[i], };
+			drmIoctl (b->drm.fd, DRM_IOCTL_GEM_CLOSE, &arg);
+			dmabuf->gem_handles[i] = 0;
+		}
+	}
+}
+
 static struct drm_fb *
 drm_fb_get_from_dmabuf(struct linux_dmabuf_buffer *dmabuf,
 		       struct drm_backend *backend, bool is_opaque)
@@ -1168,17 +1183,23 @@
 		goto err_free;
 	}
 
-	for (i = 0; i < dmabuf->attributes.n_planes; i++) {
-		int ret;
-		ret = drmPrimeFDToHandle (fb->fd, dmabuf->attributes.fd[i], &gem_handle[i]);
-		if (ret) {
-			weston_log ("got gem_handle %x\n", gem_handle[i]);
-			goto err_free;
+	if (dmabuf->gem_handles[0] == 0) {
+		for (i = 0; i < dmabuf->attributes.n_planes; i++) {
+			int ret;
+			ret = drmPrimeFDToHandle (fb->fd, dmabuf->attributes.fd[i], &gem_handle[i]);
+			if (ret) {
+				weston_log ("got gem_handle %x\n", gem_handle[i]);
+				goto err_free;
+			}
+			fb->handles[i] = dmabuf->gem_handles[i] = gem_handle[i];
 		}
-		fb->handles[i] = gem_handle[i];
+		linux_dmabuf_buffer_gem_handle_close_cb (dmabuf, drm_close_gem_handle);
+	} else {
+		for (i = 0; i < dmabuf->attributes.n_planes; i++)
+			fb->handles[i] = dmabuf->gem_handles[i];
 	}
 
-	if (gem_handle[0] != 0)
+	if (fb->handles[0] != 0)
 		goto add_fb;
 
 	static_assert(ARRAY_LENGTH(import_mod.fds) ==
@@ -1232,13 +1253,6 @@
 add_fb:
 	ret = drm_fb_addfb(fb);
 
-	if (gem_handle[0] != 0) {
-		for (i = 0; i < dmabuf->attributes.n_planes; i++) {
-			struct drm_gem_close arg = { gem_handle[i], };
-			drmIoctl (fb->fd, DRM_IOCTL_GEM_CLOSE, &arg);
-		}
-	}
-
 	if (ret != 0)
 		goto err_free;
 
diff --git a/libweston/linux-dmabuf.c b/libweston/linux-dmabuf.c
index fefd6b1..947465c 100644
--- a/libweston/linux-dmabuf.c
+++ b/libweston/linux-dmabuf.c
@@ -141,6 +141,9 @@
 	assert(buffer->buffer_resource == resource);
 	assert(!buffer->params_resource);
 
+	if (buffer->gem_handle_close_func)
+		buffer->gem_handle_close_func(buffer);
+
 	if (buffer->user_data_destroy_func)
 		buffer->user_data_destroy_func(buffer);
 
@@ -441,6 +444,21 @@
 	return buffer;
 }
 
+/** Set drmbackend-private data
+ *
+ * set the drm gem handle close callback in the linux_dmabuf_buffer
+ *
+ * \param buffer The linux_dmabuf_buffer object to set for.
+ * \param func Destructor function to be called to close gem handle
+ *             when the linux_dmabuf_buffer gets destroyed.
+ */
+WL_EXPORT void
+linux_dmabuf_buffer_gem_handle_close_cb(struct linux_dmabuf_buffer *buffer,
+				  dmabuf_gem_handle_close_func func)
+{
+	buffer->gem_handle_close_func = func;
+}
+
 /** Set renderer-private data
  *
  * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
diff --git a/libweston/linux-dmabuf.h b/libweston/linux-dmabuf.h
index cbd83dc..5b1574b 100644
--- a/libweston/linux-dmabuf.h
+++ b/libweston/linux-dmabuf.h
@@ -39,6 +39,8 @@
 struct linux_dmabuf_buffer;
 typedef void (*dmabuf_user_data_destroy_func)(
 			struct linux_dmabuf_buffer *buffer);
+typedef void (*dmabuf_gem_handle_close_func)(
+			struct linux_dmabuf_buffer *buffer);
 
 struct dmabuf_attributes {
 	int32_t width;
@@ -76,6 +78,8 @@
 	 * feasible to scan it out directly. This would improve the
 	 * possibilities to successfully scan out, avoiding compositing.
 	 */
+	uint32_t gem_handles[MAX_DMABUF_PLANES];
+	dmabuf_gem_handle_close_func gem_handle_close_func;
 };
 
 int
@@ -85,6 +89,10 @@
 linux_dmabuf_buffer_get(struct wl_resource *resource);
 
 void
+linux_dmabuf_buffer_gem_handle_close_cb(struct linux_dmabuf_buffer *buffer,
+				  dmabuf_gem_handle_close_func func);
+
+void
 linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
 				  void *data,
 				  dmabuf_user_data_destroy_func func);