mirror of
https://github.com/mpv-player/mpv
synced 2025-02-17 21:27:08 +00:00
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.
This commit is contained in:
parent
bb434a60ed
commit
d4fc44e711
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user