Skip to content
Permalink
Browse files

vo_opengl: hwdec_vaegl: Use vaExportSurfaceHandle() if present

This new interface in libva2 offers a cleaner way to export surfaces
which can then be imported to EGL.  In particular, this works with
the Mesa driver, so we can have proper playback without a pointless
download and upload on AMD cards.

This change does nothing with libva1, and will fall back to the
libva1 interface (vaDeriveImage() + vaAcquireBufferHandle()) if
vaExportSurfaceHandle() is not present.
  • Loading branch information
fhvwy authored and wm4 committed Oct 9, 2017
1 parent 2ecf240 commit 05cb8d28afd8881667c3dea297b182a2ecdd91c8
Showing with 80 additions and 0 deletions.
  1. +80 −0 video/out/opengl/hwdec_vaegl.c
@@ -18,6 +18,7 @@
#include <stddef.h>
#include <string.h>
#include <assert.h>
#include <unistd.h>

#include <EGL/egl.h>
#include <EGL/eglext.h>
@@ -127,6 +128,11 @@ struct priv {
EGLImageKHR images[4];
VAImage current_image;
bool buffer_acquired;
#if VA_CHECK_VERSION(1, 0, 0)
bool esh_not_implemented;
VADRMPRIMESurfaceDescriptor desc;
bool surface_acquired;
#endif

EGLImageKHR (EGLAPIENTRY *CreateImageKHR)(EGLDisplay, EGLContext,
EGLenum, EGLClientBuffer,
@@ -209,6 +215,14 @@ static void mapper_unmap(struct ra_hwdec_mapper *mapper)
p->images[n] = 0;
}

#if VA_CHECK_VERSION(1, 0, 0)
if (p->surface_acquired) {
for (int n = 0; n < p->desc.num_objects; n++)
close(p->desc.objects[n].fd);
p->surface_acquired = false;
}
#endif

if (p->buffer_acquired) {
status = vaReleaseBufferHandle(display, p->current_image.buf);
CHECK_VA_STATUS(mapper, "vaReleaseBufferHandle()");
@@ -330,6 +344,72 @@ static int mapper_map(struct ra_hwdec_mapper *mapper)
VAImage *va_image = &p->current_image;
VADisplay *display = p_owner->display;

#if VA_CHECK_VERSION(1, 0, 0)
if (p->esh_not_implemented)
goto esh_failed;

status = vaExportSurfaceHandle(display, va_surface_id(mapper->src),

This comment has been minimized.

Copy link
@fritsch

fritsch Oct 31, 2017

What I really wonder is, I don't find any vaSyncSurface calls before doing the buffer exporting. Is this not needed anymore? Do I miss something?

Background: We are looking to get this new API implemented in kodi in the future.

VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME_2,
VA_EXPORT_SURFACE_READ_ONLY |
VA_EXPORT_SURFACE_SEPARATE_LAYERS,
&p->desc);
if (!CHECK_VA_STATUS(mapper, "vaAcquireSurfaceHandle()")) {
if (status == VA_STATUS_ERROR_UNIMPLEMENTED)
p->esh_not_implemented = true;
goto esh_failed;
}
p->surface_acquired = true;

for (int n = 0; n < p->num_planes; n++) {
int attribs[20] = {EGL_NONE};
int num_attribs = 0;

ADD_ATTRIB(EGL_LINUX_DRM_FOURCC_EXT, p->desc.layers[n].drm_format);
ADD_ATTRIB(EGL_WIDTH, p->tex[n]->params.w);
ADD_ATTRIB(EGL_HEIGHT, p->tex[n]->params.h);

#define ADD_PLANE_ATTRIBS(plane) do { \
ADD_ATTRIB(EGL_DMA_BUF_PLANE ## plane ## _FD_EXT, \
p->desc.objects[p->desc.layers[n].object_index[plane]].fd); \
ADD_ATTRIB(EGL_DMA_BUF_PLANE ## plane ## _OFFSET_EXT, \
p->desc.layers[n].offset[plane]); \
ADD_ATTRIB(EGL_DMA_BUF_PLANE ## plane ## _PITCH_EXT, \
p->desc.layers[n].pitch[plane]); \
} while (0)

ADD_PLANE_ATTRIBS(0);
if (p->desc.layers[n].num_planes > 1)
ADD_PLANE_ATTRIBS(1);
if (p->desc.layers[n].num_planes > 2)
ADD_PLANE_ATTRIBS(2);
if (p->desc.layers[n].num_planes > 3)
ADD_PLANE_ATTRIBS(3);

p->images[n] = p->CreateImageKHR(eglGetCurrentDisplay(),
EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs);
if (!p->images[n])
goto esh_failed;

gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]);
p->EGLImageTargetTexture2DOES(GL_TEXTURE_2D, p->images[n]);

mapper->tex[n] = p->tex[n];
}
gl->BindTexture(GL_TEXTURE_2D, 0);

if (p->desc.fourcc == VA_FOURCC_YV12)
MPSWAP(struct ra_tex*, mapper->tex[1], mapper->tex[2]);

return 0;

esh_failed:
if (p->surface_acquired) {
for (int n = 0; n < p->desc.num_objects; n++)
close(p->desc.objects[n].fd);
p->surface_acquired = false;
}
#endif

status = vaDeriveImage(display, va_surface_id(mapper->src), va_image);
if (!CHECK_VA_STATUS(mapper, "vaDeriveImage()"))
goto err;

0 comments on commit 05cb8d2

Please sign in to comment.