* [PATCH v3 0/6] ui: support multi plane texture
@ 2025-03-27 2:58 yuq825
2025-03-27 2:58 ` [PATCH v3 1/6] ui/dmabuf: extend QemuDmaBuf to support multi-plane yuq825
` (5 more replies)
0 siblings, 6 replies; 8+ messages in thread
From: yuq825 @ 2025-03-27 2:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Qiang Yu
From: Qiang Yu <yuq825@gmail.com>
mesa/radeonsi is going to support explicit modifier with this MR:
* https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/31658
The side effect is some texture will become multi-plane which
breaks qemu. Because qemu currently only support single plane
texture.
For example, texture with DCC (a compressed format) enabled modifier
will expose one plane for compressed data, another plane with metadata
for compression.
This patch serial fix qemu to support multi-plane texture for
DBus and SPICE display, other display seems not affected by multi
plane.
This patch serial also depends on the spice changes here:
* https://gitlab.freedesktop.org/spice/spice/-/merge_requests/232
SPICE client change here:
* https://gitlab.freedesktop.org/spice/spice-gtk/-/merge_requests/130
DBus client change here:
* https://gitlab.com/marcandre.lureau/qemu-display/-/merge_requests/5
v3:
* dbus rename interface, add more args
v2:
* change dmabuf API for array length
* check spice_qxl_gl_scanout2 API instead of bumping spice version
Qiang Yu (6):
ui/dmabuf: extend QemuDmaBuf to support multi-plane
ui/egl: require EGL_EXT_image_dma_buf_import_modifiers
ui/egl: use DRM_FORMAT_MOD_INVALID as default modifier
ui/egl: support multi-plane dmabuf when egl export/import
ui/dbus: change dbus ScanoutDMABUF interface
ui/spice: support multi plane dmabuf scanout
hw/display/vhost-user-gpu.c | 9 ++-
hw/display/virtio-gpu-udmabuf.c | 8 +-
hw/vfio/display.c | 7 +-
include/ui/dmabuf.h | 20 +++--
include/ui/egl-helpers.h | 5 +-
meson.build | 5 ++
ui/dbus-display1.xml | 45 +++++++++++
ui/dbus-listener.c | 127 ++++++++++++++++++++++++++++----
ui/dmabuf.c | 77 +++++++++++++------
ui/egl-helpers.c | 102 ++++++++++++++++++-------
ui/spice-display.c | 102 ++++++++++++++++++-------
11 files changed, 397 insertions(+), 110 deletions(-)
--
2.43.0
^ permalink raw reply [flat|nested] 8+ messages in thread
* [PATCH v3 1/6] ui/dmabuf: extend QemuDmaBuf to support multi-plane
2025-03-27 2:58 [PATCH v3 0/6] ui: support multi plane texture yuq825
@ 2025-03-27 2:58 ` yuq825
2025-03-27 2:58 ` [PATCH v3 2/6] ui/egl: require EGL_EXT_image_dma_buf_import_modifiers yuq825
` (4 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: yuq825 @ 2025-03-27 2:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Qiang Yu, Marc-André Lureau
From: Qiang Yu <yuq825@gmail.com>
mesa/radeonsi is going to support explicit modifier which
may export a multi-plane texture. For example, texture with
DCC enabled (a compressed format) has two planes, one with
compressed data, the other with meta data for compression.
v2:
* change API qemu_dmabuf_get_fd/offset/stride to
qemu_dmabuf_get_fds/offsets/strides.
* change API qemu_dmabuf_dup_fd to qemu_dmabuf_dup_fds.
* add an extra arg to these API for the length of the
array.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
hw/display/vhost-user-gpu.c | 6 ++-
hw/display/virtio-gpu-udmabuf.c | 6 ++-
hw/vfio/display.c | 7 +--
include/ui/dmabuf.h | 20 +++++----
ui/dbus-listener.c | 10 ++---
ui/dmabuf.c | 77 +++++++++++++++++++++++----------
ui/egl-helpers.c | 4 +-
ui/spice-display.c | 4 +-
8 files changed, 86 insertions(+), 48 deletions(-)
diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index 2aed6243f6..a7949c7078 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -249,6 +249,8 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
case VHOST_USER_GPU_DMABUF_SCANOUT: {
VhostUserGpuDMABUFScanout *m = &msg->payload.dmabuf_scanout;
int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr);
+ uint32_t offset = 0;
+ uint32_t stride = m->fd_stride;
uint64_t modifier = 0;
QemuDmaBuf *dmabuf;
@@ -282,10 +284,10 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
}
dmabuf = qemu_dmabuf_new(m->width, m->height,
- m->fd_stride, 0, 0,
+ &offset, &stride, 0, 0,
m->fd_width, m->fd_height,
m->fd_drm_fourcc, modifier,
- fd, false, m->fd_flags &
+ &fd, 1, false, m->fd_flags &
VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP);
dpy_gl_scanout_dmabuf(con, dmabuf);
diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c
index 85ca23cb32..34fbe05b7a 100644
--- a/hw/display/virtio-gpu-udmabuf.c
+++ b/hw/display/virtio-gpu-udmabuf.c
@@ -176,16 +176,18 @@ static VGPUDMABuf
struct virtio_gpu_rect *r)
{
VGPUDMABuf *dmabuf;
+ uint32_t offset = 0;
if (res->dmabuf_fd < 0) {
return NULL;
}
dmabuf = g_new0(VGPUDMABuf, 1);
- dmabuf->buf = qemu_dmabuf_new(r->width, r->height, fb->stride,
+ dmabuf->buf = qemu_dmabuf_new(r->width, r->height,
+ &offset, &fb->stride,
r->x, r->y, fb->width, fb->height,
qemu_pixman_to_drm_format(fb->format),
- 0, res->dmabuf_fd, true, false);
+ 0, &res->dmabuf_fd, 1, true, false);
dmabuf->scanout_id = scanout_id;
QTAILQ_INSERT_HEAD(&g->dmabuf.bufs, dmabuf, next);
diff --git a/hw/vfio/display.c b/hw/vfio/display.c
index ea87830fe0..9d882235fb 100644
--- a/hw/vfio/display.c
+++ b/hw/vfio/display.c
@@ -214,6 +214,7 @@ static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev,
struct vfio_device_gfx_plane_info plane;
VFIODMABuf *dmabuf;
int fd, ret;
+ uint32_t offset = 0;
memset(&plane, 0, sizeof(plane));
plane.argsz = sizeof(plane);
@@ -246,10 +247,10 @@ static VFIODMABuf *vfio_display_get_dmabuf(VFIOPCIDevice *vdev,
dmabuf = g_new0(VFIODMABuf, 1);
dmabuf->dmabuf_id = plane.dmabuf_id;
- dmabuf->buf = qemu_dmabuf_new(plane.width, plane.height,
- plane.stride, 0, 0, plane.width,
+ dmabuf->buf = qemu_dmabuf_new(plane.width, plane.height, &offset,
+ &plane.stride, 0, 0, plane.width,
plane.height, plane.drm_format,
- plane.drm_format_mod, fd, false, false);
+ plane.drm_format_mod, &fd, 1, false, false);
if (plane_type == DRM_PLANE_TYPE_CURSOR) {
vfio_display_update_cursor(dmabuf, &plane);
diff --git a/include/ui/dmabuf.h b/include/ui/dmabuf.h
index dc74ba895a..3decdca497 100644
--- a/include/ui/dmabuf.h
+++ b/include/ui/dmabuf.h
@@ -10,24 +10,29 @@
#ifndef DMABUF_H
#define DMABUF_H
+#define DMABUF_MAX_PLANES 4
+
typedef struct QemuDmaBuf QemuDmaBuf;
QemuDmaBuf *qemu_dmabuf_new(uint32_t width, uint32_t height,
- uint32_t stride, uint32_t x,
- uint32_t y, uint32_t backing_width,
- uint32_t backing_height, uint32_t fourcc,
- uint64_t modifier, int dmabuf_fd,
+ const uint32_t *offset, const uint32_t *stride,
+ uint32_t x, uint32_t y,
+ uint32_t backing_width, uint32_t backing_height,
+ uint32_t fourcc, uint64_t modifier,
+ const int32_t *dmabuf_fd, uint32_t num_planes,
bool allow_fences, bool y0_top);
void qemu_dmabuf_free(QemuDmaBuf *dmabuf);
G_DEFINE_AUTOPTR_CLEANUP_FUNC(QemuDmaBuf, qemu_dmabuf_free);
-int qemu_dmabuf_get_fd(QemuDmaBuf *dmabuf);
-int qemu_dmabuf_dup_fd(QemuDmaBuf *dmabuf);
+const int *qemu_dmabuf_get_fds(QemuDmaBuf *dmabuf, int *nfds);
+void qemu_dmabuf_dup_fds(QemuDmaBuf *dmabuf, int *fds, int nfds);
void qemu_dmabuf_close(QemuDmaBuf *dmabuf);
uint32_t qemu_dmabuf_get_width(QemuDmaBuf *dmabuf);
uint32_t qemu_dmabuf_get_height(QemuDmaBuf *dmabuf);
-uint32_t qemu_dmabuf_get_stride(QemuDmaBuf *dmabuf);
+const uint32_t *qemu_dmabuf_get_offsets(QemuDmaBuf *dmabuf, int *noffsets);
+const uint32_t *qemu_dmabuf_get_strides(QemuDmaBuf *dmabuf, int *nstrides);
+uint32_t qemu_dmabuf_get_num_planes(QemuDmaBuf *dmabuf);
uint32_t qemu_dmabuf_get_fourcc(QemuDmaBuf *dmabuf);
uint64_t qemu_dmabuf_get_modifier(QemuDmaBuf *dmabuf);
uint32_t qemu_dmabuf_get_texture(QemuDmaBuf *dmabuf);
@@ -44,6 +49,5 @@ void qemu_dmabuf_set_texture(QemuDmaBuf *dmabuf, uint32_t texture);
void qemu_dmabuf_set_fence_fd(QemuDmaBuf *dmabuf, int32_t fence_fd);
void qemu_dmabuf_set_sync(QemuDmaBuf *dmabuf, void *sync);
void qemu_dmabuf_set_draw_submitted(QemuDmaBuf *dmabuf, bool draw_submitted);
-void qemu_dmabuf_set_fd(QemuDmaBuf *dmabuf, int32_t fd);
#endif
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 51244c9240..65373d519c 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -299,7 +299,7 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
uint64_t modifier;
bool y0_top;
- fd = qemu_dmabuf_get_fd(dmabuf);
+ fd = qemu_dmabuf_get_fds(dmabuf, NULL)[0];
fd_list = g_unix_fd_list_new();
if (g_unix_fd_list_append(fd_list, fd, &err) != 0) {
error_report("Failed to setup dmabuf fdlist: %s", err->message);
@@ -310,7 +310,7 @@ static void dbus_scanout_dmabuf(DisplayChangeListener *dcl,
width = qemu_dmabuf_get_width(dmabuf);
height = qemu_dmabuf_get_height(dmabuf);
- stride = qemu_dmabuf_get_stride(dmabuf);
+ stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
fourcc = qemu_dmabuf_get_fourcc(dmabuf);
modifier = qemu_dmabuf_get_modifier(dmabuf);
y0_top = qemu_dmabuf_get_y0_top(dmabuf);
@@ -505,7 +505,7 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
#ifdef CONFIG_GBM
g_autoptr(QemuDmaBuf) dmabuf = NULL;
int fd;
- uint32_t stride, fourcc;
+ uint32_t offset = 0, stride, fourcc;
uint64_t modifier;
assert(tex_id);
@@ -515,8 +515,8 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
error_report("%s: failed to get fd for texture", __func__);
return;
}
- dmabuf = qemu_dmabuf_new(w, h, stride, x, y, backing_width,
- backing_height, fourcc, modifier, fd,
+ dmabuf = qemu_dmabuf_new(w, h, &offset, &stride, x, y, backing_width,
+ backing_height, fourcc, modifier, &fd, 1,
false, backing_y_0_top);
dbus_scanout_dmabuf(dcl, dmabuf);
diff --git a/ui/dmabuf.c b/ui/dmabuf.c
index df7a09703f..99e085fe88 100644
--- a/ui/dmabuf.c
+++ b/ui/dmabuf.c
@@ -11,10 +11,12 @@
#include "ui/dmabuf.h"
struct QemuDmaBuf {
- int fd;
+ int fd[DMABUF_MAX_PLANES];
uint32_t width;
uint32_t height;
- uint32_t stride;
+ uint32_t offset[DMABUF_MAX_PLANES];
+ uint32_t stride[DMABUF_MAX_PLANES];
+ uint32_t num_planes;
uint32_t fourcc;
uint64_t modifier;
uint32_t texture;
@@ -30,28 +32,33 @@ struct QemuDmaBuf {
};
QemuDmaBuf *qemu_dmabuf_new(uint32_t width, uint32_t height,
- uint32_t stride, uint32_t x,
- uint32_t y, uint32_t backing_width,
- uint32_t backing_height, uint32_t fourcc,
- uint64_t modifier, int32_t dmabuf_fd,
+ const uint32_t *offset, const uint32_t *stride,
+ uint32_t x, uint32_t y,
+ uint32_t backing_width, uint32_t backing_height,
+ uint32_t fourcc, uint64_t modifier,
+ const int32_t *dmabuf_fd, uint32_t num_planes,
bool allow_fences, bool y0_top) {
QemuDmaBuf *dmabuf;
+ assert(num_planes > 0 && num_planes <= DMABUF_MAX_PLANES);
+
dmabuf = g_new0(QemuDmaBuf, 1);
dmabuf->width = width;
dmabuf->height = height;
- dmabuf->stride = stride;
+ memcpy(dmabuf->offset, offset, num_planes * sizeof(*offset));
+ memcpy(dmabuf->stride, stride, num_planes * sizeof(*stride));
dmabuf->x = x;
dmabuf->y = y;
dmabuf->backing_width = backing_width;
dmabuf->backing_height = backing_height;
dmabuf->fourcc = fourcc;
dmabuf->modifier = modifier;
- dmabuf->fd = dmabuf_fd;
+ memcpy(dmabuf->fd, dmabuf_fd, num_planes * sizeof(*dmabuf_fd));
dmabuf->allow_fences = allow_fences;
dmabuf->y0_top = y0_top;
dmabuf->fence_fd = -1;
+ dmabuf->num_planes = num_planes;
return dmabuf;
}
@@ -65,31 +72,39 @@ void qemu_dmabuf_free(QemuDmaBuf *dmabuf)
g_free(dmabuf);
}
-int qemu_dmabuf_get_fd(QemuDmaBuf *dmabuf)
+const int *qemu_dmabuf_get_fds(QemuDmaBuf *dmabuf, int *nfds)
{
assert(dmabuf != NULL);
+ if (nfds)
+ *nfds = ARRAY_SIZE(dmabuf->fd);
+
return dmabuf->fd;
}
-int qemu_dmabuf_dup_fd(QemuDmaBuf *dmabuf)
+void qemu_dmabuf_dup_fds(QemuDmaBuf *dmabuf, int *fds, int nfds)
{
+ int i;
+
assert(dmabuf != NULL);
+ assert(nfds >= dmabuf->num_planes);
- if (dmabuf->fd >= 0) {
- return dup(dmabuf->fd);
- } else {
- return -1;
+ for (i = 0; i < dmabuf->num_planes; i++) {
+ fds[i] = dmabuf->fd[i] >= 0 ? dup(dmabuf->fd[i]) : -1;
}
}
void qemu_dmabuf_close(QemuDmaBuf *dmabuf)
{
+ int i;
+
assert(dmabuf != NULL);
- if (dmabuf->fd >= 0) {
- close(dmabuf->fd);
- dmabuf->fd = -1;
+ for (i = 0; i < dmabuf->num_planes; i++) {
+ if (dmabuf->fd[i] >= 0) {
+ close(dmabuf->fd[i]);
+ dmabuf->fd[i] = -1;
+ }
}
}
@@ -107,13 +122,33 @@ uint32_t qemu_dmabuf_get_height(QemuDmaBuf *dmabuf)
return dmabuf->height;
}
-uint32_t qemu_dmabuf_get_stride(QemuDmaBuf *dmabuf)
+const uint32_t *qemu_dmabuf_get_offsets(QemuDmaBuf *dmabuf, int *noffsets)
+{
+ assert(dmabuf != NULL);
+
+ if (noffsets)
+ *noffsets = ARRAY_SIZE(dmabuf->offset);
+
+ return dmabuf->offset;
+}
+
+const uint32_t *qemu_dmabuf_get_strides(QemuDmaBuf *dmabuf, int *nstrides)
{
assert(dmabuf != NULL);
+ if (nstrides)
+ *nstrides = ARRAY_SIZE(dmabuf->stride);
+
return dmabuf->stride;
}
+uint32_t qemu_dmabuf_get_num_planes(QemuDmaBuf *dmabuf)
+{
+ assert(dmabuf != NULL);
+
+ return dmabuf->num_planes;
+}
+
uint32_t qemu_dmabuf_get_fourcc(QemuDmaBuf *dmabuf)
{
assert(dmabuf != NULL);
@@ -221,9 +256,3 @@ void qemu_dmabuf_set_draw_submitted(QemuDmaBuf *dmabuf, bool draw_submitted)
assert(dmabuf != NULL);
dmabuf->draw_submitted = draw_submitted;
}
-
-void qemu_dmabuf_set_fd(QemuDmaBuf *dmabuf, int32_t fd)
-{
- assert(dmabuf != NULL);
- dmabuf->fd = fd;
-}
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index d591159480..d194d004b7 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -323,9 +323,9 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
attrs[i++] = qemu_dmabuf_get_fourcc(dmabuf);
attrs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT;
- attrs[i++] = qemu_dmabuf_get_fd(dmabuf);
+ attrs[i++] = qemu_dmabuf_get_fds(dmabuf, NULL)[0];
attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
- attrs[i++] = qemu_dmabuf_get_stride(dmabuf);
+ attrs[i++] = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
attrs[i++] = 0;
#ifdef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT
diff --git a/ui/spice-display.c b/ui/spice-display.c
index c794ae0649..40547edb5e 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -1075,10 +1075,10 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
stride, fourcc, false);
}
} else {
- stride = qemu_dmabuf_get_stride(dmabuf);
+ stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
fourcc = qemu_dmabuf_get_fourcc(dmabuf);
y_0_top = qemu_dmabuf_get_y0_top(dmabuf);
- fd = qemu_dmabuf_dup_fd(dmabuf);
+ qemu_dmabuf_dup_fds(dmabuf, &fd, 1);
trace_qemu_spice_gl_forward_dmabuf(ssd->qxl.id, width, height);
/* note: spice server will close the fd, so hand over a dup */
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 2/6] ui/egl: require EGL_EXT_image_dma_buf_import_modifiers
2025-03-27 2:58 [PATCH v3 0/6] ui: support multi plane texture yuq825
2025-03-27 2:58 ` [PATCH v3 1/6] ui/dmabuf: extend QemuDmaBuf to support multi-plane yuq825
@ 2025-03-27 2:58 ` yuq825
2025-03-27 2:58 ` [PATCH v3 3/6] ui/egl: use DRM_FORMAT_MOD_INVALID as default modifier yuq825
` (3 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: yuq825 @ 2025-03-27 2:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Qiang Yu, Marc-André Lureau
From: Qiang Yu <yuq825@gmail.com>
It's used already, just check it explicitly.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
ui/egl-helpers.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index d194d004b7..432863d702 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -257,6 +257,11 @@ int egl_rendernode_init(const char *rendernode, DisplayGLMode mode)
error_report("egl: EGL_MESA_image_dma_buf_export not supported");
goto err;
}
+ if (!epoxy_has_egl_extension(qemu_egl_display,
+ "EGL_EXT_image_dma_buf_import_modifiers")) {
+ error_report("egl: EGL_EXT_image_dma_buf_import_modifiers not supported");
+ goto err;
+ }
qemu_egl_rn_ctx = qemu_egl_init_ctx();
if (!qemu_egl_rn_ctx) {
@@ -308,7 +313,7 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
EGLImageKHR image = EGL_NO_IMAGE_KHR;
EGLint attrs[64];
int i = 0;
- uint64_t modifier;
+ uint64_t modifier = qemu_dmabuf_get_modifier(dmabuf);
uint32_t texture = qemu_dmabuf_get_texture(dmabuf);
if (texture != 0) {
@@ -328,15 +333,12 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
attrs[i++] = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
attrs[i++] = 0;
-#ifdef EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT
- modifier = qemu_dmabuf_get_modifier(dmabuf);
if (modifier) {
attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
attrs[i++] = (modifier >> 0) & 0xffffffff;
attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
attrs[i++] = (modifier >> 32) & 0xffffffff;
}
-#endif
attrs[i++] = EGL_NONE;
image = eglCreateImageKHR(qemu_egl_display,
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 3/6] ui/egl: use DRM_FORMAT_MOD_INVALID as default modifier
2025-03-27 2:58 [PATCH v3 0/6] ui: support multi plane texture yuq825
2025-03-27 2:58 ` [PATCH v3 1/6] ui/dmabuf: extend QemuDmaBuf to support multi-plane yuq825
2025-03-27 2:58 ` [PATCH v3 2/6] ui/egl: require EGL_EXT_image_dma_buf_import_modifiers yuq825
@ 2025-03-27 2:58 ` yuq825
2025-03-27 2:58 ` [PATCH v3 4/6] ui/egl: support multi-plane dmabuf when egl export/import yuq825
` (2 subsequent siblings)
5 siblings, 0 replies; 8+ messages in thread
From: yuq825 @ 2025-03-27 2:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Qiang Yu, Marc-André Lureau
From: Qiang Yu <yuq825@gmail.com>
0 is used as DRM_FORMAT_MOD_LINEAR already.
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
hw/display/vhost-user-gpu.c | 3 ++-
hw/display/virtio-gpu-udmabuf.c | 4 +++-
ui/egl-helpers.c | 3 ++-
3 files changed, 7 insertions(+), 3 deletions(-)
diff --git a/hw/display/vhost-user-gpu.c b/hw/display/vhost-user-gpu.c
index a7949c7078..a6a510db65 100644
--- a/hw/display/vhost-user-gpu.c
+++ b/hw/display/vhost-user-gpu.c
@@ -18,6 +18,7 @@
#include "chardev/char-fe.h"
#include "qapi/error.h"
#include "migration/blocker.h"
+#include "standard-headers/drm/drm_fourcc.h"
typedef enum VhostUserGpuRequest {
VHOST_USER_GPU_NONE = 0,
@@ -251,7 +252,7 @@ vhost_user_gpu_handle_display(VhostUserGPU *g, VhostUserGpuMsg *msg)
int fd = qemu_chr_fe_get_msgfd(&g->vhost_chr);
uint32_t offset = 0;
uint32_t stride = m->fd_stride;
- uint64_t modifier = 0;
+ uint64_t modifier = DRM_FORMAT_MOD_INVALID;
QemuDmaBuf *dmabuf;
if (m->scanout_id >= g->parent_obj.conf.max_outputs) {
diff --git a/hw/display/virtio-gpu-udmabuf.c b/hw/display/virtio-gpu-udmabuf.c
index 34fbe05b7a..de6ce53f16 100644
--- a/hw/display/virtio-gpu-udmabuf.c
+++ b/hw/display/virtio-gpu-udmabuf.c
@@ -25,6 +25,7 @@
#include <linux/memfd.h>
#include "qemu/memfd.h"
#include "standard-headers/linux/udmabuf.h"
+#include "standard-headers/drm/drm_fourcc.h"
static void virtio_gpu_create_udmabuf(struct virtio_gpu_simple_resource *res)
{
@@ -187,7 +188,8 @@ static VGPUDMABuf
&offset, &fb->stride,
r->x, r->y, fb->width, fb->height,
qemu_pixman_to_drm_format(fb->format),
- 0, &res->dmabuf_fd, 1, true, false);
+ DRM_FORMAT_MOD_INVALID, &res->dmabuf_fd,
+ 1, true, false);
dmabuf->scanout_id = scanout_id;
QTAILQ_INSERT_HEAD(&g->dmabuf.bufs, dmabuf, next);
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 432863d702..8c0e394d2b 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -23,6 +23,7 @@
#include "system/system.h"
#include "qapi/error.h"
#include "trace.h"
+#include "standard-headers/drm/drm_fourcc.h"
EGLDisplay *qemu_egl_display;
EGLConfig qemu_egl_config;
@@ -333,7 +334,7 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
attrs[i++] = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
attrs[i++] = 0;
- if (modifier) {
+ if (modifier != DRM_FORMAT_MOD_INVALID) {
attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
attrs[i++] = (modifier >> 0) & 0xffffffff;
attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 4/6] ui/egl: support multi-plane dmabuf when egl export/import
2025-03-27 2:58 [PATCH v3 0/6] ui: support multi plane texture yuq825
` (2 preceding siblings ...)
2025-03-27 2:58 ` [PATCH v3 3/6] ui/egl: use DRM_FORMAT_MOD_INVALID as default modifier yuq825
@ 2025-03-27 2:58 ` yuq825
2025-03-27 2:58 ` [PATCH v3 5/6] ui/dbus: change dbus ScanoutDMABUF interface yuq825
2025-03-27 2:58 ` [PATCH v3 6/6] ui/spice: support multi plane dmabuf scanout yuq825
5 siblings, 0 replies; 8+ messages in thread
From: yuq825 @ 2025-03-27 2:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Qiang Yu, Marc-André Lureau
From: Qiang Yu <yuq825@gmail.com>
v2:
* use new dmabuf API and check length
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
include/ui/egl-helpers.h | 5 ++-
ui/dbus-listener.c | 19 +++++----
ui/egl-helpers.c | 91 ++++++++++++++++++++++++++++++----------
ui/spice-display.c | 58 ++++++++++++++++---------
4 files changed, 121 insertions(+), 52 deletions(-)
diff --git a/include/ui/egl-helpers.h b/include/ui/egl-helpers.h
index 4b8c0d2281..fb80e15142 100644
--- a/include/ui/egl-helpers.h
+++ b/include/ui/egl-helpers.h
@@ -46,8 +46,9 @@ extern int qemu_egl_rn_fd;
extern struct gbm_device *qemu_egl_rn_gbm_dev;
int egl_rendernode_init(const char *rendernode, DisplayGLMode mode);
-int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc,
- EGLuint64KHR *modifier);
+bool egl_dmabuf_export_texture(uint32_t tex_id, int *fd, EGLint *offset,
+ EGLint *stride, EGLint *fourcc, int *num_planes,
+ EGLuint64KHR *modifier);
void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf);
void egl_dmabuf_release_texture(QemuDmaBuf *dmabuf);
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 65373d519c..90147972cd 100644
--- a/ui/dbus-listener.c
+++ b/ui/dbus-listener.c
@@ -504,19 +504,22 @@ static void dbus_scanout_texture(DisplayChangeListener *dcl,
backing_width, backing_height, x, y, w, h);
#ifdef CONFIG_GBM
g_autoptr(QemuDmaBuf) dmabuf = NULL;
- int fd;
- uint32_t offset = 0, stride, fourcc;
+ int fd[DMABUF_MAX_PLANES], num_planes;
+ uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc;
uint64_t modifier;
assert(tex_id);
- fd = egl_get_fd_for_texture(tex_id, (EGLint *)&stride, (EGLint *)&fourcc,
- &modifier);
- if (fd < 0) {
- error_report("%s: failed to get fd for texture", __func__);
+ if (!egl_dmabuf_export_texture(tex_id, fd, (EGLint *)offset, (EGLint *)stride,
+ (EGLint *)&fourcc, &num_planes, &modifier)) {
+ 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, 1,
+ dmabuf = qemu_dmabuf_new(w, h, offset, stride, x, y, backing_width,
+ backing_height, fourcc, modifier, fd, num_planes,
false, backing_y_0_top);
dbus_scanout_dmabuf(dcl, dmabuf);
diff --git a/ui/egl-helpers.c b/ui/egl-helpers.c
index 8c0e394d2b..f76d0c04a2 100644
--- a/ui/egl-helpers.c
+++ b/ui/egl-helpers.c
@@ -283,44 +283,85 @@ err:
return -1;
}
-int egl_get_fd_for_texture(uint32_t tex_id, EGLint *stride, EGLint *fourcc,
- EGLuint64KHR *modifier)
+bool egl_dmabuf_export_texture(uint32_t tex_id, int *fd, EGLint *offset,
+ EGLint *stride, EGLint *fourcc, int *num_planes,
+ EGLuint64KHR *modifier)
{
EGLImageKHR image;
- EGLint num_planes, fd;
+ EGLuint64KHR modifiers[DMABUF_MAX_PLANES];
image = eglCreateImageKHR(qemu_egl_display, eglGetCurrentContext(),
EGL_GL_TEXTURE_2D_KHR,
(EGLClientBuffer)(unsigned long)tex_id,
NULL);
if (!image) {
- return -1;
+ return false;
}
eglExportDMABUFImageQueryMESA(qemu_egl_display, image, fourcc,
- &num_planes, modifier);
- if (num_planes != 1) {
- eglDestroyImageKHR(qemu_egl_display, image);
- return -1;
- }
- eglExportDMABUFImageMESA(qemu_egl_display, image, &fd, stride, NULL);
+ num_planes, modifiers);
+ eglExportDMABUFImageMESA(qemu_egl_display, image, fd, stride, offset);
eglDestroyImageKHR(qemu_egl_display, image);
- return fd;
+ /* Only first modifier matters. */
+ if (modifier)
+ *modifier = modifiers[0];
+
+ return true;
}
void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
{
EGLImageKHR image = EGL_NO_IMAGE_KHR;
EGLint attrs[64];
- int i = 0;
+ int i = 0, j;
uint64_t modifier = qemu_dmabuf_get_modifier(dmabuf);
uint32_t texture = qemu_dmabuf_get_texture(dmabuf);
+ 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);
+
+ EGLint fd_attrs[] = {
+ EGL_DMA_BUF_PLANE0_FD_EXT,
+ EGL_DMA_BUF_PLANE1_FD_EXT,
+ EGL_DMA_BUF_PLANE2_FD_EXT,
+ EGL_DMA_BUF_PLANE3_FD_EXT,
+ };
+ EGLint offset_attrs[] = {
+ EGL_DMA_BUF_PLANE0_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE1_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE2_OFFSET_EXT,
+ EGL_DMA_BUF_PLANE3_OFFSET_EXT,
+ };
+ EGLint stride_attrs[] = {
+ EGL_DMA_BUF_PLANE0_PITCH_EXT,
+ EGL_DMA_BUF_PLANE1_PITCH_EXT,
+ EGL_DMA_BUF_PLANE2_PITCH_EXT,
+ EGL_DMA_BUF_PLANE3_PITCH_EXT,
+ };
+ EGLint modifier_lo_attrs[] = {
+ EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT,
+ EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT,
+ };
+ EGLint modifier_hi_attrs[] = {
+ EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT,
+ EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT,
+ EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT,
+ EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT,
+ };
if (texture != 0) {
return;
}
+ assert(nfds >= num_planes);
+ assert(noffsets >= num_planes);
+ assert(nstrides >= num_planes);
+
attrs[i++] = EGL_WIDTH;
attrs[i++] = qemu_dmabuf_get_backing_width(dmabuf);
attrs[i++] = EGL_HEIGHT;
@@ -328,18 +369,22 @@ void egl_dmabuf_import_texture(QemuDmaBuf *dmabuf)
attrs[i++] = EGL_LINUX_DRM_FOURCC_EXT;
attrs[i++] = qemu_dmabuf_get_fourcc(dmabuf);
- attrs[i++] = EGL_DMA_BUF_PLANE0_FD_EXT;
- attrs[i++] = qemu_dmabuf_get_fds(dmabuf, NULL)[0];
- attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
- attrs[i++] = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
- attrs[i++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
- attrs[i++] = 0;
- if (modifier != DRM_FORMAT_MOD_INVALID) {
- attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT;
- attrs[i++] = (modifier >> 0) & 0xffffffff;
- attrs[i++] = EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT;
- attrs[i++] = (modifier >> 32) & 0xffffffff;
+ for (j = 0; j < num_planes; j++) {
+ attrs[i++] = fd_attrs[j];
+ /* fd[1-3] may be -1 if using a joint buffer for all planes */
+ attrs[i++] = fds[j] >= 0 ? fds[j] : fds[0];
+ attrs[i++] = stride_attrs[j];
+ attrs[i++] = strides[j];
+ attrs[i++] = offset_attrs[j];
+ attrs[i++] = offsets[j];
+ if (modifier != DRM_FORMAT_MOD_INVALID) {
+ attrs[i++] = modifier_lo_attrs[j];
+ attrs[i++] = (modifier >> 0) & 0xffffffff;
+ attrs[i++] = modifier_hi_attrs[j];
+ attrs[i++] = (modifier >> 32) & 0xffffffff;
+ }
}
+
attrs[i++] = EGL_NONE;
image = eglCreateImageKHR(qemu_egl_display,
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 40547edb5e..d7ebb3682d 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -876,19 +876,24 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
- EGLint stride, fourcc;
- int fd;
if (ssd->ds) {
surface_gl_destroy_texture(ssd->gls, ssd->ds);
}
ssd->ds = new_surface;
if (ssd->ds) {
+ uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES];
+ int fd[DMABUF_MAX_PLANES], num_planes, fourcc;
+
surface_gl_create_texture(ssd->gls, ssd->ds);
- fd = egl_get_fd_for_texture(ssd->ds->texture,
- &stride, &fourcc,
- NULL);
- if (fd < 0) {
+ if (!egl_dmabuf_export_texture(ssd->ds->texture, fd, (EGLint *)offset,
+ (EGLint *)stride, &fourcc, &num_planes, NULL)) {
+ surface_gl_destroy_texture(ssd->gls, ssd->ds);
+ return;
+ }
+
+ if (num_planes > 1) {
+ fprintf(stderr, "%s: does not support multi-plane texture\n", __func__);
surface_gl_destroy_texture(ssd->gls, ssd->ds);
return;
}
@@ -899,10 +904,10 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
fourcc);
/* note: spice server will close the fd */
- spice_qxl_gl_scanout(&ssd->qxl, fd,
+ spice_qxl_gl_scanout(&ssd->qxl, fd[0],
surface_width(ssd->ds),
surface_height(ssd->ds),
- stride, fourcc, false);
+ stride[0], fourcc, false);
ssd->have_surface = true;
ssd->have_scanout = false;
@@ -941,20 +946,24 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
void *d3d_tex2d)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
- EGLint stride = 0, fourcc = 0;
- int fd = -1;
+ EGLint offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc = 0;
+ int fd[DMABUF_MAX_PLANES], num_planes;
assert(tex_id);
- fd = egl_get_fd_for_texture(tex_id, &stride, &fourcc, NULL);
- if (fd < 0) {
- fprintf(stderr, "%s: failed to get fd for texture\n", __func__);
+ if (!egl_dmabuf_export_texture(tex_id, fd, offset, stride, &fourcc,
+ &num_planes, NULL)) {
+ fprintf(stderr, "%s: failed to export dmabuf for texture\n", __func__);
+ return;
+ }
+ if (num_planes > 1) {
+ fprintf(stderr, "%s: does not support multi-plane dmabuf\n", __func__);
return;
}
trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc);
/* note: spice server will close the fd */
- spice_qxl_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
- stride, fourcc, y_0_top);
+ spice_qxl_gl_scanout(&ssd->qxl, fd[0], backing_width, backing_height,
+ stride[0], fourcc, y_0_top);
qemu_spice_gl_monitor_config(ssd, x, y, w, h);
ssd->have_surface = false;
ssd->have_scanout = true;
@@ -1064,15 +1073,26 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
/* dest framebuffer */
if (ssd->blit_fb.width != width ||
ssd->blit_fb.height != height) {
+ int fds[DMABUF_MAX_PLANES], num_planes;
+ uint32_t offsets[DMABUF_MAX_PLANES], strides[DMABUF_MAX_PLANES];
+
trace_qemu_spice_gl_render_dmabuf(ssd->qxl.id, width,
height);
egl_fb_destroy(&ssd->blit_fb);
egl_fb_setup_new_tex(&ssd->blit_fb,
width, height);
- fd = egl_get_fd_for_texture(ssd->blit_fb.texture,
- &stride, &fourcc, NULL);
- spice_qxl_gl_scanout(&ssd->qxl, fd, width, height,
- stride, fourcc, false);
+ if (!egl_dmabuf_export_texture(ssd->blit_fb.texture, fds,
+ (EGLint *)offsets, (EGLint *)strides,
+ &fourcc, &num_planes, NULL)) {
+ fprintf(stderr, "%s: failed to export dmabuf for texture\n", __func__);
+ return;
+ }
+ if (num_planes > 1) {
+ fprintf(stderr, "%s: does not support multi-plane dmabuf\n", __func__);
+ return;
+ }
+ spice_qxl_gl_scanout(&ssd->qxl, fds[0], width, height,
+ strides[0], fourcc, false);
}
} else {
stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 5/6] ui/dbus: change dbus ScanoutDMABUF interface
2025-03-27 2:58 [PATCH v3 0/6] ui: support multi plane texture yuq825
` (3 preceding siblings ...)
2025-03-27 2:58 ` [PATCH v3 4/6] ui/egl: support multi-plane dmabuf when egl export/import yuq825
@ 2025-03-27 2:58 ` yuq825
2025-03-27 2:58 ` [PATCH v3 6/6] ui/spice: support multi plane dmabuf scanout yuq825
5 siblings, 0 replies; 8+ messages in thread
From: yuq825 @ 2025-03-27 2:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Qiang Yu, Marc-André Lureau
From: Qiang Yu <yuq825@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.lureau@redhat.com>
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
ui/dbus-display1.xml | 45 +++++++++++++++++
ui/dbus-listener.c | 112 ++++++++++++++++++++++++++++++++++++++++---
2 files changed, 150 insertions(+), 7 deletions(-)
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:
diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c
index 90147972cd..58a7002611 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,85 @@ 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 +593,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 +961,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 +1151,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 +1259,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);
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* [PATCH v3 6/6] ui/spice: support multi plane dmabuf scanout
2025-03-27 2:58 [PATCH v3 0/6] ui: support multi plane texture yuq825
` (4 preceding siblings ...)
2025-03-27 2:58 ` [PATCH v3 5/6] ui/dbus: change dbus ScanoutDMABUF interface yuq825
@ 2025-03-27 2:58 ` yuq825
2025-04-29 11:25 ` Marc-André Lureau
5 siblings, 1 reply; 8+ messages in thread
From: yuq825 @ 2025-03-27 2:58 UTC (permalink / raw)
To: qemu-devel; +Cc: Marc-André Lureau, Qiang Yu
From: Qiang Yu <yuq825@gmail.com>
We need spice version >= 0.15.3 which has spice_qxl_gl_scanout2
API for multi plane scanout support.
v2:
* use new dmabuf API and check length
* check spice_qxl_gl_scanout2 present instead of
bump spice version dependency
Signed-off-by: Qiang Yu <yuq825@gmail.com>
---
meson.build | 5 +++
ui/spice-display.c | 90 +++++++++++++++++++++++++++++-----------------
2 files changed, 63 insertions(+), 32 deletions(-)
diff --git a/meson.build b/meson.build
index 9d9c11731f..7c4c81aa78 100644
--- a/meson.build
+++ b/meson.build
@@ -3173,6 +3173,11 @@ if host_os == 'windows'
}''', name: '_lock_file and _unlock_file'))
endif
+if spice.found()
+ config_host_data.set('HAVE_SPICE_QXL_GL_SCANOUT2',
+ cc.has_function('spice_qxl_gl_scanout2', dependencies: spice))
+endif
+
if host_os == 'windows'
mingw_has_setjmp_longjmp = cc.links('''
#include <setjmp.h>
diff --git a/ui/spice-display.c b/ui/spice-display.c
index d7ebb3682d..38ee47e4c1 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -28,6 +28,8 @@
#include "ui/spice-display.h"
+#include "standard-headers/drm/drm_fourcc.h"
+
bool spice_opengl;
int qemu_spice_rect_is_empty(const QXLRect* r)
@@ -872,6 +874,26 @@ static void spice_gl_update(DisplayChangeListener *dcl,
ssd->gl_updates++;
}
+static void spice_server_gl_scanout(QXLInstance *qxl,
+ const int *fd,
+ uint32_t width, uint32_t height,
+ const uint32_t *offset,
+ const uint32_t *stride,
+ uint32_t num_planes, uint32_t format,
+ uint64_t modifier, int y_0_top)
+{
+#ifdef HAVE_SPICE_QXL_GL_SCANOUT2
+ spice_qxl_gl_scanout2(qxl, fd, width, height, offset, stride,
+ num_planes, format, modifier, y_0_top);
+#else
+ if (num_planes <= 1) {
+ spice_qxl_gl_scanout(qxl, fd[0], width, height, stride[0], format, y_0_top);
+ } else {
+ error_report("SPICE server does not support multi plane GL scanout");
+ }
+#endif
+}
+
static void spice_gl_switch(DisplayChangeListener *dcl,
struct DisplaySurface *new_surface)
{
@@ -884,16 +906,11 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
if (ssd->ds) {
uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES];
int fd[DMABUF_MAX_PLANES], num_planes, fourcc;
+ uint64_t modifier;
surface_gl_create_texture(ssd->gls, ssd->ds);
if (!egl_dmabuf_export_texture(ssd->ds->texture, fd, (EGLint *)offset,
- (EGLint *)stride, &fourcc, &num_planes, NULL)) {
- surface_gl_destroy_texture(ssd->gls, ssd->ds);
- return;
- }
-
- if (num_planes > 1) {
- fprintf(stderr, "%s: does not support multi-plane texture\n", __func__);
+ (EGLint *)stride, &fourcc, &num_planes, &modifier)) {
surface_gl_destroy_texture(ssd->gls, ssd->ds);
return;
}
@@ -904,10 +921,11 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
fourcc);
/* note: spice server will close the fd */
- spice_qxl_gl_scanout(&ssd->qxl, fd[0],
- surface_width(ssd->ds),
- surface_height(ssd->ds),
- stride[0], fourcc, false);
+ spice_server_gl_scanout(&ssd->qxl, fd,
+ surface_width(ssd->ds),
+ surface_height(ssd->ds),
+ offset, stride, num_planes,
+ fourcc, modifier, false);
ssd->have_surface = true;
ssd->have_scanout = false;
@@ -930,7 +948,8 @@ static void qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl)
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
trace_qemu_spice_gl_scanout_disable(ssd->qxl.id);
- spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false);
+ spice_server_gl_scanout(&ssd->qxl, NULL, 0, 0, NULL, NULL, 0, DRM_FORMAT_INVALID,
+ DRM_FORMAT_MOD_INVALID, false);
qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0);
ssd->have_surface = false;
ssd->have_scanout = false;
@@ -948,22 +967,21 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
EGLint offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc = 0;
int fd[DMABUF_MAX_PLANES], num_planes;
+ uint64_t modifier;
assert(tex_id);
if (!egl_dmabuf_export_texture(tex_id, fd, offset, stride, &fourcc,
- &num_planes, NULL)) {
+ &num_planes, &modifier)) {
fprintf(stderr, "%s: failed to export dmabuf for texture\n", __func__);
return;
}
- if (num_planes > 1) {
- fprintf(stderr, "%s: does not support multi-plane dmabuf\n", __func__);
- return;
- }
+
trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc);
/* note: spice server will close the fd */
- spice_qxl_gl_scanout(&ssd->qxl, fd[0], backing_width, backing_height,
- stride[0], fourcc, y_0_top);
+ spice_server_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
+ (uint32_t *)offset, (uint32_t *)stride, num_planes,
+ fourcc, modifier, y_0_top);
qemu_spice_gl_monitor_config(ssd, x, y, w, h);
ssd->have_surface = false;
ssd->have_scanout = true;
@@ -1034,11 +1052,10 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
uint32_t x, uint32_t y, uint32_t w, uint32_t h)
{
SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
- EGLint stride = 0, fourcc = 0;
+ EGLint fourcc = 0;
bool render_cursor = false;
bool y_0_top = false; /* FIXME */
uint64_t cookie;
- int fd;
uint32_t width, height, texture;
if (!ssd->have_scanout) {
@@ -1075,6 +1092,7 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
ssd->blit_fb.height != height) {
int fds[DMABUF_MAX_PLANES], num_planes;
uint32_t offsets[DMABUF_MAX_PLANES], strides[DMABUF_MAX_PLANES];
+ uint64_t modifier;
trace_qemu_spice_gl_render_dmabuf(ssd->qxl.id, width,
height);
@@ -1083,27 +1101,35 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
width, height);
if (!egl_dmabuf_export_texture(ssd->blit_fb.texture, fds,
(EGLint *)offsets, (EGLint *)strides,
- &fourcc, &num_planes, NULL)) {
+ &fourcc, &num_planes, &modifier)) {
fprintf(stderr, "%s: failed to export dmabuf for texture\n", __func__);
return;
}
- if (num_planes > 1) {
- fprintf(stderr, "%s: does not support multi-plane dmabuf\n", __func__);
- return;
- }
- spice_qxl_gl_scanout(&ssd->qxl, fds[0], width, height,
- strides[0], fourcc, false);
+
+ spice_server_gl_scanout(&ssd->qxl, fds, width, height, offsets, strides,
+ num_planes, fourcc, modifier, false);
}
} else {
- stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
+ int fds[DMABUF_MAX_PLANES];
+ int noffsets, nstrides;
+ 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(noffsets >= num_planes);
+ assert(nstrides >= num_planes);
+
fourcc = qemu_dmabuf_get_fourcc(dmabuf);
y_0_top = qemu_dmabuf_get_y0_top(dmabuf);
- qemu_dmabuf_dup_fds(dmabuf, &fd, 1);
+ qemu_dmabuf_dup_fds(dmabuf, fds, DMABUF_MAX_PLANES);
trace_qemu_spice_gl_forward_dmabuf(ssd->qxl.id, width, height);
/* note: spice server will close the fd, so hand over a dup */
- spice_qxl_gl_scanout(&ssd->qxl, fd, width, height,
- stride, fourcc, y_0_top);
+ spice_server_gl_scanout(&ssd->qxl, fds, width, height,
+ offsets, strides, num_planes,
+ fourcc,
+ qemu_dmabuf_get_modifier(dmabuf),
+ y_0_top);
}
qemu_spice_gl_monitor_config(ssd, 0, 0, width, height);
ssd->guest_dmabuf_refresh = false;
--
2.43.0
^ permalink raw reply related [flat|nested] 8+ messages in thread
* Re: [PATCH v3 6/6] ui/spice: support multi plane dmabuf scanout
2025-03-27 2:58 ` [PATCH v3 6/6] ui/spice: support multi plane dmabuf scanout yuq825
@ 2025-04-29 11:25 ` Marc-André Lureau
0 siblings, 0 replies; 8+ messages in thread
From: Marc-André Lureau @ 2025-04-29 11:25 UTC (permalink / raw)
To: yuq825; +Cc: qemu-devel
Hi
On Thu, Mar 27, 2025 at 6:59 AM <yuq825@gmail.com> wrote:
>
> From: Qiang Yu <yuq825@gmail.com>
>
> We need spice version >= 0.15.3 which has spice_qxl_gl_scanout2
> API for multi plane scanout support.
>
> v2:
> * use new dmabuf API and check length
> * check spice_qxl_gl_scanout2 present instead of
> bump spice version dependency
>
> Signed-off-by: Qiang Yu <yuq825@gmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.com>
(for a single-plane case:)
Tested-by: Marc-André Lureau <marcandre.lureau@redhat.com>
Spice didn't release yet with the new API. It should be okay, but I
will wait for the Spice release plan before sending a MR.
> ---
> meson.build | 5 +++
> ui/spice-display.c | 90 +++++++++++++++++++++++++++++-----------------
> 2 files changed, 63 insertions(+), 32 deletions(-)
>
> diff --git a/meson.build b/meson.build
> index 9d9c11731f..7c4c81aa78 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -3173,6 +3173,11 @@ if host_os == 'windows'
> }''', name: '_lock_file and _unlock_file'))
> endif
>
> +if spice.found()
> + config_host_data.set('HAVE_SPICE_QXL_GL_SCANOUT2',
> + cc.has_function('spice_qxl_gl_scanout2', dependencies: spice))
> +endif
> +
> if host_os == 'windows'
> mingw_has_setjmp_longjmp = cc.links('''
> #include <setjmp.h>
> diff --git a/ui/spice-display.c b/ui/spice-display.c
> index d7ebb3682d..38ee47e4c1 100644
> --- a/ui/spice-display.c
> +++ b/ui/spice-display.c
> @@ -28,6 +28,8 @@
>
> #include "ui/spice-display.h"
>
> +#include "standard-headers/drm/drm_fourcc.h"
> +
> bool spice_opengl;
>
> int qemu_spice_rect_is_empty(const QXLRect* r)
> @@ -872,6 +874,26 @@ static void spice_gl_update(DisplayChangeListener *dcl,
> ssd->gl_updates++;
> }
>
> +static void spice_server_gl_scanout(QXLInstance *qxl,
> + const int *fd,
> + uint32_t width, uint32_t height,
> + const uint32_t *offset,
> + const uint32_t *stride,
> + uint32_t num_planes, uint32_t format,
> + uint64_t modifier, int y_0_top)
> +{
> +#ifdef HAVE_SPICE_QXL_GL_SCANOUT2
> + spice_qxl_gl_scanout2(qxl, fd, width, height, offset, stride,
> + num_planes, format, modifier, y_0_top);
> +#else
> + if (num_planes <= 1) {
> + spice_qxl_gl_scanout(qxl, fd[0], width, height, stride[0], format, y_0_top);
> + } else {
> + error_report("SPICE server does not support multi plane GL scanout");
> + }
> +#endif
> +}
> +
> static void spice_gl_switch(DisplayChangeListener *dcl,
> struct DisplaySurface *new_surface)
> {
> @@ -884,16 +906,11 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
> if (ssd->ds) {
> uint32_t offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES];
> int fd[DMABUF_MAX_PLANES], num_planes, fourcc;
> + uint64_t modifier;
>
> surface_gl_create_texture(ssd->gls, ssd->ds);
> if (!egl_dmabuf_export_texture(ssd->ds->texture, fd, (EGLint *)offset,
> - (EGLint *)stride, &fourcc, &num_planes, NULL)) {
> - surface_gl_destroy_texture(ssd->gls, ssd->ds);
> - return;
> - }
> -
> - if (num_planes > 1) {
> - fprintf(stderr, "%s: does not support multi-plane texture\n", __func__);
> + (EGLint *)stride, &fourcc, &num_planes, &modifier)) {
> surface_gl_destroy_texture(ssd->gls, ssd->ds);
> return;
> }
> @@ -904,10 +921,11 @@ static void spice_gl_switch(DisplayChangeListener *dcl,
> fourcc);
>
> /* note: spice server will close the fd */
> - spice_qxl_gl_scanout(&ssd->qxl, fd[0],
> - surface_width(ssd->ds),
> - surface_height(ssd->ds),
> - stride[0], fourcc, false);
> + spice_server_gl_scanout(&ssd->qxl, fd,
> + surface_width(ssd->ds),
> + surface_height(ssd->ds),
> + offset, stride, num_planes,
> + fourcc, modifier, false);
> ssd->have_surface = true;
> ssd->have_scanout = false;
>
> @@ -930,7 +948,8 @@ static void qemu_spice_gl_scanout_disable(DisplayChangeListener *dcl)
> SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
>
> trace_qemu_spice_gl_scanout_disable(ssd->qxl.id);
> - spice_qxl_gl_scanout(&ssd->qxl, -1, 0, 0, 0, 0, false);
> + spice_server_gl_scanout(&ssd->qxl, NULL, 0, 0, NULL, NULL, 0, DRM_FORMAT_INVALID,
> + DRM_FORMAT_MOD_INVALID, false);
> qemu_spice_gl_monitor_config(ssd, 0, 0, 0, 0);
> ssd->have_surface = false;
> ssd->have_scanout = false;
> @@ -948,22 +967,21 @@ static void qemu_spice_gl_scanout_texture(DisplayChangeListener *dcl,
> SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
> EGLint offset[DMABUF_MAX_PLANES], stride[DMABUF_MAX_PLANES], fourcc = 0;
> int fd[DMABUF_MAX_PLANES], num_planes;
> + uint64_t modifier;
>
> assert(tex_id);
> if (!egl_dmabuf_export_texture(tex_id, fd, offset, stride, &fourcc,
> - &num_planes, NULL)) {
> + &num_planes, &modifier)) {
> fprintf(stderr, "%s: failed to export dmabuf for texture\n", __func__);
> return;
> }
> - if (num_planes > 1) {
> - fprintf(stderr, "%s: does not support multi-plane dmabuf\n", __func__);
> - return;
> - }
> +
> trace_qemu_spice_gl_scanout_texture(ssd->qxl.id, w, h, fourcc);
>
> /* note: spice server will close the fd */
> - spice_qxl_gl_scanout(&ssd->qxl, fd[0], backing_width, backing_height,
> - stride[0], fourcc, y_0_top);
> + spice_server_gl_scanout(&ssd->qxl, fd, backing_width, backing_height,
> + (uint32_t *)offset, (uint32_t *)stride, num_planes,
> + fourcc, modifier, y_0_top);
> qemu_spice_gl_monitor_config(ssd, x, y, w, h);
> ssd->have_surface = false;
> ssd->have_scanout = true;
> @@ -1034,11 +1052,10 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
> uint32_t x, uint32_t y, uint32_t w, uint32_t h)
> {
> SimpleSpiceDisplay *ssd = container_of(dcl, SimpleSpiceDisplay, dcl);
> - EGLint stride = 0, fourcc = 0;
> + EGLint fourcc = 0;
> bool render_cursor = false;
> bool y_0_top = false; /* FIXME */
> uint64_t cookie;
> - int fd;
> uint32_t width, height, texture;
>
> if (!ssd->have_scanout) {
> @@ -1075,6 +1092,7 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
> ssd->blit_fb.height != height) {
> int fds[DMABUF_MAX_PLANES], num_planes;
> uint32_t offsets[DMABUF_MAX_PLANES], strides[DMABUF_MAX_PLANES];
> + uint64_t modifier;
>
> trace_qemu_spice_gl_render_dmabuf(ssd->qxl.id, width,
> height);
> @@ -1083,27 +1101,35 @@ static void qemu_spice_gl_update(DisplayChangeListener *dcl,
> width, height);
> if (!egl_dmabuf_export_texture(ssd->blit_fb.texture, fds,
> (EGLint *)offsets, (EGLint *)strides,
> - &fourcc, &num_planes, NULL)) {
> + &fourcc, &num_planes, &modifier)) {
> fprintf(stderr, "%s: failed to export dmabuf for texture\n", __func__);
> return;
> }
> - if (num_planes > 1) {
> - fprintf(stderr, "%s: does not support multi-plane dmabuf\n", __func__);
> - return;
> - }
> - spice_qxl_gl_scanout(&ssd->qxl, fds[0], width, height,
> - strides[0], fourcc, false);
> +
> + spice_server_gl_scanout(&ssd->qxl, fds, width, height, offsets, strides,
> + num_planes, fourcc, modifier, false);
> }
> } else {
> - stride = qemu_dmabuf_get_strides(dmabuf, NULL)[0];
> + int fds[DMABUF_MAX_PLANES];
> + int noffsets, nstrides;
> + 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(noffsets >= num_planes);
> + assert(nstrides >= num_planes);
> +
> fourcc = qemu_dmabuf_get_fourcc(dmabuf);
> y_0_top = qemu_dmabuf_get_y0_top(dmabuf);
> - qemu_dmabuf_dup_fds(dmabuf, &fd, 1);
> + qemu_dmabuf_dup_fds(dmabuf, fds, DMABUF_MAX_PLANES);
>
> trace_qemu_spice_gl_forward_dmabuf(ssd->qxl.id, width, height);
> /* note: spice server will close the fd, so hand over a dup */
> - spice_qxl_gl_scanout(&ssd->qxl, fd, width, height,
> - stride, fourcc, y_0_top);
> + spice_server_gl_scanout(&ssd->qxl, fds, width, height,
> + offsets, strides, num_planes,
> + fourcc,
> + qemu_dmabuf_get_modifier(dmabuf),
> + y_0_top);
> }
> qemu_spice_gl_monitor_config(ssd, 0, 0, width, height);
> ssd->guest_dmabuf_refresh = false;
> --
> 2.43.0
>
--
Marc-André Lureau
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2025-04-29 11:26 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-03-27 2:58 [PATCH v3 0/6] ui: support multi plane texture yuq825
2025-03-27 2:58 ` [PATCH v3 1/6] ui/dmabuf: extend QemuDmaBuf to support multi-plane yuq825
2025-03-27 2:58 ` [PATCH v3 2/6] ui/egl: require EGL_EXT_image_dma_buf_import_modifiers yuq825
2025-03-27 2:58 ` [PATCH v3 3/6] ui/egl: use DRM_FORMAT_MOD_INVALID as default modifier yuq825
2025-03-27 2:58 ` [PATCH v3 4/6] ui/egl: support multi-plane dmabuf when egl export/import yuq825
2025-03-27 2:58 ` [PATCH v3 5/6] ui/dbus: change dbus ScanoutDMABUF interface yuq825
2025-03-27 2:58 ` [PATCH v3 6/6] ui/spice: support multi plane dmabuf scanout yuq825
2025-04-29 11:25 ` Marc-André Lureau
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).