summaryrefslogtreecommitdiffstats
path: root/video/out
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.dev>2022-02-27 21:07:58 +0100
committerNiklas Haas <github-daiK1o@haasn.dev>2022-03-03 13:06:05 +0100
commitd4fc44e711aee61b34edb654587d6380abe39b05 (patch)
tree0e159674a73cf831882018476684592efe76a0d8 /video/out
parentbb434a60ed801723c8e3becae019352935539e50 (diff)
downloadmpv-d4fc44e711aee61b34edb654587d6380abe39b05.tar.bz2
mpv-d4fc44e711aee61b34edb654587d6380abe39b05.tar.xz
vo_gpu: move hwdec loading code to common helper
So I can reuse it in vo_gpu_next without having to reinvent the wheel. In theory, a lot of the stuff could be made more private inside the hwdec code itself, but for the time being I don't care about refactoring this code, merely sharing it.
Diffstat (limited to 'video/out')
-rw-r--r--video/out/gpu/hwdec.c179
-rw-r--r--video/out/gpu/hwdec.h28
-rw-r--r--video/out/gpu/libmpv_gpu.c2
-rw-r--r--video/out/gpu/video.c133
-rw-r--r--video/out/gpu/video.h2
-rw-r--r--video/out/vo_gpu.c2
6 files changed, 193 insertions, 153 deletions
diff --git a/video/out/gpu/hwdec.c b/video/out/gpu/hwdec.c
index dd2809f41e..b37407b064 100644
--- a/video/out/gpu/hwdec.c
+++ b/video/out/gpu/hwdec.c
@@ -105,36 +105,6 @@ struct ra_hwdec *ra_hwdec_load_driver(struct ra *ra, struct mp_log *log,
return hwdec;
}
-int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
- struct bstr name, const char **value)
-{
- struct bstr param = bstr0(*value);
- bool help = bstr_equals0(param, "help");
- if (help)
- mp_info(log, "Available hwdecs:\n");
- 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\n", drv->name);
- } else if (bstr_equals0(param, drv->name)) {
- return 1;
- }
- }
- if (help) {
- mp_info(log, " auto (behavior depends on context)\n"
- " all (load all hwdecs)\n"
- " no (do not load any and block loading on demand)\n");
- return M_OPT_EXIT;
- }
- if (!param.len)
- return 1; // "" is treated specially
- 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;
-}
-
void ra_hwdec_uninit(struct ra_hwdec *hwdec)
{
if (hwdec)
@@ -201,3 +171,152 @@ int ra_hwdec_mapper_map(struct ra_hwdec_mapper *mapper, struct mp_image *img)
}
return 0;
}
+
+int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
+ struct bstr name, const char **value)
+{
+ struct bstr param = bstr0(*value);
+ bool help = bstr_equals0(param, "help");
+ if (help)
+ mp_info(log, "Available hwdecs:\n");
+ 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\n", drv->name);
+ } else if (bstr_equals0(param, drv->name)) {
+ return 1;
+ }
+ }
+ if (help) {
+ mp_info(log, " auto (behavior depends on context)\n"
+ " all (load all hwdecs)\n"
+ " no (do not load any and block loading on demand)\n");
+ return M_OPT_EXIT;
+ }
+ if (!param.len)
+ return 1; // "" is treated specially
+ 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;
+}
+
+static void load_add_hwdec(struct ra_hwdec_ctx *ctx, struct mp_hwdec_devices *devs,
+ const struct ra_hwdec_driver *drv, bool is_auto)
+{
+ // Don't load duplicate hwdecs
+ for (int j = 0; j < ctx->num_hwdecs; j++) {
+ if (ctx->hwdecs[j]->driver == drv)
+ return;
+ }
+
+ struct ra_hwdec *hwdec =
+ ra_hwdec_load_driver(ctx->ra, ctx->log, ctx->global, devs, drv, is_auto);
+ if (hwdec)
+ MP_TARRAY_APPEND(NULL, ctx->hwdecs, ctx->num_hwdecs, hwdec);
+}
+
+static void load_hwdecs_all(struct ra_hwdec_ctx *ctx, struct mp_hwdec_devices *devs)
+{
+ if (!ctx->loading_done) {
+ for (int n = 0; ra_hwdec_drivers[n]; n++)
+ load_add_hwdec(ctx, devs, ra_hwdec_drivers[n], true);
+ ctx->loading_done = true;
+ }
+}
+
+void ra_hwdec_ctx_init(struct ra_hwdec_ctx *ctx, struct mp_hwdec_devices *devs,
+ const char *type, bool load_all_by_default)
+{
+ assert(ctx->ra);
+
+ /*
+ * By default, or if the option value is "auto", we will not pre-emptively
+ * load any interops, and instead allow them to be loaded on-demand.
+ *
+ * If the option value is "no", then no interops will be loaded now, and
+ * no interops will be loaded, even if requested later.
+ *
+ * If the option value is "all", then all interops will be loaded now, and
+ * obviously no interops will need to be loaded later.
+ *
+ * Finally, if a specific interop is requested, it will be loaded now, and
+ * no other interop will be loaded, even if requested later.
+ */
+ 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) {
+ load_hwdecs_all(ctx, devs);
+ } 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(ctx, devs, drv, false);
+ break;
+ }
+ }
+ }
+ ctx->loading_done = true;
+}
+
+void ra_hwdec_ctx_uninit(struct ra_hwdec_ctx *ctx)
+{
+ for (int n = 0; n < ctx->num_hwdecs; n++)
+ ra_hwdec_uninit(ctx->hwdecs[n]);
+
+ talloc_free(ctx->hwdecs);
+ memset(ctx, 0, sizeof(*ctx));
+}
+
+void ra_hwdec_ctx_load_fmt(struct ra_hwdec_ctx *ctx, struct mp_hwdec_devices *devs,
+ int imgfmt)
+{
+ if (ctx->loading_done) {
+ /*
+ * If we previously marked interop loading as done (for reasons
+ * discussed above), then do not load any other interops regardless
+ * of imgfmt.
+ */
+ return;
+ }
+
+ if (imgfmt == IMGFMT_NONE) {
+ MP_VERBOSE(ctx, "Loading hwdec drivers for all formats\n");
+ load_hwdecs_all(ctx, devs);
+ return;
+ }
+
+ MP_VERBOSE(ctx, "Loading hwdec drivers for format: '%s'\n",
+ mp_imgfmt_to_name(imgfmt));
+ for (int i = 0; ra_hwdec_drivers[i]; i++) {
+ bool matched_fmt = false;
+ const struct ra_hwdec_driver *drv = ra_hwdec_drivers[i];
+ for (int j = 0; drv->imgfmts[j]; j++) {
+ if (imgfmt == drv->imgfmts[j]) {
+ matched_fmt = true;
+ break;
+ }
+ }
+ if (!matched_fmt) {
+ continue;
+ }
+
+ load_add_hwdec(ctx, devs, drv, false);
+ }
+}
+
+struct ra_hwdec *ra_hwdec_get(struct ra_hwdec_ctx *ctx, int imgfmt)
+{
+ for (int n = 0; n < ctx->num_hwdecs; n++) {
+ if (ra_hwdec_test_format(ctx->hwdecs[n], imgfmt))
+ return ctx->hwdecs[n];
+ }
+
+ return NULL;
+}
diff --git a/video/out/gpu/hwdec.h b/video/out/gpu/hwdec.h
index 050a358c74..5150932743 100644
--- a/video/out/gpu/hwdec.h
+++ b/video/out/gpu/hwdec.h
@@ -5,6 +5,31 @@
#include "ra.h"
#include "video/hwdec.h"
+// Helper to organize/load hwdecs dynamically
+struct ra_hwdec_ctx {
+ // Set these before calling `ra_hwdec_ctx_init`
+ struct mp_log *log;
+ struct mpv_global *global;
+ struct ra *ra;
+
+ bool loading_done;
+ struct ra_hwdec **hwdecs;
+ int num_hwdecs;
+};
+
+int ra_hwdec_validate_opt(struct mp_log *log, const m_option_t *opt,
+ struct bstr name, const char **value);
+
+void ra_hwdec_ctx_init(struct ra_hwdec_ctx *ctx, struct mp_hwdec_devices *devs,
+ const char *opt, bool load_all_by_default);
+void ra_hwdec_ctx_uninit(struct ra_hwdec_ctx *ctx);
+
+void ra_hwdec_ctx_load_fmt(struct ra_hwdec_ctx *ctx, struct mp_hwdec_devices *devs,
+ int imgfmt);
+
+// Gets the right `ra_hwdec` for a format, if any
+struct ra_hwdec *ra_hwdec_get(struct ra_hwdec_ctx *ctx, int imgfmt);
+
struct ra_hwdec {
const struct ra_hwdec_driver *driver;
struct mp_log *log;
@@ -108,9 +133,6 @@ struct ra_hwdec *ra_hwdec_load_driver(struct ra *ra, struct mp_log *log,
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, const char **value);
-
void ra_hwdec_uninit(struct ra_hwdec *hwdec);
bool ra_hwdec_test_format(struct ra_hwdec *hwdec, int imgfmt);
diff --git a/video/out/gpu/libmpv_gpu.c b/video/out/gpu/libmpv_gpu.c
index 8b93dcadfd..0c43a71c20 100644
--- a/video/out/gpu/libmpv_gpu.c
+++ b/video/out/gpu/libmpv_gpu.c
@@ -88,7 +88,7 @@ static int init(struct render_backend *ctx, mpv_render_param *params)
p->renderer = gl_video_init(p->context->ra, ctx->log, ctx->global);
ctx->hwdec_devs = hwdec_devices_create();
- gl_video_load_hwdecs(p->renderer, ctx->hwdec_devs, true);
+ gl_video_init_hwdecs(p->renderer, ctx->hwdec_devs, true);
ctx->driver_caps = VO_CAP_ROTATE90;
return 0;
}
diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c
index e28a88de5b..e158d3bea9 100644
--- a/video/out/gpu/video.c
+++ b/video/out/gpu/video.c
@@ -281,10 +281,7 @@ struct gl_video {
struct cached_file *files;
int num_files;
- bool hwdec_interop_loading_done;
- struct ra_hwdec **hwdecs;
- int num_hwdecs;
-
+ struct ra_hwdec_ctx hwdec_ctx;
struct ra_hwdec_mapper *hwdec_mapper;
struct ra_hwdec *hwdec_overlay;
bool hwdec_active;
@@ -887,14 +884,7 @@ static void init_video(struct gl_video *p)
{
p->use_integer_conversion = false;
- 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;
- }
- }
-
+ struct ra_hwdec *hwdec = ra_hwdec_get(&p->hwdec_ctx, p->image_params.imgfmt);
if (hwdec) {
if (hwdec->driver->overlay_frame) {
MP_WARN(p, "Using HW-overlay mode. No GL filtering is performed "
@@ -3930,11 +3920,7 @@ void gl_video_uninit(struct gl_video *p)
return;
uninit_video(p);
-
- for (int n = 0; n < p->num_hwdecs; n++)
- ra_hwdec_uninit(p->hwdecs[n]);
- p->num_hwdecs = 0;
-
+ ra_hwdec_ctx_uninit(&p->hwdec_ctx);
gl_sc_destroy(p->sc);
ra_tex_free(p->ra, &p->lut_3d_texture);
@@ -3989,10 +3975,8 @@ 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;
- for (int n = 0; n < p->num_hwdecs; n++) {
- if (ra_hwdec_test_format(p->hwdecs[n], mp_format))
- return true;
- }
+ if (ra_hwdec_get(&p->hwdec_ctx, mp_format))
+ return true;
return false;
}
@@ -4326,108 +4310,23 @@ struct mp_image *gl_video_get_image(struct gl_video *p, int imgfmt, int w, int h
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)
-{
- bool needs_loading = true;
- for (int j = 0; j < p->num_hwdecs; j++) {
- const struct ra_hwdec *hwdec = p->hwdecs[j];
- if (hwdec->driver == drv) {
- needs_loading = false;
- break;
- }
- }
- if (!needs_loading) {
- return;
- }
-
- 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);
-}
-
-static void 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;
- }
-}
-
-void gl_video_load_hwdecs(struct gl_video *p, struct mp_hwdec_devices *devs,
+void gl_video_init_hwdecs(struct gl_video *p, struct mp_hwdec_devices *devs,
bool load_all_by_default)
{
- /*
- * By default, or if the option value is "auto", we will not pre-emptively
- * load any interops, and instead allow them to be loaded on-demand.
- *
- * If the option value is "no", then no interops will be loaded now, and
- * no interops will be loaded, even if requested later.
- *
- * If the option value is "all", then all interops will be loaded now, and
- * obviously no interops will need to be loaded later.
- *
- * Finally, if a specific interop is requested, it will be loaded now, and
- * no other interop will be loaded, even if requested later.
- */
- 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) {
- load_hwdecs_all(p, devs);
- } 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;
+ assert(!p->hwdec_ctx.ra);
+ p->hwdec_ctx = (struct ra_hwdec_ctx) {
+ .log = p->log,
+ .global = p->global,
+ .ra = p->ra,
+ };
+
+ ra_hwdec_ctx_init(&p->hwdec_ctx, devs, p->opts.hwdec_interop, load_all_by_default);
}
void gl_video_load_hwdecs_for_img_fmt(struct gl_video *p,
struct mp_hwdec_devices *devs,
int imgfmt)
{
- if (p->hwdec_interop_loading_done) {
- /*
- * If we previously marked interop loading as done (for reasons
- * discussed above), then do not load any other interops regardless
- * of imgfmt.
- */
- return;
- }
-
- if (imgfmt == IMGFMT_NONE) {
- MP_VERBOSE(p, "Loading hwdec drivers for all formats\n");
- load_hwdecs_all(p, devs);
- return;
- }
-
- MP_VERBOSE(p, "Loading hwdec drivers for format: '%s'\n",
- mp_imgfmt_to_name(imgfmt));
- for (int i = 0; ra_hwdec_drivers[i]; i++) {
- bool matched_fmt = false;
- const struct ra_hwdec_driver *drv = ra_hwdec_drivers[i];
- for (int j = 0; drv->imgfmts[j]; j++) {
- if (imgfmt == drv->imgfmts[j]) {
- matched_fmt = true;
- break;
- }
- }
- if (!matched_fmt) {
- continue;
- }
-
- load_add_hwdec(p, devs, drv, false);
- }
+ assert(p->hwdec_ctx.ra);
+ ra_hwdec_ctx_load_fmt(&p->hwdec_ctx, devs, imgfmt);
}
diff --git a/video/out/gpu/video.h b/video/out/gpu/video.h
index 4c6422b1ab..6aeeca732f 100644
--- a/video/out/gpu/video.h
+++ b/video/out/gpu/video.h
@@ -218,7 +218,7 @@ void gl_video_reset(struct gl_video *p);
bool gl_video_showing_interpolated_frame(struct gl_video *p);
struct mp_hwdec_devices;
-void gl_video_load_hwdecs(struct gl_video *p, struct mp_hwdec_devices *devs,
+void gl_video_init_hwdecs(struct gl_video *p, struct mp_hwdec_devices *devs,
bool load_all_by_default);
void gl_video_load_hwdecs_for_img_fmt(struct gl_video *p, struct mp_hwdec_devices *devs,
int imgfmt);
diff --git a/video/out/vo_gpu.c b/video/out/vo_gpu.c
index 817d750c76..1f471815f1 100644
--- a/video/out/vo_gpu.c
+++ b/video/out/vo_gpu.c
@@ -312,7 +312,7 @@ static int preinit(struct vo *vo)
vo->hwdec_devs = hwdec_devices_create();
hwdec_devices_set_loader(vo->hwdec_devs, call_request_hwdec_api, vo);
- gl_video_load_hwdecs(p->renderer, vo->hwdec_devs, false);
+ gl_video_init_hwdecs(p->renderer, vo->hwdec_devs, false);
return 0;