summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/interface-changes.rst9
-rw-r--r--DOCS/man/input.rst5
-rw-r--r--DOCS/man/options.rst55
-rw-r--r--libmpv/opengl_cb.h13
-rw-r--r--options/options.c5
-rw-r--r--options/options.h4
-rw-r--r--player/command.c12
-rw-r--r--video/decode/vd_lavc.c2
-rw-r--r--video/hwdec.c48
-rw-r--r--video/hwdec.h13
-rw-r--r--video/out/gpu/hwdec.c81
-rw-r--r--video/out/gpu/hwdec.h16
-rw-r--r--video/out/gpu/video.c103
-rw-r--r--video/out/gpu/video.h7
-rw-r--r--video/out/vo_gpu.c22
-rw-r--r--video/out/vo_opengl_cb.c9
16 files changed, 207 insertions, 197 deletions
diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst
index 494b769b8b..312fe9552a 100644
--- a/DOCS/interface-changes.rst
+++ b/DOCS/interface-changes.rst
@@ -48,6 +48,15 @@ Interface changes
- remove deprecated --demuxer-max-packets
- remove most of the deprecated audio and video filters
- remove the deprecated --balance option/property
+ - rename the --opengl-hwdec-interop option to --gpu-hwdec-interop, and
+ change some of its semantics: extend it take the strings "auto" and
+ "all". "all" loads all backends. "auto" behaves like "all" for
+ vo_opengl_cb, while on vo_gpu it loads nothing, but allows on demand
+ loading by the decoder. The empty string as option value behaves like
+ "auto". Old --hwdec values do not work anymore.
+ This option is hereby declared as unstable and may change any time - its
+ old use is deprecated, and it has very little use outside of debugging
+ now.
--- mpv 0.27.0 ---
- drop previously deprecated --field-dominance option
- drop previously deprecated "osd" command
diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst
index 75cb9526c6..4e81a3ce2d 100644
--- a/DOCS/man/input.rst
+++ b/DOCS/man/input.rst
@@ -1433,7 +1433,7 @@ Property list
This is known only once the VO has opened (and possibly later). With some
VOs (like ``opengl``), this might be never known in advance, but only when
the decoder attempted to create the hw decoder successfully. (Using
- ``--opengl-hwdec-interop`` can load it eagerly.) If there are multiple
+ ``--gpu-hwdec-interop`` can load it eagerly.) If there are multiple
drivers loaded, they will be separated by ``,``.
If no VO is active or no interop driver is known, this property is
@@ -1443,9 +1443,6 @@ Property list
multiple interop drivers for the same hardware decoder, depending on
platform and VO.
- This is somewhat similar to the ``--opengl-hwdec-interop`` option, but
- it returns the actually loaded backend, not the value of this option.
-
``video-format``
Video format as string.
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index f3564cffb6..f01d40e563 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -816,34 +816,33 @@ Video
frame glitches or discoloration, and you have ``--hwdec`` turned on,
the first thing you should try is disabling it.
-``--opengl-hwdec-interop=<name>``
- This is useful for the ``gpu`` and ``opengl-cb`` VOs for creating the
- hardware decoding OpenGL interop context, but without actually enabling
- hardware decoding itself (like ``--hwdec`` does).
-
- If set to an empty string (default), the ``--hwdec`` option is used.
-
- For ``gpu``, if set, do not create the interop context on demand, but
- when the VO is created.
-
- For ``opengl-cb``, if set, load the interop context as soon as the OpenGL
- context is created. Since ``opengl-cb`` has no on-demand loading, this
- allows enabling hardware decoding at runtime at all, without having
- to temporarily set the ``hwdec`` option just during OpenGL context
- initialization with ``mpv_opengl_cb_init_gl()``.
-
- See ``--opengl-hwdec-interop=help`` for accepted values. This lists the
- interop backend, with the ``--hwdec`` alias after it in ``[...]``. Consider
- all values except the proper interop backend name, ``auto``, and ``no`` as
- silently deprecated and subject to change. Also, if you use this in
- application code (e.g. via libmpv), any value other than ``auto`` and ``no``
- should be avoided, as backends can change.
-
- Currently the option sets a single value. It is possible that the option
- type changes to a list in the future.
-
- The old alias ``--hwdec-preload`` has different behavior if the option value
- is ``no``.
+``--gpu-hwdec-interop=<auto|all|no|name>``
+ This option is for troubleshooting hwdec interop issues. Since it's a
+ debugging option, its semantics may change at any time.
+
+ This is useful for the ``gpu`` and ``opengl-cb`` VOs for selecting which
+ hwdec interop context to use exactly. Effectively it also can be used
+ to block loading of certain backends.
+
+ If set to ``auto`` (default), the behavior depends on the VO: for ``gpu``,
+ it does nothing, and the interop context is loaded on demand (when the
+ decoder probes for ``--hwdec`` support). For ``opengl-cb``, which has
+ has no on-demand loading, this is equivalent to ``all``.
+
+ The empty string is equivalent to ``auto``.
+
+ If set to ``all``, it attempts to load all interop contexts at GL context
+ creation time.
+
+ Other than that, a specific backend can be set, and the list of them can
+ be queried with ``help`` (mpv CLI only).
+
+ Runtime changes to this are ignored (the current option value is used
+ whenever the renderer is created).
+
+ The old aliases ``--opengl-hwdec-interop`` and ``--hwdec-preload`` are
+ barely related to this anymore, but will be somewhat compatible in some
+ cases.
``--hwdec-image-format=<name>``
Set the internal pixel format used by hardware decoding via ``--hwdec``
diff --git a/libmpv/opengl_cb.h b/libmpv/opengl_cb.h
index 0658a2e509..ccafbf5839 100644
--- a/libmpv/opengl_cb.h
+++ b/libmpv/opengl_cb.h
@@ -116,17 +116,18 @@ extern "C" {
*
* While "normal" mpv loads the OpenGL hardware decoding interop on demand,
* this can't be done with opengl_cb for internal technical reasons. Instead,
- * make it load the interop at load time by setting the
- * "opengl-hwdec-interop"="auto" option before calling mpv_opengl_cb_init_gl()
- * ("hwdec-preload" in older mpv releases).
+ * it loads them by default, even if hardware decoding is not going to be used.
+ * In older mpv relases, this had to be done by setting the
+ * "opengl-hwdec-interop" or "hwdec-preload" options before calling
+ * mpv_opengl_cb_init_gl(). You can still use the newer "gpu-hwdec-interop"
+ * option to prevent loading of interop, or to load only a specific interop.
*
* There may be certain requirements on the OpenGL implementation:
* - Windows: ANGLE is required (although in theory GL/DX interop could be used)
* - Intel/Linux: EGL is required, and also a glMPGetNativeDisplay() callback
* must be provided (see sections below)
- * - nVidia/Linux: GLX is required (if you force "cuda", it should work on EGL
- * as well, if you have recent enough drivers and the
- * "hwaccel" option is set to "cuda" as well)
+ * - nVidia/Linux: Both GLX and EGL should work (GLX is required if vdpau is
+ * used, e.g. due to old drivers.)
* - OSX: CGL is required (CGLGetCurrentContext() returning non-NULL)
* - iOS: EAGL is required (EAGLContext.currentContext returning non-nil)
*
diff --git a/options/options.c b/options/options.c
index 348cc2f5d2..c6837a03e8 100644
--- a/options/options.c
+++ b/options/options.c
@@ -55,8 +55,6 @@
#include "video/out/drm_common.h"
#endif
-#include "video/out/gpu/hwdec.h"
-
static void print_version(struct mp_log *log)
{
mp_print_version(log, true);
@@ -184,9 +182,6 @@ static const m_option_t mp_vo_opt_list[] = {
#if HAVE_DRM
OPT_SUBSTRUCT("", drm_opts, drm_conf, 0),
#endif
- OPT_STRING_VALIDATE("opengl-hwdec-interop", gl_hwdec_interop, 0,
- ra_hwdec_validate_opt),
- OPT_REPLACED("hwdec-preload", "opengl-hwdec-interop"),
{0}
};
diff --git a/options/options.h b/options/options.h
index e2e1220fda..8bf8f1ec6a 100644
--- a/options/options.h
+++ b/options/options.h
@@ -50,10 +50,8 @@ typedef struct mp_vo_opts {
char *mmcss_profile;
- // vo_wayland, vo_drm
+ // vo_drm
struct sws_opts *sws_opts;
- // vo_opengl, vo_opengl_cb
- char *gl_hwdec_interop;
// vo_drm
struct drm_opts *drm_opts;
} mp_vo_opts;
diff --git a/player/command.c b/player/command.c
index 569272c680..9017278286 100644
--- a/player/command.c
+++ b/player/command.c
@@ -2475,14 +2475,10 @@ static int mp_property_hwdec_interop(void *ctx, struct m_property *prop,
if (!mpctx->video_out || !mpctx->video_out->hwdec_devs)
return M_PROPERTY_UNAVAILABLE;
- struct mp_hwdec_ctx *hwctx =
- hwdec_devices_get_first(mpctx->video_out->hwdec_devs);
-
- const char *name = hwctx ? hwctx->driver_name : NULL;
- if (!name && hwctx)
- name = m_opt_choice_str(mp_hwdec_names, hwctx->type);
-
- return m_property_strdup_ro(action, arg, name);
+ char *names = hwdec_devices_get_names(mpctx->video_out->hwdec_devs);
+ int res = m_property_strdup_ro(action, arg, names);
+ talloc_free(names);
+ return res;
}
/// Helper to set vo flags.
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index 2362e9aa73..21e86b91b2 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -370,7 +370,7 @@ static struct mp_hwdec_ctx *hwdec_create_dev(struct dec_video *vd,
return hwdec->create_dev(vd->global, vd->log, autoprobe);
if (vd->hwdec_devs) {
int type = hwdec->interop_type ? hwdec->interop_type : hwdec->type;
- hwdec_devices_request(vd->hwdec_devs, type);
+ hwdec_devices_request_all(vd->hwdec_devs);
return hwdec_devices_get(vd->hwdec_devs, type);
}
return NULL;
diff --git a/video/hwdec.c b/video/hwdec.c
index df0cf88839..31df1522ce 100644
--- a/video/hwdec.c
+++ b/video/hwdec.c
@@ -8,9 +8,10 @@
struct mp_hwdec_devices {
pthread_mutex_t lock;
- struct mp_hwdec_ctx *hwctx;
+ struct mp_hwdec_ctx **hwctxs;
+ int num_hwctxs;
- void (*load_api)(void *ctx, enum hwdec_type type);
+ void (*load_api)(void *ctx);
void *load_api_ctx;
};
@@ -25,7 +26,7 @@ void hwdec_devices_destroy(struct mp_hwdec_devices *devs)
{
if (!devs)
return;
- assert(!devs->hwctx); // must have been hwdec_devices_remove()ed
+ assert(!devs->num_hwctxs); // must have been hwdec_devices_remove()ed
assert(!devs->load_api); // must have been unset
pthread_mutex_destroy(&devs->lock);
talloc_free(devs);
@@ -36,8 +37,12 @@ struct mp_hwdec_ctx *hwdec_devices_get(struct mp_hwdec_devices *devs,
{
struct mp_hwdec_ctx *res = NULL;
pthread_mutex_lock(&devs->lock);
- if (devs->hwctx && devs->hwctx->type == type)
- res = devs->hwctx;
+ for (int n = 0; n < devs->num_hwctxs; n++) {
+ if (devs->hwctxs[n]->type == type) {
+ res = devs->hwctxs[n];
+ break;
+ }
+ }
pthread_mutex_unlock(&devs->lock);
return res;
}
@@ -45,7 +50,7 @@ struct mp_hwdec_ctx *hwdec_devices_get(struct mp_hwdec_devices *devs,
struct mp_hwdec_ctx *hwdec_devices_get_first(struct mp_hwdec_devices *devs)
{
pthread_mutex_lock(&devs->lock);
- struct mp_hwdec_ctx *res = devs->hwctx;
+ struct mp_hwdec_ctx *res = devs->num_hwctxs ? devs->hwctxs[0] : NULL;
pthread_mutex_unlock(&devs->lock);
return res;
}
@@ -53,42 +58,55 @@ struct mp_hwdec_ctx *hwdec_devices_get_first(struct mp_hwdec_devices *devs)
void hwdec_devices_add(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx)
{
pthread_mutex_lock(&devs->lock);
- // We support only 1 device; ignore the rest.
- if (!devs->hwctx)
- devs->hwctx = ctx;
+ MP_TARRAY_APPEND(devs, devs->hwctxs, devs->num_hwctxs, ctx);
pthread_mutex_unlock(&devs->lock);
}
void hwdec_devices_remove(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx)
{
pthread_mutex_lock(&devs->lock);
- if (devs->hwctx == ctx)
- devs->hwctx = NULL;
+ for (int n = 0; n < devs->num_hwctxs; n++) {
+ if (devs->hwctxs[n] == ctx) {
+ MP_TARRAY_REMOVE_AT(devs->hwctxs, devs->num_hwctxs, n);
+ break;
+ }
+ }
pthread_mutex_unlock(&devs->lock);
}
void hwdec_devices_set_loader(struct mp_hwdec_devices *devs,
- void (*load_api)(void *ctx, enum hwdec_type type), void *load_api_ctx)
+ void (*load_api)(void *ctx), void *load_api_ctx)
{
devs->load_api = load_api;
devs->load_api_ctx = load_api_ctx;
}
-void hwdec_devices_request(struct mp_hwdec_devices *devs, enum hwdec_type type)
+void hwdec_devices_request_all(struct mp_hwdec_devices *devs)
{
if (devs->load_api && !hwdec_devices_get_first(devs))
- devs->load_api(devs->load_api_ctx, type);
+ devs->load_api(devs->load_api_ctx);
}
void *hwdec_devices_load(struct mp_hwdec_devices *devs, enum hwdec_type type)
{
if (!devs)
return NULL;
- hwdec_devices_request(devs, type);
+ hwdec_devices_request_all(devs);
struct mp_hwdec_ctx *hwctx = hwdec_devices_get(devs, type);
return hwctx ? hwctx->ctx : NULL;
}
+char *hwdec_devices_get_names(struct mp_hwdec_devices *devs)
+{
+ char *res = NULL;
+ for (int n = 0; n < devs->num_hwctxs; n++) {
+ if (res)
+ ta_xstrdup_append(&res, ",");
+ ta_xstrdup_append(&res, devs->hwctxs[n]->driver_name);
+ }
+ return res;
+}
+
#if HAVE_D3D_HWACCEL
extern const struct hwcontext_fns hwcontext_fns_d3d11;
#endif
diff --git a/video/hwdec.h b/video/hwdec.h
index 2b89c3247c..3a551ef6f7 100644
--- a/video/hwdec.h
+++ b/video/hwdec.h
@@ -87,18 +87,18 @@ struct mp_hwdec_ctx *hwdec_devices_get_first(struct mp_hwdec_devices *devs);
void hwdec_devices_add(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx);
// Remove this from the list of internal devices. Idempotent/ignores entries
-// not added yet.
+// not added yet. This is not thread-safe.
void hwdec_devices_remove(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx);
// Can be used to enable lazy loading of an API with hwdec_devices_request().
// If used at all, this must be set/unset during initialization/uninitialization,
// as concurrent use with hwdec_devices_request() is a race condition.
void hwdec_devices_set_loader(struct mp_hwdec_devices *devs,
- void (*load_api)(void *ctx, enum hwdec_type type), void *load_api_ctx);
+ void (*load_api)(void *ctx), void *load_api_ctx);
-// Cause VO to lazily load the requested device, and will block until this is
-// done (even if not available).
-void hwdec_devices_request(struct mp_hwdec_devices *devs, enum hwdec_type type);
+// Cause VO to lazily load all devices, and will block until this is done (even
+// if not available).
+void hwdec_devices_request_all(struct mp_hwdec_devices *devs);
// Convenience function:
// - return NULL if devs==NULL
@@ -107,6 +107,9 @@ void hwdec_devices_request(struct mp_hwdec_devices *devs, enum hwdec_type type);
// - then return the mp_hwdec_ctx.ctx field
void *hwdec_devices_load(struct mp_hwdec_devices *devs, enum hwdec_type type);
+// Return "," concatenated list (for introspection/debugging). Use talloc_free().
+char *hwdec_devices_get_names(struct mp_hwdec_devices *devs);
+
struct mp_image;
// Per AV_HWDEVICE_TYPE_* functions, queryable via hwdec_get_hwcontext_fns().
diff --git a/video/out/gpu/hwdec.c b/video/out/gpu/hwdec.c
index 12f4dd7f64..4661e875bf 100644
--- a/video/out/gpu/hwdec.c
+++ b/video/out/gpu/hwdec.c
@@ -40,7 +40,7 @@ extern const struct ra_hwdec_driver ra_hwdec_cuda_nvdec;
extern const struct ra_hwdec_driver ra_hwdec_rpi_overlay;
extern const struct ra_hwdec_driver ra_hwdec_drmprime_drm;
-static const struct ra_hwdec_driver *const mpgl_hwdec_drivers[] = {
+const struct ra_hwdec_driver *const ra_hwdec_drivers[] = {
#if HAVE_VAAPI_EGL
&ra_hwdec_vaegl,
#endif
@@ -76,11 +76,11 @@ static const struct ra_hwdec_driver *const mpgl_hwdec_drivers[] = {
NULL
};
-static struct ra_hwdec *load_hwdec_driver(struct mp_log *log, struct ra *ra,
- struct mpv_global *global,
- struct mp_hwdec_devices *devs,
- const struct ra_hwdec_driver *drv,
- bool is_auto)
+struct ra_hwdec *ra_hwdec_load_driver(struct ra *ra, struct mp_log *log,
+ struct mpv_global *global,
+ struct mp_hwdec_devices *devs,
+ const struct ra_hwdec_driver *drv,
+ bool is_auto)
{
struct ra_hwdec *hwdec = talloc(NULL, struct ra_hwdec);
*hwdec = (struct ra_hwdec) {
@@ -101,81 +101,30 @@ static struct ra_hwdec *load_hwdec_driver(struct mp_log *log, struct ra *ra,
return hwdec;
}
-struct ra_hwdec *ra_hwdec_load_api(struct mp_log *log, struct ra *ra,
- struct mpv_global *g,
- struct mp_hwdec_devices *devs,
- enum hwdec_type api)
-{
- bool is_auto = HWDEC_IS_AUTO(api);
- for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
- const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n];
- if ((is_auto || api == drv->api) && !drv->testing_only) {
- struct ra_hwdec *r = load_hwdec_driver(log, ra, g, devs, drv, is_auto);
- if (r)
- return r;
- }
- }
- return NULL;
-}
-
-// Load by option name.
-struct ra_hwdec *ra_hwdec_load(struct mp_log *log, struct ra *ra,
- struct mpv_global *g,
- struct mp_hwdec_devices *devs,
- const char *name)
-{
- int g_hwdec_api;
- mp_read_option_raw(g, "hwdec", &m_option_type_choice, &g_hwdec_api);
- if (!name || !name[0])
- name = m_opt_choice_str(mp_hwdec_names, g_hwdec_api);
-
- int api_id = HWDEC_NONE;
- for (int n = 0; mp_hwdec_names[n].name; n++) {
- if (name && strcmp(mp_hwdec_names[n].name, name) == 0)
- api_id = mp_hwdec_names[n].value;
- }
-
- for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
- const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n];
- if (name && strcmp(drv->name, name) == 0) {
- struct ra_hwdec *r = load_hwdec_driver(log, ra, g, devs, drv, false);
- if (r)
- return r;
- }
- }
-
- return ra_hwdec_load_api(log, ra, g, devs, api_id);
-}
-
int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
struct bstr name, struct bstr param)
{
bool help = bstr_equals0(param, "help");
if (help)
mp_info(log, "Available hwdecs:\n");
- for (int n = 0; mpgl_hwdec_drivers[n]; n++) {
- const struct ra_hwdec_driver *drv = mpgl_hwdec_drivers[n];
- const char *api_name = m_opt_choice_str(mp_hwdec_names, drv->api);
+ for (int n = 0; ra_hwdec_drivers[n]; n++) {
+ const struct ra_hwdec_driver *drv = ra_hwdec_drivers[n];
if (help) {
- mp_info(log, " %s [%s]\n", drv->name, api_name);
- } else if (bstr_equals0(param, drv->name) ||
- bstr_equals0(param, api_name))
- {
+ mp_info(log, " %s\n", drv->name);
+ } else if (bstr_equals0(param, drv->name)) {
return 1;
}
}
if (help) {
- mp_info(log, " auto (loads best)\n"
- " (other --hwdec values)\n"
- "Setting an empty string means use --hwdec.\n");
+ mp_info(log, " auto (behavior depends on context)\n"
+ " no (do not load any and block loading on demand)\n");
return M_OPT_EXIT;
}
if (!param.len)
return 1; // "" is treated specially
- for (int n = 0; mp_hwdec_names[n].name; n++) {
- if (bstr_equals0(param, mp_hwdec_names[n].name))
- return 1;
- }
+ if (bstr_equals0(param, "all") || bstr_equals0(param, "auto") ||
+ bstr_equals0(param, "no"))
+ return 1;
mp_fatal(log, "No hwdec backend named '%.*s' found!\n", BSTR_P(param));
return M_OPT_INVALID;
}
diff --git a/video/out/gpu/hwdec.h b/video/out/gpu/hwdec.h
index 20bbaae9eb..0ff6056bfd 100644
--- a/video/out/gpu/hwdec.h
+++ b/video/out/gpu/hwdec.h
@@ -104,15 +104,13 @@ struct ra_hwdec_driver {
struct mp_rect *src, struct mp_rect *dst, bool newframe);
};
-struct ra_hwdec *ra_hwdec_load_api(struct mp_log *log, struct ra *ra,
- struct mpv_global *g,
- struct mp_hwdec_devices *devs,
- enum hwdec_type api);
-
-struct ra_hwdec *ra_hwdec_load(struct mp_log *log, struct ra *ra,
- struct mpv_global *g,
- struct mp_hwdec_devices *devs,
- const char *name);
+extern const struct ra_hwdec_driver *const ra_hwdec_drivers[];
+
+struct ra_hwdec *ra_hwdec_load_driver(struct ra *ra, struct mp_log *log,
+ struct mpv_global *global,
+ struct mp_hwdec_devices *devs,
+ const struct ra_hwdec_driver *drv,
+ bool is_auto);
int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
struct bstr name, struct bstr param);
diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c
index 4cdf20dfae..29af4b92b1 100644
--- a/video/out/gpu/video.c
+++ b/video/out/gpu/video.c
@@ -277,8 +277,12 @@ struct gl_video {
struct cached_file *files;
int num_files;
- struct ra_hwdec *hwdec;
+ bool hwdec_interop_loading_done;
+ struct ra_hwdec **hwdecs;
+ int num_hwdecs;
+
struct ra_hwdec_mapper *hwdec_mapper;
+ struct ra_hwdec *hwdec_overlay;
bool hwdec_active;
bool dsi_warned;
@@ -401,6 +405,10 @@ const struct m_sub_options gl_video_conf = {
OPT_INTRANGE("gpu-tex-pad-y", tex_pad_y, 0, 0, 4096),
OPT_SUBSTRUCT("", icc_opts, mp_icc_conf, 0),
OPT_STRING("gpu-shader-cache-dir", shader_cache_dir, 0),
+ OPT_STRING_VALIDATE("gpu-hwdec-interop", hwdec_interop, 0,
+ ra_hwdec_validate_opt),
+ OPT_REPLACED("opengl-hwdec-interop", "gpu-hwdec-interop"),
+ OPT_REPLACED("hwdec-preload", "opengl-hwdec-interop"),
OPT_REPLACED("hdr-tone-mapping", "tone-mapping"),
OPT_REPLACED("opengl-shaders", "glsl-shaders"),
OPT_REPLACED("opengl-shader", "glsl-shader"),
@@ -803,18 +811,27 @@ static void init_video(struct gl_video *p)
{
p->use_integer_conversion = false;
- if (p->hwdec && ra_hwdec_test_format(p->hwdec, p->image_params.imgfmt)) {
- if (p->hwdec->driver->overlay_frame) {
+ struct ra_hwdec *hwdec = NULL;
+ for (int n = 0; n < p->num_hwdecs; n++) {
+ if (ra_hwdec_test_format(p->hwdecs[n], p->image_params.imgfmt)) {
+ hwdec = p->hwdecs[n];
+ break;
+ }
+ }
+
+ if (hwdec) {
+ if (hwdec->driver->overlay_frame) {
MP_WARN(p, "Using HW-overlay mode. No GL filtering is performed "
"on the video!\n");
+ p->hwdec_overlay = hwdec;
} else {
- p->hwdec_mapper = ra_hwdec_mapper_create(p->hwdec, &p->image_params);
+ p->hwdec_mapper = ra_hwdec_mapper_create(hwdec, &p->image_params);
if (!p->hwdec_mapper)
MP_ERR(p, "Initializing texture for hardware decoding failed.\n");
}
if (p->hwdec_mapper)
p->image_params = p->hwdec_mapper->dst_params;
- const char **exts = p->hwdec->glsl_extensions;
+ const char **exts = hwdec->glsl_extensions;
for (int n = 0; exts && exts[n]; n++)
gl_sc_enable_extension(p->sc, (char *)exts[n]);
p->hwdec_active = true;
@@ -957,8 +974,8 @@ static void unref_current_image(struct gl_video *p)
// lead to flickering artifacts.
static void unmap_overlay(struct gl_video *p)
{
- if (p->hwdec_active && p->hwdec->driver->overlay_frame)
- p->hwdec->driver->overlay_frame(p->hwdec, NULL, NULL, NULL, true);
+ if (p->hwdec_overlay)
+ p->hwdec_overlay->driver->overlay_frame(p->hwdec_overlay, NULL, NULL, NULL, true);
}
static void uninit_video(struct gl_video *p)
@@ -981,6 +998,7 @@ static void uninit_video(struct gl_video *p)
p->real_image_params = (struct mp_image_params){0};
p->image_params = p->real_image_params;
p->hwdec_active = false;
+ p->hwdec_overlay = NULL;
ra_hwdec_mapper_free(&p->hwdec_mapper);
}
@@ -3005,15 +3023,15 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,
p->ra->fns->clear(p->ra, fbo.tex, color, &target_rc);
}
- if (p->hwdec_active && p->hwdec->driver->overlay_frame) {
+ if (p->hwdec_overlay) {
if (has_frame) {
- float *color = p->hwdec->overlay_colorkey;
+ float *color = p->hwdec_overlay->overlay_colorkey;
p->ra->fns->clear(p->ra, fbo.tex, color, &p->dst_rect);
}
- p->hwdec->driver->overlay_frame(p->hwdec, frame->current,
- &p->src_rect, &p->dst_rect,
- frame->frame_id != p->image.id);
+ p->hwdec_overlay->driver->overlay_frame(p->hwdec_overlay, frame->current,
+ &p->src_rect, &p->dst_rect,
+ frame->frame_id != p->image.id);
if (frame->current)
p->osd_pts = frame->current->pts;
@@ -3507,6 +3525,10 @@ void gl_video_uninit(struct gl_video *p)
uninit_video(p);
+ for (int n = 0; n < p->num_hwdecs; n++)
+ ra_hwdec_uninit(p->hwdecs[n]);
+ p->num_hwdecs = 0;
+
gl_sc_destroy(p->sc);
ra_tex_free(p->ra, &p->lut_3d_texture);
@@ -3561,8 +3583,10 @@ bool gl_video_check_format(struct gl_video *p, int mp_format)
if (ra_get_imgfmt_desc(p->ra, mp_format, &desc) &&
is_imgfmt_desc_supported(p, &desc))
return true;
- if (p->hwdec && ra_hwdec_test_format(p->hwdec, mp_format))
- return true;
+ for (int n = 0; n < p->num_hwdecs; n++) {
+ if (ra_hwdec_test_format(p->hwdecs[n], mp_format))
+ return true;
+ }
return false;
}
@@ -3782,13 +3806,6 @@ void gl_video_set_ambient_lux(struct gl_video *p, int lux)
}
}
-void gl_video_set_hwdec(struct gl_video *p, struct ra_hwdec *hwdec)
-{
- unref_current_image(p);
- ra_hwdec_mapper_free(&p->hwdec_mapper);
- p->hwdec = hwdec;
-}
-
static void *gl_video_dr_alloc_buffer(struct gl_video *p, size_t size)
{
struct ra_buf_params params = {
@@ -3845,3 +3862,47 @@ struct mp_image *gl_video_get_image(struct gl_video *p, int imgfmt, int w, int h
gl_video_dr_free_buffer(p, ptr);
return res;
}
+
+static void load_add_hwdec(struct gl_video *p, struct mp_hwdec_devices *devs,
+ const struct ra_hwdec_driver *drv, bool is_auto)
+{
+ struct ra_hwdec *hwdec =
+ ra_hwdec_load_driver(p->ra, p->log, p->global, devs, drv, is_auto);
+ if (hwdec)
+ MP_TARRAY_APPEND(p, p->hwdecs, p->num_hwdecs, hwdec);
+}
+
+void gl_video_load_hwdecs(struct gl_video *p, struct mp_hwdec_devices *devs,
+ bool load_all_by_default)
+{
+ char *type = p->opts.hwdec_interop;
+ if (!type || !type[0] || strcmp(type, "auto") == 0) {
+ if (!load_all_by_default)
+ return;
+ type = "all";
+ }
+ if (strcmp(type, "no") == 0) {
+ // do nothing, just block further loading
+ } else if (strcmp(type, "all") == 0) {
+ for (int n = 0; ra_hwdec_drivers[n]; n++)
+ load_add_hwdec(p, devs, ra_hwdec_drivers[n], true);
+ } else {
+ for (int n = 0; ra_hwdec_drivers[n]; n++) {
+ const struct ra_hwdec_driver *drv = ra_hwdec_drivers[n];
+ if (strcmp(type, drv->name) == 0) {
+ load_add_hwdec(p, devs, drv, false);
+ break;
+ }
+ }
+ }
+ p->hwdec_interop_loading_done = true;
+}
+
+void gl_video_load_hwdecs_all(struct gl_video *p, struct mp_hwdec_devices *devs)
+{
+ if (!p->hwdec_interop_loading_done) {
+ for (int n = 0; ra_hwdec_drivers[n]; n++)
+ load_add_hwdec(p, devs, ra_hwdec_drivers[n], true);
+ p->hwdec_interop_loading_done = true;
+ }
+}
diff --git a/video/out/gpu/video.h b/video/out/gpu/video.h
index b87390f4d1..78f8828f99 100644
--- a/video/out/gpu/video.h
+++ b/video/out/gpu/video.h
@@ -139,6 +139,7 @@ struct gl_video_opts {
struct mp_icc_opts *icc_opts;
int early_flush;
char *shader_cache_dir;
+ char *hwdec_interop;
};
extern const struct m_sub_options gl_video_conf;
@@ -176,8 +177,10 @@ struct mp_colorspace gl_video_get_output_colorspace(struct gl_video *p);
void gl_video_reset(struct gl_video *p);
bool gl_video_showing_interpolated_frame(struct gl_video *p);
-struct ra_hwdec;
-void gl_video_set_hwdec(struct gl_video *p, struct ra_hwdec *hwdec);
+struct mp_hwdec_devices;
+void gl_video_load_hwdecs(struct gl_video *p, struct mp_hwdec_devices *devs,
+ bool load_all_by_default);
+void gl_video_load_hwdecs_all(struct gl_video *p, struct mp_hwdec_devices *devs);
struct vo;
void gl_video_configure_queue(struct gl_video *p, struct vo *vo);
diff --git a/video/out/vo_gpu.c b/video/out/vo_gpu.c
index d739cf6bfa..6a971dd94b 100644
--- a/video/out/vo_gpu.c
+++ b/video/out/vo_gpu.c
@@ -50,7 +50,6 @@ struct gpu_priv {
char *context_type;
struct ra_ctx_opts opts;
struct gl_video *renderer;
- struct ra_hwdec *hwdec;
int events;
};
@@ -120,23 +119,18 @@ static int reconfig(struct vo *vo, struct mp_image_params *params)
return 0;
}
-static void request_hwdec_api(struct vo *vo, void *api)
+static void request_hwdec_api(struct vo *vo)
{
struct gpu_priv *p = vo->priv;
- if (p->hwdec)
- return;
-
- p->hwdec = ra_hwdec_load_api(vo->log, p->ctx->ra, vo->global,
- vo->hwdec_devs, (intptr_t)api);
- gl_video_set_hwdec(p->renderer, p->hwdec);
+ gl_video_load_hwdecs_all(p->renderer, vo->hwdec_devs);
}
-static void call_request_hwdec_api(void *ctx, enum hwdec_type type)
+static void call_request_hwdec_api(void *ctx)
{
// Roundabout way to run hwdec loading on the VO thread.
// Redirects to request_hwdec_api().
- vo_control(ctx, VOCTRL_LOAD_HWDEC_API, (void *)(intptr_t)type);
+ vo_control(ctx, VOCTRL_LOAD_HWDEC_API, NULL);
}
static void get_and_update_icc_profile(struct gpu_priv *p)
@@ -195,7 +189,7 @@ static int control(struct vo *vo, uint32_t request, void *data)
return true;
}
case VOCTRL_LOAD_HWDEC_API:
- request_hwdec_api(vo, data);
+ request_hwdec_api(vo);
return true;
case VOCTRL_UPDATE_RENDER_OPTS: {
gl_video_configure_queue(p->renderer, vo);
@@ -266,7 +260,6 @@ static void uninit(struct vo *vo)
struct gpu_priv *p = vo->priv;
gl_video_uninit(p->renderer);
- ra_hwdec_uninit(p->hwdec);
if (vo->hwdec_devs) {
hwdec_devices_set_loader(vo->hwdec_devs, NULL, NULL);
hwdec_devices_destroy(vo->hwdec_devs);
@@ -298,12 +291,9 @@ static int preinit(struct vo *vo)
get_and_update_icc_profile(p);
vo->hwdec_devs = hwdec_devices_create();
-
hwdec_devices_set_loader(vo->hwdec_devs, call_request_hwdec_api, vo);
- p->hwdec = ra_hwdec_load(vo->log, p->ctx->ra, vo->global,
- vo->hwdec_devs, vo->opts->gl_hwdec_interop);