From 9d68d8fb0f806f25408435c09ac5dbbe34b95462 Mon Sep 17 00:00:00 2001 From: wm4 Date: Tue, 17 Jan 2017 14:51:08 +0100 Subject: [PATCH] vo_opengl, vo_opengl_cb: better hwdec interop backend selection Introduce the --opengl-hwdec-interop option, which replaces --hwdec-preload. The new option allows explicit selection of the interop backend. This is relatively complex, and I would have preferred not to add this, but it's probably useful to debug certain problems. In exchange, the "new" option documents that pretty much any but the simplest use of it will not be forward compatible. --- DOCS/interface-changes.rst | 6 ++++ DOCS/man/input.rst | 7 +++-- DOCS/man/options.rst | 17 ++++++++-- options/options.c | 8 +++-- options/options.h | 2 +- video/out/opengl/hwdec.c | 63 ++++++++++++++++++++++++++++++++++++++ video/out/opengl/hwdec.h | 8 +++++ video/out/vo_opengl.c | 11 ++----- video/out/vo_opengl_cb.c | 10 ++---- 9 files changed, 109 insertions(+), 23 deletions(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index a6133a3848..90b7720a51 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -19,6 +19,12 @@ Interface changes :: + --- mpv 0.24.0 --- + - deprecate --hwdec-api and replace it with --opengl-hwdec-interop. + The new option accepts both --hwdec values, as well as named backends. + A minor difference is that --hwdec-api=no (which used to be the default) + now actually does not preload any interop layer, while the new default + ("") uses the value of --hwdec. --- mpv 0.23.0 --- - remove deprecated vf_vdpaurb (use "--hwdec=vdpau-copy" instead) - the following properties now have new semantics: diff --git a/DOCS/man/input.rst b/DOCS/man/input.rst index 70a05dcaef..68f5ae53e8 100644 --- a/DOCS/man/input.rst +++ b/DOCS/man/input.rst @@ -1331,8 +1331,8 @@ 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 - ``--hwdec-preload`` can load it eagerly.) If there are multiple drivers - loaded, they will be separated by ``,``. + ``--opengl-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 unavailable. @@ -1341,6 +1341,9 @@ 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 3794ff23e3..a812fb088c 100644 --- a/DOCS/man/options.rst +++ b/DOCS/man/options.rst @@ -746,12 +746,12 @@ Video In particular, ``auto-copy`` will only select safe modes (although potentially slower than other methods). -``--hwdec-preload=`` +``--opengl-hwdec-interop=`` This is useful for the ``opengl`` 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 ``no`` (default), the ``--hwdec`` option is used. + If set to an empty string (default), the ``--hwdec`` option is used. For ``opengl``, if set, do not create the interop context on demand, but when the VO is created. @@ -762,6 +762,19 @@ Video 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``. + ``--videotoolbox-format=`` Set the internal pixel format used by ``--hwdec=videotoolbox`` on OSX. The choice of the format can influence performance considerably. On the other diff --git a/options/options.c b/options/options.c index f79df7d82f..bc9ddf8614 100644 --- a/options/options.c +++ b/options/options.c @@ -40,6 +40,7 @@ #include "stream/stream.h" #include "video/csputils.h" #include "video/hwdec.h" +#include "video/out/opengl/hwdec.h" #include "video/image_writer.h" #include "sub/osd.h" #include "audio/filter/af.h" @@ -150,7 +151,6 @@ const struct m_sub_options stream_cache_conf = { static const m_option_t mp_vo_opt_list[] = { OPT_SETTINGSLIST("vo", video_driver_list, 0, &vo_obj_list, ), - OPT_CHOICE_C("hwdec-preload", hwdec_preload_api, 0, mp_hwdec_names), OPT_SUBSTRUCT("sws", sws_opts, sws_conf, 0), OPT_FLAG("taskbar-progress", taskbar_progress, 0), OPT_FLAG("ontop", ontop, 0), @@ -199,7 +199,11 @@ static const m_option_t mp_vo_opt_list[] = { 0, drm_validate_connector_opt), OPT_INT("drm-mode", drm_mode_id, 0), #endif - +#if HAVE_GL + OPT_STRING_VALIDATE("opengl-hwdec-interop", gl_hwdec_interop, 0, + gl_hwdec_validate_opt), + OPT_REPLACED("hwdec-preload", "opengl-hwdec-interop"), +#endif {0} }; diff --git a/options/options.h b/options/options.h index fc37e98f8a..1d79d55c31 100644 --- a/options/options.h +++ b/options/options.h @@ -50,7 +50,7 @@ typedef struct mp_vo_opts { // vo_wayland, vo_drm struct sws_opts *sws_opts; // vo_opengl, vo_opengl_cb - int hwdec_preload_api; + char *gl_hwdec_interop; // vo_drm char *drm_connector_spec; int drm_mode_id; diff --git a/video/out/opengl/hwdec.c b/video/out/opengl/hwdec.c index 261931a8d4..ab365df8ff 100644 --- a/video/out/opengl/hwdec.c +++ b/video/out/opengl/hwdec.c @@ -22,6 +22,7 @@ #include "common/common.h" #include "common/msg.h" +#include "options/m_config.h" #include "hwdec.h" extern const struct gl_hwdec_driver gl_hwdec_vaegl; @@ -110,6 +111,68 @@ struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl, return NULL; } +// Load by option name. +struct gl_hwdec *gl_hwdec_load(struct mp_log *log, GL *gl, + 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 gl_hwdec_driver *drv = mpgl_hwdec_drivers[n]; + if (name && strcmp(drv->name, name) == 0) { + struct gl_hwdec *r = load_hwdec_driver(log, gl, g, devs, drv, false); + if (r) + return r; + } + } + + return gl_hwdec_load_api(log, gl, g, devs, api_id); +} + +int gl_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 gl_hwdec_driver *drv = mpgl_hwdec_drivers[n]; + const char *api_name = m_opt_choice_str(mp_hwdec_names, drv->api); + if (help) { + mp_info(log, " %s [%s]\n", drv->name, api_name); + } else if (bstr_equals0(param, drv->name) || + bstr_equals0(param, api_name)) + { + return 1; + } + } + if (help) { + mp_info(log, " auto (loads best)\n" + " (other --hwdec values)\n" + "Setting an empty string means use --hwdec.\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; + } + mp_fatal(log, "No hwdec backend named '%.*s' found!\n", BSTR_P(param)); + return M_OPT_INVALID; +} + void gl_hwdec_uninit(struct gl_hwdec *hwdec) { if (hwdec) diff --git a/video/out/opengl/hwdec.h b/video/out/opengl/hwdec.h index 6a1bb98bff..948b42bc74 100644 --- a/video/out/opengl/hwdec.h +++ b/video/out/opengl/hwdec.h @@ -81,6 +81,14 @@ struct gl_hwdec *gl_hwdec_load_api(struct mp_log *log, GL *gl, struct mp_hwdec_devices *devs, enum hwdec_type api); +struct gl_hwdec *gl_hwdec_load(struct mp_log *log, GL *gl, + struct mpv_global *g, + struct mp_hwdec_devices *devs, + const char *name); + +int gl_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt, + struct bstr name, struct bstr param); + void gl_hwdec_uninit(struct gl_hwdec *hwdec); bool gl_hwdec_test_format(struct gl_hwdec *hwdec, int imgfmt); diff --git a/video/out/vo_opengl.c b/video/out/vo_opengl.c index 7f65a1eafc..be187f63c3 100644 --- a/video/out/vo_opengl.c +++ b/video/out/vo_opengl.c @@ -411,14 +411,9 @@ static int preinit(struct vo *vo) hwdec_devices_set_loader(vo->hwdec_devs, call_request_hwdec_api, vo); - int hwdec = vo->opts->hwdec_preload_api; - if (hwdec == HWDEC_NONE) - hwdec = vo->global->opts->hwdec_api; - if (hwdec != HWDEC_NONE) { - p->hwdec = gl_hwdec_load_api(p->vo->log, p->gl, vo->global, - vo->hwdec_devs, hwdec); - gl_video_set_hwdec(p->renderer, p->hwdec); - } + p->hwdec = gl_hwdec_load(p->vo->log, p->gl, vo->global, + vo->hwdec_devs, vo->opts->gl_hwdec_interop); + gl_video_set_hwdec(p->renderer, p->hwdec); return 0; diff --git a/video/out/vo_opengl_cb.c b/video/out/vo_opengl_cb.c index c2c0f795e1..9ecdf5eaed 100644 --- a/video/out/vo_opengl_cb.c +++ b/video/out/vo_opengl_cb.c @@ -167,15 +167,9 @@ int mpv_opengl_cb_init_gl(struct mpv_opengl_cb_context *ctx, const char *exts, m_config_cache_update(ctx->vo_opts_cache); - int g_hwdec_api; - mp_read_option_raw(ctx->global, "hwdec", &m_option_type_choice, &g_hwdec_api); - ctx->hwdec_devs = hwdec_devices_create(); - int hwdec_api = ctx->vo_opts->hwdec_preload_api; - if (hwdec_api == HWDEC_NONE) - hwdec_api = g_hwdec_api; - ctx->hwdec = gl_hwdec_load_api(ctx->log, ctx->gl, ctx->global, - ctx->hwdec_devs, hwdec_api); + ctx->hwdec = gl_hwdec_load(ctx->log, ctx->gl, ctx->global, + ctx->hwdec_devs, ctx->vo_opts->gl_hwdec_interop); gl_video_set_hwdec(ctx->renderer, ctx->hwdec); pthread_mutex_lock(&ctx->lock);