/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <sys/ioctl.h>
#include <poll.h>
#include <sys/stat.h>
#include <unistd.h>
#include <limits.h>
#include <math.h>
#include <time.h>
#include <drm_fourcc.h>
#include "config.h"
#if HAVE_CONSIO_H
#include <sys/consio.h>
#else
#include <sys/vt.h>
#endif
#include "drm_common.h"
#include "common/common.h"
#include "common/msg.h"
#include "osdep/io.h"
#include "osdep/timer.h"
#include "misc/ctype.h"
#include "video/out/vo.h"
#define EVT_RELEASE 1
#define EVT_ACQUIRE 2
#define EVT_INTERRUPT 255
#define HANDLER_ACQUIRE 0
#define HANDLER_RELEASE 1
#define RELEASE_SIGNAL SIGUSR1
#define ACQUIRE_SIGNAL SIGUSR2
#define MAX_CONNECTOR_NAME_LEN 20
static int vt_switcher_pipe[2];
static int drm_connector_opt_help(
struct mp_log *log, const struct m_option *opt, struct bstr name);
static int drm_mode_opt_help(
struct mp_log *log, const struct m_option *opt, struct bstr name);
static int drm_validate_mode_opt(
struct mp_log *log, const struct m_option *opt, struct bstr name,
const char **value);
static void kms_show_available_modes(
struct mp_log *log, const drmModeConnector *connector);
static void kms_show_available_connectors(struct mp_log *log, int card_no,
const char *card_path);
static double mode_get_Hz(const drmModeModeInfo *mode);
#define OPT_BASE_STRUCT struct drm_opts
const struct m_sub_options drm_conf = {
.opts = (const struct m_option[]) {
{"drm-device", OPT_STRING(drm_device_path), .flags = M_OPT_FILE},
{"drm-connector", OPT_STRING(drm_connector_spec),
.help = drm_connector_opt_help},
{"drm-mode", OPT_STRING_VALIDATE(drm_mode_spec, drm_validate_mode_opt),
.help = drm_mode_opt_help},
{"drm-atomic", OPT_CHOICE(drm_atomic, {"no", 0}, {"auto", 1})},
{"drm-draw-plane", OPT_CHOICE(drm_draw_plane,
{"primary", DRM_OPTS_PRIMARY_PLANE},
{"overlay", DRM_OPTS_OVERLAY_PLANE}),
M_RANGE(0, INT_MAX)},
{"drm-drmprime-video-plane", OPT_CHOICE(drm_drmprime_video_plane,
{"primary", DRM_OPTS_PRIMARY_PLANE},
{"overlay", DRM_OPTS_OVERLAY_PLANE}),
M_RANGE(0, INT_MAX)},
{"drm-format", OPT_CHOICE(drm_format,
{"xrgb8888", DRM_OPTS_FORMAT_XRGB8888},
{"xrgb2101010", DRM_OPTS_FORMAT_XRGB2101010},
{"xbgr8888", DRM_OPTS_FORMAT_XBGR8888},
{"xbgr2101010", DRM_OPTS_FORMAT_XBGR2101010})},
{"drm-draw-surface-size", OPT_SIZE_BOX(drm_draw_surface_size)},
{"drm-osd-plane-id", OPT_REPLACED("drm-draw-plane")},
{"drm-video-plane-id", OPT_REPLACED("drm-drmprime-video-plane")},
{"drm-osd-size", OPT_REPLACED("drm-draw-surface-size")},
{"drm-vrr-enabled", OPT_CHOICE(drm_vrr_enabled,
{"no", 0}, {"yes", 1}, {"auto", -1})},
{0},
},
.defaults = &(const struct drm_opts) {
.drm_mode_spec = "preferred",
.drm_atomic = 1,
.drm_draw_plane = DRM_OPTS_PRIMARY_PLANE,
.drm_drmprime_video_plane = DRM_OPTS_OVERLAY_PLANE,
.drm_vrr_enabled = 0,
},
.size = sizeof(struct drm_opts),
};
static const char *connector_names[] = {
"Unknown", // DRM_MODE_CONNECTOR_Unknown
"VGA", // DRM_MODE_CONNECTOR_VGA
"DVI-I", // DRM_MODE_CONNECTOR_DVII
"DVI-D", // DRM_MODE_CONNECTOR_DVID
"DVI-A", // DRM_MODE_CONNECTOR_DVIA
"Composite", // DRM_MODE_CONNECTOR_Composite
"SVIDEO", // DRM_MODE_CONNECTOR_SVIDEO
"LVDS", // DRM_MODE_CONNECTOR_LVDS
"Component", // DRM_MODE_CONNECTOR_Component
"DIN", // DRM_MODE_CONNECTOR_9PinDIN
"DP", // DRM_MODE_CONNECTOR_DisplayPort
"HDMI-A", // DRM_MODE_CONNECTOR_HDMIA
"HDMI-B", // DRM_MODE_CONNECTOR_HDMIB
"TV", // DRM_MODE_CONNECTOR_TV
"eDP", // DRM_MODE_CONNECTOR_eDP
"Virtual", // DRM_MODE_CONNECTOR_VIRTUAL
"DSI", // DRM_MODE_CONNECTOR_DSI
"DPI", // DRM_MODE_CONNECTOR_DPI
"Writeback", // DRM_MODE_CONNECTOR_WRITEBACK
"SPI", // DRM_MODE_CONNECTOR_SPI
"USB", // DRM_MODE_CONNECTOR_USB
};
struct drm_mode_spec {
enum {
DRM_MODE_SPEC_BY_IDX, // Specified by idx
DRM_MODE_SPEC_BY_NUMBERS, // Specified by width, height and opt. refresh
DRM_MODE_SPEC_PREFERRED, // Select the preferred mode of the display
DRM_MODE_SPEC_HIGHEST, // Select the mode with the highest resolution
} type;
unsigned int idx;
unsigned int width;
unsigned int height;
double refresh;
};
// KMS ------------------------------------------------------------------------
static void get_connector_name(const drmModeConnector *connector,
char ret[MAX_CONNECTOR_NAME_LEN])
{
const char *type_name;
if (connector->connector_type < MP_ARRAY_SIZE(connector_names)) {
type_name = connector_names[connector->connector_type];
} else {
type_name = "UNKNOWN";
}
snprintf(ret, MAX_CONNECTOR_NAME_LEN, "%s-%d", type_name,
connector->connector_type_id);
}
// Gets the first connector whose name matches the input parameter.
// The returned connector may be disconnected.
// Result must be freed with drmModeFreeConnector.
static drmModeConnector *get_connector_by_name(const struct kms *kms,
const drmModeRes *res,
const char *connector_n
|