From cbfd8542c6488c3f58d12ee9a4f5ada1fa6848ec Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 21 Oct 2023 16:34:46 +0200 Subject: [PATCH 1/4] dmabuf: Require valid fds for all planes This seems to be what everyone does, so we should do it, too. Previously it was assumed that an fd of -1 would mean reusing the previous fd with a different offset, but that seems to be uncommon. --- gdk/gdkdmabuftexturebuilder.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/gdk/gdkdmabuftexturebuilder.c b/gdk/gdkdmabuftexturebuilder.c index 98699d5bb7..25979287e6 100644 --- a/gdk/gdkdmabuftexturebuilder.c +++ b/gdk/gdkdmabuftexturebuilder.c @@ -964,6 +964,8 @@ gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self, gpointer data, GError **error) { + unsigned i; + g_return_val_if_fail (GDK_IS_DMABUF_TEXTURE_BUILDER (self), NULL); g_return_val_if_fail (destroy == NULL || data != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); @@ -971,8 +973,8 @@ gdk_dmabuf_texture_builder_build (GdkDmabufTextureBuilder *self, g_return_val_if_fail (self->height > 0, NULL); g_return_val_if_fail (self->dmabuf.fourcc != 0, NULL); - for (int i = 0; i < self->dmabuf.n_planes; i++) - g_return_val_if_fail (self->dmabuf.planes[i].fd != -1 || self->dmabuf.planes[i].offset != 0, NULL); + for (i = 0; i < self->dmabuf.n_planes; i++) + g_return_val_if_fail (self->dmabuf.planes[i].fd != -1, NULL); if (GDK_DEBUG_CHECK (DMABUF_DISABLE)) { From 2d9fbb16bcd0a443875b82853b9d11a47c48192e Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 21 Oct 2023 16:37:33 +0200 Subject: [PATCH 2/4] testdmabuf: Use the actual pixel The previous code would subsample the luma channel, too. Don't do that. --- tests/testdmabuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/testdmabuf.c b/tests/testdmabuf.c index 075906bcd5..d7596d75c3 100644 --- a/tests/testdmabuf.c +++ b/tests/testdmabuf.c @@ -145,7 +145,7 @@ y_u_v_create_buffer (uint32_t drm_format, * sub-sampling does not require proper * filtering/averaging/siting. */ - argb = *(rgb_row + x / 2 * 2); + argb = rgb_row[x]; /* * A stupid way of "sub-sampling" chroma. This does not @@ -213,7 +213,7 @@ nv12_create_buffer (uint32_t drm_format, * sub-sampling does not require proper * filtering/averaging/siting. */ - argb = *(rgb_row + x / 2 * 2); + argb = rgb_row[x]; /* * A stupid way of "sub-sampling" chroma. This does not From 7ab9056c1197e0768ac2ee59d207fd6ce955f2da Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 21 Oct 2023 16:39:53 +0200 Subject: [PATCH 3/4] testdmabuf: Fix NV12 The code was computing the wrong size. --- tests/testdmabuf.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/testdmabuf.c b/tests/testdmabuf.c index d7596d75c3..73b575ff6a 100644 --- a/tests/testdmabuf.c +++ b/tests/testdmabuf.c @@ -180,7 +180,7 @@ nv12_create_buffer (uint32_t drm_format, int x, y; uint32_t *rgb_row; uint8_t *y_base; - uint16_t *uv_base; + uint8_t *uv_base; uint8_t *y_row; uint16_t *uv_row; uint32_t argb; @@ -190,21 +190,22 @@ nv12_create_buffer (uint32_t drm_format, g_assert (drm_format == DRM_FORMAT_NV12); - /* Full size Y, quarter UV */ + /* Full size Y plane, half size UV plane */ bytes = rgb_width * rgb_height + - (rgb_width / 2) * (rgb_height / 2) * sizeof (uint16_t); + rgb_width * (rgb_height / 2); + *size = bytes; buf = g_new0 (guchar, bytes); *uv_offset = rgb_width * rgb_height; y_base = buf; - uv_base = (uint16_t *)(y_base + rgb_width * rgb_height); + uv_base = y_base + rgb_width * rgb_height; for (y = 0; y < rgb_height; y++) { rgb_row = (uint32_t *) (rgb_data + y * 4 * rgb_width); y_row = y_base + y * rgb_width; - uv_row = (uint16_t *) (uv_base + (y / 2) * (rgb_width / 2)); + uv_row = (uint16_t *) (uv_base + (y / 2) * rgb_width); for (x = 0; x < rgb_width; x++) { From 58a0e4ffaaf0ee281dbb5b316b72d41046da50fe Mon Sep 17 00:00:00 2001 From: Benjamin Otte Date: Sat, 21 Oct 2023 16:40:09 +0200 Subject: [PATCH 4/4] testdmabuf: Add --disjoint and --undecorated The code now by default puts all planes into the same fd - like v4l does, too. The old behavior of one fd per plane can be enabled via --disjoint. Also, am --undecorated option has been added so that the window isn't decorated and all that the renderer has to do is display the dmabuf. This is useful when debugging just the dmabuf rendering. --- tests/testdmabuf.c | 129 +++++++++++++++++++++++++++++---------------- 1 file changed, 84 insertions(+), 45 deletions(-) diff --git a/tests/testdmabuf.c b/tests/testdmabuf.c index 73b575ff6a..e2ab28e863 100644 --- a/tests/testdmabuf.c +++ b/tests/testdmabuf.c @@ -36,9 +36,9 @@ allocate_dma_buf (gsize size) } static void -populate_dma_buf (int fd, - guchar *data, - gsize size) +populate_dma_buf (int fd, + const guchar *data, + gsize size) { guchar *buf; @@ -235,9 +235,54 @@ nv12_create_buffer (uint32_t drm_format, return buf; } +static void +texture_builder_set_planes (GdkDmabufTextureBuilder *builder, + gboolean disjoint, + const guchar *buf, + unsigned size, + unsigned n_planes, + unsigned strides[4], + unsigned sizes[4]) +{ + gdk_dmabuf_texture_builder_set_n_planes (builder, n_planes); + + if (disjoint) + { + unsigned offset = 0; + unsigned i; + + for (i = 0; i < n_planes; i++) + { + int fd = allocate_dma_buf (sizes[i]); + populate_dma_buf (fd, buf + offset, sizes[i]); + + gdk_dmabuf_texture_builder_set_fd (builder, i, fd); + gdk_dmabuf_texture_builder_set_stride (builder, i, strides[i]); + gdk_dmabuf_texture_builder_set_offset (builder, i, 0); + offset += sizes[i]; + } + } + else + { + unsigned offset = 0; + unsigned i; + int fd = allocate_dma_buf (size); + populate_dma_buf (fd, buf, size); + + for (i = 0; i < n_planes; i++) + { + gdk_dmabuf_texture_builder_set_fd (builder, i, fd); + gdk_dmabuf_texture_builder_set_stride (builder, i, strides[i]); + gdk_dmabuf_texture_builder_set_offset (builder, i, offset); + offset += sizes[i]; + } + } +} + static GdkTexture * make_dmabuf_texture (const char *filename, - guint32 format) + guint32 format, + gboolean disjoint) { GdkTexture *texture; int width, height; @@ -284,30 +329,15 @@ make_dmabuf_texture (const char *filename, guchar *buf; int size, u_offset, v_offset; - gdk_dmabuf_texture_builder_set_n_planes (builder, 3); - buf = y_u_v_create_buffer (format, rgb_data, width, height, &size, &u_offset, &v_offset); - fd = allocate_dma_buf (width * height); - populate_dma_buf (fd, buf, width * height); - - gdk_dmabuf_texture_builder_set_fd (builder, 0, fd); - gdk_dmabuf_texture_builder_set_stride (builder, 0, width); - gdk_dmabuf_texture_builder_set_offset (builder, 0, 0); - - fd = allocate_dma_buf ((width / 2) * (height / 2)); - populate_dma_buf (fd, buf + u_offset, (width / 2) * (height / 2)); - - gdk_dmabuf_texture_builder_set_fd (builder, 1, fd); - gdk_dmabuf_texture_builder_set_stride (builder, 1, width / 2); - gdk_dmabuf_texture_builder_set_offset (builder, 1, 0); - - fd = allocate_dma_buf ((width / 2) * (height / 2)); - populate_dma_buf (fd, buf + v_offset, (width / 2) * (height / 2)); - - gdk_dmabuf_texture_builder_set_fd (builder, 2, fd); - gdk_dmabuf_texture_builder_set_stride (builder, 2, width / 2); - gdk_dmabuf_texture_builder_set_offset (builder, 2, 0); + texture_builder_set_planes (builder, + disjoint, + buf, + size, + 3, + (unsigned[4]) { width, width / 2, width / 2 }, + (unsigned[4]) { width * height, width * height / 4, width * height / 4 }); g_free (buf); } @@ -316,23 +346,15 @@ make_dmabuf_texture (const char *filename, guchar *buf; int size, uv_offset; - gdk_dmabuf_texture_builder_set_n_planes (builder, 2); - buf = nv12_create_buffer (format, rgb_data, width, height, &size, &uv_offset); - fd = allocate_dma_buf (width * height); - populate_dma_buf (fd, buf, width * height); - - gdk_dmabuf_texture_builder_set_fd (builder, 0, fd); - gdk_dmabuf_texture_builder_set_stride (builder, 0, width); - gdk_dmabuf_texture_builder_set_offset (builder, 0, 0); - - fd = allocate_dma_buf ((width / 2) * (height / 2) * sizeof (uint16_t)); - populate_dma_buf (fd, buf + uv_offset, (width / 2) * (height / 2) * sizeof (uint16_t)); - - gdk_dmabuf_texture_builder_set_fd (builder, 1, fd); - gdk_dmabuf_texture_builder_set_stride (builder, 1, width); - gdk_dmabuf_texture_builder_set_offset (builder, 1, 0); + texture_builder_set_planes (builder, + disjoint, + buf, + size, + 2, + (unsigned[4]) { width, width, }, + (unsigned[4]) { width * height, width * height / 2 }); g_free (buf); } @@ -388,7 +410,7 @@ static void usage (void) { char *formats = supported_formats_to_string (); - g_print ("Usage: testdmabuf FORMAT FILE\n" + g_print ("Usage: testdmabuf [--bare] [--disjoint] FORMAT FILE\n" "Supported formats: %s\n", formats); g_free (formats); exit (1); @@ -415,9 +437,25 @@ main (int argc, char *argv[]) GtkWidget *window, *picture; char *filename; guint32 format; + gboolean disjoint = FALSE; + gboolean decorated = TRUE; + unsigned i; - if (argc != 3) - usage (); + for (i = 1; i < argc; i++) + { + if (g_str_equal (argv[i], "--disjoint")) + disjoint = TRUE; + if (g_str_equal (argv[i], "--undecorated")) + decorated = FALSE; + else + break; + } + + if (argc - i != 2) + { + usage (); + return 1; + } format = parse_format (argv[1]); filename = argv[2]; @@ -427,11 +465,12 @@ main (int argc, char *argv[]) /* Get the list of supported formats with GDK_DEBUG=opengl */ gdk_display_get_dmabuf_formats (gdk_display_get_default ()); - texture = make_dmabuf_texture (filename, format); + texture = make_dmabuf_texture (filename, format, disjoint); gdk_texture_save_to_png (texture, "testdmabuf.out.png"); window = gtk_window_new (); + gtk_window_set_decorated (GTK_WINDOW (window), decorated); picture = gtk_picture_new_for_paintable (GDK_PAINTABLE (texture));