diff options
Diffstat (limited to 'video/out/hwdec')
-rw-r--r-- | video/out/hwdec/dmabuf_interop.h | 4 | ||||
-rw-r--r-- | video/out/hwdec/dmabuf_interop_gl.c | 190 | ||||
-rw-r--r-- | video/out/hwdec/dmabuf_interop_pl.c | 5 | ||||
-rw-r--r-- | video/out/hwdec/dmabuf_interop_wl.c | 36 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_aimagereader.c | 49 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_cuda.c | 47 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_cuda.h | 12 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_cuda_gl.c | 40 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_cuda_vk.c | 196 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_drmprime.c | 53 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_drmprime_overlay.c | 31 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_ios_gl.m | 222 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_mac_gl.c | 169 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_vaapi.c | 48 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_vt.c | 141 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_vt.h | 63 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_vt_pl.m | 312 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_vulkan.c | 333 |
18 files changed, 1697 insertions, 254 deletions
diff --git a/video/out/hwdec/dmabuf_interop.h b/video/out/hwdec/dmabuf_interop.h index 90c96399d7..3bf01a0fca 100644 --- a/video/out/hwdec/dmabuf_interop.h +++ b/video/out/hwdec/dmabuf_interop.h @@ -19,11 +19,11 @@ #include <libavutil/hwcontext_drm.h> -#include "config.h" #include "video/out/gpu/hwdec.h" struct dmabuf_interop { bool use_modifiers; + bool composed_layers; bool (*interop_init)(struct ra_hwdec_mapper *mapper, const struct ra_imgfmt_desc *desc); @@ -38,7 +38,7 @@ struct dmabuf_interop { struct dmabuf_interop_priv { int num_planes; struct mp_image layout; - struct ra_tex *tex[4]; + struct ra_tex *tex[AV_DRM_MAX_PLANES]; AVDRMFrameDescriptor desc; bool surface_acquired; diff --git a/video/out/hwdec/dmabuf_interop_gl.c b/video/out/hwdec/dmabuf_interop_gl.c index 2d83c1c096..0f6fb89e20 100644 --- a/video/out/hwdec/dmabuf_interop_gl.c +++ b/video/out/hwdec/dmabuf_interop_gl.c @@ -15,7 +15,6 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" #include "dmabuf_interop.h" #include <drm_fourcc.h> @@ -53,39 +52,28 @@ typedef void *EGLImageKHR; #define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A struct vaapi_gl_mapper_priv { - GLuint gl_textures[4]; - EGLImageKHR images[4]; + GLuint gl_textures[AV_DRM_MAX_PLANES]; + EGLImageKHR images[AV_DRM_MAX_PLANES]; + + const struct ra_format *planes[AV_DRM_MAX_PLANES]; EGLImageKHR (EGLAPIENTRY *CreateImageKHR)(EGLDisplay, EGLContext, EGLenum, EGLClientBuffer, const EGLint *); EGLBoolean (EGLAPIENTRY *DestroyImageKHR)(EGLDisplay, EGLImageKHR); void (EGLAPIENTRY *EGLImageTargetTexture2DOES)(GLenum, GLeglImageOES); + void (EGLAPIENTRY *EGLImageTargetTexStorageEXT)(GLenum, GLeglImageOES, + const GLint *); }; -static bool vaapi_gl_mapper_init(struct ra_hwdec_mapper *mapper, - const struct ra_imgfmt_desc *desc) +static bool gl_create_textures(struct ra_hwdec_mapper *mapper) { struct dmabuf_interop_priv *p_mapper = mapper->priv; - struct vaapi_gl_mapper_priv *p = talloc_ptrtype(NULL, p); - p_mapper->interop_mapper_priv = p; - - *p = (struct vaapi_gl_mapper_priv) { - // EGL_KHR_image_base - .CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR"), - .DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR"), - // GL_OES_EGL_image - .EGLImageTargetTexture2DOES = - (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES"), - }; - - if (!p->CreateImageKHR || !p->DestroyImageKHR || - !p->EGLImageTargetTexture2DOES) - return false; + struct vaapi_gl_mapper_priv *p = p_mapper->interop_mapper_priv; GL *gl = ra_gl_get(mapper->ra); - gl->GenTextures(4, p->gl_textures); - for (int n = 0; n < desc->num_planes; n++) { + gl->GenTextures(AV_DRM_MAX_PLANES, p->gl_textures); + for (int n = 0; n < p_mapper->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); @@ -98,7 +86,7 @@ static bool vaapi_gl_mapper_init(struct ra_hwdec_mapper *mapper, .w = mp_image_plane_w(&p_mapper->layout, n), .h = mp_image_plane_h(&p_mapper->layout, n), .d = 1, - .format = desc->planes[n], + .format = p->planes[n], .render_src = true, .src_linear = true, }; @@ -115,44 +103,99 @@ static bool vaapi_gl_mapper_init(struct ra_hwdec_mapper *mapper, return true; } +static void gl_delete_textures(const struct ra_hwdec_mapper *mapper) +{ + struct dmabuf_interop_priv *p_mapper = mapper->priv; + struct vaapi_gl_mapper_priv *p = p_mapper->interop_mapper_priv; + + GL *gl = ra_gl_get(mapper->ra); + gl->DeleteTextures(AV_DRM_MAX_PLANES, p->gl_textures); + for (int n = 0; n < AV_DRM_MAX_PLANES; n++) { + p->gl_textures[n] = 0; + ra_tex_free(mapper->ra, &p_mapper->tex[n]); + } +} + +static bool vaapi_gl_mapper_init(struct ra_hwdec_mapper *mapper, + const struct ra_imgfmt_desc *desc) +{ + struct dmabuf_interop_priv *p_mapper = mapper->priv; + struct vaapi_gl_mapper_priv *p = talloc_ptrtype(NULL, p); + p_mapper->interop_mapper_priv = p; + + *p = (struct vaapi_gl_mapper_priv) { + // EGL_KHR_image_base + .CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR"), + .DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR"), + }; + if (ra_gl_get(mapper->ra)->es) { + // GL_OES_EGL_image + p->EGLImageTargetTexture2DOES = + (void *)eglGetProcAddress("glEGLImageTargetTexture2DOES"); + } else { + // GL_EXT_EGL_image_storage + p->EGLImageTargetTexStorageEXT = + (void *)eglGetProcAddress("glEGLImageTargetTexStorageEXT"); + } + + if (!p->CreateImageKHR || !p->DestroyImageKHR || + (!p->EGLImageTargetTexture2DOES && !p->EGLImageTargetTexStorageEXT)) { + return false; + } + + static_assert(MP_ARRAY_SIZE(desc->planes) == AV_DRM_MAX_PLANES, ""); + static_assert(MP_ARRAY_SIZE(mapper->tex) == AV_DRM_MAX_PLANES, ""); + + // remember format to allow texture recreation + for (int n = 0; n < desc->num_planes; n++) { + p->planes[n] = desc->planes[n]; + } + if (p->EGLImageTargetTexture2DOES) { + // created only once + if (!gl_create_textures(mapper)) + return false; + } + + return true; +} + static void vaapi_gl_mapper_uninit(const struct ra_hwdec_mapper *mapper) { struct dmabuf_interop_priv *p_mapper = mapper->priv; struct vaapi_gl_mapper_priv *p = p_mapper->interop_mapper_priv; if (p) { - 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_mapper->tex[n]); - } + gl_delete_textures(mapper); talloc_free(p); p_mapper->interop_mapper_priv = NULL; } } -#define ADD_ATTRIB(name, value) \ - do { \ - assert(num_attribs + 3 < MP_ARRAY_SIZE(attribs)); \ - attribs[num_attribs++] = (name); \ - attribs[num_attribs++] = (value); \ - attribs[num_attribs] = EGL_NONE; \ +#define ADD_ATTRIB(name, value) \ + do { \ + assert(num_attribs + 3 < MP_ARRAY_SIZE(attribs)); \ + attribs[num_attribs++] = (name); \ + attribs[num_attribs++] = (value); \ + attribs[num_attribs] = EGL_NONE; \ } while(0) -#define ADD_PLANE_ATTRIBS(plane) do { \ - uint64_t drm_format_modifier = p_mapper->desc.objects[p_mapper->desc.layers[i].planes[j].object_index].format_modifier; \ - ADD_ATTRIB(EGL_DMA_BUF_PLANE ## plane ## _FD_EXT, \ - p_mapper->desc.objects[p_mapper->desc.layers[i].planes[j].object_index].fd); \ - ADD_ATTRIB(EGL_DMA_BUF_PLANE ## plane ## _OFFSET_EXT, \ - p_mapper->desc.layers[i].planes[j].offset); \ - ADD_ATTRIB(EGL_DMA_BUF_PLANE ## plane ## _PITCH_EXT, \ - p_mapper->desc.layers[i].planes[j].pitch); \ - if (dmabuf_interop->use_modifiers && drm_format_modifier != DRM_FORMAT_MOD_INVALID) { \ - ADD_ATTRIB(EGL_DMA_BUF_PLANE ## plane ## _MODIFIER_LO_EXT, drm_format_modifier & 0xfffffffful); \ - ADD_ATTRIB(EGL_DMA_BUF_PLANE ## plane ## _MODIFIER_HI_EXT, drm_format_modifier >> 32); \ - } \ - } while (0) +#define ADD_PLANE_ATTRIBS(nplane) \ + do { \ + const AVDRMPlaneDescriptor *plane = &p_mapper->desc.layers[i].planes[j]; \ + const AVDRMObjectDescriptor *object = \ + &p_mapper->desc.objects[plane->object_index]; \ + ADD_ATTRIB(EGL_DMA_BUF_PLANE ## nplane ## _FD_EXT, object->fd); \ + ADD_ATTRIB(EGL_DMA_BUF_PLANE ## nplane ## _OFFSET_EXT, plane->offset); \ + ADD_ATTRIB(EGL_DMA_BUF_PLANE ## nplane ## _PITCH_EXT, plane->pitch); \ + uint64_t drm_format_modifier = object->format_modifier; \ + if (dmabuf_interop->use_modifiers && \ + drm_format_modifier != DRM_FORMAT_MOD_INVALID) { \ + ADD_ATTRIB(EGL_DMA_BUF_PLANE ## nplane ## _MODIFIER_LO_EXT, \ + drm_format_modifier & 0xfffffffful); \ + ADD_ATTRIB(EGL_DMA_BUF_PLANE ## nplane ## _MODIFIER_HI_EXT, \ + drm_format_modifier >> 32); \ + } \ + } while (0) static bool vaapi_gl_map(struct ra_hwdec_mapper *mapper, struct dmabuf_interop *dmabuf_interop, @@ -163,6 +206,11 @@ static bool vaapi_gl_map(struct ra_hwdec_mapper *mapper, GL *gl = ra_gl_get(mapper->ra); + if (p->EGLImageTargetTexStorageEXT) { + if (!gl_create_textures(mapper)) + return false; + } + for (int i = 0, n = 0; i < p_mapper->desc.nb_layers; i++) { /* * As we must map surfaces as one texture per plane, we can only support @@ -177,10 +225,20 @@ static bool vaapi_gl_map(struct ra_hwdec_mapper *mapper, if (p_mapper->desc.layers[i].nb_planes > 1) { switch (p_mapper->desc.layers[i].format) { case DRM_FORMAT_NV12: + case DRM_FORMAT_NV16: format[0] = DRM_FORMAT_R8; format[1] = DRM_FORMAT_GR88; break; + case DRM_FORMAT_YUV420: + format[0] = DRM_FORMAT_R8; + format[1] = DRM_FORMAT_R8; + format[2] = DRM_FORMAT_R8; + break; case DRM_FORMAT_P010: + case DRM_FORMAT_P210: +#ifdef DRM_FORMAT_P030 /* Format added in a newer libdrm version than minimum */ + case DRM_FORMAT_P030: +#endif format[0] = DRM_FORMAT_R16; format[1] = DRM_FORMAT_GR1616; break; @@ -243,7 +301,11 @@ static bool vaapi_gl_map(struct ra_hwdec_mapper *mapper, } gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); - p->EGLImageTargetTexture2DOES(GL_TEXTURE_2D, p->images[n]); + if (p->EGLImageTargetTexStorageEXT) { + p->EGLImageTargetTexStorageEXT(GL_TEXTURE_2D, p->images[n], NULL); + } else { + p->EGLImageTargetTexture2DOES(GL_TEXTURE_2D, p->images[n]); + } mapper->tex[n] = p_mapper->tex[n]; } @@ -258,19 +320,25 @@ static void vaapi_gl_unmap(struct ra_hwdec_mapper *mapper) struct dmabuf_interop_priv *p_mapper = mapper->priv; struct vaapi_gl_mapper_priv *p = p_mapper->interop_mapper_priv; - if (p) { - for (int n = 0; n < 4; n++) { - if (p->images[n]) - p->DestroyImageKHR(eglGetCurrentDisplay(), p->images[n]); - p->images[n] = 0; - } + if (!p) + return; + + if (p->EGLImageTargetTexStorageEXT) { + // textures are immutable, can't reuse + gl_delete_textures(mapper); + } + + for (int n = 0; n < AV_DRM_MAX_PLANES; n++) { + if (p->images[n]) + p->DestroyImageKHR(eglGetCurrentDisplay(), p->images[n]); + p->images[n] = 0; } } bool dmabuf_interop_gl_init(const struct ra_hwdec *hw, struct dmabuf_interop *dmabuf_interop) { - if (!ra_is_gl(hw->ra)) { + if (!ra_is_gl(hw->ra_ctx->ra)) { // This is not an OpenGL RA. return false; } @@ -282,17 +350,19 @@ bool dmabuf_interop_gl_init(const struct ra_hwdec *hw, if (!exts) return false; - GL *gl = ra_gl_get(hw->ra); + GL *gl = ra_gl_get(hw->ra_ctx->ra); + const char *imageext = gl->es ? "GL_OES_EGL_image" : "GL_EXT_EGL_image_storage"; if (!gl_check_extension(exts, "EGL_EXT_image_dma_buf_import") || !gl_check_extension(exts, "EGL_KHR_image_base") || - !gl_check_extension(gl->extensions, "GL_OES_EGL_image") || - !(gl->mpgl_caps & MPGL_CAP_TEX_RG)) + !gl_check_extension(gl->extensions, imageext) || + !(gl->mpgl_caps & MPGL_CAP_TEX_RG)) { return false; + } dmabuf_interop->use_modifiers = gl_check_extension(exts, "EGL_EXT_image_dma_buf_import_modifiers"); - MP_VERBOSE(hw, "using EGL dmabuf interop\n"); + MP_VERBOSE(hw, "Using EGL dmabuf interop via %s\n", imageext); dmabuf_interop->interop_init = vaapi_gl_mapper_init; dmabuf_interop->interop_uninit = vaapi_gl_mapper_uninit; diff --git a/video/out/hwdec/dmabuf_interop_pl.c b/video/out/hwdec/dmabuf_interop_pl.c index 7e1ac05a75..1f036e3281 100644 --- a/video/out/hwdec/dmabuf_interop_pl.c +++ b/video/out/hwdec/dmabuf_interop_pl.c @@ -18,7 +18,6 @@ #include <errno.h> #include <unistd.h> -#include "config.h" #include "dmabuf_interop.h" #include "video/out/placebo/ra_pl.h" #include "video/out/placebo/utils.h" @@ -111,14 +110,14 @@ static bool vaapi_pl_map(struct ra_hwdec_mapper *mapper, static void vaapi_pl_unmap(struct ra_hwdec_mapper *mapper) { - for (int n = 0; n < 4; n++) + for (int n = 0; n < MP_ARRAY_SIZE(mapper->tex); n++) ra_tex_free(mapper->ra, &mapper->tex[n]); } bool dmabuf_interop_pl_init(const struct ra_hwdec *hw, struct dmabuf_interop *dmabuf_interop) { - pl_gpu gpu = ra_pl_get(hw->ra); + pl_gpu gpu = ra_pl_get(hw->ra_ctx->ra); if (!gpu) { // This is not a libplacebo RA; return false; diff --git a/video/out/hwdec/dmabuf_interop_wl.c b/video/out/hwdec/dmabuf_interop_wl.c index 74b421d583..78baf146f0 100644 --- a/video/out/hwdec/dmabuf_interop_wl.c +++ b/video/out/hwdec/dmabuf_interop_wl.c @@ -15,15 +15,11 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ #include "video/out/wldmabuf/ra_wldmabuf.h" -#include "config.h" #include "dmabuf_interop.h" static bool mapper_init(struct ra_hwdec_mapper *mapper, const struct ra_imgfmt_desc *desc) { - struct dmabuf_interop_priv *p = mapper->priv; - - p->num_planes = 1; return true; } @@ -35,6 +31,33 @@ static bool map(struct ra_hwdec_mapper *mapper, struct dmabuf_interop *dmabuf_interop, bool probing) { + // 1. only validate format when composed layers is enabled (i.e. vaapi) + // 2. for drmprime, just return true for now, as this use case + // has not been tested. + if (!dmabuf_interop->composed_layers) + return true; + + int layer_no = 0; + struct dmabuf_interop_priv *mapper_p = mapper->priv; + uint32_t drm_format = mapper_p->desc.layers[layer_no].format; + + if (mapper_p->desc.nb_layers != 1) { + MP_VERBOSE(mapper, "Mapped surface has separate layers - expected composed layers.\n"); + return false; + } else if (!ra_compatible_format(mapper->ra, drm_format, + mapper_p->desc.objects[0].format_modifier)) { + MP_VERBOSE(mapper, "Mapped surface with format %s; drm format '%s(%016" PRIx64 ")' " + "is not supported by compositor.\n", + mp_imgfmt_to_name(mapper->src->params.hw_subfmt), + mp_tag_str(drm_format), + mapper_p->desc.objects[0].format_modifier); + return false; + } + + MP_VERBOSE(mapper, "Supported Wayland display format %s: '%s(%016" PRIx64 ")'\n", + mp_imgfmt_to_name(mapper->src->params.hw_subfmt), + mp_tag_str(drm_format), mapper_p->desc.objects[0].format_modifier); + return true; } @@ -45,9 +68,12 @@ static void unmap(struct ra_hwdec_mapper *mapper) bool dmabuf_interop_wl_init(const struct ra_hwdec *hw, struct dmabuf_interop *dmabuf_interop) { - if (!ra_is_wldmabuf(hw->ra)) + if (!ra_is_wldmabuf(hw->ra_ctx->ra)) return false; + if (strstr(hw->driver->name, "vaapi") != NULL) + dmabuf_interop->composed_layers = true; + dmabuf_interop->interop_init = mapper_init; dmabuf_interop->interop_uninit = mapper_uninit; dmabuf_interop->interop_map = map; diff --git a/video/out/hwdec/hwdec_aimagereader.c b/video/out/hwdec/hwdec_aimagereader.c index 10f1c85687..1aa92eea4a 100644 --- a/video/out/hwdec/hwdec_aimagereader.c +++ b/video/out/hwdec/hwdec_aimagereader.c @@ -18,7 +18,6 @@ */ #include <assert.h> -#include <pthread.h> #include <dlfcn.h> #include <EGL/egl.h> #include <media/NdkImageReader.h> @@ -28,6 +27,7 @@ #include <libavutil/hwcontext_mediacodec.h> #include "misc/jni.h" +#include "osdep/threads.h" #include "osdep/timer.h" #include "video/out/gpu/hwdec.h" #include "video/out/opengl/ra_gl.h" @@ -63,8 +63,8 @@ struct priv { AImage *image; EGLImageKHR egl_image; - pthread_mutex_t lock; - pthread_cond_t cond; + mp_mutex lock; + mp_cond cond; bool image_available; EGLImageKHR (EGLAPIENTRY *CreateImageKHR)( @@ -75,7 +75,7 @@ struct priv { void (EGLAPIENTRY *EGLImageTargetTexture2DOES)(GLenum, GLeglImageOES); }; -const static struct { const char *symbol; int offset; } lib_functions[] = { +static const struct { const char *symbol; int offset; } lib_functions[] = { { "AImageReader_newWithUsage", offsetof(struct priv_owner, AImageReader_newWithUsage) }, { "AImageReader_getWindow", offsetof(struct priv_owner, AImageReader_getWindow) }, { "AImageReader_setImageListener", offsetof(struct priv_owner, AImageReader_setImageListener) }, @@ -129,7 +129,7 @@ static int init(struct ra_hwdec *hw) { struct priv_owner *p = hw->priv; - if (!ra_is_gl(hw->ra)) + if (!ra_is_gl(hw->ra_ctx->ra)) return -1; if (!eglGetCurrentContext()) return -1; @@ -138,12 +138,16 @@ static int init(struct ra_hwdec *hw) if (!gl_check_extension(exts, "EGL_ANDROID_image_native_buffer")) return -1; + JNIEnv *env = MP_JNI_GET_ENV(hw); + if (!env) + return -1; + if (!load_lib_functions(p, hw->log)) return -1; static const char *es2_exts[] = {"GL_OES_EGL_image_external", 0}; static const char *es3_exts[] = {"GL_OES_EGL_image_external_essl3", 0}; - GL *gl = ra_gl_get(hw->ra); + GL *gl = ra_gl_get(hw->ra_ctx->ra); if (gl_check_extension(gl->extensions, es3_exts[0])) hw->glsl_extensions = es3_exts; else @@ -167,8 +171,6 @@ static int init(struct ra_hwdec *hw) } assert(window); - JNIEnv *env = MP_JNI_GET_ENV(hw); - assert(env); jobject surface = p->ANativeWindow_toSurface(env, window); p->surface = (*env)->NewGlobalRef(env, surface); (*env)->DeleteLocalRef(env, surface); @@ -178,6 +180,12 @@ static int init(struct ra_hwdec *hw) .av_device_ref = create_mediacodec_device_ref(p->surface), .hw_imgfmt = IMGFMT_MEDIACODEC, }; + + if (!p->hwctx.av_device_ref) { + MP_VERBOSE(hw, "Failed to create hwdevice_ctx\n"); + return -1; + } + hwdec_devices_add(hw->devs, &p->hwctx); return 0; @@ -186,10 +194,10 @@ static int init(struct ra_hwdec *hw) static void uninit(struct ra_hwdec *hw) { struct priv_owner *p = hw->priv; - JNIEnv *env = MP_JNI_GET_ENV(hw); - assert(env); if (p->surface) { + JNIEnv *env = MP_JNI_GET_ENV(hw); + assert(env); (*env)->DeleteGlobalRef(env, p->surface); p->surface = NULL; } @@ -212,10 +220,10 @@ static void image_callback(void *context, AImageReader *reader) { struct priv *p = context; - pthread_mutex_lock(&p->lock); + mp_mutex_lock(&p->lock); p->image_available = true; - pthread_cond_signal(&p->cond); - pthread_mutex_unlock(&p->lock); + mp_cond_signal(&p->cond); + mp_mutex_unlock(&p->lock); } static int mapper_init(struct ra_hwdec_mapper *mapper) @@ -225,8 +233,8 @@ static int mapper_init(struct ra_hwdec_mapper *mapper) GL *gl = ra_gl_get(mapper->ra); p->log = mapper->log; - pthread_mutex_init(&p->lock, NULL); - pthread_cond_init(&p->cond, NULL); + mp_mutex_init(&p->lock); + mp_cond_init(&p->cond); p->CreateImageKHR = (void *)eglGetProcAddress("eglCreateImageKHR"); p->DestroyImageKHR = (void *)eglGetProcAddress("eglDestroyImageKHR"); @@ -292,8 +300,8 @@ static void mapper_uninit(struct ra_hwdec_mapper *mapper) ra_tex_free(mapper->ra, &mapper->tex[0]); - pthread_mutex_destroy(&p->lock); - pthread_cond_destroy(&p->cond); + mp_mutex_destroy(&p->lock); + mp_cond_destroy(&p->cond); } static void mapper_unmap(struct ra_hwdec_mapper *mapper) @@ -326,16 +334,15 @@ static int mapper_map(struct ra_hwdec_mapper *mapper) } bool image_available = false; - pthread_mutex_lock(&p->lock); + mp_mutex_lock(&p->lock); if (!p->image_available) { - struct timespec ts = mp_rel_time_to_timespec(0.1); - pthread_cond_timedwait(&p->cond, &p->lock, &ts); + mp_cond_timedwait(&p->cond, &p->lock, MP_TIME_MS_TO_NS(100)); if (!p->image_available) MP_WARN(mapper, "Waiting for frame timed out!\n"); } image_available = p->image_available; p->image_available = false; - pthread_mutex_unlock(&p->lock); + mp_mutex_unlock(&p->lock); media_status_t ret = o->AImageReader_acquireLatestImage(o->reader, &p->image); if (ret != AMEDIA_OK) { diff --git a/video/out/hwdec/hwdec_cuda.c b/video/out/hwdec/hwdec_cuda.c index 68ad60d465..8987cf3407 100644 --- a/video/out/hwdec/hwdec_cuda.c +++ b/video/out/hwdec/hwdec_cuda.c @@ -57,12 +57,12 @@ int check_cu(const struct ra_hwdec *hw, CUresult err, const char *func) #define CHECK_CU(x) check_cu(hw, (x), #x) -const static cuda_interop_init interop_inits[] = { +static const struct cuda_interop_fn *interop_fns[] = { #if HAVE_GL - cuda_gl_init, + &cuda_gl_fn, #endif #if HAVE_VULKAN - cuda_vk_init, + &cuda_vk_fn, #endif NULL }; @@ -73,25 +73,36 @@ static int cuda_init(struct ra_hwdec *hw) CUcontext dummy; int ret = 0; struct cuda_hw_priv *p = hw->priv; - CudaFunctions *cu; + CudaFunctions *cu = NULL; int level = hw->probing ? MSGL_V : MSGL_ERR; - - ret = cuda_load_functions(&p->cu, NULL); - if (ret != 0) { - MP_MSG(hw, level, "Failed to load CUDA symbols\n"); - return -1; - } - cu = p->cu; - - ret = CHECK_CU(cu->cuInit(0)); - if (ret < 0) - return -1; + bool initialized = false; // Initialise CUDA context from backend. - for (int i = 0; interop_inits[i]; i++) { - if (interop_inits[i](hw)) { - break; + // Note that the interop check doesn't require the CUDA backend to be initialized. + // This is important because cuInit wakes up the dgpu (even if the cuda hwdec won't be used!) + // Doing this allows us to check if CUDA should be used without waking up the dgpu, avoiding + // a few seconds of delay and improving battery life for laptops! + for (int i = 0; interop_fns[i]; i++) { + if (!interop_fns[i]->check(hw)) + continue; + + if (!initialized) { + ret = cuda_load_functions(&p->cu, NULL); + if (ret != 0) { + MP_MSG(hw, level, "Failed to load CUDA symbols\n"); + return -1; + } + + cu = p->cu; + ret = CHECK_CU(cu->cuInit(0)); + if (ret < 0) + return -1; + + initialized = true; } + + if (interop_fns[i]->init(hw)) + break; } if (!p->ext_init || !p->ext_uninit) { diff --git a/video/out/hwdec/hwdec_cuda.h b/video/out/hwdec/hwdec_cuda.h index 1d42505179..6e671b364e 100644 --- a/video/out/hwdec/hwdec_cuda.h +++ b/video/out/hwdec/hwdec_cuda.h @@ -29,9 +29,6 @@ struct cuda_hw_priv { CUcontext display_ctx; CUcontext decode_ctx; - // Stored as int to avoid depending on libplacebo enum - int handle_type; - // Do we need to do a full CPU sync after copying bool do_full_sync; @@ -53,10 +50,13 @@ struct cuda_mapper_priv { void *ext[4]; }; -typedef bool (*cuda_interop_init)(const struct ra_hwdec *hw); +struct cuda_interop_fn { + bool (*check)(const struct ra_hwdec *hw); + bool (*init)(const struct ra_hwdec *hw); +}; -bool cuda_gl_init(const struct ra_hwdec *hw); +extern struct cuda_interop_fn cuda_gl_fn; -bool cuda_vk_init(const struct ra_hwdec *hw); +extern struct cuda_interop_fn cuda_vk_fn; int check_cu(const struct ra_hwdec *hw, CUresult err, const char *func); diff --git a/video/out/hwdec/hwdec_cuda_gl.c b/video/out/hwdec/hwdec_cuda_gl.c index 0e6160da87..4c2535232f 100644 --- a/video/out/hwdec/hwdec_cuda_gl.c +++ b/video/out/hwdec/hwdec_cuda_gl.c @@ -17,15 +17,14 @@ * License along with mpv. If not, see <http://www.gnu.org/licenses/>. */ -#include "config.h" #include "hwdec_cuda.h" #include "options/m_config.h" +#include "options/options.h" #include "video/out/opengl/formats.h" #include "video/out/opengl/ra_gl.h" #include <libavutil/hwcontext.h> #include <libavutil/hwcontext_cuda.h> -#include <unistd.h> #define CHECK_CU(x) check_cu((mapper)->owner, (x), #x) @@ -106,22 +105,24 @@ static void cuda_ext_gl_uninit(const struct ra_hwdec_mapper *mapper, int n) #undef CHECK_CU #define CHECK_CU(x) check_cu(hw, (x), #x) -bool cuda_gl_init(const struct ra_hwdec *hw) { - int ret = 0; - struct cuda_hw_priv *p = hw->priv; - CudaFunctions *cu = p->cu; +static bool cuda_gl_check(const struct ra_hwdec *hw) { + if (!ra_is_gl(hw->ra_ctx->ra)) + return false; // This is not an OpenGL RA. - if (ra_is_gl(hw->ra)) { - GL *gl = ra_gl_get(hw->ra); - if (gl->version < 210 && gl->es < 300) { - MP_VERBOSE(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n"); - return false; - } - } else { - // This is not an OpenGL RA. + GL *gl = ra_gl_get(hw->ra_ctx->ra); + if (gl->version < 210 && gl->es < 300) { + MP_VERBOSE(hw, "need OpenGL >= 2.1 or OpenGL-ES >= 3.0\n"); return false; } + return true; +} + +static bool cuda_gl_init(const struct ra_hwdec *hw) { + int ret = 0; + struct cuda_hw_priv *p = hw->priv; + CudaFunctions *cu = p->cu; + CUdevice display_dev; unsigned int device_count; ret = CHECK_CU(cu->cuGLGetDevices(&device_count, &display_dev, 1, @@ -136,9 +137,9 @@ bool cuda_gl_init(const struct ra_hwdec *hw) { p->decode_ctx = p->display_ctx; - int decode_dev_idx = -1; - mp_read_option_raw(hw->global, "cuda-decode-device", &m_option_type_choice, - &decode_dev_idx); + struct cuda_opts *opts = mp_get_config_group(NULL, hw->global, &cuda_conf); + int decode_dev_idx = opts->cuda_device; + talloc_free(opts); if (decode_dev_idx > -1) { CUcontext dummy; @@ -172,3 +173,8 @@ bool cuda_gl_init(const struct ra_hwdec *hw) { return true; } + +struct cuda_interop_fn cuda_gl_fn = { + .check = cuda_gl_check, + .init = cuda_gl_init +}; diff --git a/video/out/hwdec/hwdec_cuda_vk.c b/video/out/hwdec/hwdec_cuda_vk.c index 3b058d740f..e744ff628a 100644 --- a/video/out/hwdec/hwdec_cuda_vk.c +++ b/video/out/hwdec/hwdec_cuda_vk.c @@ -23,10 +23,15 @@ #include <libavutil/hwcontext.h> #include <libavutil/hwcontext_cuda.h> -#include <unistd.h> +#include <libplacebo/vulkan.h> + +#include "osdep/io.h" #if HAVE_WIN32_DESKTOP #include <versionhelpers.h> +#define HANDLE_TYPE PL_HANDLE_WIN32 +#else +#define HANDLE_TYPE PL_HANDLE_FD #endif #define CHECK_CU(x) check_cu((mapper)->owner, (x), #x) @@ -36,10 +41,9 @@ struct ext_vk { CUmipmappedArray mma; pl_tex pltex; - pl_sync sync; - - CUexternalSemaphore ss; - CUexternalSemaphore ws; + pl_vulkan_sem vk_sem; + union pl_handle sem_handle; + CUexternalSemaphore cuda_sem; }; static bool cuda_ext_vk_init(struct ra_hwdec_mapper *mapper, @@ -48,7 +52,7 @@ static bool cuda_ext_vk_init(struct ra_hwdec_mapper *mapper, struct cuda_hw_priv *p_owner = mapper->owner->priv; struct cuda_mapper_priv *p = mapper->priv; CudaFunctions *cu = p_owner->cu; - int mem_fd = -1, wait_fd = -1, signal_fd = -1; + int mem_fd = -1; int ret = 0; struct ext_vk *evk = talloc_ptrtype(NULL, evk); @@ -62,7 +66,7 @@ static bool cuda_ext_vk_init(struct ra_hwdec_mapper *mapper, .d = 0, .format = ra_pl_fmt_get(format), .sampleable = true, - .export_handle = p_owner->handle_type, + .export_handle = HANDLE_TYPE, }; evk->pltex = pl_tex_create(gpu, &tex_params); @@ -80,19 +84,14 @@ static bool cuda_ext_vk_init(struct ra_hwdec_mapper *mapper, mapper->tex[n] = ratex; #if !HAVE_WIN32_DESKTOP - if (evk->pltex->params.export_handle == PL_HANDLE_FD) { - mem_fd = dup(evk->pltex->shared_mem.handle.fd); - if (mem_fd < 0) { - goto error; - } - } + mem_fd = dup(evk->pltex->shared_mem.handle.fd); + if (mem_fd < 0) + goto error; #endif CUDA_EXTERNAL_MEMORY_HANDLE_DESC ext_desc = { #if HAVE_WIN32_DESKTOP - .type = IsWindows8OrGreater() - ? CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32 - : CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32_KMT, + .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_WIN32, .handle.win32.handle = evk->pltex->shared_mem.handle.handle, #else .type = CU_EXTERNAL_MEMORY_HANDLE_TYPE_OPAQUE_FD, @@ -141,51 +140,31 @@ static bool cuda_ext_vk_init(struct ra_hwdec_mapper *mapper, if (ret < 0) goto error; - evk->sync = pl_sync_create(gpu, p_owner->handle_type); - if (!evk->sync) { - ret = -1; - goto error; - } - -#if !HAVE_WIN32_DESKTOP - if (evk->sync->handle_type == PL_HANDLE_FD) { - wait_fd = dup(evk->sync->wait_handle.fd); - signal_fd = dup(evk-> |