Hi
On Wed, Mar 26, 2025 at 1:34 PM <[email protected]> wrote:
>
> From: Qiang Yu <[email protected]>
>
> To handle multi plane.
>
> v2:
> * use new dmabuf API and check length
>
> Signed-off-by: Qiang Yu <[email protected]>
> ---
> 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