diff options
-rw-r--r-- | DOCS/interface-changes.rst | 9 | ||||
-rw-r--r-- | DOCS/man/input.rst | 5 | ||||
-rw-r--r-- | DOCS/man/options.rst | 55 | ||||
-rw-r--r-- | libmpv/opengl_cb.h | 13 | ||||
-rw-r--r-- | options/options.c | 5 | ||||
-rw-r--r-- | options/options.h | 4 | ||||
-rw-r--r-- | player/command.c | 12 | ||||
-rw-r--r-- | video/decode/vd_lavc.c | 2 | ||||
-rw-r--r-- | video/hwdec.c | 48 | ||||
-rw-r--r-- | video/hwdec.h | 13 | ||||
-rw-r--r-- | video/out/gpu/hwdec.c | 81 | ||||
-rw-r--r-- | video/out/gpu/hwdec.h | 16 | ||||
-rw-r--r-- | video/out/gpu/video.c | 103 | ||||
-rw-r--r-- | video/out/gpu/video.h | 7 | ||||
-rw-r--r-- | video/out/vo_gpu.c | 22 | ||||
-rw-r--r-- | video/out/vo_opengl_cb.c | 9 |
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_unini |