mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-03 15:53:54 -06:00
ui/egl: support multi-plane dmabuf when egl export/import
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> [ Fix style ] Signed-off-by: Marc-André Lureau <marcandre.lureau@redhat.com> Message-ID: <20250327025848.46962-5-yuq825@gmail.com>
This commit is contained in:
parent
ac70568902
commit
0e15d0b927
4 changed files with 124 additions and 52 deletions
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
dmabuf = qemu_dmabuf_new(w, h, &offset, &stride, x, y, backing_width,
|
||||
backing_height, fourcc, modifier, &fd, 1,
|
||||
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);
|
||||
|
||||
dbus_scanout_dmabuf(dcl, dmabuf);
|
||||
|
|
|
@ -283,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;
|
||||
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 +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_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,
|
||||
|
|
|
@ -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,28 @@ 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];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue