summaryrefslogtreecommitdiffstats
path: root/video/out/hwdec
diff options
context:
space:
mode:
Diffstat (limited to 'video/out/hwdec')
-rw-r--r--video/out/hwdec/dmabuf_interop.h4
-rw-r--r--video/out/hwdec/dmabuf_interop_gl.c190
-rw-r--r--video/out/hwdec/dmabuf_interop_pl.c5
-rw-r--r--video/out/hwdec/dmabuf_interop_wl.c36
-rw-r--r--video/out/hwdec/hwdec_aimagereader.c49
-rw-r--r--video/out/hwdec/hwdec_cuda.c47
-rw-r--r--video/out/hwdec/hwdec_cuda.h12
-rw-r--r--video/out/hwdec/hwdec_cuda_gl.c40
-rw-r--r--video/out/hwdec/hwdec_cuda_vk.c196
-rw-r--r--video/out/hwdec/hwdec_drmprime.c53
-rw-r--r--video/out/hwdec/hwdec_drmprime_overlay.c31
-rw-r--r--video/out/hwdec/hwdec_ios_gl.m222
-rw-r--r--video/out/hwdec/hwdec_mac_gl.c169
-rw-r--r--video/out/hwdec/hwdec_vaapi.c48
-rw-r--r--video/out/hwdec/hwdec_vt.c141
-rw-r--r--video/out/hwdec/hwdec_vt.h63
-rw-r--r--video/out/hwdec/hwdec_vt_pl.m312
-rw-r--r--video/out/hwdec/hwdec_vulkan.c333
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->