[2/7] dmabuf: implement linux_dmabuf extension

Submitted by Louis-Francis Ratté-Boulianne on Dec. 12, 2014, 9:51 p.m.

Details

Message ID 1418421068-3854-3-git-send-email-lfrb@collabora.com
State RFC
Headers show

Not browsing as part of any series.

Commit Message

Louis-Francis Ratté-Boulianne Dec. 12, 2014, 9:51 p.m.
From: Pekka Paalanen <pekka.paalanen@collabora.co.uk>

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb@collabora.com>
---
 Makefile.am        |   2 +
 src/linux-dmabuf.c | 322 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/linux-dmabuf.h |  45 ++++++++
 3 files changed, 369 insertions(+)
 create mode 100644 src/linux-dmabuf.c
 create mode 100644 src/linux-dmabuf.h

Patch hide | download patch | download mbox

diff --git a/Makefile.am b/Makefile.am
index 0462fdd..16f5d13 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -72,6 +72,8 @@  weston_SOURCES =					\
 	src/timeline.c					\
 	src/timeline.h					\
 	src/timeline-object.h				\
+	src/linux-dmabuf.c				\
+	src/linux-dmabuf.h				\
 	shared/matrix.c					\
 	shared/matrix.h					\
 	shared/zalloc.h					\
diff --git a/src/linux-dmabuf.c b/src/linux-dmabuf.c
new file mode 100644
index 0000000..769bf60
--- /dev/null
+++ b/src/linux-dmabuf.c
@@ -0,0 +1,322 @@ 
+/*
+ * Copyright © 2014 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+
+#include "compositor.h"
+#include "linux-dmabuf.h"
+#include "linux-dmabuf-server-protocol.h"
+
+struct dmabuf_item {
+	int fd;
+	int n_planes;
+	int32_t offset[3];
+	int32_t stride[3];
+};
+
+struct dmabuf_batch {
+	struct wl_resource *resource;
+	int n_bufs;
+	struct wl_array bufs; /* struct dmabuf_item */
+};
+
+static void
+destroy_dmabuf_batch(struct wl_resource *dmabuf_batch_resource)
+{
+	struct dmabuf_batch *batch;
+	struct dmabuf_item *buf;
+
+	batch = wl_resource_get_user_data(dmabuf_batch_resource);
+
+	wl_array_for_each(buf, &batch->bufs)
+		close(buf->fd);
+	wl_array_release(&batch->bufs);
+
+	free(batch);
+}
+
+static void
+dmabuf_batch_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static void
+dmabuf_batch_add(struct wl_client *client,
+		 struct wl_resource *resource,
+		 int32_t name,
+		 int32_t offset0,
+		 int32_t stride0,
+		 int32_t offset1,
+		 int32_t stride1,
+		 int32_t offset2,
+		 int32_t stride2)
+{
+	struct dmabuf_batch *batch = wl_resource_get_user_data(resource);
+	struct dmabuf_item *buf;
+
+	buf = wl_array_add(&batch->bufs, sizeof *buf);
+	if (!buf) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	buf->fd = name;
+	buf->n_planes = 1;
+	buf->offset[0] = offset0;
+	buf->stride[0] = stride0;
+
+	if (offset1 && stride1) {
+		buf->offset[buf->n_planes] = offset1;
+		buf->stride[buf->n_planes] = stride1;
+		buf->n_planes++;
+	}
+
+	if (offset2 && stride2) {
+		buf->offset[buf->n_planes] = offset2;
+		buf->stride[buf->n_planes] = stride2;
+		buf->n_planes++;
+	}
+}
+
+static const struct dmabuf_batch_interface dmabuf_batch_implementation = {
+	dmabuf_batch_destroy,
+	dmabuf_batch_add
+};
+
+static void
+linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static void
+linux_dmabuf_create_batch(struct wl_client *client,
+			  struct wl_resource *linux_dmabuf_resource,
+			  uint32_t batch_id)
+{
+	struct dmabuf_batch *batch;
+	uint32_t version = wl_resource_get_version(linux_dmabuf_resource);
+
+	batch = zalloc(sizeof *batch);
+	if (!batch)
+		goto err_out;
+
+	batch->resource = wl_resource_create(client, &dmabuf_batch_interface,
+					     version, batch_id);
+	if (!batch->resource)
+		goto err_dealloc;
+
+	wl_resource_set_implementation(batch->resource,
+				       &dmabuf_batch_implementation,
+				       batch, destroy_dmabuf_batch);
+
+	batch->n_bufs = 0;
+	wl_array_init(&batch->bufs);
+
+	return;
+
+err_dealloc:
+	free(batch);
+
+err_out:
+	wl_resource_post_no_memory(linux_dmabuf_resource);
+}
+
+static void
+linux_dmabuf_buffer_close(struct linux_dmabuf_buffer *buffer)
+{
+	int i;
+	int last = -1;
+
+	for (i = MAX_DMABUF_PLANES - 1; i >= 0; i--) {
+		if (last != buffer->dmabuf_fd[i]) {
+			last = buffer->dmabuf_fd[i];
+			close(last);
+		}
+		buffer->dmabuf_fd[i] = -1;
+	}
+}
+
+static void
+destroy_linux_dmabuf_buffer(struct wl_resource *resource)
+{
+	struct linux_dmabuf_buffer *buffer;
+
+	buffer = wl_resource_get_user_data(resource);
+	linux_dmabuf_buffer_close(buffer);
+	free(buffer);
+}
+
+static void
+linux_dmabuf_buffer_destroy(struct wl_client *client,
+			    struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
+	linux_dmabuf_buffer_destroy
+};
+
+static int
+is_linux_dmabuf_supported(struct wl_resource *linux_dmabuf_resource,
+			  struct linux_dmabuf_buffer *buffer)
+{
+	/* XXX: todo */
+	/* XXX: verify from the renderer, that this is ok */
+	return 1;
+}
+
+static void
+linux_dmabuf_create_buffer(struct wl_client *client,
+			   struct wl_resource *linux_dmabuf_resource,
+			   struct wl_resource *batch_resource,
+			   int32_t width,
+			   int32_t height,
+			   uint32_t format,
+			   uint32_t feedback_id)
+{
+	struct dmabuf_batch *batch = wl_resource_get_user_data(batch_resource);
+	struct linux_dmabuf_buffer *buffer;
+	struct wl_resource *feedback;
+	struct dmabuf_item *it;
+	int plane;
+
+	buffer = zalloc(sizeof *buffer);
+	if (!buffer) {
+		wl_resource_post_no_memory(linux_dmabuf_resource);
+		return;
+	}
+
+	buffer->width = width;
+	buffer->height = height;
+	buffer->format = format;
+	feedback = wl_resource_create(client,
+				      &zlinux_dmabuf_create_feedback_interface,
+				      1, feedback_id);
+
+	plane = 0;
+	wl_array_for_each(it, &batch->bufs) {
+		int i;
+
+		for (i = 0; i < it->n_planes; i++) {
+			if (plane < MAX_DMABUF_PLANES) {
+				buffer->dmabuf_fd[plane] = it->fd;
+				buffer->offset[plane] = it->offset[i];
+				buffer->stride[plane] = it->stride[i];
+			}
+			plane++;
+		}
+
+		it->fd = -1;
+	}
+	buffer->n_planes = plane;
+
+	for (; plane < MAX_DMABUF_PLANES; plane++)
+		buffer->dmabuf_fd[plane] = -1;
+
+	if (buffer->n_planes >= MAX_DMABUF_PLANES) {
+		wl_resource_post_error(linux_dmabuf_resource,
+			ZLINUX_DMABUF_ERROR_FORMAT_DMABUFS_MISMATCH,
+			"too many dmabuf planes in total");
+		goto err_close;
+	}
+
+	if (!is_linux_dmabuf_supported(linux_dmabuf_resource, buffer))
+		goto err_close;
+
+	buffer->resource = wl_resource_create(client, &wl_buffer_interface,
+					      1, 0);
+	if (!buffer->resource) {
+		wl_resource_post_no_memory(linux_dmabuf_resource);
+		goto err_close;
+	}
+
+	wl_resource_set_implementation(buffer->resource,
+				       &linux_dmabuf_buffer_implementation,
+				       buffer, destroy_linux_dmabuf_buffer);
+
+	zlinux_dmabuf_create_feedback_send_create_successful(feedback,
+							     buffer->resource);
+	wl_resource_destroy(feedback);
+	return;
+
+err_close:
+	zlinux_dmabuf_create_feedback_send_create_failed(feedback);
+	wl_resource_destroy(feedback);
+	linux_dmabuf_buffer_close(buffer);
+	free(buffer);
+}
+
+WL_EXPORT struct linux_dmabuf_buffer *
+linux_dmabuf_buffer_get(struct wl_resource *resource)
+{
+	if (!resource)
+		return NULL;
+
+	if (wl_resource_instance_of(resource, &wl_buffer_interface,
+				    &linux_dmabuf_buffer_implementation))
+		return wl_resource_get_user_data(resource);
+	return NULL;
+}
+
+static const struct zlinux_dmabuf_interface linux_dmabuf_implementation = {
+	linux_dmabuf_destroy,
+	linux_dmabuf_create_batch,
+	linux_dmabuf_create_buffer
+};
+
+static void
+bind_linux_dmabuf(struct wl_client *client,
+		  void *data, uint32_t version, uint32_t id)
+{
+	struct weston_compositor *compositor = data;
+	struct wl_resource *resource;
+
+	resource = wl_resource_create(client, &zlinux_dmabuf_interface,
+				      MIN(version, 1), id);
+	if (resource == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
+				       compositor, NULL);
+
+	/* EGL_EXT_image_dma_buf_import does not provide a way to query the
+	 * supported pixel formats. */
+	/* XXX: send formats */
+}
+
+WL_EXPORT int
+linux_dmabuf_setup(struct weston_compositor *compositor)
+{
+	if (!wl_global_create(compositor->wl_display,
+			      &zlinux_dmabuf_interface, 1,
+			      compositor, bind_linux_dmabuf))
+		return -1;
+
+	return 0;
+}
diff --git a/src/linux-dmabuf.h b/src/linux-dmabuf.h
new file mode 100644
index 0000000..bc9cf63
--- /dev/null
+++ b/src/linux-dmabuf.h
@@ -0,0 +1,45 @@ 
+/*
+ * Copyright © 2014 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef WESTON_LINUX_DMABUF_H
+#define WESTON_LINUX_DMABUF_H
+
+#define MAX_DMABUF_PLANES 3
+
+struct linux_dmabuf_buffer {
+	struct wl_resource *resource;
+	int32_t width;
+	int32_t height;
+	uint32_t format;
+	int n_planes;
+	int dmabuf_fd[MAX_DMABUF_PLANES];
+	int offset[MAX_DMABUF_PLANES];
+	int stride[MAX_DMABUF_PLANES];
+};
+
+int
+linux_dmabuf_setup(struct weston_compositor *compositor);
+
+struct linux_dmabuf_buffer *
+linux_dmabuf_buffer_get(struct wl_resource *resource);
+
+#endif /* WESTON_LINUX_DMABUF_H */