diff options
Diffstat (limited to 'video/out/hwdec/hwdec_vaapi.c')
-rw-r--r-- | video/out/hwdec/hwdec_vaapi.c | 451 |
1 files changed, 294 insertions, 157 deletions
diff --git a/video/out/hwdec/hwdec_vaapi.c b/video/out/hwdec/hwdec_vaapi.c index 2ff0d98df3..eed79799e9 100644 --- a/video/out/hwdec/hwdec_vaapi.c +++ b/video/out/hwdec/hwdec_vaapi.c @@ -20,9 +20,6 @@ #include <assert.h> #include <unistd.h> -#include <EGL/egl.h> -#include <EGL/eglext.h> - #include <va/va_drmcommon.h> #include <libavutil/common.h> @@ -34,8 +31,17 @@ #include "video/out/gpu/hwdec.h" #include "video/mp_image_pool.h" #include "video/vaapi.h" -#include "common.h" -#include "ra_gl.h" + +#if HAVE_VULKAN +#include "video/out/placebo/ra_pl.h" +#include "video/out/vulkan/common.h" +#endif + +#if HAVE_GL +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include "video/out/opengl/common.h" +#include "video/out/opengl/ra_gl.h" #include "libmpv/render_gl.h" #ifndef GL_OES_EGL_image @@ -53,6 +59,8 @@ typedef void *EGLImageKHR; #define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274 #endif +#endif // HAVE_GL + #if HAVE_VAAPI_X11 #include <va/va_x11.h> @@ -124,9 +132,12 @@ struct priv_owner { struct priv { int num_planes; + struct mp_image layout; struct ra_tex *tex[4]; +#if HAVE_GL GLuint gl_textures[4]; EGLImageKHR images[4]; +#endif VAImage current_image; bool buffer_acquired; #if VA_CHECK_VERSION(1, 1, 0) @@ -135,11 +146,13 @@ struct priv { bool surface_acquired; #endif +#if HAVE_GL EGLImageKHR (EGLAPIENTRY *CreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *); EGLBoolean (EGLAPIENTRY *DestroyImageKHR)(EGLDisplay, EGLImageKHR); void (EGLAPIENTRY *EGLImageTargetTexture2DOES)(GLenum, GLeglImageOES); +#endif }; static void determine_working_formats(struct ra_hwdec *hw); @@ -156,19 +169,38 @@ static int init(struct ra_hwdec *hw) { struct priv_owner *p = hw->priv; - if (!ra_is_gl(hw->ra) || !eglGetCurrentContext()) - return -1; +#if HAVE_GL + if (ra_is_gl(hw->ra)) { + if (!eglGetCurrentContext()) + return -1; - const char *exts = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS); - if (!exts) - return -1; + const char *exts = eglQueryString(eglGetCurrentDisplay(), EGL_EXTENSIONS); + if (!exts) + return -1; - GL *gl = ra_gl_get(hw->ra); - if (!strstr(exts, "EXT_image_dma_buf_import") || - !strstr(exts, "EGL_KHR_image_base") || - !strstr(gl->extensions, "GL_OES_EGL_image") || - !(gl->mpgl_caps & MPGL_CAP_TEX_RG)) - return -1; + GL *gl = ra_gl_get(hw->ra); + if (!strstr(exts, "EXT_image_dma_buf_import") || + !strstr(exts, "EGL_KHR_image_base") || + !strstr(gl->extensions, "GL_OES_EGL_image") || + !(gl->mpgl_caps & MPGL_CAP_TEX_RG)) + return -1; + + MP_VERBOSE(hw, "using VAAPI EGL interop\n"); + } +#endif + +#if HAVE_VULKAN + if (ra_pl_get(hw->ra)) { + const struct pl_gpu *gpu = ra_pl_get(hw->ra); + if (!(gpu->import_caps.tex & PL_HANDLE_DMA_BUF)) { + MP_VERBOSE(hw, "VAAPI Vulkan interop requires support for " + "dma_buf import in Vulkan.\n"); + return -1; + } + + MP_VERBOSE(hw, "using VAAPI Vulkan interop\n"); + } +#endif p->display = create_native_va_display(hw->ra, hw->log); if (!p->display) { @@ -190,8 +222,6 @@ static int init(struct ra_hwdec *hw) return -1; } - MP_VERBOSE(hw, "using VAAPI EGL interop\n"); - determine_working_formats(hw); if (!p->formats || !p->formats[0]) { return -1; @@ -209,11 +239,26 @@ static void mapper_unmap(struct ra_hwdec_mapper *mapper) VADisplay *display = p_owner->display; struct priv *p = mapper->priv; VAStatus status; +#if HAVE_GL + bool is_gl = ra_is_gl(mapper->ra); +#endif +#if HAVE_VULKAN + const struct pl_gpu *gpu = ra_pl_get(mapper->ra); +#endif for (int n = 0; n < 4; n++) { - if (p->images[n]) - p->DestroyImageKHR(eglGetCurrentDisplay(), p->images[n]); - p->images[n] = 0; +#if HAVE_GL + if (is_gl) { + if (p->images[n]) + p->DestroyImageKHR(eglGetCurrentDisplay(), p->images[n]); + p->images[n] = 0; + } +#endif +#if HAVE_VULKAN + if (gpu) { + ra_tex_free(mapper->ra, &mapper->tex[n]); + } +#endif } #if VA_CHECK_VERSION(1, 1, 0) @@ -238,14 +283,18 @@ static void mapper_unmap(struct ra_hwdec_mapper *mapper) static void mapper_uninit(struct ra_hwdec_mapper *mapper) { +#if HAVE_GL struct priv *p = mapper->priv; - GL *gl = ra_gl_get(mapper->ra); - gl->DeleteTextures(4, p->gl_textures); - for (int n = 0; n < 4; n++) { - p->gl_textures[n] = 0; - ra_tex_free(mapper->ra, &p->tex[n]); + if (ra_is_gl(mapper->ra)) { + GL *gl = ra_gl_get(mapper->ra); + gl->DeleteTextures(4, p->gl_textures); + for (int n = 0; n < 4; n++) { + p->gl_textures[n] = 0; + ra_tex_free(mapper->ra, &p->tex[n]); + } } +#endif } static bool check_fmt(struct ra_hwdec_mapper *mapper, int fmt) @@ -262,61 +311,71 @@ static int mapper_init(struct ra_hwdec_mapper *mapper) { struct priv_owner *p_owner = mapper->owner->priv; struct priv *p = mapper->priv; - GL *gl = ra_gl_get(mapper->ra); +#if HAVE_GL + bool is_gl = ra_is_gl(mapper->ra); +#endif p->current_image.buf = p->current_image.image_id = VA_INVALID_ID; - // EGL_KHR_image_base - p->CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR"); - p->DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR"); - // GL_OES_EGL_image - p->EGLImageTargetTexture2DOES = - (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES"); - - if (!p->CreateImageKHR || !p->DestroyImageKHR || - !p->EGLImageTargetTexture2DOES) - return -1; +#if HAVE_GL + if (is_gl) { + // EGL_KHR_image_base + p->CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR"); + p->DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR"); + // GL_OES_EGL_image + p->EGLImageTargetTexture2DOES = + (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES"); + + if (!p->CreateImageKHR || !p->DestroyImageKHR || + !p->EGLImageTargetTexture2DOES) + return -1; + } +#endif mapper->dst_params = mapper->src_params; mapper->dst_params.imgfmt = mapper->src_params.hw_subfmt; mapper->dst_params.hw_subfmt = 0; struct ra_imgfmt_desc desc = {0}; - struct mp_image layout = {0}; if (!ra_get_imgfmt_desc(mapper->ra, mapper->dst_params.imgfmt, &desc)) return -1; p->num_planes = desc.num_planes; - mp_image_set_params(&layout, &mapper->dst_params); - - gl->GenTextures(4, p->gl_textures); - for (int n = 0; n < desc.num_planes; n++) { - gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - gl->BindTexture(GL_TEXTURE_2D, 0); - - struct ra_tex_params params = { - .dimensions = 2, - .w = mp_image_plane_w(&layout, n), - .h = mp_image_plane_h(&layout, n), - .d = 1, - .format = desc.planes[n], - .render_src = true, - .src_linear = true, - }; - - if (params.format->ctype != RA_CTYPE_UNORM) - return -1; - - p->tex[n] = ra_create_wrapped_tex(mapper->ra, ¶ms, - p->gl_textures[n]); - if (!p->tex[n]) - return -1; + mp_image_set_params(&p->layout, &mapper->dst_params); + +#if HAVE_GL + if (is_gl) { + GL *gl = ra_gl_get(mapper->ra); + gl->GenTextures(4, p->gl_textures); + for (int n = 0; n < desc.num_planes; n++) { + gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + gl->BindTexture(GL_TEXTURE_2D, 0); + + struct ra_tex_params params = { + .dimensions = 2, + .w = mp_image_plane_w(&p->layout, n), + .h = mp_image_plane_h(&p->layout, n), + .d = 1, + .format = desc.planes[n], + .render_src = true, + .src_linear = true, + }; + + if (params.format->ctype != RA_CTYPE_UNORM) + return -1; + + p->tex[n] = ra_create_wrapped_tex(mapper->ra, ¶ms, + p->gl_textures[n]); + if (!p->tex[n]) + return -1; + } } +#endif if (!p_owner->probing_formats && !check_fmt(mapper, mapper->dst_params.imgfmt)) { @@ -340,9 +399,13 @@ static int mapper_map(struct ra_hwdec_mapper *mapper) { struct priv_owner *p_owner = mapper->owner->priv; struct priv *p = mapper->priv; - GL *gl = ra_gl_get(mapper->ra); +#if HAVE_GL + bool is_gl = ra_is_gl(mapper->ra); +#endif +#if HAVE_VULKAN + const struct pl_gpu *gpu = ra_pl_get(mapper->ra); +#endif VAStatus status; - VAImage *va_image = &p->current_image; VADisplay *display = p_owner->display; #if VA_CHECK_VERSION(1, 1, 0) @@ -354,49 +417,110 @@ static int mapper_map(struct ra_hwdec_mapper *mapper) VA_EXPORT_SURFACE_READ_ONLY | VA_EXPORT_SURFACE_SEPARATE_LAYERS, &p->desc); - if (!CHECK_VA_STATUS(mapper, "vaAcquireSurfaceHandle()")) { + if (!CHECK_VA_STATUS(mapper, "vaExportSurfaceHandle()")) { 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]) +#if HAVE_GL + if (is_gl) { + GL *gl = ra_gl_get(mapper->ra); + 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); + } +#endif +#if HAVE_VULKAN + if (gpu) { + struct ra_imgfmt_desc desc = {0}; + if (!ra_get_imgfmt_desc(mapper->ra, mapper->dst_params.imgfmt, &desc)) 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]; + for (int n = 0; n < p->desc.num_layers; n++) { + if (p->desc.layers[n].num_planes > 1) { + // Should never happen because we request separate layers + MP_ERR(mapper, "Multi-plane VA surfaces are not supported\n"); + goto esh_failed; + } + + const struct ra_format *format = desc.planes[n]; + int id = p->desc.layers[n].object_index[0]; + int fd = p->desc.objects[id].fd; + uint32_t size = p->desc.objects[id].size; + uint32_t offset = p->desc.layers[n].offset[0]; + + struct pl_tex_params tex_params = { + .w = mp_image_plane_w(&p->layout, n), + .h = mp_image_plane_h(&p->layout, n), + .d = 0, + .format = format->priv, + .sampleable = true, + .sample_mode = format->linear_filter ? PL_TEX_SAMPLE_LINEAR + : PL_TEX_SAMPLE_NEAREST, + .import_handle = PL_HANDLE_DMA_BUF, + .shared_mem = (struct pl_shared_mem) { + .handle = { + .fd = fd, + }, + .size = size, + .offset = offset, + }, + }; + + const struct pl_tex *pltex = pl_tex_create(gpu, &tex_params); + if (!pltex) { + goto esh_failed; + } + + struct ra_tex *ratex = talloc_ptrtype(NULL, ratex); + int ret = mppl_wrap_tex(mapper->ra, pltex, ratex); + if (!ret) { + pl_tex_destroy(gpu, &pltex); + talloc_free(ratex); + goto esh_failed; + } + mapper->tex[n] = ratex; + + MP_TRACE(mapper, "Object %d with fd %d imported as %p\n", + id, fd, ratex); + } } - gl->BindTexture(GL_TEXTURE_2D, 0); +#endif if (p->desc.fourcc == VA_FOURCC_YV12) MPSWAP(struct ra_tex*, mapper->tex[1], mapper->tex[2]); @@ -409,67 +533,80 @@ esh_failed: 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; - - VABufferInfo buffer_info = {.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME}; - status = vaAcquireBufferHandle(display, va_image->buf, &buffer_info); - if (!CHECK_VA_STATUS(mapper, "vaAcquireBufferHandle()")) - goto err; - p->buffer_acquired = true; - - int drm_fmts[8] = { - // 1 bytes per component, 1-4 components - MKTAG('R', '8', ' ', ' '), // DRM_FORMAT_R8 - MKTAG('G', 'R', '8', '8'), // DRM_FORMAT_GR88 - 0, // untested (DRM_FORMAT_RGB888?) - 0, // untested (DRM_FORMAT_RGBA8888?) - // 2 bytes per component, 1-4 components - MKTAG('R', '1', '6', ' '), // proposed DRM_FORMAT_R16 - MKTAG('G', 'R', '3', '2'), // proposed DRM_FORMAT_GR32 - 0, // N/A - 0, // N/A - }; - - for (int n = 0; n < p->num_planes; n++) { - int attribs[20] = {EGL_NONE}; - int num_attribs = 0; - - const struct ra_format *fmt = p->tex[n]->params.format; - int n_comp = fmt->num_components; - int comp_s = fmt->component_size[n] / 8; - if (n_comp < 1 || n_comp > 3 || comp_s < 1 || comp_s > 2) - goto err; - int drm_fmt = drm_fmts[n_comp - 1 + (comp_s - 1) * 4]; - if (!drm_fmt) +#endif // VA_CHECK_VERSION + +#if HAVE_GL + if (is_gl) { + GL *gl = ra_gl_get(mapper->ra); + VAImage *va_image = &p->current_image; + status = vaDeriveImage(display, va_surface_id(mapper->src), va_image); + if (!CHECK_VA_STATUS(mapper, "vaDeriveImage()")) goto err; - ADD_ATTRIB(EGL_LINUX_DRM_FOURCC_EXT, drm_fmt); - ADD_ATTRIB(EGL_WIDTH, p->tex[n]->params.w); - ADD_ATTRIB(EGL_HEIGHT, p->tex[n]->params.h); - ADD_ATTRIB(EGL_DMA_BUF_PLANE0_FD_EXT, buffer_info.handle); - ADD_ATTRIB(EGL_DMA_BUF_PLANE0_OFFSET_EXT, va_image->offsets[n]); - ADD_ATTRIB(EGL_DMA_BUF_PLANE0_PITCH_EXT, va_image->pitches[n]); - - p->images[n] = p->CreateImageKHR(eglGetCurrentDisplay(), - EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); - if (!p->images[n]) + VABufferInfo buffer_info = {.mem_type = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME}; + status = vaAcquireBufferHandle(display, va_image->buf, &buffer_info); + if (!CHECK_VA_STATUS(mapper, "vaAcquireBufferHandle()")) goto err; + p->buffer_acquired = true; + + int drm_fmts[8] = { + // 1 bytes per component, 1-4 components + MKTAG('R', '8', ' ', ' '), // DRM_FORMAT_R8 + MKTAG('G', 'R', '8', '8'), // DRM_FORMAT_GR88 + 0, // untested (DRM_FORMAT_RGB888?) + 0, // untested (DRM_FORMAT_RGBA8888?) + // 2 bytes per component, 1-4 components + MKTAG('R', '1', '6', ' '), // proposed DRM_FORMAT_R16 + MKTAG('G', 'R', '3', '2'), // proposed DRM_FORMAT_GR32 + 0, // N/A + 0, // N/A + }; - 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); + for (int n = 0; n < p->num_planes; n++) { + int attribs[20] = {EGL_NONE}; + int num_attribs = 0; + + const struct ra_format *fmt = p->tex[n]->params.format; + int n_comp = fmt->num_components; + int comp_s = fmt->component_size[n] / 8; + if (n_comp < 1 || n_comp > 3 || comp_s < 1 || comp_s > 2) + goto err; + int drm_fmt = drm_fmts[n_comp - 1 + (comp_s - 1) * 4]; + if (!drm_fmt) + goto err; + + ADD_ATTRIB(EGL_LINUX_DRM_FOURCC_EXT, drm_fmt); + ADD_ATTRIB(EGL_WIDTH, p->tex[n]->params.w); + ADD_ATTRIB(EGL_HEIGHT, p->tex[n]->params.h); + ADD_ATTRIB(EGL_DMA_BUF_PLANE0_FD_EXT, buffer_info.handle); + ADD_ATTRIB(EGL_DMA_BUF_PLANE0_OFFSET_EXT, va_image->offsets[n]); + ADD_ATTRIB(EGL_DMA_BUF_PLANE0_PITCH_EXT, va_image->pitches[n]); + + p->images[n] = p->CreateImageKHR(eglGetCurrentDisplay(), + EGL_NO_CONTEXT, EGL_LINUX_DMA_BUF_EXT, NULL, attribs); + if (!p->images[n]) + goto err; + + 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 (va_image->format.fourcc == VA_FOURCC_YV12) - MPSWAP(struct ra_tex*, mapper->tex[1], mapper->tex[2]); + if (va_image->format.fourcc == VA_FOURCC_YV12) + MPSWAP(struct ra_tex*, mapper->tex[1], mapper->tex[2]); - return 0; + return 0; + } +#endif +#if HAVE_VULKAN + // Seems unnecessary to support Vulkan interop with old libva API. + if (gpu) { + mapper_unmap(mapper); + goto err; + } +#endif err: if (!p_owner->probing_formats) |