diff options
author | Dudemanguy <random342@airmail.cc> | 2023-01-04 21:34:26 -0600 |
---|---|---|
committer | Dudemanguy <random342@airmail.cc> | 2023-01-21 17:08:29 +0000 |
commit | 92a6f2d687e90452c9080a2e0b471ced7557518f (patch) | |
tree | 0676341e88224c4e670e7ed0f3904b04e204b8bd | |
parent | 8c617765fe88a5d5597fb58d4b593161049de710 (diff) | |
download | mpv-92a6f2d687e90452c9080a2e0b471ced7557518f.tar.bz2 mpv-92a6f2d687e90452c9080a2e0b471ced7557518f.tar.xz |
drm: rewrite based around vo_drm_state
A longstanding pain point of the drm VOs is the relative lack of state
sharing. While drm_common does provide some sharing, it's far less than
other platforms like x11 or wayland. What we do here is essentially copy
them by creating a new vo_drm_state struct and using it in vo_drm and
context_drm_egl. Much of the functionality that was essentially
duplicated in both VOs/contexts is now reduced simple functions in
drm_common. The usage of the term 'kms' was also mostly eliminated since
this is libdrm nowadays from a userspace perspective.
-rw-r--r-- | options/options.c | 11 | ||||
-rw-r--r-- | options/options.h | 4 | ||||
-rw-r--r-- | video/drmprime.c | 2 | ||||
-rw-r--r-- | video/out/drm_atomic.c | 10 | ||||
-rw-r--r-- | video/out/drm_atomic.h | 9 | ||||
-rw-r--r-- | video/out/drm_common.c | 1081 | ||||
-rw-r--r-- | video/out/drm_common.h | 119 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_drmprime.c | 2 | ||||
-rw-r--r-- | video/out/hwdec/hwdec_drmprime_overlay.c | 5 | ||||
-rw-r--r-- | video/out/opengl/context_drm_egl.c | 429 | ||||
-rw-r--r-- | video/out/vo.h | 1 | ||||
-rw-r--r-- | video/out/vo_drm.c | 461 |
12 files changed, 956 insertions, 1178 deletions
diff --git a/options/options.c b/options/options.c index b4cccd3348..dbd2a3f9bd 100644 --- a/options/options.c +++ b/options/options.c @@ -48,10 +48,6 @@ #include "stream/stream.h" #include "demux/demux.h" -#if HAVE_DRM -#include "video/out/drm_common.h" -#endif - static void print_version(struct mp_log *log) { mp_print_version(log, true); @@ -187,9 +183,6 @@ static const m_option_t mp_vo_opt_list[] = { #if HAVE_WIN32_DESKTOP {"vo-mmcss-profile", OPT_STRING(mmcss_profile)}, #endif -#if HAVE_DRM - {"", OPT_SUBSTRUCT(drm_opts, drm_conf)}, -#endif #if HAVE_EGL_ANDROID {"android-surface-size", OPT_SIZE_BOX(android_surface_size)}, #endif @@ -829,6 +822,10 @@ static const m_option_t mp_opts[] = { {"", OPT_SUBSTRUCT(macos_opts, macos_conf)}, #endif +#if HAVE_DRM + {"", OPT_SUBSTRUCT(drm_opts, drm_conf)}, +#endif + #if HAVE_WAYLAND {"", OPT_SUBSTRUCT(wayland_opts, wayland_conf)}, #endif diff --git a/options/options.h b/options/options.h index 5560f40554..86e95dc826 100644 --- a/options/options.h +++ b/options/options.h @@ -66,9 +66,6 @@ typedef struct mp_vo_opts { double timing_offset; int video_sync; - // vo_drm - struct drm_opts *drm_opts; - struct m_geometry android_surface_size; int swapchain_depth; // max number of images to render ahead @@ -360,6 +357,7 @@ typedef struct MPOpts { struct d3d11va_opts *d3d11va_opts; struct cocoa_opts *cocoa_opts; struct macos_opts *macos_opts; + struct drm_opts *drm_opts; struct wayland_opts *wayland_opts; struct dvd_opts *dvd_opts; struct vaapi_opts *vaapi_opts; diff --git a/video/drmprime.c b/video/drmprime.c index b8fda3b726..c7bd11a8fa 100644 --- a/video/drmprime.c +++ b/video/drmprime.c @@ -29,7 +29,7 @@ static struct AVBufferRef *drm_create_standalone(struct mpv_global *global, { void *tmp = talloc_new(NULL); struct drm_opts *drm_opts = mp_get_config_group(tmp, global, &drm_conf); - const char *opt_path = drm_opts->drm_device_path; + const char *opt_path = drm_opts->device_path; const char *device_path = opt_path ? opt_path : "/dev/dri/renderD128"; AVBufferRef* ref = NULL; diff --git a/video/out/drm_atomic.c b/video/out/drm_atomic.c index dfd27c6f52..5754504e98 100644 --- a/video/out/drm_atomic.c +++ b/video/out/drm_atomic.c @@ -107,14 +107,14 @@ int drm_object_set_property(drmModeAtomicReq *request, struct drm_object *object return -EINVAL; } -struct drm_object * drm_object_create(struct mp_log *log, int fd, - uint32_t object_id, uint32_t type) +struct drm_object *drm_object_create(struct mp_log *log, int fd, + uint32_t object_id, uint32_t type) { struct drm_object *obj = NULL; obj = talloc_zero(NULL, struct drm_object); + obj->fd = fd; obj->id = object_id; obj->type = type; - obj->fd = fd; if (drm_object_create_properties(log, fd, obj)) { talloc_free(obj); @@ -195,7 +195,6 @@ struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd, if (connector->connector_id == connector_id) ctx->connector = drm_object_create(log, ctx->fd, connector->connector_id, DRM_MODE_OBJECT_CONNECTOR); - drmModeFreeConnector(connector); if (ctx->connector) break; @@ -211,8 +210,7 @@ struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd, drmplane = NULL; if (possible_crtcs & (1 << crtc_index)) { - plane = drm_object_create(log, ctx->fd, plane_id, - DRM_MODE_OBJECT_PLANE); + plane = drm_object_create(log, ctx->fd, plane_id, DRM_MODE_OBJECT_PLANE); if (!plane) { mp_err(log, "Failed to create Plane object from plane ID %d\n", diff --git a/video/out/drm_atomic.h b/video/out/drm_atomic.h index 32e56c7f97..499aa33319 100644 --- a/video/out/drm_atomic.h +++ b/video/out/drm_atomic.h @@ -24,15 +24,11 @@ #include <xf86drmMode.h> #include "common/msg.h" +#include "drm_common.h" #define DRM_OPTS_PRIMARY_PLANE -1 #define DRM_OPTS_OVERLAY_PLANE -2 -struct drm_mode { - drmModeModeInfo mode; - uint32_t blob_id; -}; - struct drm_atomic_plane_state { uint64_t fb_id; uint64_t crtc_id; @@ -83,13 +79,12 @@ struct drm_atomic_context { struct drm_atomic_state old_state; }; - int drm_object_create_properties(struct mp_log *log, int fd, struct drm_object *object); void drm_object_free_properties(struct drm_object *object); int drm_object_get_property(struct drm_object *object, char *name, uint64_t *value); int drm_object_set_property(drmModeAtomicReq *request, struct drm_object *object, char *name, uint64_t value); drmModePropertyBlobPtr drm_object_get_property_blob(struct drm_object *object, char *name); -struct drm_object * drm_object_create(struct mp_log *log, int fd, uint32_t object_id, uint32_t type); +struct drm_object *drm_object_create(struct mp_log *log, int fd, uint32_t object_id, uint32_t type); void drm_object_free(struct drm_object *object); void drm_object_print_info(struct mp_log *log, struct drm_object *object); struct drm_atomic_context *drm_atomic_create_context(struct mp_log *log, int fd, int crtc_id, int connector_id, diff --git a/video/out/drm_common.c b/video/out/drm_common.c index 7845edb734..09494d6317 100644 --- a/video/out/drm_common.c +++ b/video/out/drm_common.c @@ -35,10 +35,12 @@ #include <sys/vt.h> #endif +#include "drm_atomic.h" #include "drm_common.h" #include "common/common.h" #include "common/msg.h" +#include "options/m_config.h" #include "osdep/io.h" #include "osdep/timer.h" #include "misc/ctype.h" @@ -55,38 +57,36 @@ 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_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_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 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 drm_show_available_modes(struct mp_log *log, const drmModeConnector *connector); -static void kms_show_available_connectors(struct mp_log *log, int card_no, +static void drm_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), + {"drm-device", OPT_STRING(device_path), .flags = M_OPT_FILE}, + {"drm-connector", OPT_STRING(connector_spec), .help = drm_connector_opt_help}, - {"drm-mode", OPT_STRING_VALIDATE(drm_mode_spec, drm_validate_mode_opt), + {"drm-mode", OPT_STRING_VALIDATE(mode_spec, drm_validate_mode_opt), .help = drm_mode_opt_help}, {"drm-atomic", OPT_CHOICE(drm_atomic, {"no", 0}, {"auto", 1}), .deprecation_message = "this option is deprecated: DRM Atomic is required"}, - {"drm-draw-plane", OPT_CHOICE(drm_draw_plane, + {"drm-draw-plane", OPT_CHOICE(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, + {"drm-drmprime-video-plane", OPT_CHOICE(drmprime_video_plane, {"primary", DRM_OPTS_PRIMARY_PLANE}, {"overlay", DRM_OPTS_OVERLAY_PLANE}), M_RANGE(0, INT_MAX)}, @@ -95,21 +95,21 @@ const struct m_sub_options drm_conf = { {"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-draw-surface-size", OPT_SIZE_BOX(draw_surface_size)}, + {"drm-vrr-enabled", OPT_CHOICE(vrr_enabled, + {"no", 0}, {"yes", 1}, {"auto", -1})}, {"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", + .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, + .draw_plane = DRM_OPTS_PRIMARY_PLANE, + .drmprime_video_plane = DRM_OPTS_OVERLAY_PLANE, + .vrr_enabled = 0, }, .size = sizeof(struct drm_opts), }; @@ -151,8 +151,299 @@ struct drm_mode_spec { double refresh; }; -// KMS ------------------------------------------------------------------------ +/* VT Switcher */ +static void vt_switcher_sighandler(int sig) +{ + unsigned char event = sig == RELEASE_SIGNAL ? EVT_RELEASE : EVT_ACQUIRE; + (void)write(vt_switcher_pipe[1], &event, sizeof(event)); +} + +static bool has_signal_installed(int signo) +{ + struct sigaction act = { 0 }; + sigaction(signo, 0, &act); + return act.sa_handler != 0; +} + +static int install_signal(int signo, void (*handler)(int)) +{ + struct sigaction act = { 0 }; + act.sa_handler = handler; + sigemptyset(&act.sa_mask); + act.sa_flags = SA_RESTART; + return sigaction(signo, &act, NULL); +} + +static void release_vt(void *data) +{ + struct vo_drm_state *drm = data; + MP_VERBOSE(drm, "Releasing VT\n"); + vo_drm_release_crtc(drm); +} + +static void acquire_vt(void *data) +{ + struct vo_drm_state *drm = data; + MP_VERBOSE(drm, "Acquiring VT\n"); + vo_drm_acquire_crtc(drm); +} + +static void vt_switcher_acquire(struct vt_switcher *s, + void (*handler)(void*), void *user_data) +{ + s->handlers[HANDLER_ACQUIRE] = handler; + s->handler_data[HANDLER_ACQUIRE] = user_data; +} + +static void vt_switcher_release(struct vt_switcher *s, + void (*handler)(void*), void *user_data) +{ + s->handlers[HANDLER_RELEASE] = handler; + s->handler_data[HANDLER_RELEASE] = user_data; +} + +static bool vt_switcher_init(struct vt_switcher *s, struct mp_log *log) +{ + s->tty_fd = -1; + s->log = log; + vt_switcher_pipe[0] = -1; + vt_switcher_pipe[1] = -1; + + if (mp_make_cloexec_pipe(vt_switcher_pipe)) { + mp_err(log, "Creating pipe failed: %s\n", mp_strerror(errno)); + return false; + } + + s->tty_fd = open("/dev/tty", O_RDWR | O_CLOEXEC); + if (s->tty_fd < 0) { + mp_err(log, "Can't open TTY for VT control: %s\n", mp_strerror(errno)); + return false; + } + + if (has_signal_installed(RELEASE_SIGNAL)) { + mp_err(log, "Can't handle VT release - signal already used\n"); + return false; + } + if (has_signal_installed(ACQUIRE_SIGNAL)) { + mp_err(log, "Can't handle VT acquire - signal already used\n"); + return false; + } + + if (install_signal(RELEASE_SIGNAL, vt_switcher_sighandler)) { + mp_err(log, "Failed to install release signal: %s\n", mp_strerror(errno)); + return false; + } + if (install_signal(ACQUIRE_SIGNAL, vt_switcher_sighandler)) { + mp_err(log, "Failed to install acquire signal: %s\n", mp_strerror(errno)); + return false; + } + + struct vt_mode vt_mode = { 0 }; + if (ioctl(s->tty_fd, VT_GETMODE, &vt_mode) < 0) { + mp_err(log, "VT_GETMODE failed: %s\n", mp_strerror(errno)); + return false; + } + + vt_mode.mode = VT_PROCESS; + vt_mode.relsig = RELEASE_SIGNAL; + vt_mode.acqsig = ACQUIRE_SIGNAL; + // frsig is a signal for forced release. Not implemented on Linux, + // Solaris, BSDs but must be set to a valid signal on some of those. + vt_mode.frsig = SIGIO; // unused + if (ioctl(s->tty_fd, VT_SETMODE, &vt_mode) < 0) { + mp_err(log, "VT_SETMODE failed: %s\n", mp_strerror(errno)); + return false; + } + + // Block the VT switching signals from interrupting the VO thread (they will + // still be picked up by other threads, which will fill vt_switcher_pipe for us) + sigset_t set; + sigemptyset(&set); + sigaddset(&set, RELEASE_SIGNAL); + sigaddset(&set, ACQUIRE_SIGNAL); + pthread_sigmask(SIG_BLOCK, &set, NULL); + + return true; +} + +static void vt_switcher_interrupt_poll(struct vt_switcher *s) +{ + unsigned char event = EVT_INTERRUPT; + (void)write(vt_switcher_pipe[1], &event, sizeof(event)); +} + +static void vt_switcher_destroy(struct vt_switcher *s) +{ + struct vt_mode vt_mode = {0}; + vt_mode.mode = VT_AUTO; + if (ioctl(s->tty_fd, VT_SETMODE, &vt_mode) < 0) { + MP_ERR(s, "VT_SETMODE failed: %s\n", mp_strerror(errno)); + return; + } + + install_signal(RELEASE_SIGNAL, SIG_DFL); + install_signal(ACQUIRE_SIGNAL, SIG_DFL); + close(s->tty_fd); + close(vt_switcher_pipe[0]); + close(vt_switcher_pipe[1]); +} + +static void vt_switcher_poll(struct vt_switcher *s, int timeout_ms) +{ + struct pollfd fds[1] = { + { .events = POLLIN, .fd = vt_switcher_pipe[0] }, + }; + poll(fds, 1, timeout_ms); + if (!fds[0].revents) + return; + unsigned char event; + if (read(fds[0].fd, &event, sizeof(event)) != sizeof(event)) + return; + + switch (event) { + case EVT_RELEASE: + s->handlers[HANDLER_RELEASE](s->handler_data[HANDLER_RELEASE]); + if (ioctl(s->tty_fd, VT_RELDISP, 1) < 0) { + MP_ERR(s, "Failed to release virtual terminal\n"); + } + break; + case EVT_ACQUIRE: + s->handlers[HANDLER_ACQUIRE](s->handler_data[HANDLER_ACQUIRE]); + if (ioctl(s->tty_fd, VT_RELDISP, VT_ACKACQ) < 0) { + MP_ERR(s, "Failed to acquire virtual terminal\n"); + } + break; + case EVT_INTERRUPT: + break; + } +} + +bool vo_drm_acquire_crtc(struct vo_drm_state *drm) +{ + if (drm->active) + return true; + drm->active = true; + + if (drmSetMaster(drm->fd)) { + MP_WARN(drm, "Failed to acquire DRM master: %s\n", + mp_strerror(errno)); + } + + struct drm_atomic_context *atomic_ctx = drm->atomic_context; + + if (!drm_atomic_save_old_state(atomic_ctx)) + MP_WARN(drm, "Failed to save old DRM atomic state\n"); + + drmModeAtomicReqPtr request = drmModeAtomicAlloc(); + if (!request) { + MP_ERR(drm, "Failed to allocate drm atomic request\n"); + goto err; + } + + if (drm_object_set_property(request, atomic_ctx->connector, "CRTC_ID", drm->crtc_id) < 0) { + MP_ERR(drm, "Could not set CRTC_ID on connector\n"); + goto err; + } + + if (!drm_mode_ensure_blob(drm->fd, &drm->mode)) { + MP_ERR(drm, "Failed to create DRM mode blob\n"); + goto err; + } + if (drm_object_set_property(request, atomic_ctx->crtc, "MODE_ID", drm->mode.blob_id) < 0) { + MP_ERR(drm, "Could not set MODE_ID on crtc\n"); + goto err; + } + if (drm_object_set_property(request, atomic_ctx->crtc, "ACTIVE", 1) < 0) { + MP_ERR(drm, "Could not set ACTIVE on crtc\n"); + goto err; + } + + /* + * VRR related properties were added in kernel 5.0. We will not fail if we + * cannot query or set the value, but we will log as appropriate. + */ + uint64_t vrr_capable = 0; + drm_object_get_property(atomic_ctx->connector, "VRR_CAPABLE", &vrr_capable); + MP_VERBOSE(drm, "crtc is%s VRR capable\n", vrr_capable ? "" : " not"); + + uint64_t vrr_requested = drm->opts->vrr_enabled; + if (vrr_requested == 1 || (vrr_capable && vrr_requested == -1)) { + if (drm_object_set_property(request, atomic_ctx->crtc, "VRR_ENABLED", 1) < 0) { + MP_WARN(drm, "Could not enable VRR on crtc\n"); + } else { + MP_VERBOSE(drm, "Enabled VRR on crtc\n"); + } + } + + drm_object_set_property(request, atomic_ctx->draw_plane, "FB_ID", drm->fb->id); + drm_object_set_property(request, atomic_ctx->draw_plane, "CRTC_ID", drm->crtc_id); + drm_object_set_property(request, atomic_ctx->draw_plane, "SRC_X", 0); + drm_object_set_property(request, atomic_ctx->draw_plane, "SRC_Y", 0); + drm_object_set_property(request, atomic_ctx->draw_plane, "SRC_W", drm->width << 16); + drm_object_set_property(request, atomic_ctx->draw_plane, "SRC_H", drm->height << 16); + drm_object_set_property(request, atomic_ctx->draw_plane, "CRTC_X", 0); + drm_object_set_property(request, atomic_ctx->draw_plane, "CRTC_Y", 0); + drm_object_set_property(request, atomic_ctx->draw_plane, "CRTC_W", drm->mode.mode.hdisplay); + drm_object_set_property(request, atomic_ctx->draw_plane, "CRTC_H", drm->mode.mode.vdisplay); + + if (drmModeAtomicCommit(drm->fd, request, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL)) { + MP_ERR(drm, "Failed to commit ModeSetting atomic request: %s\n", strerror(errno)); + goto err; + } + + drmModeAtomicFree(request); + return true; + +err: + drmModeAtomicFree(request); + return false; +} + + +void vo_drm_release_crtc(struct vo_drm_state *drm) +{ + if (!drm->active) + return; + drm->active = false; + + if (!drm->atomic_context->old_state.saved) + return; + + bool success = true; + struct drm_atomic_context *atomic_ctx = drm->atomic_context; + drmModeAtomicReqPtr request = drmModeAtomicAlloc(); + if (!request) { + MP_ERR(drm, "Failed to allocate drm atomic request\n"); + success = false; + } + + if (request && !drm_atomic_restore_old_state(request, atomic_ctx)) { + MP_WARN(drm, "Got error while restoring old state\n"); + success = false; + } + + if (request) { + if (drmModeAtomicCommit(drm->fd, request, DRM_MODE_ATOMIC_ALLOW_MODESET, NULL)) { + MP_WARN(drm, "Failed to commit ModeSetting atomic request: %s\n", + mp_strerror(errno)); + success = false; + } + } + + if (request) + drmModeAtomicFree(request); + + if (!success) + MP_ERR(drm, "Failed to restore previous mode\n"); + + if (drmDropMaster(drm->fd)) { + MP_WARN(drm, "Failed to drop DRM master: %s\n", + mp_strerror(errno)); + } +} + +/* libdrm */ static void get_connector_name(const drmModeConnector *connector, char ret[MAX_CONNECTOR_NAME_LEN]) { @@ -171,13 +462,13 @@ static void get_connector_name(const drmModeConnector *connector, // 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_name) +static drmModeConnector *get_connector_by_name(const drmModeRes *res, + const char *connector_name, + int fd) { for (int i = 0; i < res->count_connectors; i++) { drmModeConnector *connector - = drmModeGetConnector(kms->fd, res->connectors[i]); + = drmModeGetConnector(fd, res->connectors[i]); if (!connector) continue; char other_connector_name[MAX_CONNECTOR_NAME_LEN]; @@ -191,16 +482,14 @@ static drmModeConnector *get_connector_by_name(const struct kms *kms, // Gets the first connected connector. // Result must be freed with drmModeFreeConnector. -static drmModeConnector *get_first_connected_connector(const struct kms *kms, - const drmModeRes *res) +static drmModeConnector *get_first_connected_connector(const drmModeRes *res, + int fd) { for (int i = 0; i < res->count_connectors; i++) { - drmModeConnector *connector - = drmModeGetConnector(kms->fd, res->connectors[i]); + drmModeConnector *connector = drmModeGetConnector(fd, res->connectors[i]); if (!connector) continue; - if (connector->connection == DRM_MODE_CONNECTED - && connector->count_modes > 0) { + if (connector->connection == DRM_MODE_CONNECTED && connector->count_modes > 0) { return connector; } drmModeFreeConnector(connector); @@ -208,61 +497,58 @@ static drmModeConnector *get_first_connected_connector(const struct kms *kms, return NULL; } -static bool setup_connector(struct kms *kms, const drmModeRes *res, +static bool setup_connector(struct vo_drm_state *drm, const drmModeRes *res, const char *connector_name) { drmModeConnector *connector; - if (connector_name - && strcmp(connector_name, "") - && strcmp(connector_name, "auto")) { - connector = get_connector_by_name(kms, res, connector_name); + if (connector_name && strcmp(connector_name, "") && strcmp(connector_name, "auto")) { + connector = get_connector_by_name(res, connector_name, drm->fd); if (!connector) { - MP_ERR(kms, "No connector with name %s found\n", connector_name); - kms_show_available_connectors(kms->log, kms->card_no, - kms->primary_node_path); + MP_ERR(drm, "No connector with name %s found\n", connector_name); + drm_show_available_connectors(drm->log, drm->card_no, drm->card_path); return false; } } else { - connector = get_first_connected_connector(kms, res); + connector = get_first_connected_connector(res, drm->fd); if (!connector) { - MP_ERR(kms, "No connected connectors found\n"); + MP_ERR(drm, "No connected connectors found\n"); return false; } } if (connector->connection != DRM_MODE_CONNECTED) { drmModeFreeConnector(connector); - MP_ERR(kms, "Chosen connector is disconnected\n"); + MP_ERR(drm, "Chosen connector is disconnected\n"); return false; } if (connector->count_modes == 0) { drmModeFreeConnector(connector); - MP_ERR(kms, "Chosen connector has no valid modes\n"); + MP_ERR(drm, "Chosen connector has no valid modes\n"); return false; } - kms->connector = connector; + drm->connector = connector; return true; } -static bool setup_crtc(struct kms *kms, const drmModeRes *res) +static bool setup_crtc(struct vo_drm_state *drm, const drmModeRes *res) { // First try to find currently connected encoder and its current CRTC for (unsigned int i = 0; i < res->count_encoders; i++) { - drmModeEncoder *encoder = drmModeGetEncoder(kms->fd, res->encoders[i]); + drmModeEncoder *encoder = drmModeGetEncoder(drm->fd, res->encoders[i]); if (!encoder) { - MP_WARN(kms, "Cannot retrieve encoder %u:%u: %s\n", + MP_WARN(drm, "Cannot retrieve encoder %u:%u: %s\n", i, res->encoders[i], mp_strerror(errno)); continue; } - if (encoder->encoder_id == kms->connector->encoder_id && encoder->crtc_id != 0) { - MP_VERBOSE(kms, "Connector %u currently connected to encoder %u\n", - kms->connector->connector_id, kms->connector->encoder_id); - kms->encoder = encoder; - kms->crtc_id = encoder->crtc_id; + if (encoder->encoder_id == drm->connector->encoder_id && encoder->crtc_id != 0) { + MP_VERBOSE(drm, "Connector %u currently connected to encoder %u\n", + drm->connector->connector_id, drm->connector->encoder_id); + drm->encoder = encoder; + drm->crtc_id = encoder->crtc_id; goto success; } @@ -270,12 +556,12 @@ static bool setup_crtc(struct kms *kms, const drmModeRes *res) } // Otherwise pick first legal encoder and CRTC combo for the connector - for (unsigned int i = 0; i < kms->connector->count_encoders; ++i) { + for (unsigned int i = 0; i < drm->connector->count_encoders; ++i) { drmModeEncoder *encoder - = drmModeGetEncoder(kms->fd, kms->connector->encoders[i]); + = drmModeGetEncoder(drm->fd, drm->connector->encoders[i]); if (!encoder) { - MP_WARN(kms, "Cannot retrieve encoder %u:%u: %s\n", - i, kms->connector->encoders[i], mp_strerror(errno)); + MP_WARN(drm, "Cannot retrieve encoder %u:%u: %s\n", + i, drm->connector->encoders[i], mp_strerror(errno)); continue; } @@ -285,21 +571,21 @@ static bool setup_crtc(struct kms *kms, const drmModeRes *res) if (!(encoder->possible_crtcs & (1 << j))) continue; - kms->encoder = encoder; - kms->crtc_id = res->crtcs[j]; + drm->encoder = encoder; + drm->crtc_id = res->crtcs[j]; goto success; } drmModeFreeEncoder(encoder); } - MP_ERR(kms, "Connector %u has no suitable CRTC\n", - kms->connector->connector_id); + MP_ERR(drm, "Connector %u has no suitable CRTC\n", + drm->connector->connector_id); return false; success: - MP_VERBOSE(kms, "Selected Encoder %u with CRTC %u\n", - kms->encoder->encoder_id, kms->crtc_id); + MP_VERBOSE(drm, "Selected Encoder %u with CRTC %u\n", + drm->encoder->encoder_id, drm->crtc_id); return true; } @@ -388,15 +674,15 @@ static bool parse_mode_spec(const char *spec, struct drm_mode_spec *parse_result return true; } -static bool setup_mode_by_idx(struct kms *kms, unsigned int mode_idx) +static bool setup_mode_by_idx(struct vo_drm_state *drm, unsigned int mode_idx) { - if (mode_idx >= kms->connector->count_modes) { - MP_ERR(kms, "Bad mode index (max = %d).\n", - kms->connector->count_modes - 1); + if (mode_idx >= drm->connector->count_modes) { + MP_ERR(drm, "Bad mode index (max = %d).\n", + drm->connector->count_modes - 1); return false; } - kms->mode.mode = kms->connector->modes[mode_idx]; + drm->mode.mode = drm->connector->modes[mode_idx]; return true; } @@ -418,46 +704,45 @@ static bool mode_match(const drmModeModeInfo *mode, } } -static bool setup_mode_by_numbers(struct kms *kms, +static bool setup_mode_by_numbers(struct vo_drm_state *drm, unsigned int width, unsigned int height, - double refresh, - const char *mode_spec) + double refresh) { - for (unsigned int i = 0; i < kms->connector->count_modes; ++i) { - drmModeModeInfo *current_mode = &kms->connector->modes[i]; + for (unsigned int i = 0; i < drm->connector->count_modes; ++i) { + drmModeModeInfo *current_mode = &drm->connector->modes[i]; if (mode_match(current_mode, width, height, refresh)) { - kms->mode.mode = *current_mode; + drm->mode.mode = *current_mode; return true; } } - MP_ERR(kms, "Could not find mode matching %s\n", mode_spec); + MP_ERR(drm, "Could not find mode matching %s\n", drm->opts->mode_spec); return false; } -static bool setup_mode_preferred(struct kms *kms) +static bool setup_mode_preferred(struct vo_drm_state *drm) { - for (unsigned int i = 0; i < kms->connector->count_modes; ++i) { - drmModeModeInfo *current_mode = &kms->connector->modes[i]; + for (unsigned int i = 0; i < drm->connector->count_modes; ++i) { + drmModeModeInfo *current_mode = &drm->connector->modes[i]; if (current_mode->type & DRM_MODE_TYPE_PREFERRED) { - kms->mode.mode = *current_mode; + drm->mode.mode = *current_mode; return true; } } // Fall back to first mode - MP_WARN(kms, "Could not find any preferred mode. Picking the first mode.\n"); - kms->mode.mode = kms->connector->modes[0]; + MP_WARN(drm, "Could not find any preferred mode. Picking the first mode.\n"); + drm->mode.mode = drm->connector->modes[0]; return true; } -static bool setup_mode_highest(struct kms *kms) +static bool setup_mode_highest(struct vo_drm_state *drm) { unsigned int area = 0; - drmModeModeInfo *highest_resolution_mode = &kms->connector->modes[0]; - for (unsigned int i = 0; i < kms->connector->count_modes; ++i) { - drmModeModeInfo *current_mode = &kms->connector->modes[i]; + drmModeModeInfo *highest_resolution_mode = &drm->connector->modes[0]; + for (unsigned int i = 0; i < drm->connector->count_modes; ++i) { + drmModeModeInfo *current_mode = &drm->connector->modes[i]; const unsigned int current_area = current_mode->hdisplay * current_mode->vdisplay; @@ -467,55 +752,54 @@ static bool setup_mode_highest(struct kms *kms) } } - kms->mode.mode = *highest_resolution_mode; + drm->mode.mode = *highest_resolution_mode; return true; } -static bool setup_mode(struct kms *kms, const char *mode_spec) +static bool setup_mode(struct vo_drm_state *drm) { - if (kms->connector->count_modes <= 0) { - MP_ERR(kms, "No available modes\n"); + if (drm->connector->count_modes <= 0) { + MP_ERR(drm, "No available modes\n"); return false; } struct drm_mode_spec parsed; - if (!parse_mode_spec(mode_spec, &parsed)) { - MP_ERR(kms, "Parse error\n"); + if (!parse_mode_spec(drm->opts->mode_spec, &parsed)) { + MP_ERR(drm, "Parse error\n"); goto err; } switch (parsed.type) { case DRM_MODE_SPEC_BY_IDX: - if (!setup_mode_by_idx(kms, parsed.idx)) + if (!setup_mode_by_idx(drm, parsed.idx)) goto err; break; case DRM_MODE_SPEC_BY_NUMBERS: - if (!setup_mode_by_numbers(kms, parsed.width, parsed.height, parsed.refresh, - mode_spec)) + if (!setup_mode_by_numbers(drm, parsed.width, parsed.height, parsed.refresh)) goto err; break; case DRM_MODE_SPEC_PREFERRED: - if (!setup_mode_preferred(kms)) + if (!setup_mode_preferred(drm)) goto err; break; case DRM_MODE_SPEC_HIGHEST: - if (!setup_mode_highest(kms)) + if (!setup_mode_highest(drm)) goto err; break; default: - MP_ERR(kms, "setup_mode: Internal error\n"); + MP_ERR(drm, "setup_mode: Internal error\n"); goto err; } - drmModeModeInfo *mode = &kms->mode.mode; - MP_VERBOSE(kms, "Selected mode: %s (%dx%d@%.2fHz)\n", + drmModeModeInfo *mode = &drm->mode.mode; + MP_VERBOSE(drm, "Selected mode: %s (%dx%d@%.2fHz)\n", mode-&g |