From 05cb8d28afd8881667c3dea297b182a2ecdd91c8 Mon Sep 17 00:00:00 2001 From: Mark Thompson Date: Sat, 7 Oct 2017 17:49:56 +0100 Subject: 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. --- video/out/opengl/hwdec_vaegl.c | 80 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/video/out/opengl/hwdec_vaegl.c b/video/out/opengl/hwdec_vaegl.c index 6078222bd5..5d690d6131 100644 --- a/video/out/opengl/hwdec_vaegl.c +++ b/video/out/opengl/hwdec_vaegl.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -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), + 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; -- cgit v1.2.3