From 0fbcfd32cdacfbd3c1e32cf3832fcea02467baa7 Mon Sep 17 00:00:00 2001
From: huangwujie <huangwujie@allwinnertech.com>
Date: Thu, 30 Oct 2025 10:28:12 +0800
Subject: [PATCH] fix:gst-plugins-bad-waylandsink:gst-waylandsink compatibility
 with Weston 12.

fix the black screen issue of waylandsink after weston update.
The cause is that the inconsistent protocol version between gst and wayland leads to the inability to negotiate plugin caps, preventing pipeline establishment.
Solved by adding format retrieval handling in the modifier callback of wayland version 3.

Scope:All
IssueID:486942
---
 ext/wayland/wldisplay.c | 114 ++++++++++++++++++++++++++++++++++++++--
 ext/wayland/wldisplay.h |  10 ++++
 2 files changed, 120 insertions(+), 4 deletions(-)

diff --git a/ext/wayland/wldisplay.c b/ext/wayland/wldisplay.c
index f326091..e365256 100644
--- a/ext/wayland/wldisplay.c
+++ b/ext/wayland/wldisplay.c
@@ -47,6 +47,8 @@ gst_wl_display_init (GstWlDisplay * self)
 {
   self->shm_formats = g_array_new (FALSE, FALSE, sizeof (uint32_t));
   self->dmabuf_formats = g_array_new (FALSE, FALSE, sizeof (uint32_t));
+  self->dmabuf_format_modifiers = g_array_new (FALSE, FALSE, sizeof (GstWlDmaBufFormatModifier));
+  self->dmabuf_version = 0;
   self->wl_fd_poll = gst_poll_new (TRUE);
   self->buffers = g_hash_table_new (g_direct_hash, g_direct_equal);
   g_mutex_init (&self->buffers_mutex);
@@ -78,8 +80,9 @@ gst_wl_display_finalize (GObject * gobject)
       (GHFunc) gst_wl_buffer_force_release_and_unref, NULL);
   g_hash_table_remove_all (self->buffers);
 
-  g_array_unref (self->shm_formats);
   g_array_unref (self->dmabuf_formats);
+  g_array_unref (self->dmabuf_format_modifiers);
+  g_array_unref (self->shm_formats);
   gst_poll_free (self->wl_fd_poll);
   g_hash_table_unref (self->buffers);
   g_mutex_clear (&self->buffers_mutex);
@@ -144,11 +147,67 @@ dmabuf_format (void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
   GstWlDisplay *self = data;
 
   if (gst_wl_dmabuf_format_to_video_format (format) != GST_VIDEO_FORMAT_UNKNOWN)
-    g_array_append_val (self->dmabuf_formats, format);
+  {
+    for (guint i = 0; i < self->dmabuf_formats->len; i++) {
+      if (g_array_index (self->dmabuf_formats, uint32_t, i) == format)
+          break;
+      g_array_append_val (self->dmabuf_formats, format);
+    }
+  }
+}
+static void
+dmabuf_modifier(void *data, struct zwp_linux_dmabuf_v1 *zwp_linux_dmabuf,
+                uint32_t format, uint32_t modifier_hi, uint32_t modifier_lo)
+{
+    GstWlDisplay *self = data;
+    uint64_t modifier = ((uint64_t)modifier_hi << 32) | modifier_lo;
+    GstWlDmaBufFormatModifier fmt_mod;
+    gboolean format_exists = FALSE;
+    gboolean modifier_exists = FALSE;
+    guint i;
+
+    GST_DEBUG_OBJECT (self, "DMABuf modifier: format=0x%x, modifier=0x%" PRIx64 " (0x%x, 0x%x)",
+        format, modifier, modifier_hi, modifier_lo);
+
+    if (gst_wl_dmabuf_format_to_video_format (format) != GST_VIDEO_FORMAT_UNKNOWN) {
+        for (i = 0; i < self->dmabuf_formats->len; i++) {
+            if (g_array_index (self->dmabuf_formats, uint32_t, i) == format) {
+                format_exists = TRUE;
+                break;
+            }
+        }
+
+        for (i = 0; i < self->dmabuf_format_modifiers->len; i++) {
+            GstWlDmaBufFormatModifier *existing = &g_array_index (self->dmabuf_format_modifiers,
+                                                                 GstWlDmaBufFormatModifier, i);
+            if (existing->format == format && existing->modifier == modifier) {
+                modifier_exists = TRUE;
+                break;
+            }
+        }
+
+        if (!modifier_exists) {
+            fmt_mod.format = format;
+            fmt_mod.modifier = modifier;
+            g_array_append_val (self->dmabuf_format_modifiers, fmt_mod);
+            GST_DEBUG_OBJECT (self, "Added new format-modifier combination: format=0x%x, modifier=0x%" PRIx64,
+                format, modifier);
+        } else {
+            GST_DEBUG_OBJECT (self, "Skipping duplicate format-modifier combination: format=0x%x, modifier=0x%" PRIx64,
+                format, modifier);
+        }
+
+        // Support for Wayland lower versions where only the dmabuf_format callback is available.
+        if (!format_exists) {
+            g_array_append_val (self->dmabuf_formats, format);
+            GST_DEBUG_OBJECT (self, "Added new format: 0x%x", format);
+        }
+    }
 }
 
 static const struct zwp_linux_dmabuf_v1_listener dmabuf_listener = {
   dmabuf_format,
+  dmabuf_modifier
 };
 
 gboolean
@@ -195,6 +254,44 @@ gst_wl_display_check_format_for_dmabuf (GstWlDisplay * display,
   return FALSE;
 }
 
+gboolean
+gst_wl_display_check_format_modifier_for_dmabuf (GstWlDisplay * display,
+    GstVideoFormat format, uint64_t modifier)
+{
+  guint i,dmabuf_fmt;
+
+  g_return_val_if_fail (GST_IS_WL_DISPLAY (display), FALSE);
+
+  dmabuf_fmt = gst_video_format_to_wl_dmabuf_format (format);
+  if (dmabuf_fmt == (guint) - 1) {
+    GST_DEBUG_OBJECT (display, "Cannot convert format %s to DRM format",
+        gst_video_format_to_string (format));
+    return FALSE;
+  }
+
+  for (i = 0; i < display->dmabuf_format_modifiers->len; i++) {
+    GstWlDmaBufFormatModifier *fmt_mod = &g_array_index (display->dmabuf_format_modifiers,
+        GstWlDmaBufFormatModifier, i);
+
+    if (fmt_mod->format == dmabuf_fmt && fmt_mod->modifier == modifier) {
+      GST_DEBUG_OBJECT (display, "Found supported format-modifier combination: format=0x%x, modifier=0x%" PRIx64,
+          dmabuf_fmt, modifier);
+      return TRUE;
+    }
+  }
+
+  GST_DEBUG_OBJECT (display, "Unsupported format-modifier combination: format=0x%x, modifier=0x%" PRIx64,
+      dmabuf_fmt, modifier);
+  return FALSE;
+}
+
+uint32_t
+gst_wl_display_get_dmabuf_version (GstWlDisplay * display)
+{
+  g_return_val_if_fail (GST_IS_WL_DISPLAY (display), 0);
+  return display->dmabuf_version;
+}
+
 static void
 handle_xdg_wm_base_ping (void *user_data, struct xdg_wm_base *xdg_wm_base,
     uint32_t serial)
@@ -234,9 +331,18 @@ registry_handle_global (void *data, struct wl_registry *registry,
     self->viewporter =
         wl_registry_bind (registry, id, &wp_viewporter_interface, 1);
   } else if (g_strcmp0 (interface, "zwp_linux_dmabuf_v1") == 0) {
-    self->dmabuf =
-        wl_registry_bind (registry, id, &zwp_linux_dmabuf_v1_interface, 1);
+    GST_DEBUG_OBJECT (self, "Wayland DMABuf interface version: %d", version);
+
+    self->dmabuf_version = version;
+
+    guint32 bind_version = MIN (version, 3); // Support maximum Wayland version 3
+    GST_DEBUG_OBJECT (self, "Binding DMABuf interface with version: %d", bind_version);
+
+    self->dmabuf = wl_registry_bind (registry, id, &zwp_linux_dmabuf_v1_interface, bind_version);
     zwp_linux_dmabuf_v1_add_listener (self->dmabuf, &dmabuf_listener, self);
+
+    g_array_set_size (self->dmabuf_formats, 0);
+    g_array_set_size (self->dmabuf_format_modifiers, 0);
   }
 }
 
diff --git a/ext/wayland/wldisplay.h b/ext/wayland/wldisplay.h
index f2025a6..d12b04a 100644
--- a/ext/wayland/wldisplay.h
+++ b/ext/wayland/wldisplay.h
@@ -41,6 +41,11 @@ G_BEGIN_DECLS
 typedef struct _GstWlDisplay GstWlDisplay;
 typedef struct _GstWlDisplayClass GstWlDisplayClass;
 
+typedef struct {
+    guint32 format;
+    guint64 modifier;
+} GstWlDmaBufFormatModifier;
+
 struct _GstWlDisplay
 {
   GObject parent_instance;
@@ -62,6 +67,8 @@ struct _GstWlDisplay
   struct zwp_linux_dmabuf_v1 *dmabuf;
   GArray *shm_formats;
   GArray *dmabuf_formats;
+  GArray *dmabuf_format_modifiers;  /* Store the supported format-modifier combinations. */
+  guint32 dmabuf_version;          /* dmabuf interface version */
 
   /* private */
   gboolean own_display;
@@ -94,6 +101,9 @@ gboolean gst_wl_display_check_format_for_shm (GstWlDisplay * display,
     GstVideoFormat format);
 gboolean gst_wl_display_check_format_for_dmabuf (GstWlDisplay * display,
     GstVideoFormat format);
+gboolean gst_wl_display_check_format_modifier_for_dmabuf (GstWlDisplay * display,
+    GstVideoFormat format, uint64_t modifier);
+uint32_t gst_wl_display_get_dmabuf_version (GstWlDisplay * display);
 
 G_END_DECLS
 
-- 
2.25.1

