[PATCH v2 4/6] ui/egl: support multi-plane dmabuf when egl export/import

yuq825@gmail.com posted 6 patches 1 week ago
There is a newer version of this series
[PATCH v2 4/6] ui/egl: support multi-plane dmabuf when egl export/import
Posted by yuq825@gmail.com 1 week ago
From: Qiang Yu <yuq825@gmail.com>

v2:
  * use new dmabuf API and check length

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
Re: [PATCH v2 4/6] ui/egl: support multi-plane dmabuf when egl export/import
Posted by Marc-André Lureau 1 week ago
On Wed, Mar 26, 2025 at 1:34 PM <yuq825@gmail.com> wrote:
>
> From: Qiang Yu <yuq825@gmail.com>
>
> v2:
>   * use new dmabuf API and check length
>
> Signed-off-by: Qiang Yu <yuq825@gmail.com>

Reviewed-by: Marc-André Lureau <marcandre.lureau@redhat.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
>


-- 
Marc-André Lureau