From: Qiang Yu <yuq...@gmail.com> To handle multi plane.
v3: * rename interface * add x/y/backing_width/backing_height arg v2: * use new dmabuf API and check length Reviewed-by: Marc-André Lureau <marcandre.lur...@redhat.com> Signed-off-by: Qiang Yu <yuq...@gmail.com> Message-ID: <20250327025848.46962-6-yuq...@gmail.com> [ Fix style ] Signed-off-by: Marc-André Lureau <marcandre.lur...@redhat.com> --- ui/dbus-listener.c | 114 ++++++++++++++++++++++++++++++++++++++++--- ui/dbus-display1.xml | 45 +++++++++++++++++ 2 files changed, 152 insertions(+), 7 deletions(-) diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 90147972cd..42875b8eed 100644 --- a/ui/dbus-listener.c +++ b/ui/dbus-listener.c @@ -85,6 +85,7 @@ struct _DBusDisplayListener { #endif #else /* !WIN32 */ QemuDBusDisplay1ListenerUnixMap *map_proxy; + QemuDBusDisplay1ListenerUnixScanoutDMABUF2 *scanout_dmabuf_v2_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_v1(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,87 @@ 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_v2(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 x, y, width, height, fourcc, backing_width, backing_height; + 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); + + x = qemu_dmabuf_get_x(dmabuf); + y = qemu_dmabuf_get_y(dmabuf); + width = qemu_dmabuf_get_width(dmabuf); + height = qemu_dmabuf_get_height(dmabuf); + fourcc = qemu_dmabuf_get_fourcc(dmabuf); + backing_width = qemu_dmabuf_get_backing_width(dmabuf); + backing_height = qemu_dmabuf_get_backing_height(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_scanout_dmabuf2_call_scanout_dmabuf2( + ddl->scanout_dmabuf_v2_proxy, fd, x, y, width, height, offset, stride, + num_planes, fourcc, backing_width, backing_height, 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->scanout_dmabuf_v2_proxy) { + dbus_scanout_dmabuf_v2(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_v1(ddl, dmabuf); + } +} #endif /* GBM */ #endif /* OPENGL */ @@ -514,10 +595,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 +963,8 @@ dbus_display_listener_dispose(GObject *object) #ifdef CONFIG_OPENGL egl_fb_destroy(&ddl->fb); #endif +#else /* !WIN32 */ + g_clear_object(&ddl->scanout_dmabuf_v2_proxy); #endif G_OBJECT_CLASS(dbus_display_listener_parent_class)->dispose(object); @@ -1074,6 +1153,26 @@ dbus_display_listener_setup_shared_map(DBusDisplayListener *ddl) #endif } +static void dbus_display_listener_setup_scanout_dmabuf_v2(DBusDisplayListener *ddl) +{ +#ifndef WIN32 + g_autoptr(GError) err = NULL; + + if (!dbus_display_listener_implements( + ddl, "org.qemu.Display1.Listener.Unix.ScanoutDMABUF2")) { + return; + } + ddl->scanout_dmabuf_v2_proxy = + qemu_dbus_display1_listener_unix_scanout_dmabuf2_proxy_new_sync( + ddl->conn, G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, + "/org/qemu/Display1/Listener", NULL, &err); + if (!ddl->scanout_dmabuf_v2_proxy) { + g_debug("Failed to setup Unix scanout dmabuf v2 proxy: %s", err->message); + return; + } +#endif +} + static GDBusMessage * dbus_filter(GDBusConnection *connection, GDBusMessage *message, @@ -1162,6 +1261,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_scanout_dmabuf_v2(ddl); con = qemu_console_lookup_by_index(dbus_display_console_get_index(console)); assert(con); diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml index 72deefa455..4a41a7e0f3 100644 --- a/ui/dbus-display1.xml +++ b/ui/dbus-display1.xml @@ -614,6 +614,51 @@ </method> </interface> + <!-- + org.qemu.Display1.Listener.Unix.ScanoutDMABUF2: + + This optional client-side interface can complement + org.qemu.Display1.Listener on ``/org/qemu/Display1/Listener`` for + Unix-specific DMABUF scanout setup which support multi plane. + --> + <?if $(env.HOST_OS) != windows?> + <interface name="org.qemu.Display1.Listener.Unix.ScanoutDMABUF2"> + <!-- + ScanoutDMABUF2: + @dmabuf: DMABUF file descriptor of each plane. + @x: display x offset, in pixels + @y: display y offset, in pixels + @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. + @backing_width: backing framebuffer width, in pixels + @backing_height: backing framebuffer height, in pixels + @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="x" direction="in"/> + <arg type="u" name="y" 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="u" name="backing_width" direction="in"/> + <arg type="u" name="backing_height" direction="in"/> + <arg type="t" name="modifier" direction="in"/> + <arg type="b" name="y0_top" direction="in"/> + </method> + </interface> + <?endif?> + <!-- org.qemu.Display1.Clipboard: -- 2.49.0