diff options
Diffstat (limited to 'ui')
-rw-r--r-- | ui/dbus-display1.xml | 45 | ||||
-rw-r--r-- | ui/dbus-listener.c | 129 | ||||
-rw-r--r-- | ui/dmabuf.c | 80 | ||||
-rw-r--r-- | ui/egl-helpers.c | 103 | ||||
-rw-r--r-- | ui/spice-display.c | 108 |
5 files changed, 373 insertions, 92 deletions
diff --git a/ui/dbus-display1.xml b/ui/dbus-display1.xml index 72deefa..4a41a7e 100644 --- a/ui/dbus-display1.xml +++ b/ui/dbus-display1.xml @@ -615,6 +615,51 @@ </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: This interface must be implemented by both the client and the server on diff --git a/ui/dbus-listener.c b/ui/dbus-listener.c index 51244c9..42875b8 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; @@ -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); @@ -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 */ @@ -504,19 +585,18 @@ 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 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; } - 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, num_planes, false, backing_y_0_top); dbus_scanout_dmabuf(dcl, dmabuf); @@ -883,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); @@ -1071,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, @@ -1159,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/dmabuf.c b/ui/dmabuf.c index df7a097..7433a26 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,40 @@ 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 +123,35 @@ 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 +259,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 d591159..9cda2bb 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; @@ -257,6 +258,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) { @@ -277,44 +283,86 @@ 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; - uint64_t modifier; + 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; @@ -322,21 +370,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_fd(dmabuf); - attrs[i++] = EGL_DMA_BUF_PLANE0_PITCH_EXT; - attrs[i++] = qemu_dmabuf_get_stride(dmabuf); - 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; + 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; + } } -#endif + attrs[i++] = EGL_NONE; image = eglCreateImageKHR(qemu_egl_display, diff --git a/ui/spice-display.c b/ui/spice-display.c index c794ae0..9c39d2c 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,23 +874,48 @@ 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) { 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; + uint64_t modifier; + 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, + &modifier)) { surface_gl_destroy_texture(ssd->gls, ssd->ds); return; } @@ -899,10 +926,11 @@ static void spice_gl_switch(DisplayChangeListener *dcl, fourcc); /* note: spice server will close the fd */ - spice_qxl_gl_scanout(&ssd->qxl, fd, - surface_width(ssd->ds), - surface_height(ssd->ds), - stride, 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; @@ -925,7 +953,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; @@ -941,20 +970,23 @@ 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; + uint64_t modifier; 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, &modifier)) { + fprintf(stderr, "%s: failed to export dmabuf for texture\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_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; @@ -1025,11 +1057,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) { @@ -1064,26 +1095,47 @@ 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]; + uint64_t modifier; + 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, &modifier)) { + fprintf(stderr, + "%s: failed to export dmabuf for texture\n", __func__); + return; + } + + spice_server_gl_scanout(&ssd->qxl, fds, width, height, offsets, strides, + num_planes, fourcc, modifier, false); } } else { - stride = qemu_dmabuf_get_stride(dmabuf); + 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); - fd = qemu_dmabuf_dup_fd(dmabuf); + 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; |