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
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
© 2016 - 2025 Red Hat, Inc.