From 8182fb57046a06ef6a51d42d70fdf93a0bd0fa0a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 6 Jan 2024 21:37:46 -0500 Subject: [PATCH 1/9] dmabuf: Move a declaration We will need to access this struct from the Wayland backend. --- gdk/gdkdmabufformats.c | 8 -------- gdk/gdkdmabufformatsprivate.h | 8 ++++++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/gdk/gdkdmabufformats.c b/gdk/gdkdmabufformats.c index 3e45e22ff97..3c22b6c9b2b 100644 --- a/gdk/gdkdmabufformats.c +++ b/gdk/gdkdmabufformats.c @@ -49,14 +49,6 @@ * Since: 4.14 */ -struct _GdkDmabufFormats -{ - int ref_count; - - gsize n_formats; - GdkDmabufFormat *formats; -}; - G_DEFINE_BOXED_TYPE (GdkDmabufFormats, gdk_dmabuf_formats, gdk_dmabuf_formats_ref, gdk_dmabuf_formats_unref) /** diff --git a/gdk/gdkdmabufformatsprivate.h b/gdk/gdkdmabufformatsprivate.h index 67c633dc1c4..05525b05e5d 100644 --- a/gdk/gdkdmabufformatsprivate.h +++ b/gdk/gdkdmabufformatsprivate.h @@ -9,6 +9,14 @@ struct _GdkDmabufFormat guint64 modifier; }; +struct _GdkDmabufFormats +{ + int ref_count; + + gsize n_formats; + GdkDmabufFormat *formats; +}; + GdkDmabufFormats * gdk_dmabuf_formats_new (GdkDmabufFormat *formats, gsize n_formats); -- GitLab From 4a8ecd4114cb1b9cc452a5cdf474609844d17559 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 23 Oct 2023 11:15:03 -0400 Subject: [PATCH 2/9] 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 | 34 ++++++++++++++- gdk/gdkdmabufformats.h | 4 ++ gdk/gdkdmabufformatsbuilder.c | 62 ++++++++++++++++------------ gdk/gdkdmabufformatsbuilderprivate.h | 2 + gdk/gdkdmabufformatsprivate.h | 1 + testsuite/gdk/dmabufformats.c | 53 ++++++++++++++++++++++++ 6 files changed, 127 insertions(+), 29 deletions(-) diff --git a/gdk/gdkdmabufformats.c b/gdk/gdkdmabufformats.c index 3c22b6c9b2b..4c6fac23913 100644 --- a/gdk/gdkdmabufformats.c +++ b/gdk/gdkdmabufformats.c @@ -144,7 +144,36 @@ gdk_dmabuf_formats_get_format (GdkDmabufFormats *formats, } /** - * gdk_dmabuf_formats_contains: + * 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.16 + */ +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` * @fourcc: a format code * @modifier: a format modifier @@ -241,7 +270,8 @@ gdk_dmabuf_formats_equal (const GdkDmabufFormats *formats1, GdkDmabufFormat *f2 = &formats2->formats[i]; if (f1->fourcc != f2->fourcc || - f1->modifier != f2->modifier) + f1->modifier != f2->modifier || + f1->next_priority != f2->next_priority) return FALSE; } diff --git a/gdk/gdkdmabufformats.h b/gdk/gdkdmabufformats.h index 0fef96ae83e..e214e423a4d 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_16 +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 6d29bf71e2c..ccb6f2f7c70 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 e739f3f998a..737fa3c6f56 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 05525b05e5d..7ea52371af9 100644 --- a/gdk/gdkdmabufformatsprivate.h +++ b/gdk/gdkdmabufformatsprivate.h @@ -7,6 +7,7 @@ struct _GdkDmabufFormat { guint32 fourcc; guint64 modifier; + gsize next_priority; }; struct _GdkDmabufFormats diff --git a/testsuite/gdk/dmabufformats.c b/testsuite/gdk/dmabufformats.c index e2d69bdd865..c1281c6a16a 100644 --- a/testsuite/gdk/dmabufformats.c +++ b/testsuite/gdk/dmabufformats.c @@ -5,6 +5,8 @@ #include #include #include +#include +#include static void test_dmabuf_formats_basic (void) @@ -82,6 +84,56 @@ test_dmabuf_formats_builder (void) gdk_dmabuf_formats_unref (formats1); } +#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); +} + int main (int argc, char *argv[]) { @@ -89,6 +141,7 @@ main (int argc, char *argv[]) g_test_add_func ("/dmabuf/formats/basic", test_dmabuf_formats_basic); g_test_add_func ("/dmabuf/formats/builder", test_dmabuf_formats_builder); + g_test_add_func ("/dmabuf/formats/priorities", test_priorities); return g_test_run (); } -- GitLab From 1217cc91d7bb48130edce060d559704878192aed Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 25 Dec 2023 10:53:11 -0500 Subject: [PATCH 3/9] dmabuf: Redo format collection Arrange for the following tranches to be collected With GL: - Regular EGL formats - Mmap formats (that aren't included already And with GLES: - Regular EGL formats - External EGL formats - Mmap formats (that aren't included already Also, move the debug spew for formats from the downloaders to the display, so we can print them properly sorted, and in their tranches. The only thing we don't have anymore here is the downloader name. --- gdk/gdkdisplay.c | 24 ++++++++++++++++++++++++ gdk/gdkdmabuf.c | 4 ---- gdk/gdkdmabufegl.c | 33 +++++++++++++++++---------------- 3 files changed, 41 insertions(+), 20 deletions(-) diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c index 75b0535a6af..0a0f2ca1c02 100644 --- a/gdk/gdkdisplay.c +++ b/gdk/gdkdisplay.c @@ -2004,6 +2004,7 @@ gdk_display_init_dmabuf (GdkDisplay *self) #ifdef HAVE_EGL gdk_display_add_dmabuf_downloader (self, gdk_dmabuf_get_egl_downloader (self, builder)); + gdk_dmabuf_formats_builder_next_priority (builder); #endif gdk_dmabuf_formats_builder_add_formats (builder, @@ -2016,6 +2017,29 @@ gdk_display_init_dmabuf (GdkDisplay *self) GDK_DISPLAY_DEBUG (self, DMABUF, "Initialized support for %zu dmabuf formats", gdk_dmabuf_formats_get_n_formats (self->dmabuf_formats)); + +#ifdef G_ENABLE_DEBUG + if (GDK_DISPLAY_DEBUG_CHECK (self, DMABUF)) + { + for (gsize i = 0; i < gdk_dmabuf_formats_get_n_formats (self->dmabuf_formats); i++) + { + guint32 fourcc; + guint64 modifier; + + gdk_dmabuf_formats_get_format (self->dmabuf_formats, i, &fourcc, &modifier); + + gdk_debug_message (" %.4s:%#" G_GINT64_MODIFIER "x%s", + (char *) &fourcc, + modifier, + gdk_dmabuf_formats_contains (self->egl_external_formats, fourcc, modifier) ? " (external)" : ""); + + if (i + 1 < gdk_dmabuf_formats_get_n_formats (self->dmabuf_formats) && + gdk_dmabuf_formats_next_priority (self->dmabuf_formats, i) == i + 1) + gdk_debug_message ("------"); + + } + } +#endif } /** diff --git a/gdk/gdkdmabuf.c b/gdk/gdkdmabuf.c index 66979344163..9f0c8bd65c4 100644 --- a/gdk/gdkdmabuf.c +++ b/gdk/gdkdmabuf.c @@ -1965,10 +1965,6 @@ gdk_dmabuf_get_mmap_formats (void) if (!supported_formats[i].download) continue; - GDK_DEBUG (DMABUF, - "mmap dmabuf format %.4s:%#0" G_GINT64_MODIFIER "x", - (char *) &supported_formats[i].fourcc, (guint64) DRM_FORMAT_MOD_LINEAR); - gdk_dmabuf_formats_builder_add_format (builder, supported_formats[i].fourcc, DRM_FORMAT_MOD_LINEAR); diff --git a/gdk/gdkdmabufegl.c b/gdk/gdkdmabufegl.c index 96b17018f51..ea3ccd784f1 100644 --- a/gdk/gdkdmabufegl.c +++ b/gdk/gdkdmabufegl.c @@ -93,24 +93,17 @@ gdk_dmabuf_egl_downloader_collect_formats (GdkDisplay *display, for (int j = 0; j < num_modifiers; j++) { - /* All linear formats we support are already added my the mmap downloader. - * We don't add external formats, unless we can use them (via GLES) - */ - if (modifiers[j] != DRM_FORMAT_MOD_LINEAR && - (!external_only[j] || gdk_gl_context_get_use_es (context))) + if (!external_only[j]) { - GDK_DISPLAY_DEBUG (display, DMABUF, - "%s EGL dmabuf format %.4s:%#" G_GINT64_MODIFIER "x", - external_only[j] ? "external " : "", - (char *) &fourccs[i], - modifiers[j]); - gdk_dmabuf_formats_builder_add_format (formats, fourccs[i], modifiers[j]); + all_external = FALSE; } - if (external_only[j]) - gdk_dmabuf_formats_builder_add_format (external, fourccs[i], modifiers[j]); else - all_external = FALSE; + { + if (gdk_gl_context_get_use_es (context)) + gdk_dmabuf_formats_builder_add_format (external, fourccs[i], modifiers[j]); + + } } /* Accept implicit modifiers as long as we accept the format at all. @@ -120,9 +113,9 @@ gdk_dmabuf_egl_downloader_collect_formats (GdkDisplay *display, * As an extra wrinkle, treat the implicit modifier as 'external only' * if all formats with the same fourcc are 'external only'. */ - if (!all_external || gdk_gl_context_get_use_es (context)) + if (!all_external) gdk_dmabuf_formats_builder_add_format (formats, fourccs[i], DRM_FORMAT_MOD_INVALID); - if (all_external) + else if (gdk_gl_context_get_use_es (context)) gdk_dmabuf_formats_builder_add_format (external, fourccs[i], DRM_FORMAT_MOD_INVALID); } @@ -149,6 +142,7 @@ GdkDmabufDownloader * gdk_dmabuf_get_egl_downloader (GdkDisplay *display, GdkDmabufFormatsBuilder *builder) { + GdkGLContext *context; GdkDmabufFormatsBuilder *formats; GdkDmabufFormatsBuilder *external; gboolean retval = FALSE; @@ -163,6 +157,8 @@ gdk_dmabuf_get_egl_downloader (GdkDisplay *display, return NULL; previous = gdk_gl_context_get_current (); + context = gdk_display_get_gl_context (display); + formats = gdk_dmabuf_formats_builder_new (); external = gdk_dmabuf_formats_builder_new (); @@ -172,6 +168,11 @@ gdk_dmabuf_get_egl_downloader (GdkDisplay *display, display->egl_external_formats = gdk_dmabuf_formats_builder_free_to_formats (external); gdk_dmabuf_formats_builder_add_formats (builder, display->egl_dmabuf_formats); + if (gdk_gl_context_get_use_es (context)) + { + gdk_dmabuf_formats_builder_next_priority (builder); + gdk_dmabuf_formats_builder_add_formats (builder, display->egl_external_formats); + } if (!retval) { -- GitLab From 3674497163d2e639dba9c5bedf9bf2e66cc93fb8 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 7 Feb 2024 10:19:02 +0000 Subject: [PATCH 4/9] dmabuf: Add Wayland information Add device and scanout information for dmabuf formats. While this is not a great API, there is no good alternative to making this information available to applications that want to negotiate dmabuf formats suitable for graphics offload. The getters for Wayland-specific information are kept as Wayland backend apis. Tests included. --- gdk/gdkdmabufformats.c | 13 ++++- gdk/gdkdmabufformatsbuilder.c | 34 +++++++++--- gdk/gdkdmabufformatsbuilderprivate.h | 24 ++++++--- gdk/gdkdmabufformatsprivate.h | 6 ++- gdk/wayland/gdkdmabuf-wayland.c | 76 +++++++++++++++++++++++++++ gdk/wayland/gdkwayland.h | 1 + gdk/wayland/gdkwaylanddmabufformats.h | 40 ++++++++++++++ gdk/wayland/meson.build | 1 + testsuite/gdk/dmabufformats.c | 51 ++++++++++++++++++ 9 files changed, 228 insertions(+), 18 deletions(-) create mode 100644 gdk/wayland/gdkwaylanddmabufformats.h diff --git a/gdk/gdkdmabufformats.c b/gdk/gdkdmabufformats.c index 4c6fac23913..bdfd41b2b09 100644 --- a/gdk/gdkdmabufformats.c +++ b/gdk/gdkdmabufformats.c @@ -205,6 +205,8 @@ gdk_dmabuf_formats_contains (GdkDmabufFormats *formats, * gdk_dmabuf_formats_new: * @formats: the formats * @n_formats: the length of @formats + * @device: the DRM device that the compositor uses, or + * 0 if this object doesn't describe compositor formats * * Creates a new `GdkDmabufFormats struct for * the given formats. @@ -218,7 +220,8 @@ gdk_dmabuf_formats_contains (GdkDmabufFormats *formats, */ GdkDmabufFormats * gdk_dmabuf_formats_new (GdkDmabufFormat *formats, - gsize n_formats) + gsize n_formats, + guint64 device) { GdkDmabufFormats *self; @@ -227,6 +230,7 @@ gdk_dmabuf_formats_new (GdkDmabufFormat *formats, self->ref_count = 1; self->n_formats = n_formats; self->formats = g_new (GdkDmabufFormat, n_formats); + self->device = device; memcpy (self->formats, formats, n_formats * sizeof (GdkDmabufFormat)); @@ -261,6 +265,9 @@ gdk_dmabuf_formats_equal (const GdkDmabufFormats *formats1, if (formats1 == NULL || formats2 == NULL) return FALSE; + if (formats1->device != formats2->device) + return FALSE; + if (formats1->n_formats != formats2->n_formats) return FALSE; @@ -271,7 +278,9 @@ gdk_dmabuf_formats_equal (const GdkDmabufFormats *formats1, if (f1->fourcc != f2->fourcc || f1->modifier != f2->modifier || - f1->next_priority != f2->next_priority) + f1->next_priority != f2->next_priority || + f1->flags != f2->flags || + f1->device != f2->device) return FALSE; } diff --git a/gdk/gdkdmabufformatsbuilder.c b/gdk/gdkdmabufformatsbuilder.c index ccb6f2f7c70..109ed5532f8 100644 --- a/gdk/gdkdmabufformatsbuilder.c +++ b/gdk/gdkdmabufformatsbuilder.c @@ -69,7 +69,9 @@ gdk_dmabuf_format_equal (gconstpointer data_a, const GdkDmabufFormat *b = data_b; return a->fourcc == b->fourcc && - a->modifier == b->modifier; + a->flags == b->flags && + a->modifier == b->modifier && + a->device == b->device; } static void @@ -82,7 +84,8 @@ gdk_dmabuf_formats_builder_sort (GdkDmabufFormatsBuilder *self) } GdkDmabufFormats * -gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self) +gdk_dmabuf_formats_builder_free_to_formats_for_device (GdkDmabufFormatsBuilder *self, + guint64 device) { GdkDmabufFormats *formats; @@ -90,19 +93,28 @@ gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self) gdk_dmabuf_formats_builder_sort (self); formats = gdk_dmabuf_formats_new (gdk_dmabuf_formats_builder_get_data (self), - gdk_dmabuf_formats_builder_get_size (self)); + gdk_dmabuf_formats_builder_get_size (self), + device); gdk_dmabuf_formats_builder_clear (self); g_free (self); return formats; } +GdkDmabufFormats * +gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self) +{ + return gdk_dmabuf_formats_builder_free_to_formats_for_device (self, 0); +} + void -gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self, - guint32 fourcc, - guint64 modifier) +gdk_dmabuf_formats_builder_add_format_for_device (GdkDmabufFormatsBuilder *self, + guint32 fourcc, + guint32 flags, + guint64 modifier, + guint64 device) { - GdkDmabufFormat format = { fourcc, modifier, G_MAXSIZE }; + GdkDmabufFormat format = { fourcc, flags, modifier, device, G_MAXSIZE }; for (gsize i = 0; i < gdk_dmabuf_formats_builder_get_size (self); i++) { @@ -113,6 +125,14 @@ gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self, gdk_dmabuf_formats_builder_append (self, &format); } +void +gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self, + guint32 fourcc, + guint64 modifier) +{ + gdk_dmabuf_formats_builder_add_format_for_device (self, fourcc, 0, modifier, 0); +} + void gdk_dmabuf_formats_builder_next_priority (GdkDmabufFormatsBuilder *self) { diff --git a/gdk/gdkdmabufformatsbuilderprivate.h b/gdk/gdkdmabufformatsbuilderprivate.h index 737fa3c6f56..027000a89d9 100644 --- a/gdk/gdkdmabufformatsbuilderprivate.h +++ b/gdk/gdkdmabufformatsbuilderprivate.h @@ -4,13 +4,21 @@ typedef struct GdkDmabufFormatsBuilder GdkDmabufFormatsBuilder; -GdkDmabufFormatsBuilder * gdk_dmabuf_formats_builder_new (void); -GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self); +GdkDmabufFormatsBuilder *gdk_dmabuf_formats_builder_new (void); +GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats (GdkDmabufFormatsBuilder *self); -void gdk_dmabuf_formats_builder_add_format (GdkDmabufFormatsBuilder *self, - guint32 fourcc, - guint64 modifier); +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); +GdkDmabufFormats * gdk_dmabuf_formats_builder_free_to_formats_for_device (GdkDmabufFormatsBuilder *self, + guint64 device); +void gdk_dmabuf_formats_builder_add_format_for_device (GdkDmabufFormatsBuilder *self, + guint32 fourcc, + guint32 flags, + guint64 modifier, + guint64 device); + +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 7ea52371af9..b9804861774 100644 --- a/gdk/gdkdmabufformatsprivate.h +++ b/gdk/gdkdmabufformatsprivate.h @@ -6,7 +6,9 @@ typedef struct _GdkDmabufFormat GdkDmabufFormat; struct _GdkDmabufFormat { guint32 fourcc; + guint32 flags; guint64 modifier; + guint64 device; gsize next_priority; }; @@ -16,9 +18,11 @@ struct _GdkDmabufFormats gsize n_formats; GdkDmabufFormat *formats; + guint64 device; }; GdkDmabufFormats * gdk_dmabuf_formats_new (GdkDmabufFormat *formats, - gsize n_formats); + gsize n_formats, + guint64 device); const GdkDmabufFormat * gdk_dmabuf_formats_peek_formats (GdkDmabufFormats *self); diff --git a/gdk/wayland/gdkdmabuf-wayland.c b/gdk/wayland/gdkdmabuf-wayland.c index 2b9020153b3..bca115a559e 100644 --- a/gdk/wayland/gdkdmabuf-wayland.c +++ b/gdk/wayland/gdkdmabuf-wayland.c @@ -1,6 +1,7 @@ #include "config.h" #include "gdkdmabuf-wayland-private.h" +#include "gdkwaylanddmabufformats.h" #include "gdkdebugprivate.h" #include "gdkdmabufformatsprivate.h" @@ -239,3 +240,78 @@ dmabuf_formats_info_free (DmabufFormatsInfo *info) g_free (info); } + +/** + * gdk_wayland_dmabuf_formats_get_main_device: + * @formats: a `GdkDmabufFormats` + * + * Returns the DRM device that the compositor uses for compositing. + * + * If this information isn't available (e.g. because @formats wasn't + * obtained from the compositor), then 0 is returned. + * + * Returns: the main DRM device that the compositor prefers + * + * Since: 4.16 + */ +dev_t +gdk_wayland_dmabuf_formats_get_main_device (GdkDmabufFormats *formats) +{ + return formats->device; +} + +/** + * gdk_wayland_dmabuf_formats_get_target_device: + * @formats: a `GdkDmabufFormats` + * @idx: the index of the format to return + * + * Returns the target DRM device that should be used for creating buffers + * with this format. + * + * If this information isn't available (e.g. because @formats wasn't + * obtained from the compositor), then 0 is returned. + * + * Returns: the target DRM device for this format + * + * Since: 4.16 + */ +dev_t +gdk_wayland_dmabuf_formats_get_target_device (GdkDmabufFormats *formats, + gsize idx) +{ + GdkDmabufFormat *format; + + g_return_val_if_fail (idx < formats->n_formats, 0); + + format = &formats->formats[idx]; + + return format->device; +} + +/** + * gdk_wayland_dmabuf_formats_is_scanout: + * @formats: a `GdkDmabufFormats` + * @idx: the index of the format to return + * + * Returns whether the compositor may use buffers with this + * format for scanout. + * + * If this information isn't available (e.g. because @formats wasn't + * obtained from the compositor), then `FALSE` is returned. + * + * Returns: whether the format will be used for scanout + * + * Since: 4.16 + */ +gboolean +gdk_wayland_dmabuf_formats_is_scanout (GdkDmabufFormats *formats, + gsize idx) +{ + GdkDmabufFormat *format; + + g_return_val_if_fail (idx < formats->n_formats, FALSE); + + format = &formats->formats[idx]; + + return (format->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT) != 0; +} diff --git a/gdk/wayland/gdkwayland.h b/gdk/wayland/gdkwayland.h index 846445910e4..f366783f618 100644 --- a/gdk/wayland/gdkwayland.h +++ b/gdk/wayland/gdkwayland.h @@ -30,6 +30,7 @@ #include #include +#include #include #include #include diff --git a/gdk/wayland/gdkwaylanddmabufformats.h b/gdk/wayland/gdkwaylanddmabufformats.h new file mode 100644 index 00000000000..624acedbb05 --- /dev/null +++ b/gdk/wayland/gdkwaylanddmabufformats.h @@ -0,0 +1,40 @@ +/* gdkwaylanddmabufformats.h + * + * Copyright 2023 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see . + */ + +#pragma once + +#if !defined (__GDKWAYLAND_H_INSIDE__) && !defined (GTK_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +GDK_AVAILABLE_IN_4_16 +dev_t gdk_wayland_dmabuf_formats_get_main_device (GdkDmabufFormats *formats); + +GDK_AVAILABLE_IN_4_16 +dev_t gdk_wayland_dmabuf_formats_get_target_device (GdkDmabufFormats *formats, + gsize idx); + +GDK_AVAILABLE_IN_4_16 +gboolean gdk_wayland_dmabuf_formats_is_scanout (GdkDmabufFormats *formats, + gsize idx); + +G_END_DECLS diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build index fab877f3a85..7a60950c213 100644 --- a/gdk/wayland/meson.build +++ b/gdk/wayland/meson.build @@ -30,6 +30,7 @@ gdk_wayland_sources = files([ gdk_wayland_public_headers = files([ 'gdkwaylanddevice.h', 'gdkwaylanddisplay.h', + 'gdkwaylanddmabufformats.h', 'gdkwaylandglcontext.h', 'gdkwaylandmonitor.h', 'gdkwaylandpopup.h', diff --git a/testsuite/gdk/dmabufformats.c b/testsuite/gdk/dmabufformats.c index c1281c6a16a..7cfeff057f1 100644 --- a/testsuite/gdk/dmabufformats.c +++ b/testsuite/gdk/dmabufformats.c @@ -8,6 +8,10 @@ #include #include +#ifdef GDK_WINDOWING_WAYLAND +#include +#endif + static void test_dmabuf_formats_basic (void) { @@ -134,6 +138,52 @@ test_priorities (void) gdk_dmabuf_formats_unref (formats); } +static void +test_wayland (void) +{ + GdkDmabufFormatsBuilder *builder; + GdkDmabufFormats *formats1, *formats2; + + builder = gdk_dmabuf_formats_builder_new (); + gdk_dmabuf_formats_builder_add_format_for_device (builder, + DRM_FORMAT_RGBA8888, + 0, + DRM_FORMAT_MOD_LINEAR, + 0); + gdk_dmabuf_formats_builder_add_format_for_device (builder, + DRM_FORMAT_ARGB8888, + 0, + DRM_FORMAT_MOD_LINEAR, + 1); + formats1 = gdk_dmabuf_formats_builder_free_to_formats_for_device (builder, 2); + +#ifdef GDK_WINDOWING_WAYLAND + g_assert_true (gdk_wayland_dmabuf_formats_get_main_device (formats1) == 2); + g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats1, 0) == 0); + g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats1, 1) == 1); + g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats1, 0)); + g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats1, 1)); +#endif + + builder = gdk_dmabuf_formats_builder_new (); + gdk_dmabuf_formats_builder_add_format (builder, DRM_FORMAT_ARGB8888, DRM_FORMAT_MOD_LINEAR); + gdk_dmabuf_formats_builder_add_format (builder, DRM_FORMAT_RGBA8888, DRM_FORMAT_MOD_LINEAR); + formats2 = gdk_dmabuf_formats_builder_free_to_formats (builder); + +#ifdef GDK_WINDOWING_WAYLAND + g_assert_true (gdk_wayland_dmabuf_formats_get_main_device (formats2) == 0); + g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats2, 0) == 0); + g_assert_true (gdk_wayland_dmabuf_formats_get_target_device (formats2, 1) == 0); + g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats2, 0)); + g_assert_false (gdk_wayland_dmabuf_formats_is_scanout (formats2, 1)); +#endif + + g_assert_false (gdk_dmabuf_formats_equal (formats1, formats2)); + + gdk_dmabuf_formats_unref (formats1); + gdk_dmabuf_formats_unref (formats2); +} + int main (int argc, char *argv[]) { @@ -142,6 +192,7 @@ main (int argc, char *argv[]) g_test_add_func ("/dmabuf/formats/basic", test_dmabuf_formats_basic); g_test_add_func ("/dmabuf/formats/builder", test_dmabuf_formats_builder); g_test_add_func ("/dmabuf/formats/priorities", test_priorities); + g_test_add_func ("/dmabuf/formats/wayland", test_wayland); return g_test_run (); } -- GitLab From 66bc0c968fef84149cd957b61e227130c67ec8cc Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 7 Feb 2024 10:29:41 +0000 Subject: [PATCH 5/9] surface: Add a dmabuf-formats property Add a property to GdkSurface that carries the effective dmabuf formats for the surface. This will be either the formats according to the surfaces own Wayland dmabuf feedback, or the formats of the topmost subsurface. --- gdk/gdksubsurface.c | 80 ++++++++++++++++++++++++++++++++++- gdk/gdksubsurfaceprivate.h | 5 +++ gdk/gdksurface.c | 87 ++++++++++++++++++++++++++++++++++++++ gdk/gdksurface.h | 4 ++ gdk/gdksurfaceprivate.h | 9 ++++ 5 files changed, 184 insertions(+), 1 deletion(-) diff --git a/gdk/gdksubsurface.c b/gdk/gdksubsurface.c index 20d4810a4c7..f177da26c38 100644 --- a/gdk/gdksubsurface.c +++ b/gdk/gdksubsurface.c @@ -21,6 +21,7 @@ #include "gdksurfaceprivate.h" #include "gdktexture.h" #include "gsk/gskrectprivate.h" +#include "gdkdebugprivate.h" G_DEFINE_TYPE (GdkSubsurface, gdk_subsurface, G_TYPE_OBJECT) @@ -36,6 +37,7 @@ gdk_subsurface_finalize (GObject *object) g_ptr_array_remove (subsurface->parent->subsurfaces, subsurface); g_clear_object (&subsurface->parent); + g_clear_pointer (&subsurface->dmabuf_formats, gdk_dmabuf_formats_unref); G_OBJECT_CLASS (gdk_subsurface_parent_class)->finalize (object); } @@ -116,6 +118,28 @@ insert_subsurface (GdkSubsurface *subsurface, } } +static inline gboolean +is_topmost_subsurface (GdkSubsurface *subsurface) +{ + GdkSurface *parent = subsurface->parent; + + return !subsurface->sibling_above && parent->subsurfaces_below != subsurface; +} + +static inline GdkSubsurface * +find_topmost_subsurface (GdkSurface *surface) +{ + GdkSubsurface *top = surface->subsurfaces_above; + + if (top) + { + while (top->sibling_above) + top = top->sibling_above; + } + + return top; +} + /*< private > * gdk_subsurface_attach: * @subsurface: the `GdkSubsurface` @@ -150,7 +174,7 @@ gdk_subsurface_attach (GdkSubsurface *subsurface, GdkSubsurface *sibling) { GdkSurface *parent = subsurface->parent; - gboolean result; + gboolean was_topmost, is_topmost, result; g_return_val_if_fail (GDK_IS_SUBSURFACE (subsurface), FALSE); g_return_val_if_fail (GDK_IS_TEXTURE (texture), FALSE); @@ -164,6 +188,8 @@ gdk_subsurface_attach (GdkSubsurface *subsurface, g_return_val_if_fail (sibling == NULL || GDK_IS_SUBSURFACE (sibling), FALSE); g_return_val_if_fail (sibling == NULL || sibling->parent == subsurface->parent, FALSE); + was_topmost = is_topmost_subsurface (subsurface); + result = GDK_SUBSURFACE_GET_CLASS (subsurface)->attach (subsurface, texture, source, @@ -198,6 +224,29 @@ gdk_subsurface_attach (GdkSubsurface *subsurface, } } + is_topmost = is_topmost_subsurface (subsurface); + + if (!was_topmost && is_topmost) + { + GDK_DISPLAY_DEBUG (parent->display, DMABUF, "Using formats of topmost subsurface %p", subsurface); + gdk_surface_set_effective_dmabuf_formats (parent, subsurface->dmabuf_formats); + } + else if (was_topmost && !is_topmost) + { + GdkSubsurface *top = find_topmost_subsurface (parent); + + if (top) + { + GDK_DISPLAY_DEBUG (parent->display, DMABUF, "Using formats of topmost subsurface %p", top); + gdk_surface_set_effective_dmabuf_formats (parent, top->dmabuf_formats); + } + else + { + GDK_DISPLAY_DEBUG (parent->display, DMABUF, "Using formats of main surface"); + gdk_surface_set_effective_dmabuf_formats (parent, parent->dmabuf_formats); + } + } + return result; } @@ -212,10 +261,25 @@ gdk_subsurface_attach (GdkSubsurface *subsurface, void gdk_subsurface_detach (GdkSubsurface *subsurface) { + gboolean was_topmost; + g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); + was_topmost = is_topmost_subsurface (subsurface); + remove_subsurface (subsurface); + if (was_topmost) + { + GdkSurface *parent = subsurface->parent; + GdkSubsurface *top = find_topmost_subsurface (parent); + + if (top) + gdk_surface_set_effective_dmabuf_formats (parent, top->dmabuf_formats); + else + gdk_surface_set_effective_dmabuf_formats (parent, parent->dmabuf_formats); + } + GDK_SUBSURFACE_GET_CLASS (subsurface)->detach (subsurface); } @@ -370,3 +434,17 @@ gdk_subsurface_get_bounds (GdkSubsurface *subsurface, if (gdk_subsurface_get_background_rect (subsurface, &background)) graphene_rect_union (bounds, &background, bounds); } + +void +gdk_subsurface_set_dmabuf_formats (GdkSubsurface *subsurface, + GdkDmabufFormats *formats) +{ + g_return_if_fail (GDK_IS_SUBSURFACE (subsurface)); + g_return_if_fail (formats != NULL); + + g_clear_pointer (&subsurface->dmabuf_formats, gdk_dmabuf_formats_unref); + subsurface->dmabuf_formats = gdk_dmabuf_formats_ref (formats); + + if (is_topmost_subsurface (subsurface)) + gdk_surface_set_effective_dmabuf_formats (subsurface->parent, formats); +} diff --git a/gdk/gdksubsurfaceprivate.h b/gdk/gdksubsurfaceprivate.h index 6a28ac3f1df..27c4ed194c5 100644 --- a/gdk/gdksubsurfaceprivate.h +++ b/gdk/gdksubsurfaceprivate.h @@ -21,6 +21,7 @@ #include "gdkenumtypes.h" #include "gdksurface.h" +#include "gdkdmabufformats.h" #include G_BEGIN_DECLS @@ -45,6 +46,8 @@ struct _GdkSubsurface gboolean above_parent; GdkSubsurface *sibling_above; GdkSubsurface *sibling_below; + + GdkDmabufFormats *dmabuf_formats; }; typedef enum { @@ -109,6 +112,8 @@ gboolean gdk_subsurface_get_background_rect (GdkSubsurface *subsu graphene_rect_t *rect); void gdk_subsurface_get_bounds (GdkSubsurface *subsurface, graphene_rect_t *bounds); +void gdk_subsurface_set_dmabuf_formats (GdkSubsurface *subsurface, + GdkDmabufFormats *formats); G_END_DECLS diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index 6876f8967ed..695a0fbab87 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -91,6 +91,7 @@ enum { PROP_0, PROP_CURSOR, PROP_DISPLAY, + PROP_DMABUF_FORMATS, PROP_FRAME_CLOCK, PROP_MAPPED, PROP_WIDTH, @@ -548,6 +549,18 @@ gdk_surface_class_init (GdkSurfaceClass *klass) GDK_TYPE_DISPLAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); + /** + * GdkSurface:dmabuf-formats: (attributes org.gtk.Property.get=gdk_surface_get_dmabuf_formats) + * + * The dmabuf formats that can be used with this surface. + * + * Since: 4.14 + */ + properties[PROP_DMABUF_FORMATS] = + g_param_spec_boxed ("dmabuf-formats", NULL, NULL, + GDK_TYPE_DMABUF_FORMATS, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + /** * GdkSurface:frame-clock: (attributes org.gtk.Property.get=gdk_surface_get_frame_clock) * @@ -773,6 +786,9 @@ gdk_surface_finalize (GObject *object) g_ptr_array_unref (surface->subsurfaces); + g_clear_pointer (&surface->dmabuf_formats, gdk_dmabuf_formats_unref); + g_clear_pointer (&surface->effective_dmabuf_formats, gdk_dmabuf_formats_unref); + G_OBJECT_CLASS (gdk_surface_parent_class)->finalize (object); } @@ -827,6 +843,10 @@ gdk_surface_get_property (GObject *object, g_value_set_object (value, surface->display); break; + case PROP_DMABUF_FORMATS: + g_value_set_boxed (value, surface->effective_dmabuf_formats); + break; + case PROP_FRAME_CLOCK: g_value_set_object (value, surface->frame_clock); break; @@ -3076,3 +3096,70 @@ gdk_surface_get_subsurface (GdkSurface *surface, { return g_ptr_array_index (surface->subsurfaces, idx); } + +void +gdk_surface_set_dmabuf_formats (GdkSurface *surface, + GdkDmabufFormats *formats) +{ + g_return_if_fail (GDK_IS_SURFACE (surface)); + g_return_if_fail (formats != NULL); + + g_clear_pointer (&surface->dmabuf_formats, gdk_dmabuf_formats_unref); + surface->dmabuf_formats = gdk_dmabuf_formats_ref (formats); + + if (surface->subsurfaces_above == NULL) + { + GDK_DISPLAY_DEBUG (surface->display, DMABUF, "Using main surface formats"); + gdk_surface_set_effective_dmabuf_formats (surface, formats); + } +} + +void +gdk_surface_set_effective_dmabuf_formats (GdkSurface *surface, + GdkDmabufFormats *formats) +{ + g_return_if_fail (GDK_IS_SURFACE (surface)); + + if (!formats) + return; + + if (gdk_dmabuf_formats_equal (surface->effective_dmabuf_formats, formats)) + { + GDK_DISPLAY_DEBUG (surface->display, DMABUF, "Formats unchanged"); + return; + } + + g_clear_pointer (&surface->effective_dmabuf_formats, gdk_dmabuf_formats_unref); + surface->effective_dmabuf_formats = gdk_dmabuf_formats_ref (formats); + + g_object_notify_by_pspec (G_OBJECT (surface), properties[PROP_DMABUF_FORMATS]); +} + +/** + * gdk_surface_get_dmabuf_formats: + * @surface: a `GdkSurface` + * + * Returns the dma-buf formats that are supported on this surface. + * + * What formats can be used may depend on the geometry and stacking + * order of the surface and its subsurfaces, and can change over time. + * + * The formats returned by this function can be used for negotiating + * buffer formats with producers such as v4l, pipewire or GStreamer. + * + * To learn more about dma-bufs, see [class@Gdk.DmabufTextureBuilder]. + * + * Returns: (transfer none): a `GdkDmabufFormats` object + * + * Since: 4.16 + */ +GdkDmabufFormats * +gdk_surface_get_dmabuf_formats (GdkSurface *surface) +{ + g_return_val_if_fail (GDK_IS_SURFACE (surface), NULL); + + if (surface->effective_dmabuf_formats) + return surface->effective_dmabuf_formats; + else + return gdk_display_get_dmabuf_formats (surface->display); +} diff --git a/gdk/gdksurface.h b/gdk/gdksurface.h index 5c8025c38f9..b712754fa9e 100644 --- a/gdk/gdksurface.h +++ b/gdk/gdksurface.h @@ -139,6 +139,10 @@ GdkVulkanContext * gdk_surface_create_vulkan_context(GdkSurface *surface, GError **error); +GDK_AVAILABLE_IN_4_16 +GdkDmabufFormats * + gdk_surface_get_dmabuf_formats (GdkSurface *surface); + G_DEFINE_AUTOPTR_CLEANUP_FUNC (GdkSurface, g_object_unref) G_END_DECLS diff --git a/gdk/gdksurfaceprivate.h b/gdk/gdksurfaceprivate.h index d06ba31148b..66cb60bdaa3 100644 --- a/gdk/gdksurfaceprivate.h +++ b/gdk/gdksurfaceprivate.h @@ -105,6 +105,9 @@ struct _GdkSurface */ GdkSubsurface *subsurfaces_above; GdkSubsurface *subsurfaces_below; + + GdkDmabufFormats *dmabuf_formats; + GdkDmabufFormats *effective_dmabuf_formats; }; struct _GdkSurfaceClass @@ -355,4 +358,10 @@ gsize gdk_surface_get_n_subsurfaces (GdkSurface *surface); GdkSubsurface * gdk_surface_get_subsurface (GdkSurface *surface, gsize idx); +void gdk_surface_set_dmabuf_formats (GdkSurface *surface, + GdkDmabufFormats *formats); + +void gdk_surface_set_effective_dmabuf_formats (GdkSurface *surface, + GdkDmabufFormats *formats); + G_END_DECLS -- GitLab From ad636b2afb20befb39c3edcb61e5af32b2220415 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 27 Apr 2024 12:11:25 -0400 Subject: [PATCH 6/9] wayland: Hook up default dmabuf feedback Keep the dmabuf formats from the default feedback events around in the display, instead of just printing out debug spew. The formats will be used in the future. --- gdk/wayland/gdkdisplay-wayland.c | 16 ++- gdk/wayland/gdkdisplay-wayland.h | 1 + gdk/wayland/gdkdmabuf-wayland-private.h | 18 ++- gdk/wayland/gdkdmabuf-wayland.c | 170 +++++++++++++++++++----- 4 files changed, 168 insertions(+), 37 deletions(-) diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c index 4e6f0d8727a..372c2c271a0 100644 --- a/gdk/wayland/gdkdisplay-wayland.c +++ b/gdk/wayland/gdkdisplay-wayland.c @@ -337,6 +337,16 @@ static void gdk_wayland_display_remove_output (GdkWaylandDisplay *display_wa static void gdk_wayland_display_init_xdg_output (GdkWaylandDisplay *display_wayland); static void gdk_wayland_display_get_xdg_output (GdkWaylandMonitor *monitor); +static void +dmabuf_formats_callback (gpointer data, + DmabufFormatsInfo *info) +{ + GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (data); + + g_clear_pointer (&display_wayland->wayland_dmabuf_formats, gdk_dmabuf_formats_unref); + display_wayland->wayland_dmabuf_formats = gdk_dmabuf_formats_ref (info->formats); +} + static void gdk_registry_handle_global (void *data, struct wl_registry *registry, @@ -370,7 +380,10 @@ gdk_registry_handle_global (void *data, feedback = zwp_linux_dmabuf_v1_get_default_feedback (display_wayland->linux_dmabuf); display_wayland->dmabuf_formats_info = dmabuf_formats_info_new (GDK_DISPLAY (display_wayland), "default", - feedback); + NULL, + feedback, + dmabuf_formats_callback, + display_wayland); _gdk_wayland_display_async_roundtrip (display_wayland); } else if (strcmp (interface, "xdg_wm_base") == 0) @@ -744,6 +757,7 @@ gdk_wayland_display_dispose (GObject *object) g_clear_pointer (&display_wayland->single_pixel_buffer, wp_single_pixel_buffer_manager_v1_destroy); g_clear_pointer (&display_wayland->linux_dmabuf, zwp_linux_dmabuf_v1_destroy); g_clear_pointer (&display_wayland->dmabuf_formats_info, dmabuf_formats_info_free); + g_clear_pointer (&display_wayland->wayland_dmabuf_formats, gdk_dmabuf_formats_unref); g_clear_pointer (&display_wayland->shm, wl_shm_destroy); g_clear_pointer (&display_wayland->wl_registry, wl_registry_destroy); diff --git a/gdk/wayland/gdkdisplay-wayland.h b/gdk/wayland/gdkdisplay-wayland.h index 3000c47f819..7df3512bb08 100644 --- a/gdk/wayland/gdkdisplay-wayland.h +++ b/gdk/wayland/gdkdisplay-wayland.h @@ -100,6 +100,7 @@ struct _GdkWaylandDisplay struct wl_shm *shm; struct zwp_linux_dmabuf_v1 *linux_dmabuf; DmabufFormatsInfo *dmabuf_formats_info; + GdkDmabufFormats *wayland_dmabuf_formats; struct xdg_wm_base *xdg_wm_base; struct zxdg_shell_v6 *zxdg_shell_v6; struct gtk_shell1 *gtk_shell; diff --git a/gdk/wayland/gdkdmabuf-wayland-private.h b/gdk/wayland/gdkdmabuf-wayland-private.h index 97cc938a3b1..9c5179094ee 100644 --- a/gdk/wayland/gdkdmabuf-wayland-private.h +++ b/gdk/wayland/gdkdmabuf-wayland-private.h @@ -54,24 +54,40 @@ typedef struct typedef struct DmabufFormatsInfo DmabufFormatsInfo; +typedef void (* DmabufFormatsUpdateCallback) (gpointer data, + DmabufFormatsInfo *formats); + struct DmabufFormatsInfo { GdkDisplay *display; char *name; struct zwp_linux_dmabuf_feedback_v1 *feedback; + DmabufFormatsUpdateCallback callback; + gpointer data; + gsize n_dmabuf_formats; DmabufFormat *dmabuf_format_table; DmabufFormats *dmabuf_formats; DmabufFormats *pending_dmabuf_formats; DmabufTranche *pending_tranche; + + GdkDmabufFormats *egl_formats; + GdkDmabufFormats *formats; }; DmabufFormatsInfo * dmabuf_formats_info_new (GdkDisplay *display, const char *name, - struct zwp_linux_dmabuf_feedback_v1 *feedback); + GdkDmabufFormats *egl_formats, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + DmabufFormatsUpdateCallback callback, + gpointer data); void dmabuf_formats_info_free (DmabufFormatsInfo *info); +void dmabuf_formats_info_set_egl_formats + (DmabufFormatsInfo *info, + GdkDmabufFormats *egl_formats); + G_END_DECLS diff --git a/gdk/wayland/gdkdmabuf-wayland.c b/gdk/wayland/gdkdmabuf-wayland.c index bca115a559e..a7462eddfb4 100644 --- a/gdk/wayland/gdkdmabuf-wayland.c +++ b/gdk/wayland/gdkdmabuf-wayland.c @@ -46,44 +46,116 @@ dmabuf_formats_free (DmabufFormats *formats) g_free (formats); } +static gboolean +is_in_tranche (GdkDmabufFormats *formats, + gsize idx, + guint32 fourcc, + guint64 modifier) +{ + gsize end; + guint32 f; + guint64 m; + + end = gdk_dmabuf_formats_next_priority (formats, idx); + for (gsize i = idx; i < end; i++) + { + gdk_dmabuf_formats_get_format (formats, i, &f, &m); + if (f == fourcc && m == modifier) + return TRUE; + } + + return FALSE; +} + +static void +gdk_wayland_dmabuf_formats_dump (GdkDmabufFormats *formats, + const char *name) +{ + gdk_debug_message ("Wayland %s dmabuf formats: (%lu entries)", name, formats->n_formats); + gdk_debug_message ("Main device: %u %u", + major (formats->device), + minor (formats->device)); + + gsize i = 0; + while (i < formats->n_formats) + { + GdkDmabufFormat *format = &formats->formats[i]; + gsize next_priority = format->next_priority; + + if (i > 0) + gdk_debug_message ("------"); + + gdk_debug_message ("Tranche target device: %u %u", + major (format->device), + minor (format->device)); + if (format->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT) + gdk_debug_message ("Tranche is scanout"); + gdk_debug_message ("Tranche formats (%lu entries)", next_priority - i); + + for (; i < next_priority; i++) + { + format = &formats->formats[i]; + gdk_debug_message (" %.4s:%#" G_GINT64_MODIFIER "x", (char *) &format->fourcc, format->modifier); + } + } +} + static void update_dmabuf_formats (DmabufFormatsInfo *info) { + GdkDmabufFormatsBuilder *builder; + GdkDmabufFormats *egl_formats = info->egl_formats; DmabufFormats *formats = info->dmabuf_formats; - GDK_DISPLAY_DEBUG (info->display, MISC, - "dmabuf format table (%lu entries)", info->n_dmabuf_formats); - GDK_DISPLAY_DEBUG (info->display, MISC, - "dmabuf main device: %u %u", - major (formats->main_device), - minor (formats->main_device)); + builder = gdk_dmabuf_formats_builder_new (); for (gsize i = 0; i < formats->tranches->len; i++) { DmabufTranche *tranche = g_ptr_array_index (formats->tranches, i); - GDK_DISPLAY_DEBUG (info->display, MISC, - "dmabuf tranche target device: %u %u", - major (tranche->target_device), - minor (tranche->target_device)); - - GDK_DISPLAY_DEBUG (info->display, MISC, - "dmabuf%s tranche (%lu entries):", - tranche->flags & ZWP_LINUX_DMABUF_FEEDBACK_V1_TRANCHE_FLAGS_SCANOUT ? " scanout" : "", - tranche->n_formats); - - for (gsize j = 0; j < tranche->n_formats; j++) + if (egl_formats) + { + for (gsize k = 0; k < gdk_dmabuf_formats_get_n_formats (egl_formats); k = gdk_dmabuf_formats_next_priority (egl_formats, k)) + { + for (gsize j = 0; j < tranche->n_formats; j++) + { + if (is_in_tranche (egl_formats, k, + tranche->formats[j].fourcc, + tranche->formats[j].modifier)) + gdk_dmabuf_formats_builder_add_format_for_device (builder, + tranche->formats[j].fourcc, + tranche->flags, + tranche->formats[j].modifier, + tranche->target_device); + } + gdk_dmabuf_formats_builder_next_priority (builder); + } + } + else { - GDK_DISPLAY_DEBUG (info->display, MISC, - " %.4s:%#" G_GINT64_MODIFIER "x", - (char *) &(tranche->formats[j].fourcc), - tranche->formats[j].modifier); + for (gsize j = 0; j < tranche->n_formats; j++) + { + gdk_dmabuf_formats_builder_add_format_for_device (builder, + tranche->formats[j].fourcc, + tranche->flags, + tranche->formats[j].modifier, + tranche->target_device); + } + gdk_dmabuf_formats_builder_next_priority (builder); } } + + g_clear_pointer (&info->formats, gdk_dmabuf_formats_unref); + info->formats = gdk_dmabuf_formats_builder_free_to_formats_for_device (builder, formats->main_device); + + if (GDK_DISPLAY_DEBUG_CHECK (info->display, DMABUF)) + gdk_wayland_dmabuf_formats_dump (info->formats, info->name); + + info->callback (info->data, info); } static void -linux_dmabuf_done (void *data, +linux_dmabuf_done (void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback) { DmabufFormatsInfo *info = data; @@ -97,10 +169,10 @@ linux_dmabuf_done (void *data, } static void -linux_dmabuf_format_table (void *data, +linux_dmabuf_format_table (void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, - int32_t fd, - uint32_t size) + int32_t fd, + uint32_t size) { DmabufFormatsInfo *info = data; @@ -112,9 +184,9 @@ linux_dmabuf_format_table (void *data, } static void -linux_dmabuf_main_device (void *data, +linux_dmabuf_main_device (void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, - struct wl_array *device) + struct wl_array *device) { DmabufFormatsInfo *info = data; dev_t dev; @@ -128,7 +200,7 @@ linux_dmabuf_main_device (void *data, } static void -linux_dmabuf_tranche_done (void *data, +linux_dmabuf_tranche_done (void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback) { DmabufFormatsInfo *info = data; @@ -140,9 +212,9 @@ linux_dmabuf_tranche_done (void *data, } static void -linux_dmabuf_tranche_target_device (void *data, +linux_dmabuf_tranche_target_device (void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, - struct wl_array *device) + struct wl_array *device) { DmabufFormatsInfo *info = data; dev_t dev; @@ -159,9 +231,9 @@ linux_dmabuf_tranche_target_device (void *data, } static void -linux_dmabuf_tranche_formats (void *data, +linux_dmabuf_tranche_formats (void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, - struct wl_array *indices) + struct wl_array *indices) { DmabufFormatsInfo *info = data; DmabufTranche *tranche; @@ -182,9 +254,9 @@ linux_dmabuf_tranche_formats (void *data, } static void -linux_dmabuf_tranche_flags (void *data, +linux_dmabuf_tranche_flags (void *data, struct zwp_linux_dmabuf_feedback_v1 *feedback, - uint32_t flags) + uint32_t flags) { DmabufFormatsInfo *info = data; DmabufTranche *tranche; @@ -207,7 +279,10 @@ static const struct zwp_linux_dmabuf_feedback_v1_listener feedback_listener = { DmabufFormatsInfo * dmabuf_formats_info_new (GdkDisplay *display, const char *name, - struct zwp_linux_dmabuf_feedback_v1 *feedback) + GdkDmabufFormats *egl_formats, + struct zwp_linux_dmabuf_feedback_v1 *feedback, + DmabufFormatsUpdateCallback callback, + gpointer data) { DmabufFormatsInfo *info; @@ -215,11 +290,21 @@ dmabuf_formats_info_new (GdkDisplay *display, info->display = display; info->name = g_strdup (name); + if (egl_formats) + { + info->egl_formats = gdk_dmabuf_formats_ref (egl_formats); + info->formats = gdk_dmabuf_formats_ref (egl_formats); + } info->feedback = feedback; + info->callback = callback; + info->data = data; + if (info->feedback) zwp_linux_dmabuf_feedback_v1_add_listener (info->feedback, &feedback_listener, info); + else + info->callback (info->data, info); return info; } @@ -228,6 +313,8 @@ void dmabuf_formats_info_free (DmabufFormatsInfo *info) { g_free (info->name); + g_clear_pointer (&info->formats, gdk_dmabuf_formats_unref); + g_clear_pointer (&info->egl_formats, gdk_dmabuf_formats_unref); g_clear_pointer (&info->feedback, zwp_linux_dmabuf_feedback_v1_destroy); if (info->dmabuf_format_table) { @@ -241,6 +328,19 @@ dmabuf_formats_info_free (DmabufFormatsInfo *info) g_free (info); } +void +dmabuf_formats_info_set_egl_formats (DmabufFormatsInfo *info, + GdkDmabufFormats *egl_formats) +{ + if (info->egl_formats) + return; + + info->egl_formats = gdk_dmabuf_formats_ref (egl_formats); + + if (info->dmabuf_formats) + update_dmabuf_formats (info); +} + /** * gdk_wayland_dmabuf_formats_get_main_device: * @formats: a `GdkDmabufFormats` -- GitLab From dbb890240a2a51ec69cf84d37935c2d5e535cc17 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 7 Feb 2024 10:30:22 +0000 Subject: [PATCH 7/9] wayland: Hook up surface dmabuf feedback Make the surface and subsurface code handle the dmabuf feedback, and update the :dmabuf-formats property on the surface to reflect the Wayland dmabuf information. --- gdk/gdksubsurface.c | 2 +- gdk/wayland/gdksubsurface-wayland-private.h | 5 ++- gdk/wayland/gdksubsurface-wayland.c | 35 ++++++++++++++++++++- gdk/wayland/gdksurface-wayland-private.h | 2 ++ gdk/wayland/gdksurface-wayland.c | 34 ++++++++++++++++++++ 5 files changed, 75 insertions(+), 3 deletions(-) diff --git a/gdk/gdksubsurface.c b/gdk/gdksubsurface.c index f177da26c38..4c95aac3430 100644 --- a/gdk/gdksubsurface.c +++ b/gdk/gdksubsurface.c @@ -445,6 +445,6 @@ gdk_subsurface_set_dmabuf_formats (GdkSubsurface *subsurface, g_clear_pointer (&subsurface->dmabuf_formats, gdk_dmabuf_formats_unref); subsurface->dmabuf_formats = gdk_dmabuf_formats_ref (formats); - if (is_topmost_subsurface (subsurface)) + if (subsurface->parent && is_topmost_subsurface (subsurface)) gdk_surface_set_effective_dmabuf_formats (subsurface->parent, formats); } diff --git a/gdk/wayland/gdksubsurface-wayland-private.h b/gdk/wayland/gdksubsurface-wayland-private.h index 9b8378ccc2d..345ad597c24 100644 --- a/gdk/wayland/gdksubsurface-wayland-private.h +++ b/gdk/wayland/gdksubsurface-wayland-private.h @@ -1,6 +1,8 @@ #pragma once +#include "gdk/gdkdmabufformats.h" #include "gdksubsurfaceprivate.h" +#include "gdkdmabuf-wayland-private.h" #include "wayland-client-protocol.h" @@ -35,6 +37,8 @@ struct _GdkWaylandSubsurface struct wp_viewport *bg_viewport; cairo_rectangle_int_t bg_rect; gboolean bg_attached; + + DmabufFormatsInfo *formats; }; struct _GdkWaylandSubsurfaceClass @@ -48,4 +52,3 @@ void gdk_wayland_subsurface_request_frame (GdkSubsurface *subsurface); void gdk_wayland_subsurface_clear_frame_callback (GdkSubsurface *subsurface); GdkSubsurface * gdk_wayland_surface_create_subsurface (GdkSurface *surface); - diff --git a/gdk/wayland/gdksubsurface-wayland.c b/gdk/wayland/gdksubsurface-wayland.c index 666c66b428a..4ae9fd50f60 100644 --- a/gdk/wayland/gdksubsurface-wayland.c +++ b/gdk/wayland/gdksubsurface-wayland.c @@ -27,6 +27,7 @@ #include "gdksubsurfaceprivate.h" #include "gdkdebugprivate.h" #include "gsk/gskrectprivate.h" +#include "gdkprivate.h" #include "linux-dmabuf-unstable-v1-client-protocol.h" @@ -51,6 +52,7 @@ gdk_wayland_subsurface_finalize (GObject *object) g_clear_pointer (&self->bg_viewport, wp_viewport_destroy); g_clear_pointer (&self->bg_subsurface, wl_subsurface_destroy); g_clear_pointer (&self->bg_surface, wl_surface_destroy); + g_clear_pointer (&self->formats, dmabuf_formats_info_free); G_OBJECT_CLASS (gdk_wayland_subsurface_parent_class)->finalize (object); } @@ -790,6 +792,15 @@ gdk_wayland_subsurface_clear_frame_callback (GdkSubsurface *sub) g_clear_pointer (&self->frame_callback, wl_callback_destroy); } +static void +dmabuf_formats_callback (gpointer data, + DmabufFormatsInfo *info) +{ + GdkSubsurface *sub = data; + + gdk_subsurface_set_dmabuf_formats (sub, info->formats); +} + GdkSubsurface * gdk_wayland_surface_create_subsurface (GdkSurface *surface) { @@ -798,6 +809,8 @@ gdk_wayland_surface_create_subsurface (GdkSurface *surface) GdkWaylandDisplay *disp = GDK_WAYLAND_DISPLAY (display); GdkWaylandSubsurface *sub; struct wl_region *region; + struct zwp_linux_dmabuf_feedback_v1 *feedback; + char *name; if (disp->subcompositor == NULL || disp->viewporter == NULL) { @@ -825,8 +838,28 @@ gdk_wayland_surface_create_subsurface (GdkSurface *surface) wl_region_add (sub->opaque_region, 0, 0, G_MAXINT, G_MAXINT); wl_surface_set_opaque_region (sub->surface, sub->opaque_region); + gdk_display_init_dmabuf (display); + + if (disp->linux_dmabuf) + { + dmabuf_formats_info_set_egl_formats (disp->dmabuf_formats_info, display->dmabuf_formats); + feedback = zwp_linux_dmabuf_v1_get_surface_feedback (disp->linux_dmabuf, sub->surface); + } + else + { + feedback = NULL; + } + + name = g_strdup_printf ("subsurface %p", sub); + sub->formats = dmabuf_formats_info_new (display, + name, + display->dmabuf_formats, + feedback, + dmabuf_formats_callback, + sub); + g_free (name); + GDK_DISPLAY_DEBUG (display, OFFLOAD, "Subsurface %p of surface %p created", sub, impl); return GDK_SUBSURFACE (sub); } - diff --git a/gdk/wayland/gdksurface-wayland-private.h b/gdk/wayland/gdksurface-wayland-private.h index b62e30f661e..0021051458a 100644 --- a/gdk/wayland/gdksurface-wayland-private.h +++ b/gdk/wayland/gdksurface-wayland-private.h @@ -89,6 +89,8 @@ struct _GdkWaylandSurface uint32_t last_configure_serial; int state_freeze_count; + + DmabufFormatsInfo *formats; }; typedef struct _GdkWaylandSurfaceClass GdkWaylandSurfaceClass; diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c index 2ebeed05da0..21ab187f585 100644 --- a/gdk/wayland/gdksurface-wayland.c +++ b/gdk/wayland/gdksurface-wayland.c @@ -936,6 +936,15 @@ gdk_wayland_surface_create_wl_surface (GdkSurface *surface) self->display_server.wl_surface = wl_surface; } +static void +dmabuf_formats_callback (gpointer data, + DmabufFormatsInfo *info) +{ + GdkSurface *surface = data; + + gdk_surface_set_dmabuf_formats (surface, info->formats); +} + static void gdk_wayland_surface_constructed (GObject *object) { @@ -944,6 +953,8 @@ gdk_wayland_surface_constructed (GObject *object) GdkDisplay *display = gdk_surface_get_display (surface); GdkWaylandDisplay *display_wayland = GDK_WAYLAND_DISPLAY (display); GdkFrameClock *frame_clock = gdk_surface_get_frame_clock (surface); + struct zwp_linux_dmabuf_feedback_v1 *feedback; + char *name; self->event_queue = wl_display_create_queue (display_wayland->wl_display); display_wayland->event_queues = g_list_prepend (display_wayland->event_queues, @@ -969,6 +980,29 @@ gdk_wayland_surface_constructed (GObject *object) gdk_wayland_surface_create_wl_surface (surface); + gdk_display_init_dmabuf (display); + + if (display_wayland->linux_dmabuf) + { + dmabuf_formats_info_set_egl_formats (display_wayland->dmabuf_formats_info, + display->dmabuf_formats); + feedback = zwp_linux_dmabuf_v1_get_surface_feedback (display_wayland->linux_dmabuf, + self->display_server.wl_surface); + } + else + { + feedback = NULL; + } + + name = g_strdup_printf ("surface %p", surface); + self->formats = dmabuf_formats_info_new (display, + name, + display->dmabuf_formats, + feedback, + dmabuf_formats_callback, + surface); + g_free (name); + g_signal_connect (frame_clock, "before-paint", G_CALLBACK (on_frame_clock_before_paint), surface); g_signal_connect (frame_clock, "after-paint", G_CALLBACK (on_frame_clock_after_paint), surface); -- GitLab From 349a29bb49fb9d99130390b8ed6ddf97973d0f59 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 7 Feb 2024 12:19:55 +0000 Subject: [PATCH 8/9] gstreamer: Use surface dmabuf formats Use surface formats instead of display formats, for better results. This does not pay attention to priorities yet, and renegotiation is still missing. --- modules/media/gtkgstpaintable.c | 3 +++ modules/media/gtkgstsink.c | 11 +++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/media/gtkgstpaintable.c b/modules/media/gtkgstpaintable.c index 66bb29985d5..88dffbc0668 100644 --- a/modules/media/gtkgstpaintable.c +++ b/modules/media/gtkgstpaintable.c @@ -132,12 +132,15 @@ gtk_gst_paintable_video_renderer_create_video_sink (GstPlayerVideoRenderer *rend GstPlayer *player) { GtkGstPaintable *self = GTK_GST_PAINTABLE (renderer); + GdkDmabufFormats *dmabuf_formats; GstElement *sink; GdkGLContext *ctx; + dmabuf_formats = gdk_display_get_dmabuf_formats (gdk_display_get_default ()); sink = g_object_new (GTK_TYPE_GST_SINK, "paintable", self, "gl-context", self->context, + "dmabuf-formats", dmabuf_formats, NULL); if (self->context != NULL) diff --git a/modules/media/gtkgstsink.c b/modules/media/gtkgstsink.c index b870d6de3a6..c71335bc76e 100644 --- a/modules/media/gtkgstsink.c +++ b/modules/media/gtkgstsink.c @@ -178,13 +178,12 @@ gtk_gst_sink_get_caps (GstBaseSink *bsink, { tmp = gst_pad_get_pad_template_caps (GST_BASE_SINK_PAD (bsink)); #ifdef HAVE_GSTREAMER_DRM - { - GdkDisplay *display = gdk_gl_context_get_display (self->gdk_context); - GdkDmabufFormats *formats = gdk_display_get_dmabuf_formats (display); + GdkSurface *surface; - tmp = gst_caps_make_writable (tmp); - add_drm_formats_and_modifiers (tmp, formats); - } + tmp = gst_caps_make_writable (tmp); + + surface = gdk_gl_context_get_surface (self->gdk_context); + add_drm_formats_and_modifiers (tmp, gdk_surface_get_dmabuf_formats (surface)); #endif } else -- GitLab From d0c9c66c388a52faedea021aaf37b421e1fd230a Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Wed, 7 Feb 2024 09:40:42 +0000 Subject: [PATCH 9/9] gsk: Don't notify surface properties during render The offloading may change subsurface stacking order, and thereby change the effective dmabuf formats of the surface. But we don't want to trigger callbacks during frame processing, so delay the change notification until after we're done with that. --- gsk/gskrenderer.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c index b10286c0753..00b8e591a22 100644 --- a/gsk/gskrenderer.c +++ b/gsk/gskrenderer.c @@ -483,6 +483,12 @@ gsk_renderer_render (GskRenderer *renderer, if (priv->surface == NULL) return; + /* Offloading can change subsurface stacking, which may trigger + * surface property changes. We don't want them to take effect + * during frame processing. + */ + g_object_freeze_notify (G_OBJECT (priv->surface)); + renderer_class = GSK_RENDERER_GET_CLASS (renderer); clip = cairo_region_copy (region); @@ -528,6 +534,8 @@ gsk_renderer_render (GskRenderer *renderer, cairo_region_destroy (clip); g_clear_pointer (&offload, gsk_offload_free); priv->prev_node = gsk_render_node_ref (root); + + g_object_thaw_notify (G_OBJECT (priv->surface)); } /*< private > -- GitLab