From 98a050ca93afd8686b78c3a71cbeef23e0bc420b Mon Sep 17 00:00:00 2001 From: Qiang Yu Date: Thu, 27 Mar 2025 10:58:48 +0800 Subject: [PATCH] ui/spice: support multi plane dmabuf scanout MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Marc-André Lureau Tested-by: Marc-André Lureau [ Fix style ] Signed-off-by: Marc-André Lureau Message-ID: <20250327025848.46962-7-yuq825@gmail.com> --- meson.build | 5 +++ ui/spice-display.c | 98 ++++++++++++++++++++++++++++++---------------- 2 files changed, 69 insertions(+), 34 deletions(-) diff --git a/meson.build b/meson.build index 8ae70dbe45..9831f0bd71 100644 --- a/meson.build +++ b/meson.build @@ -3168,6 +3168,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 diff --git a/ui/spice-display.c b/ui/spice-display.c index a9fee87a72..9c39d2c5c8 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,16 @@ 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__); + 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; } @@ -904,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[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 +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; @@ -948,22 +972,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 +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) { @@ -1075,6 +1097,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,29 +1106,36 @@ 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.39.5