video/out/gpu/context: convert --gpu-api to object settings list

This follows up 96e1f1dfa5 which converted --gpu-context, and has the
same advantages as listed there.

Unlike with --gpu-context auto can be used anywhere in the list, e.g.
--gpu-api=d3d11,auto works.

I wanted to use the list of GPU contexts as the description in
get_type_desc(), but there is no talloc context to allocate it to, so I
set a print_help_list to print them. The APIs go before the contexts so
that etc/_mpv.zsh doesn't try to complete the contexts.
This commit is contained in:
Guido Cella 2024-07-04 19:50:39 +02:00 committed by Dudemanguy
parent 3f43999bd6
commit dc523b137f
4 changed files with 71 additions and 33 deletions

View File

@ -6546,8 +6546,8 @@ them.
macvk
Vulkan on macOS with a metal surface through a translation layer (experimental)
``--gpu-api=<type>``
Controls which type of graphics APIs will be accepted:
``--gpu-api=<type1,type2,...[,]>``
Specify a priority list of accepted graphics APIs.
auto
Use any available API (default). Note that the default GPU API used for this

View File

@ -7391,7 +7391,7 @@ void mp_option_change_callback(void *ctx, struct m_config_option *co, int flags,
if (opt_ptr == &opts->vo->video_driver_list ||
opt_ptr == &opts->ra_ctx_opts->context_list ||
opt_ptr == &opts->ra_ctx_opts->context_type) {
opt_ptr == &opts->ra_ctx_opts->context_type_list) {
struct track *track = mpctx->current_track[0][STREAM_VIDEO];
uninit_video_out(mpctx);
handle_force_window(mpctx, true);

View File

@ -166,34 +166,51 @@ const struct m_obj_list ra_ctx_obj_list = {
.use_global_options = true,
};
static int ra_ctx_api_help(struct mp_log *log, const struct m_option *opt,
struct bstr name)
static bool get_type_desc(struct m_obj_desc *dst, int index)
{
mp_info(log, "GPU APIs (contexts):\n");
for (int n = 0; n < MP_ARRAY_SIZE(contexts); n++) {
mp_info(log, " %s (%s)\n", contexts[n]->type, contexts[n]->name);
int api_index = 0;
for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) {
if (i && strcmp(contexts[i - 1]->type, contexts[i]->type))
api_index++;
if (api_index == index) {
*dst = (struct m_obj_desc) {
.name = contexts[i]->type,
.description = "",
};
return true;
}
}
return M_OPT_EXIT;
return false;
}
static inline OPT_STRING_VALIDATE_FUNC(ra_ctx_validate_api)
static void print_context_apis(struct mp_log *log)
{
struct bstr param = bstr0(*value);
for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) {
if (bstr_equals0(param, contexts[i]->type))
return 1;
mp_info(log, "Available GPU APIs and contexts:\n");
for (int n = 0; n < MP_ARRAY_SIZE(contexts); n++) {
mp_info(log, " %s %s\n", contexts[n]->type, contexts[n]->name);
}
return M_OPT_INVALID;
}
const struct m_obj_list ra_ctx_type_obj_list = {
.get_desc = get_type_desc,
.check_unknown_entry = check_unknown_entry,
.description = "GPU APIs",
.allow_trailer = true,
.disallow_positional_parameters = true,
.use_global_options = true,
.print_help_list = print_context_apis,
};
#define OPT_BASE_STRUCT struct ra_ctx_opts
const struct m_sub_options ra_ctx_conf = {
.opts = (const m_option_t[]) {
{"gpu-context",
OPT_SETTINGSLIST(context_list, &ra_ctx_obj_list)},
{"gpu-api",
OPT_STRING_VALIDATE(context_type, ra_ctx_validate_api),
.help = ra_ctx_api_help},
OPT_SETTINGSLIST(context_type_list, &ra_ctx_type_obj_list)},
{"gpu-debug", OPT_BOOL(debug)},
{"gpu-sw", OPT_BOOL(allow_sw)},
{0}
@ -201,15 +218,26 @@ const struct m_sub_options ra_ctx_conf = {
.size = sizeof(struct ra_ctx_opts),
};
static struct ra_ctx *create_in_contexts(struct vo *vo, const char *name, bool api_auto,
const struct ra_ctx_fns *ctxs[],
size_t size, struct ra_ctx_opts opts)
static struct ra_ctx *create_in_contexts(struct vo *vo, const char *name,
struct m_obj_settings *context_type_list,
const struct ra_ctx_fns *ctxs[], size_t size,
struct ra_ctx_opts opts)
{
for (int i = 0; i < size; i++) {
if (strcmp(name, ctxs[i]->name) != 0)
continue;
if (!api_auto && strcmp(ctxs[i]->type, opts.context_type) != 0)
continue;
if (context_type_list) {
bool found = false;
for (int j = 0; context_type_list[j].name; j++) {
if (strcmp(context_type_list[j].name, "auto") == 0 ||
strcmp(context_type_list[j].name, ctxs[i]->type) == 0) {
found = true;
break;
}
}
if (!found)
continue;
}
struct ra_ctx *ctx = talloc_ptrtype(NULL, ctx);
*ctx = (struct ra_ctx) {
.vo = vo,
@ -230,11 +258,11 @@ static struct ra_ctx *create_in_contexts(struct vo *vo, const char *name, bool a
struct ra_ctx *ra_ctx_create_by_name(struct vo *vo, const char *name)
{
struct ra_ctx_opts dummy = {0};
struct ra_ctx *ctx = create_in_contexts(vo, name, true, contexts,
struct ra_ctx *ctx = create_in_contexts(vo, name, NULL, contexts,
MP_ARRAY_SIZE(contexts), dummy);
if (ctx)
return ctx;
return create_in_contexts(vo, name, true, no_api_contexts,
return create_in_contexts(vo, name, NULL, no_api_contexts,
MP_ARRAY_SIZE(no_api_contexts), dummy);
}
@ -242,7 +270,6 @@ struct ra_ctx *ra_ctx_create_by_name(struct vo *vo, const char *name)
// vo_flags: passed to the backend's create window function
struct ra_ctx *ra_ctx_create(struct vo *vo, struct ra_ctx_opts opts)
{
bool api_auto = !opts.context_type || strcmp(opts.context_type, "auto") == 0;
bool ctx_auto = !opts.context_list ||
(opts.context_list[0].name &&
strcmp(opts.context_list[0].name, "auto") == 0);
@ -259,16 +286,27 @@ struct ra_ctx *ra_ctx_create(struct vo *vo, struct ra_ctx_opts opts)
struct ra_ctx *ctx = NULL;
if (opts.probing) {
for (int i = 0; i < MP_ARRAY_SIZE(contexts); i++) {
ctx = create_in_contexts(vo, contexts[i]->name, api_auto,
contexts, MP_ARRAY_SIZE(contexts), opts);
if (ctx)
goto done;
struct m_obj_settings context_type_list[2] = {{.name = "auto"}, {0}};
for (int i = 0;
opts.context_type_list ? opts.context_type_list[i].name != NULL : i == 0;
i++) {
for (int j = 0; j < MP_ARRAY_SIZE(contexts); j++) {
if (opts.context_type_list)
context_type_list[0].name = opts.context_type_list[i].name;
ctx = create_in_contexts(vo, contexts[j]->name, context_type_list,
contexts, MP_ARRAY_SIZE(contexts),
opts);
if (ctx)
goto done;
}
}
}
for (int i = 0; opts.context_list && opts.context_list[i].name; i++) {
ctx = create_in_contexts(vo, opts.context_list[i].name, api_auto,
contexts, MP_ARRAY_SIZE(contexts), opts);
ctx = create_in_contexts(vo, opts.context_list[i].name,
opts.context_type_list, contexts,
MP_ARRAY_SIZE(contexts), opts);
if (ctx)
goto done;
}

View File

@ -11,7 +11,7 @@ struct ra_ctx_opts {
bool debug; // enable debugging layers/callbacks etc.
bool probing; // the backend was auto-probed
struct m_obj_settings *context_list; // list of `ra_ctx_fns.name` to probe
char *context_type; // filter by `ra_ctx_fns.type`
struct m_obj_settings *context_type_list; // list of `ra_ctx_fns.type` to probe
};
extern const struct m_sub_options ra_ctx_conf;