From 8261924db93eb436a9e1606d437f0fe64e56dc66 Mon Sep 17 00:00:00 2001 From: Anton Kindestam Date: Sat, 2 Jun 2018 12:53:58 +0200 Subject: [PATCH] drm_common: Add proper help option to drm-mode This was implemented by using OPT_STRING_VALIDATE for drm-mode, instead of OPT_INT. Using a string here also prepares for future additions to drm-mode that aim to allow specifying a mode by its resolution. --- DOCS/man/vo.rst | 5 +- video/out/drm_common.c | 102 +++++++++++++++++++++++------ video/out/drm_common.h | 10 ++- video/out/opengl/context_drm_egl.c | 2 +- video/out/vo_drm.c | 2 +- 5 files changed, 95 insertions(+), 26 deletions(-) diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index a735dbc059..0583eb6c43 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -479,13 +479,14 @@ Available video output drivers are: ``--drm-connector=[.]`` Select the connector to use (usually this is a monitor.) If ```` is empty or ``auto``, mpv renders the output on the first available - connector. Use ``--drm-connector=help`` to get list of available + connector. Use ``--drm-connector=help`` to get a list of available connectors. When using multiple graphic cards, use the ```` argument to disambiguate. (default: empty) ``--drm-mode=`` - Mode ID to use (resolution and frame rate). + Mode ID to use (resolution and frame rate). Use ``--drm-mode=help`` to + get a list of available modes for all active connectors. (default: 0) ``--drm-atomic=`` diff --git a/video/out/drm_common.c b/video/out/drm_common.c index 36e72b3b9a..3a08cbf468 100644 --- a/video/out/drm_common.c +++ b/video/out/drm_common.c @@ -30,6 +30,7 @@ #include "common/common.h" #include "common/msg.h" #include "osdep/io.h" +#include "misc/ctype.h" #define EVT_RELEASE 1 #define EVT_ACQUIRE 2 @@ -47,7 +48,8 @@ const struct m_sub_options drm_conf = { .opts = (const struct m_option[]) { OPT_STRING_VALIDATE("drm-connector", drm_connector_spec, 0, drm_validate_connector_opt), - OPT_INT("drm-mode", drm_mode_id, 0), + OPT_STRING_VALIDATE("drm-mode", drm_mode_spec, + 0, drm_validate_mode_opt), OPT_CHOICE("drm-atomic", drm_atomic, 0, ({"no", 0}, {"auto", 1})), @@ -98,8 +100,8 @@ static const char *connector_names[] = { // KMS ------------------------------------------------------------------------ -static void get_connector_name( - drmModeConnector *connector, char ret[MAX_CONNECTOR_NAME_LEN]) +static void get_connector_name(const drmModeConnector *connector, + char ret[MAX_CONNECTOR_NAME_LEN]) { snprintf(ret, MAX_CONNECTOR_NAME_LEN, "%s-%d", connector_names[connector->connector_type], @@ -240,12 +242,15 @@ static bool setup_crtc(struct kms *kms, const drmModeRes *res) return true; } -static bool setup_mode(struct kms *kms, int mode_id) +static bool setup_mode(struct kms *kms, const char *mode_spec) { + const int mode_id = (mode_spec != NULL) ? atoi(mode_spec) : 0; + if (mode_id < 0 || mode_id >= kms->connector->count_modes) { MP_ERR(kms, "Bad mode ID (max = %d).\n", kms->connector->count_modes - 1); + MP_INFO(kms, "Available modes:\n"); kms_show_available_modes(kms->log, kms->connector); return false; } @@ -281,7 +286,8 @@ static void parse_connector_spec(struct mp_log *log, } struct kms *kms_create(struct mp_log *log, const char *connector_spec, - int mode_id, int draw_plane, int drmprime_video_plane, + const char* mode_spec, + int draw_plane, int drmprime_video_plane, bool use_atomic) { int card_no = -1; @@ -317,7 +323,7 @@ struct kms *kms_create(struct mp_log *log, const char *connector_spec, goto err; if (!setup_crtc(kms, res)) goto err; - if (!setup_mode(kms, mode_id)) + if (!setup_mode(kms, mode_spec)) goto err; // Universal planes allows accessing all the planes (including primary) @@ -381,9 +387,8 @@ static double mode_get_Hz(const drmModeModeInfo *mode) void kms_show_available_modes( struct mp_log *log, const drmModeConnector *connector) { - mp_info(log, "Available modes:\n"); for (unsigned int i = 0; i < connector->count_modes; i++) { - mp_info(log, "Mode %d: %s (%dx%d@%.2fHz)\n", i, + mp_info(log, " Mode %d: %s (%dx%d@%.2fHz)\n", i, connector->modes[i].name, connector->modes[i].hdisplay, connector->modes[i].vdisplay, @@ -391,10 +396,10 @@ void kms_show_available_modes( } } -void kms_show_available_connectors(struct mp_log *log, int card_no) +static void kms_show_foreach_connector(struct mp_log *log, int card_no, + void (*show_fn)(struct mp_log*, int, + const drmModeConnector*)) { - mp_info(log, "Available connectors for card %d:\n", card_no); - int fd = open_card(card_no); if (fd < 0) { mp_err(log, "Failed to open card %d\n", card_no); @@ -412,12 +417,7 @@ void kms_show_available_connectors(struct mp_log *log, int card_no) = drmModeGetConnector(fd, res->connectors[i]); if (!connector) continue; - char other_connector_name[MAX_CONNECTOR_NAME_LEN]; - get_connector_name(connector, other_connector_name); - mp_info(log, "%s (%s)\n", other_connector_name, - connector->connection == DRM_MODE_CONNECTED - ? "connected" - : "disconnected"); + show_fn(log, card_no, connector); drmModeFreeConnector(connector); } @@ -428,17 +428,65 @@ err: drmModeFreeResources(res); } -void kms_show_available_cards_and_connectors(struct mp_log *log) +static void kms_show_connector_name_and_state_callback( + struct mp_log *log, int card_no, const drmModeConnector *connector) +{ + char other_connector_name[MAX_CONNECTOR_NAME_LEN]; + get_connector_name(connector, other_connector_name); + const char *connection_str = + (connector->connection == DRM_MODE_CONNECTED) ? "connected" : "disconnected"; + mp_info(log, " %s (%s)\n", other_connector_name, connection_str); +} + +void kms_show_available_connectors(struct mp_log *log, int card_no) +{ + mp_info(log, "Available connectors for card %d:\n", card_no); + kms_show_foreach_connector( + log, card_no, kms_show_connector_name_and_state_callback); + mp_info(log, "\n"); +} + +static void kms_show_connector_modes_callback(struct mp_log *log, int card_no, + const drmModeConnector *connector) +{ + if (connector->connection != DRM_MODE_CONNECTED) + return; + + char other_connector_name[MAX_CONNECTOR_NAME_LEN]; + get_connector_name(connector, other_connector_name); + mp_info(log, "Available modes for drm-connector=%d.%s\n", + card_no, other_connector_name); + kms_show_available_modes(log, connector); + mp_info(log, "\n"); +} + +void kms_show_available_connectors_and_modes(struct mp_log *log, int card_no) +{ + kms_show_foreach_connector(log, card_no, kms_show_connector_modes_callback); +} + +static void kms_show_foreach_card( + struct mp_log *log, void (*show_fn)(struct mp_log*,int)) { for (int card_no = 0; card_no < DRM_MAX_MINOR; card_no++) { int fd = open_card(card_no); if (fd < 0) break; close(fd); - kms_show_available_connectors(log, card_no); + show_fn(log, card_no); } } +void kms_show_available_cards_and_connectors(struct mp_log *log) +{ + kms_show_foreach_card(log, kms_show_available_connectors); +} + +void kms_show_available_cards_connectors_and_modes(struct mp_log *log) +{ + kms_show_foreach_card(log, kms_show_available_connectors_and_modes); +} + double kms_get_display_fps(const struct kms *kms) { return mode_get_Hz(&kms->mode.mode); @@ -454,7 +502,21 @@ int drm_validate_connector_opt(struct mp_log *log, const struct m_option *opt, return 1; } - +int drm_validate_mode_opt(struct mp_log *log, const struct m_option *opt, + struct bstr name, struct bstr param) +{ + if (bstr_equals0(param, "help")) { + kms_show_available_cards_connectors_and_modes(log); + return M_OPT_EXIT; + } + for (unsigned i = 0; i < param.len; ++i) { + if (!mp_isdigit(param.start[i])) { + mp_fatal(log, "Invalid value for option drm-mode. Must be a positive number or 'help'\n"); + return M_OPT_INVALID; + } + } + return 1; +} // VT switcher ---------------------------------------------------------------- diff --git a/video/out/drm_common.h b/video/out/drm_common.h index f700e90ef5..036b28de9c 100644 --- a/video/out/drm_common.h +++ b/video/out/drm_common.h @@ -47,7 +47,7 @@ struct vt_switcher { struct drm_opts { char *drm_connector_spec; - int drm_mode_id; + char *drm_mode_spec; int drm_atomic; int drm_draw_plane; int drm_drmprime_video_plane; @@ -66,7 +66,8 @@ void vt_switcher_release(struct vt_switcher *s, void (*handler)(void*), void *user_data); struct kms *kms_create(struct mp_log *log, const char *connector_spec, - int mode_id, int draw_plane, int drmprime_video_plane, + const char *mode_spec, + int draw_plane, int drmprime_video_plane, bool use_atomic); void kms_destroy(struct kms *kms); double kms_get_display_fps(const struct kms *kms); @@ -74,9 +75,14 @@ double kms_get_display_fps(const struct kms *kms); void kms_show_available_connectors(struct mp_log *log, int card_no); void kms_show_available_modes(struct mp_log *log, const drmModeConnector *connector); +void kms_show_available_connectors_and_modes(struct mp_log *log, int card_no); void kms_show_available_cards_and_connectors(struct mp_log *log); +void kms_show_available_cards_connectors_and_modes(struct mp_log *log); int drm_validate_connector_opt(struct mp_log *log, const struct m_option *opt, struct bstr name, struct bstr param); +int drm_validate_mode_opt(struct mp_log *log, const struct m_option *opt, + struct bstr name, struct bstr param); + #endif diff --git a/video/out/opengl/context_drm_egl.c b/video/out/opengl/context_drm_egl.c index f8360d3e62..c4cc28b762 100644 --- a/video/out/opengl/context_drm_egl.c +++ b/video/out/opengl/context_drm_egl.c @@ -764,7 +764,7 @@ static bool drm_egl_init(struct ra_ctx *ctx) MP_VERBOSE(ctx, "Initializing KMS\n"); p->kms = kms_create(ctx->log, ctx->vo->opts->drm_opts->drm_connector_spec, - ctx->vo->opts->drm_opts->drm_mode_id, + ctx->vo->opts->drm_opts->drm_mode_spec, ctx->vo->opts->drm_opts->drm_draw_plane, ctx->vo->opts->drm_opts->drm_drmprime_video_plane, ctx->vo->opts->drm_opts->drm_atomic); diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c index 61553f7eee..281235e911 100644 --- a/video/out/vo_drm.c +++ b/video/out/vo_drm.c @@ -419,7 +419,7 @@ static int preinit(struct vo *vo) p->kms = kms_create(vo->log, vo->opts->drm_opts->drm_connector_spec, - vo->opts->drm_opts->drm_mode_id, + vo->opts->drm_opts->drm_mode_spec, 0, 0, false); if (!p->kms) { MP_ERR(vo, "Failed to create KMS.\n");