[PATCH v2 5/6] ui/dbus: change dbus ScanoutDMABUF interface

yuq825@gmail.com posted 6 patches 1 week ago
There is a newer version of this series
[PATCH v2 5/6] ui/dbus: change dbus ScanoutDMABUF interface
Posted by yuq825@gmail.com 1 week ago
From: Qiang Yu <yuq825@gmail.com>

To handle multi plane.

v2:
  * use new dmabuf API and check length

Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
 ui/dbus-display1.xml |  37 +++++++++++++++
 ui/dbus-listener.c   | 108 ++++++++++++++++++++++++++++++++++++++++---
 2 files changed, 138 insertions(+), 7 deletions(-)

diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
index 72deefa455..c1d1a402b7 100644
--- a/ui/dbus-display1.xml
+++ b/ui/dbus-display1.xml
@@ -614,6 +614,43 @@
     </method>
   </interface>
 
+  <!--
+      org.qemu.Display1.Listener.Unix.MultiPlane:
+
+      This optional client-side interface can complement
+      org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for
+      Unix-specific multi plane DMABUF scanout setup.
+  -->
+  <?if $(env.HOST_OS) != windows?>
+  <interface name="org.qemu.Display1.Listener.Unix.MultiPlane">
+    <!--
+        ScanoutDMABUF2:
+        @dmabuf: DMABUF file descriptor of each plane.
+        @width: display width, in pixels.
+        @height: display height, in pixels.
+        @offset: offset of each plane, in bytes.
+        @stride: stride of each plane, in bytes.
+        @num_planes: plane number.
+        @fourcc: DMABUF fourcc.
+        @modifier: DMABUF modifier.
+        @y0_top: whether Y position 0 is the top or not.
+
+        Resize and update the display content with DMABUF.
+    -->
+    <method name="ScanoutDMABUF2">
+      <arg type="ah" name="dmabuf" direction="in"/>
+      <arg type="u" name="width" direction="in"/>
+      <arg type="u" name="height" direction="in"/>
+      <arg type="au" name="offset" direction="in"/>
+      <arg type="au" name="stride" direction="in"/>
+      <arg type="u" name="num_planes" direction="in"/>
+      <arg type="u" name="fourcc" direction="in"/>
+      <arg type="t" name="modifier" direction="in"/>
+      <arg type="b" name="y0_top" direction="in"/>
+    </method>
+  </interface>
+  <?endif?>
+
   <!--
       org.qemu.Display1.Clipboard:
 
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 90147972cd..a225890084 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -85,6 +85,7 @@ struct _DBusDisplayListener {
 #endif
 #else /* !WIN32 */
     QemuDBusDisplay1ListenerUnixMap *map_proxy;
+    QemuDBusDisplay1ListenerUnixMultiPlane *multi_plane_proxy;
 #endif
 
     guint dbus_filter;
@@ -288,10 +289,9 @@ static void dbus_call_update_gl(DisplayChangeListener *dcl,
 }
 
 #ifdef CONFIG_GBM
-static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
-                                QemuDmaBuf *dmabuf)
+static void dbus_scanout_dmabuf_single_plane(DBusDisplayListener *ddl,
+                                             QemuDmaBuf *dmabuf)
 {
-    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
     g_autoptr(GError) err = NULL;
     g_autoptr(GUnixFDList) fd_list = NULL;
     int fd;
@@ -322,6 +322,81 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
         y0_top, G_DBUS_CALL_FLAGS_NONE,
         -1, fd_list, NULL, NULL, NULL);
 }
+
+static void dbus_scanout_dmabuf_multi_plane(DBusDisplayListener *ddl,
+                                            QemuDmaBuf *dmabuf)
+{
+    g_autoptr(GError) err = NULL;
+    g_autoptr(GUnixFDList) fd_list = NULL;
+    int i, fd_index[DMABUF_MAX_PLANES], num_fds;
+    uint32_t width, height, fourcc;
+    GVariant *fd, *offset, *stride, *fd_handles[DMABUF_MAX_PLANES];
+    uint64_t modifier;
+    bool y0_top;
+    int nfds, noffsets, nstrides;
+    const int *fds = qemu_dmabuf_get_fds(dmabuf, &nfds);
+    const uint32_t *offsets = qemu_dmabuf_get_offsets(dmabuf, &noffsets);
+    const uint32_t *strides = qemu_dmabuf_get_strides(dmabuf, &nstrides);
+    uint32_t num_planes = qemu_dmabuf_get_num_planes(dmabuf);
+
+    assert(nfds >= num_planes);
+    assert(noffsets >= num_planes);
+    assert(nstrides >= num_planes);
+
+    fd_list = g_unix_fd_list_new();
+
+    for (num_fds = 0; num_fds < num_planes; num_fds++) {
+        int plane_fd = fds[num_fds];
+
+        if (plane_fd < 0)
+            break;
+
+        fd_index[num_fds] = g_unix_fd_list_append(fd_list, plane_fd, &err);
+        if (fd_index[num_fds] < 0) {
+            error_report("Failed to setup dmabuf fdlist: %s", err->message);
+            return;
+        }
+    }
+
+    ddl_discard_display_messages(ddl);
+
+    width = qemu_dmabuf_get_width(dmabuf);
+    height = qemu_dmabuf_get_height(dmabuf);
+    fourcc = qemu_dmabuf_get_fourcc(dmabuf);
+    modifier = qemu_dmabuf_get_modifier(dmabuf);
+    y0_top = qemu_dmabuf_get_y0_top(dmabuf);
+
+    offset = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+                                       offsets, num_planes, sizeof(uint32_t));
+    stride = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
+                                       strides, num_planes, sizeof(uint32_t));
+
+    for (i = 0; i < num_fds; i++) {
+        fd_handles[i] = g_variant_new_handle(fd_index[i]);
+    }
+    fd = g_variant_new_array(G_VARIANT_TYPE_HANDLE, fd_handles, num_fds);
+
+    qemu_dbus_display1_listener_unix_multi_plane_call_scanout_dmabuf2(
+        ddl->multi_plane_proxy, fd, width, height, offset, stride, num_planes,
+        fourcc, modifier, y0_top, G_DBUS_CALL_FLAGS_NONE,
+        -1, fd_list, NULL, NULL, NULL);
+}
+
+static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
+                                QemuDmaBuf *dmabuf)
+{
+    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
+
+    if (ddl->multi_plane_proxy) {
+        dbus_scanout_dmabuf_multi_plane(ddl, dmabuf);
+    } else {
+        if (qemu_dmabuf_get_num_planes(dmabuf) > 1) {
+            g_debug("org.qemu.Display1.Listener.ScanoutDMABUF does not support mutli plane");
+            return;
+        }
+        dbus_scanout_dmabuf_single_plane(ddl, dmabuf);
+    }
+}
 #endif /* GBM */
 #endif /* OPENGL */
 
@@ -514,10 +589,6 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
         error_report("%s: failed to export dmabuf for texture", __func__);
         return;
     }
-    if (num_planes > 1) {
-        error_report("%s: does not support multi-plane dmabuf", __func__);
-        return;
-    }
     dmabuf = qemu_dmabuf_new(w, h, offset, stride, x, y, backing_width,
                              backing_height, fourcc, modifier, fd, num_planes,
                              false, backing_y_0_top);
@@ -886,6 +957,8 @@ dbus_display_listener_dispose(GObject *object)
 #ifdef CONFIG_OPENGL
     egl_fb_destroy(&ddl->fb);
 #endif
+#else /* !WIN32 */
+    g_clear_object(&ddl->multi_plane_proxy);
 #endif
 
     G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
@@ -1074,6 +1147,26 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
 #endif
 }
 
+static void dbus_display_listener_setup_multi_plane(DBusDisplayListener *ddl)
+{
+#ifndef WIN32
+    g_autoptr(GError) err = NULL;
+
+    if (!dbus_display_listener_implements(
+            ddl, "org.qemu.Display1.Listener.Unix.MultiPlane")) {
+        return;
+    }
+    ddl->multi_plane_proxy =
+        qemu_dbus_display1_listener_unix_multi_plane_proxy_new_sync(
+            ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
+            "/org/qemu/Display1/Listener", NULL, &err);
+    if (!ddl->multi_plane_proxy) {
+        g_debug("Failed to setup Unix multi plane proxy: %s", err->message);
+        return;
+    }
+#endif
+}
+
 static GDBusMessage *
 dbus_filter(GDBusConnection *connection,
             GDBusMessage    *message,
@@ -1162,6 +1255,7 @@ dbus_display_listener_new(const char *bus_name,
     dbus_display_listener_setup_shared_map(ddl);
     trace_dbus_can_share_map(ddl->can_share_map);
     dbus_display_listener_setup_d3d11(ddl);
+    dbus_display_listener_setup_multi_plane(ddl);
 
     con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
     assert(con);
-- 
2.43.0
Re: [PATCH v2 5/6] ui/dbus: change dbus ScanoutDMABUF interface
Posted by Marc-André Lureau 1 week ago
Hi

On Wed, Mar 26, 2025 at 1:34 PM <yuq825@gmail.com> wrote:
>
> From: Qiang Yu <yuq825@gmail.com>
>
> To handle multi plane.
>
> v2:
>   * use new dmabuf API and check length
>
> Signed-off-by: Qiang Yu <yuq825@gmail.com>
> ---
>  ui/dbus-display1.xml |  37 +++++++++++++++
>  ui/dbus-listener.c   | 108 ++++++++++++++++++++++++++++++++++++++++---
>  2 files changed, 138 insertions(+), 7 deletions(-)
>
> diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml
> index 72deefa455..c1d1a402b7 100644
> --- a/ui/dbus-display1.xml
> +++ b/ui/dbus-display1.xml
> @@ -614,6 +614,43 @@
>      </method>
>    </interface>
>
> +  <!--
> +      org.qemu.Display1.Listener.Unix.MultiPlane:
> +
> +      This optional client-side interface can complement
> +      org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for
> +      Unix-specific multi plane DMABUF scanout setup.
> +  -->
> +  <?if $(env.HOST_OS) != windows?>
> +  <interface name="org.qemu.Display1.Listener.Unix.MultiPlane">

As it may be used with single plane, it is essentially ScanoutDMABUF2,
I think we should use that name rather than MultiPlane.

> +    <!--
> +        ScanoutDMABUF2:
> +        @dmabuf: DMABUF file descriptor of each plane.
> +        @width: display width, in pixels.
> +        @height: display height, in pixels.
> +        @offset: offset of each plane, in bytes.
> +        @stride: stride of each plane, in bytes.
> +        @num_planes: plane number.
> +        @fourcc: DMABUF fourcc.
> +        @modifier: DMABUF modifier.
> +        @y0_top: whether Y position 0 is the top or not.

Let's use this opportunity adding a few fields that went missing in
V1: x, y, backing_width, backing_height.

lgtm otherwise

> +
> +        Resize and update the display content with DMABUF.
> +    -->
> +    <method name="ScanoutDMABUF2">
> +      <arg type="ah" name="dmabuf" direction="in"/>
> +      <arg type="u" name="width" direction="in"/>
> +      <arg type="u" name="height" direction="in"/>
> +      <arg type="au" name="offset" direction="in"/>
> +      <arg type="au" name="stride" direction="in"/>
> +      <arg type="u" name="num_planes" direction="in"/>
> +      <arg type="u" name="fourcc" direction="in"/>
> +      <arg type="t" name="modifier" direction="in"/>
> +      <arg type="b" name="y0_top" direction="in"/>
> +    </method>
> +  </interface>
> +  <?endif?>
> +
>    <!--
>        org.qemu.Display1.Clipboard:
>
> diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
> index 90147972cd..a225890084 100644
> --- a/ui/dbus-listener.c
> +++ b/ui/dbus-listener.c
> @@ -85,6 +85,7 @@ struct _DBusDisplayListener {
>  #endif
>  #else /* !WIN32 */
>      QemuDBusDisplay1ListenerUnixMap *map_proxy;
> +    QemuDBusDisplay1ListenerUnixMultiPlane *multi_plane_proxy;
>  #endif
>
>      guint dbus_filter;
> @@ -288,10 +289,9 @@ static void dbus_call_update_gl(DisplayChangeListener *dcl,
>  }
>
>  #ifdef CONFIG_GBM
> -static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
> -                                QemuDmaBuf *dmabuf)
> +static void dbus_scanout_dmabuf_single_plane(DBusDisplayListener *ddl,
> +                                             QemuDmaBuf *dmabuf)
>  {
> -    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
>      g_autoptr(GError) err = NULL;
>      g_autoptr(GUnixFDList) fd_list = NULL;
>      int fd;
> @@ -322,6 +322,81 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
>          y0_top, G_DBUS_CALL_FLAGS_NONE,
>          -1, fd_list, NULL, NULL, NULL);
>  }
> +
> +static void dbus_scanout_dmabuf_multi_plane(DBusDisplayListener *ddl,
> +                                            QemuDmaBuf *dmabuf)
> +{
> +    g_autoptr(GError) err = NULL;
> +    g_autoptr(GUnixFDList) fd_list = NULL;
> +    int i, fd_index[DMABUF_MAX_PLANES], num_fds;
> +    uint32_t width, height, fourcc;
> +    GVariant *fd, *offset, *stride, *fd_handles[DMABUF_MAX_PLANES];
> +    uint64_t modifier;
> +    bool y0_top;
> +    int nfds, noffsets, nstrides;
> +    const int *fds = qemu_dmabuf_get_fds(dmabuf, &nfds);
> +    const uint32_t *offsets = qemu_dmabuf_get_offsets(dmabuf, &noffsets);
> +    const uint32_t *strides = qemu_dmabuf_get_strides(dmabuf, &nstrides);
> +    uint32_t num_planes = qemu_dmabuf_get_num_planes(dmabuf);
> +
> +    assert(nfds >= num_planes);
> +    assert(noffsets >= num_planes);
> +    assert(nstrides >= num_planes);
> +
> +    fd_list = g_unix_fd_list_new();
> +
> +    for (num_fds = 0; num_fds < num_planes; num_fds++) {
> +        int plane_fd = fds[num_fds];
> +
> +        if (plane_fd < 0)
> +            break;
> +
> +        fd_index[num_fds] = g_unix_fd_list_append(fd_list, plane_fd, &err);
> +        if (fd_index[num_fds] < 0) {
> +            error_report("Failed to setup dmabuf fdlist: %s", err->message);
> +            return;
> +        }
> +    }
> +
> +    ddl_discard_display_messages(ddl);
> +
> +    width = qemu_dmabuf_get_width(dmabuf);
> +    height = qemu_dmabuf_get_height(dmabuf);
> +    fourcc = qemu_dmabuf_get_fourcc(dmabuf);
> +    modifier = qemu_dmabuf_get_modifier(dmabuf);
> +    y0_top = qemu_dmabuf_get_y0_top(dmabuf);
> +
> +    offset = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
> +                                       offsets, num_planes, sizeof(uint32_t));
> +    stride = g_variant_new_fixed_array(G_VARIANT_TYPE_UINT32,
> +                                       strides, num_planes, sizeof(uint32_t));
> +
> +    for (i = 0; i < num_fds; i++) {
> +        fd_handles[i] = g_variant_new_handle(fd_index[i]);
> +    }
> +    fd = g_variant_new_array(G_VARIANT_TYPE_HANDLE, fd_handles, num_fds);
> +
> +    qemu_dbus_display1_listener_unix_multi_plane_call_scanout_dmabuf2(
> +        ddl->multi_plane_proxy, fd, width, height, offset, stride, num_planes,
> +        fourcc, modifier, y0_top, G_DBUS_CALL_FLAGS_NONE,
> +        -1, fd_list, NULL, NULL, NULL);
> +}
> +
> +static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
> +                                QemuDmaBuf *dmabuf)
> +{
> +    DBusDisplayListener *ddl = container_of(dcl, DBusDisplayListener, dcl);
> +
> +    if (ddl->multi_plane_proxy) {
> +        dbus_scanout_dmabuf_multi_plane(ddl, dmabuf);
> +    } else {
> +        if (qemu_dmabuf_get_num_planes(dmabuf) > 1) {
> +            g_debug("org.qemu.Display1.Listener.ScanoutDMABUF does not support mutli plane");
> +            return;
> +        }
> +        dbus_scanout_dmabuf_single_plane(ddl, dmabuf);
> +    }
> +}
>  #endif /* GBM */
>  #endif /* OPENGL */
>
> @@ -514,10 +589,6 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
>          error_report("%s: failed to export dmabuf for texture", __func__);
>          return;
>      }
> -    if (num_planes > 1) {
> -        error_report("%s: does not support multi-plane dmabuf", __func__);
> -        return;
> -    }
>      dmabuf = qemu_dmabuf_new(w, h, offset, stride, x, y, backing_width,
>                               backing_height, fourcc, modifier, fd, num_planes,
>                               false, backing_y_0_top);
> @@ -886,6 +957,8 @@ dbus_display_listener_dispose(GObject *object)
>  #ifdef CONFIG_OPENGL
>      egl_fb_destroy(&ddl->fb);
>  #endif
> +#else /* !WIN32 */
> +    g_clear_object(&ddl->multi_plane_proxy);
>  #endif
>
>      G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object);
> @@ -1074,6 +1147,26 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl)
>  #endif
>  }
>
> +static void dbus_display_listener_setup_multi_plane(DBusDisplayListener *ddl)
> +{
> +#ifndef WIN32
> +    g_autoptr(GError) err = NULL;
> +
> +    if (!dbus_display_listener_implements(
> +            ddl, "org.qemu.Display1.Listener.Unix.MultiPlane")) {
> +        return;
> +    }
> +    ddl->multi_plane_proxy =
> +        qemu_dbus_display1_listener_unix_multi_plane_proxy_new_sync(
> +            ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL,
> +            "/org/qemu/Display1/Listener", NULL, &err);
> +    if (!ddl->multi_plane_proxy) {
> +        g_debug("Failed to setup Unix multi plane proxy: %s", err->message);
> +        return;
> +    }
> +#endif
> +}
> +
>  static GDBusMessage *
>  dbus_filter(GDBusConnection *connection,
>              GDBusMessage    *message,
> @@ -1162,6 +1255,7 @@ dbus_display_listener_new(const char *bus_name,
>      dbus_display_listener_setup_shared_map(ddl);
>      trace_dbus_can_share_map(ddl->can_share_map);
>      dbus_display_listener_setup_d3d11(ddl);
> +    dbus_display_listener_setup_multi_plane(ddl);
>
>      con = qemu_console_lookup_by_index(dbus_display_console_get_index(console));
>      assert(con);
> --
> 2.43.0
>


-- 
Marc-André Lureau