On Wed, Mar 26, 2025 at 1:34 PM <yuq...@gmail.com> wrote: > > From: Qiang Yu <yuq...@gmail.com> > > v2: > * use new dmabuf API and check length > > Signed-off-by: Qiang Yu <yuq...@gmail.com>
Reviewed-by: Marc-André Lureau <marcandre.lur...@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