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.
This commit is contained in:
Anton Kindestam 2018-06-02 12:53:58 +02:00 committed by sfan5
parent a776628d88
commit 8261924db9
5 changed files with 95 additions and 26 deletions

View File

@ -479,13 +479,14 @@ Available video output drivers are:
``--drm-connector=[<gpu_number>.]<name>``
Select the connector to use (usually this is a monitor.) If ``<name>``
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 ``<gpu_number>``
argument to disambiguate.
(default: empty)
``--drm-mode=<number>``
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=<no|auto>``

View File

@ -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 ----------------------------------------------------------------

View File

@ -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

View File

@ -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);

View File

@ -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");