From 28024c992ea3c7cd2b85a6c5bde5bcb8e181cf49 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 23 Oct 2023 11:15:03 -0400 Subject: [PATCH] dmabuf: Add priorities to formats This will be used to influence the sorting of formats, so we can prefer 'native' formats over those that we can't import. Test included. --- gdk/gdkdmabufformats.c | 29 +++++++++++++ gdk/gdkdmabufformats.h | 4 ++ gdk/gdkdmabufformatsbuilder.c | 62 ++++++++++++++++------------ gdk/gdkdmabufformatsbuilderprivate.h | 2 + gdk/gdkdmabufformatsprivate.h | 1 + testsuite/gdk/dmabuftexture.c | 53 ++++++++++++++++++++++++ 6 files changed, 124 insertions(+), 27 deletions(-) diff --git a/gdk/gdkdmabufformats.c b/gdk/gdkdmabufformats.c index 744f141e80..7214451e6b 100644 --- a/gdk/gdkdmabufformats.c +++ b/gdk/gdkdmabufformats.c @@ -151,6 +151,35 @@ gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats, *modifier = format->modifier; } +/** + * gdk_dmabuf_formats_next_priority: + * @formats: a `GdkDmabufFormats` + * @idx: the index of the format to query +* + * Returns the index of the next-lower-priority format. + * + * The formats in a `GdkDmabufFormats` are sorted by decreasing + * priority. This function lets you identify formats with the + * same priority: all the formats between @idx and the return + * value of this function have the same priority. + * + * Returns: the index of the next lower priority format + * + * Since: 4.14 + */ +gsize +gdk_dmabuf_formats_next_priority (GdkDmabufFormats *formats, + gsize idx) +{ + GdkDmabufFormat *format; + + g_return_val_if_fail (idx < formats->n_formats, G_MAXSIZE); + + format = &formats->formats[idx]; + + return format->next_priority; +} + /** * gdk_dmabuf_format_contains: * @formats: a `GdkDmabufFormats` diff --git a/gdk/gdkdmabufformats.h b/gdk/gdkdmabufformats.h index 6ca612502e..c3bb5e037b 100644 --- a/gdk/gdkdmabufformats.h +++ b/gdk/gdkdmabufformats.h @@ -46,6 +46,10 @@ void gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats guint32 *fourcc, guint64 *modifier); +GDK_AVAILABLE_IN_4_14 +gsize gdk_dmabuf_formats_next_priority (GdkDmabufFormats *formats, + gsize idx); + GDK_AVAILABLE_IN_4_14 gboolean gdk_dmabuf_formats_contains (GdkDmabufFormats *formats, guint32 fourcc, diff --git a/gdk/gdkdmabufformatsbuilder.c b/gdk/gdkdmabufformatsbuilder.c index 6d29bf71e2..ccb6f2f7c7 100644 --- a/gdk/gdkdmabufformatsbuilder.c +++ b/gdk/gdkdmabufformatsbuilder.c @@ -52,7 +52,9 @@ gdk_dmabuf_format_compare (gconstpointer data_a, const GdkDmabufFormat *a = data_a; const GdkDmabufFormat *b = data_b; - if (a->fourcc == b->fourcc) + if (a->next_priority != b->next_priority) + return (a->next_priority < b->next_priority) ? -1 : 1; + else if (a->fourcc == b->fourcc) return (a->modifier - b->modifier) >> 8 * (sizeof (gint64) - sizeof (gint)); else return a->fourcc - b->fourcc; @@ -79,31 +81,13 @@ gdk_dmabuf_formats_builder_sort (GdkDmabufFormatsBuilder *self) gdk_dmabuf_format_compare); } -/* list must be sorted */ -static void -gdk_dmabuf_formats_builder_remove_duplicates (GdkDmabufFormatsBuilder *self) -{ - gsize i, j; - - for (i = 1, j = 0; i < gdk_dmabuf_formats_builder_get_size (self); i++) - { - if (gdk_dmabuf_format_equal (gdk_dmabuf_formats_builder_get (self, i), - gdk_dmabuf_formats_builder_get (self, j))) - continue; - - j++; - if (i != j) - *gdk_dmabuf_formats_builder_index (self, j) = *gdk_dmabuf_formats_builder_index (self, i); - } -} - GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self) { GdkDmabufFormats *formats; + gdk_dmabuf_formats_builder_next_priority (self); gdk_dmabuf_formats_builder_sort (self); - gdk_dmabuf_formats_builder_remove_duplicates (self); formats = gdk_dmabuf_formats_new (gdk_dmabuf_formats_builder_get_data (self), gdk_dmabuf_formats_builder_get_size (self)); @@ -118,17 +102,41 @@ gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self, guint32 fourcc, guint64 modifier) { - gdk_dmabuf_formats_builder_append (self, &(GdkDmabufFormat) { fourcc, modifier }); + GdkDmabufFormat format = { fourcc, modifier, G_MAXSIZE }; + + for (gsize i = 0; i < gdk_dmabuf_formats_builder_get_size (self); i++) + { + if (gdk_dmabuf_format_equal (gdk_dmabuf_formats_builder_get (self, i), &format)) + return; + } + + gdk_dmabuf_formats_builder_append (self, &format); +} + +void +gdk_dmabuf_formats_builder_next_priority (GdkDmabufFormatsBuilder *self) +{ + for (gsize i = gdk_dmabuf_formats_builder_get_size (self); i > 0; i--) + { + GdkDmabufFormat *format = gdk_dmabuf_formats_builder_get (self, i - 1); + + if (format->next_priority != G_MAXSIZE) + break; + + format->next_priority = gdk_dmabuf_formats_builder_get_size (self); + } } void gdk_dmabuf_formats_builder_add_formats (GdkDmabufFormatsBuilder *self, GdkDmabufFormats *formats) { - gdk_dmabuf_formats_builder_splice (self, - gdk_dmabuf_formats_builder_get_size (self), - 0, - FALSE, - gdk_dmabuf_formats_peek_formats (formats), - gdk_dmabuf_formats_get_n_formats (formats)); + for (gsize i = 0; i < gdk_dmabuf_formats_get_n_formats (formats); i++) + { + guint32 fourcc; + guint64 modifier; + + gdk_dmabuf_formats_get_format (formats, i, &fourcc, &modifier); + gdk_dmabuf_formats_builder_add_format (self, fourcc, modifier); + } } diff --git a/gdk/gdkdmabufformatsbuilderprivate.h b/gdk/gdkdmabufformatsbuilderprivate.h index e739f3f998..737fa3c6f5 100644 --- a/gdk/gdkdmabufformatsbuilderprivate.h +++ b/gdk/gdkdmabufformatsbuilderprivate.h @@ -10,5 +10,7 @@ GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats void gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self, guint32 fourcc, guint64 modifier); + +void gdk_dmabuf_formats_builder_next_priority (GdkDmabufFormatsBuilder *self); void gdk_dmabuf_formats_builder_add_formats (GdkDmabufFormatsBuilder *self, GdkDmabufFormats *formats); diff --git a/gdk/gdkdmabufformatsprivate.h b/gdk/gdkdmabufformatsprivate.h index 67c633dc1c..dde03e0abe 100644 --- a/gdk/gdkdmabufformatsprivate.h +++ b/gdk/gdkdmabufformatsprivate.h @@ -7,6 +7,7 @@ struct _GdkDmabufFormat { guint32 fourcc; guint64 modifier; + gsize next_priority; }; GdkDmabufFormats * gdk_dmabuf_formats_new (GdkDmabufFormat *formats, diff --git a/testsuite/gdk/dmabuftexture.c b/testsuite/gdk/dmabuftexture.c index d56fb29ef0..338ab57717 100644 --- a/testsuite/gdk/dmabuftexture.c +++ b/testsuite/gdk/dmabuftexture.c @@ -4,6 +4,8 @@ #include #include #include +#include +#include #ifdef HAVE_DMABUF #include @@ -34,6 +36,56 @@ test_dmabuf_formats (void) #endif } +#define AAAA fourcc_code ('A', 'A', 'A', 'A') +#define BBBB fourcc_code ('B', 'B', 'B', 'B') +#define CCCC fourcc_code ('C', 'C', 'C', 'C') +#define DDDD fourcc_code ('D', 'D', 'D', 'D') + +static gboolean +dmabuf_format_matches (const GdkDmabufFormat *f1, guint32 fourcc, guint64 modifier, gsize next_priority) +{ + return f1->fourcc == fourcc && + f1->modifier == modifier && + f1->next_priority == next_priority; +} + +/* Test that sorting respects priorities, and the highest priority instance + * of duplicates is kept. + */ +static void +test_priorities (void) +{ + GdkDmabufFormatsBuilder *builder; + GdkDmabufFormats *formats; + const GdkDmabufFormat *f; + + builder = gdk_dmabuf_formats_builder_new (); + + gdk_dmabuf_formats_builder_add_format (builder, AAAA, DRM_FORMAT_MOD_LINEAR); + gdk_dmabuf_formats_builder_add_format (builder, BBBB, DRM_FORMAT_MOD_LINEAR); + gdk_dmabuf_formats_builder_add_format (builder, AAAA, I915_FORMAT_MOD_X_TILED); + gdk_dmabuf_formats_builder_next_priority (builder); + gdk_dmabuf_formats_builder_add_format (builder, DDDD, I915_FORMAT_MOD_X_TILED); + gdk_dmabuf_formats_builder_add_format (builder, BBBB, I915_FORMAT_MOD_X_TILED); + gdk_dmabuf_formats_builder_add_format (builder, CCCC, DRM_FORMAT_MOD_LINEAR); + gdk_dmabuf_formats_builder_add_format (builder, BBBB, DRM_FORMAT_MOD_LINEAR); // a duplicate + + formats = gdk_dmabuf_formats_builder_free_to_formats (builder); + + g_assert_true (gdk_dmabuf_formats_get_n_formats (formats) == 6); + + f = gdk_dmabuf_formats_peek_formats (formats); + + g_assert_true (dmabuf_format_matches (&f[0], AAAA, DRM_FORMAT_MOD_LINEAR, 3)); + g_assert_true (dmabuf_format_matches (&f[1], AAAA, I915_FORMAT_MOD_X_TILED, 3)); + g_assert_true (dmabuf_format_matches (&f[2], BBBB, DRM_FORMAT_MOD_LINEAR, 3)); + g_assert_true (dmabuf_format_matches (&f[3], BBBB, I915_FORMAT_MOD_X_TILED, 6)); + g_assert_true (dmabuf_format_matches (&f[4], CCCC, DRM_FORMAT_MOD_LINEAR, 6)); + g_assert_true (dmabuf_format_matches (&f[5], DDDD, I915_FORMAT_MOD_X_TILED, 6)); + + gdk_dmabuf_formats_unref (formats); +} + static cairo_surface_t * make_surface (int width, int height) @@ -288,6 +340,7 @@ main (int argc, char *argv[]) gtk_test_init (&argc, &argv, NULL); g_test_add_func ("/dmabuf/formats", test_dmabuf_formats); + g_test_add_func ("/dmabuf/priorities", test_priorities); g_test_add_func ("/dmabuf/export", test_dmabuf_export); g_test_add_func ("/dmabuf/import", test_dmabuf_import);