[PATCH v2] clients/simple-dmabuf-drm: import with dmabuf modifiers

Varad Gautam varadgautam at gmail.com
Wed Nov 23 08:33:21 UTC 2016


From: Varad Gautam <varad.gautam at collabora.com>

mesa's freedreno driver supports importing dmabufs with format
DRM_FORMAT_NV12 and DRM_FORMAT_MOD_SAMSUNG_64_32_TILE modifier.
demonstrate weston modifier advertising and import path using this
combination when run with --import-format=NV12.

v2:
 - hard code format if platform doesn't implement
   EGL_EXT_image_dma_buf_import_modifiers and cannot advertise
   format/modifier support.
 - squash using valid frame data to fill dmabuf planes

Signed-off-by: Varad Gautam <varad.gautam at collabora.com>
---
 Makefile.am                 |   4 +-
 clients/simple-dmabuf-drm.c | 185 +++++++++++++++++++++++++++++++++++---------
 configure.ac                |   2 +-
 3 files changed, 153 insertions(+), 38 deletions(-)

diff --git a/Makefile.am b/Makefile.am
index 3b58e29..7d4fad9 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -584,7 +584,9 @@ endif
 
 if BUILD_SIMPLE_DMABUF_DRM_CLIENT
 demo_clients += weston-simple-dmabuf-drm
-weston_simple_dmabuf_drm_SOURCES = clients/simple-dmabuf-drm.c
+weston_simple_dmabuf_drm_SOURCES =			\
+	clients/simple-dmabuf-drm.c			\
+	clients/simple-dmabuf-drm-data.h
 nodist_weston_simple_dmabuf_drm_SOURCES =		\
 	protocol/xdg-shell-unstable-v6-protocol.c		\
 	protocol/xdg-shell-unstable-v6-client-protocol.h	\
diff --git a/clients/simple-dmabuf-drm.c b/clients/simple-dmabuf-drm.c
index 7cf0208..4934af2 100644
--- a/clients/simple-dmabuf-drm.c
+++ b/clients/simple-dmabuf-drm.c
@@ -23,6 +23,7 @@
  */
 
 #include "config.h"
+#include "simple-dmabuf-drm-data.h"
 
 #include <stdint.h>
 #include <stdio.h>
@@ -47,10 +48,12 @@
 
 #include <wayland-client.h>
 #include "shared/zalloc.h"
+#include "shared/platform.h"
 #include "xdg-shell-unstable-v6-client-protocol.h"
 #include "fullscreen-shell-unstable-v1-client-protocol.h"
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
 
+extern const unsigned nv12_tiled[];
 struct buffer;
 
 struct display {
@@ -61,7 +64,10 @@ struct display {
 	struct zwp_fullscreen_shell_v1 *fshell;
 	struct zwp_linux_dmabuf_v1 *dmabuf;
 	int xrgb8888_format_found;
+	int nv12_format_found;
+	int nv12_modifier_found;
 	int req_dmabuf_immediate;
+	int req_dmabuf_modifiers;
 };
 
 struct drm_device {
@@ -98,6 +104,7 @@ struct buffer {
 	int height;
 	int bpp;
 	unsigned long stride;
+	int format;
 };
 
 #define NUM_BUFFERS 3
@@ -246,11 +253,19 @@ fill_content(struct buffer *my_buf)
 
 	assert(my_buf->mmap);
 
-	for (y = 0; y < my_buf->height; y++) {
-		pix = (uint32_t *)(my_buf->mmap + y * my_buf->stride);
-		for (x = 0; x < my_buf->width; x++) {
-			*pix++ = (0xff << 24) | ((x % 256) << 16) |
-			         ((y % 256) << 8) | 0xf0;
+	if (my_buf->format == DRM_FORMAT_NV12) {
+		pix = (uint32_t *) my_buf->mmap;
+		for (y = 0; y < my_buf->height; y++)
+			memcpy(&pix[y * my_buf->width / 4],
+			       &nv12_tiled[my_buf->width * y / 4],
+			       my_buf->width);
+	}
+	else {
+		for (y = 0; y < my_buf->height; y++) {
+			pix = (uint32_t *)(my_buf->mmap + y * my_buf->stride);
+			for (x = 0; x < my_buf->width; x++)
+				*pix++ = (0xff << 24) | ((x % 256) << 16) |
+					 ((y % 256) << 8) | 0xf0;
 		}
 	}
 }
@@ -382,10 +397,10 @@ static const struct zwp_linux_buffer_params_v1_listener params_listener = {
 
 static int
 create_dmabuf_buffer(struct display *display, struct buffer *buffer,
-		     int width, int height)
+		     int width, int height, int format)
 {
 	struct zwp_linux_buffer_params_v1 *params;
-	uint64_t modifier;
+	uint64_t modifier = 0;
 	uint32_t flags;
 	struct drm_device *drm_dev;
 
@@ -396,8 +411,18 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
 	drm_dev = buffer->dev;
 
 	buffer->width = width;
-	buffer->height = height;
-	buffer->bpp = 32; /* hardcoded XRGB8888 format */
+	switch (format) {
+	case DRM_FORMAT_NV12:
+		/* adjust height for allocation of NV12 Y and UV planes */
+		buffer->height = height * 3 / 2;
+		buffer->bpp = 8;
+		modifier = DRM_FORMAT_MOD_SAMSUNG_64_32_TILE;
+		break;
+	default:
+		buffer->height = height;
+		buffer->bpp = 32;
+	}
+	buffer->format = format;
 
 	if (!drm_dev->alloc_bo(buffer)) {
 		fprintf(stderr, "alloc_bo failed\n");
@@ -420,10 +445,13 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
 		goto error2;
 	}
 
-	/* We now have a dmabuf! It should contain 2x2 tiles (i.e. each tile
-	 * is 256x256) of misc colours, and be mappable, either as ARGB8888, or
-	 * XRGB8888. */
-	modifier = 0;
+	/* We now have a dmabuf! For format XRGB8888, it should contain 2x2
+	 * tiles (i.e. each tile is 256x256) of misc colours, and be mappable,
+	 * either as ARGB8888, or XRGB8888. For format NV12, it should contain
+	 * the Y and UV components, and needs to be re-adjusted for passing the
+	 * correct height to the compositor.
+	 */
+	buffer->height = height;
 	flags = 0;
 
 	params = zwp_linux_dmabuf_v1_create_params(display->dmabuf);
@@ -434,12 +462,23 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
 				       buffer->stride,
 				       modifier >> 32,
 				       modifier & 0xffffffff);
+
+	if (format == DRM_FORMAT_NV12) {
+		/* add the second plane params */
+		zwp_linux_buffer_params_v1_add(params,
+					       buffer->dmabuf_fd,
+					       1,
+					       buffer->width * buffer->height,
+					       buffer->stride,
+					       modifier >> 32,
+					       modifier & 0xffffffff);
+	}
 	zwp_linux_buffer_params_v1_add_listener(params, &params_listener, buffer);
 	if (display->req_dmabuf_immediate) {
 		buffer->buffer = zwp_linux_buffer_params_v1_create_immed(params,
 					  buffer->width,
 					  buffer->height,
-					  DRM_FORMAT_XRGB8888,
+					  format,
 					  flags);
 		wl_buffer_add_listener(buffer->buffer, &buffer_listener, buffer);
 	}
@@ -447,7 +486,7 @@ create_dmabuf_buffer(struct display *display, struct buffer *buffer,
 		zwp_linux_buffer_params_v1_create(params,
 					  buffer->width,
 					  buffer->height,
-					  DRM_FORMAT_XRGB8888,
+					  format,
 					  flags);
 
 	return 0;
@@ -496,7 +535,7 @@ static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
 };
 
 static struct window *
-create_window(struct display *display, int width, int height)
+create_window(struct display *display, int width, int height, int format)
 {
 	struct window *window;
 	int i;
@@ -545,7 +584,7 @@ create_window(struct display *display, int width, int height)
 
 	for (i = 0; i < NUM_BUFFERS; ++i) {
 		ret = create_dmabuf_buffer(display, &window->buffers[i],
-		                               width, height);
+		                               width, height, format);
 
 		if (ret < 0)
 			return NULL;
@@ -632,7 +671,11 @@ static void
 dmabuf_modifiers(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
 		 uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
 {
-	/* XXX: do something useful with modifiers */
+	struct display *d = data;
+	uint64_t modifier = ((uint64_t) modifier_hi << 32) | modifier_lo;
+
+	if (modifier == DRM_FORMAT_MOD_SAMSUNG_64_32_TILE)
+		d->nv12_modifier_found = 1;
 }
 
 static void
@@ -640,8 +683,15 @@ dmabuf_format(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf, uint32_t
 {
 	struct display *d = data;
 
-	if (format == DRM_FORMAT_XRGB8888)
+	switch (format) {
+	case DRM_FORMAT_XRGB8888:
 		d->xrgb8888_format_found = 1;
+		break;
+	case DRM_FORMAT_NV12:
+		d->nv12_format_found = 1;
+	default:
+		break;
+	}
 }
 
 static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
@@ -677,9 +727,16 @@ registry_handle_global(void *data, struct wl_registry *registry,
 		d->fshell = wl_registry_bind(registry,
 					     id, &zwp_fullscreen_shell_v1_interface, 1);
 	} else if (strcmp(interface, "zwp_linux_dmabuf_v1") == 0) {
+		int ver;
+		if (d->req_dmabuf_modifiers)
+			ver = 3;
+		else if (d->req_dmabuf_immediate)
+			ver = 2;
+		else
+			ver = 1;
 		d->dmabuf = wl_registry_bind(registry,
 					     id, &zwp_linux_dmabuf_v1_interface,
-					     d->req_dmabuf_immediate ? 2 : 1);
+					     ver);
 		zwp_linux_dmabuf_v1_add_listener(d->dmabuf, &dmabuf_listener, d);
 	}
 }
@@ -696,9 +753,10 @@ static const struct wl_registry_listener registry_listener = {
 };
 
 static struct display *
-create_display(int is_immediate)
+create_display(int is_immediate, int format)
 {
 	struct display *display;
+	const char *extensions;
 
 	display = malloc(sizeof *display);
 	if (display == NULL) {
@@ -708,9 +766,17 @@ create_display(int is_immediate)
 	display->display = wl_display_connect(NULL);
 	assert(display->display);
 
-	/* XXX: fake, because the compositor does not yet advertise anything */
-	display->xrgb8888_format_found = 1;
 	display->req_dmabuf_immediate = is_immediate;
+	display->req_dmabuf_modifiers = (format == DRM_FORMAT_NV12);
+
+	/*
+	 * hard code format if the platform egl doesn't support format
+	 * querying / advertising.
+	 */
+	extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+	if (extensions && !weston_check_egl_extension(extensions,
+				"EGL_EXT_image_dma_buf_import_modifiers"))
+		display->xrgb8888_format_found = 1;
 
 	display->registry = wl_display_get_registry(display->display);
 	wl_registry_add_listener(display->registry,
@@ -723,8 +789,10 @@ create_display(int is_immediate)
 
 	wl_display_roundtrip(display->display);
 
-	if (!display->xrgb8888_format_found) {
-		fprintf(stderr, "DRM_FORMAT_XRGB8888 not available\n");
+	if ((format == DRM_FORMAT_XRGB8888 && !display->xrgb8888_format_found) ||
+		(format == DRM_FORMAT_NV12 && (!display->nv12_format_found ||
+			!display->nv12_modifier_found))) {
+		fprintf(stderr, "requested format is not available\n");
 		exit(1);
 	}
 
@@ -758,6 +826,43 @@ signal_int(int signum)
 	running = 0;
 }
 
+static void
+print_usage_and_exit(void)
+{
+	printf("usage flags:\n"
+		"\t'--import-immediate=<>'\n\t\t0 to import dmabuf via roundtrip,"
+		"\n\t\t1 to enable import without roundtrip\n"
+		"\t'--import-format=<>'\n\t\tXRGB to import dmabuf as XRGB8888,"
+		"\n\t\tNV12 to import as multi plane NV12 with tiling modifier\n");
+	exit(0);
+}
+
+static int
+is_import_mode_immediate(const char* c)
+{
+	if (!strcmp(c, "1"))
+		return 1;
+	else if (!strcmp(c, "0"))
+		return 0;
+	else
+		print_usage_and_exit();
+
+	return 0;
+}
+
+static int
+parse_import_format(const char* c)
+{
+	if (!strcmp(c, "NV12"))
+		return DRM_FORMAT_NV12;
+	else if (!strcmp(c, "XRGB"))
+		return DRM_FORMAT_XRGB8888;
+	else
+		print_usage_and_exit();
+
+	return 0;
+}
+
 int
 main(int argc, char **argv)
 {
@@ -765,22 +870,30 @@ main(int argc, char **argv)
 	struct display *display;
 	struct window *window;
 	int is_immediate = 0;
-	int ret = 0;
+	int import_format = DRM_FORMAT_XRGB8888;
+	int ret = 0, i = 0;
 
 	if (argc > 1) {
-		if (!strcmp(argv[1], "immed")) {
-			is_immediate = 1;
-		}
-		else {
-			fprintf(stderr, "usage:\n\tsimple-dmabuf-intel [options]\n"
-				"available options:\n\timmed: avoid dmabuf "
-				"creation roundtrip and import immediately\n");
-			return 1;
+		static const char import_mode[] = "--import-immediate=";
+		static const char format[] = "--import-format=";
+		for (i = 1; i < argc; i++) {
+			if (!strncmp(argv[i], import_mode,
+				     sizeof(import_mode) - 1)) {
+				is_immediate = is_import_mode_immediate(argv[i]
+							+ sizeof(import_mode) - 1);
+			}
+			else if (!strncmp(argv[i], format, sizeof(format) - 1)) {
+				import_format = parse_import_format(argv[i]
+							+ sizeof(format) - 1);
+			}
+			else {
+				print_usage_and_exit();
+			}
 		}
 	}
 
-	display = create_display(is_immediate);
-	window = create_window(display, 250, 250);
+	display = create_display(is_immediate, import_format);
+	window = create_window(display, 256, 256, import_format);
 	if (!window)
 		return 1;
 
diff --git a/configure.ac b/configure.ac
index b959637..2916b42 100644
--- a/configure.ac
+++ b/configure.ac
@@ -392,7 +392,7 @@ AC_ARG_ENABLE(simple-dmabuf-drm-client,
                              [do not build the simple dmabuf drm client]),,
               enable_simple_dmabuf_drm_client="auto")
 if ! test "x$enable_simple_dmabuf_drm_client" = "xno"; then
-  PKG_CHECK_MODULES(SIMPLE_DMABUF_DRM_CLIENT, [wayland-client libdrm],
+  PKG_CHECK_MODULES(SIMPLE_DMABUF_DRM_CLIENT, [wayland-client libdrm egl],
     [PKG_CHECK_MODULES(LIBDRM_PLATFORM, [libdrm_freedreno],
       AC_DEFINE([HAVE_LIBDRM_FREEDRENO], [1], [Build freedreno dmabuf client]) have_simple_dmabuf_drm_client=freedreno,
     [PKG_CHECK_MODULES(LIBDRM_PLATFORM, [libdrm_intel],
-- 
2.6.2



More information about the wayland-devel mailing list