summaryrefslogtreecommitdiffstats
path: root/video/out/vo_drm.c
diff options
context:
space:
mode:
authorrr- <mkurczew@gmail.com>2015-11-07 12:41:40 +0000
committerwm4 <wm4@nowhere>2015-11-08 14:58:34 +0100
commit67caea357c23443cf583ad401a38bbaae19e3df8 (patch)
treeb1f3a1ca52b1a173d096e1f2b4f4bb36a1f7a58e /video/out/vo_drm.c
parentb1893d2084aa3fa83dbf098f46399101e6b21a68 (diff)
downloadmpv-67caea357c23443cf583ad401a38bbaae19e3df8.tar.bz2
mpv-67caea357c23443cf583ad401a38bbaae19e3df8.tar.xz
vo_drm: move initialization to drm_common
Makes KMS initialization procedures reusable so that they can be used by the upcoming DRM EGL adapter.
Diffstat (limited to 'video/out/vo_drm.c')
-rw-r--r--video/out/vo_drm.c294
1 files changed, 75 insertions, 219 deletions
diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c
index b8a1660fb9..467d9bc82c 100644
--- a/video/out/vo_drm.c
+++ b/video/out/vo_drm.c
@@ -47,7 +47,7 @@
#define USE_MASTER 0
#define BUF_COUNT 2
-struct modeset_buf {
+struct framebuffer {
uint32_t width;
uint32_t height;
uint32_t stride;
@@ -57,28 +57,20 @@ struct modeset_buf {
uint32_t fb;
};
-struct modeset_dev {
- struct modeset_buf bufs[BUF_COUNT];
- drmModeModeInfo mode;
- drmModeEncoder *enc;
- uint32_t conn;
- uint32_t crtc;
- int front_buf;
-};
-
struct priv {
char *device_path;
int connector_id;
int mode_id;
- int fd;
- struct modeset_dev *dev;
+ struct kms *kms;
drmModeCrtc *old_crtc;
drmEventContext ev;
bool vt_switcher_active;
struct vt_switcher vt_switcher;
+ struct framebuffer bufs[BUF_COUNT];
+ int front_buf;
bool active;
bool pflip_happening;
@@ -92,27 +84,7 @@ struct priv {
struct mp_sws_context *sws;
};
-static int modeset_open(struct vo *vo, int *out, const char *node)
-{
- *out = -1;
-
- int fd = open(node, O_RDWR | O_CLOEXEC);
- if (fd < 0) {
- MP_ERR(vo, "Cannot open \"%s\": %s.\n", node, mp_strerror(errno));
- return -errno;
- }
-
- uint64_t has_dumb;
- if (drmGetCap(fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0) {
- MP_ERR(vo, "Device \"%s\" does not support dumb buffers.\n", node);
- return -EOPNOTSUPP;
- }
-
- *out = fd;
- return 0;
-}
-
-static void modeset_destroy_fb(int fd, struct modeset_buf *buf)
+static void fb_destroy(int fd, struct framebuffer *buf)
{
if (buf->map) {
munmap(buf->map, buf->size);
@@ -128,7 +100,7 @@ static void modeset_destroy_fb(int fd, struct modeset_buf *buf)
}
}
-static int modeset_create_fb(struct vo *vo, int fd, struct modeset_buf *buf)
+static int fb_setup_single(struct vo *vo, int fd, struct framebuffer *buf)
{
int ret = 0;
@@ -186,192 +158,60 @@ end:
return 0;
}
- modeset_destroy_fb(fd, buf);
+ fb_destroy(fd, buf);
return ret;
}
-static int modeset_find_crtc(struct vo *vo, int fd, drmModeRes *res,
- drmModeConnector *conn, struct modeset_dev *dev)
-{
- for (unsigned int i = 0; i < conn->count_encoders; ++i) {
- drmModeEncoder *enc = drmModeGetEncoder(fd, conn->encoders[i]);
- if (!enc) {
- MP_WARN(vo, "Cannot retrieve encoder %u:%u: %s\n",
- i, conn->encoders[i], mp_strerror(errno));
- continue;
- }
-
- // iterate all global CRTCs
- for (unsigned int j = 0; j < res->count_crtcs; ++j) {
- // check whether this CRTC works with the encoder
- if (!(enc->possible_crtcs & (1 << j)))
- continue;
-
- dev->enc = enc;
- dev->crtc = enc->crtc_id;
- return 0;
- }
-
- drmModeFreeEncoder(enc);
- }
-
- MP_ERR(vo, "Connector %u has no suitable CRTC\n", conn->connector_id);
- return -ENOENT;
-}
-
-static bool is_connector_valid(struct vo *vo, int conn_id,
- drmModeConnector *conn, bool silent)
+static int fb_setup_double_buffering(struct vo *vo)
{
- if (!conn) {
- if (!silent) {
- MP_ERR(vo, "Cannot get connector %d: %s\n", conn_id,
- mp_strerror(errno));
- }
- return false;
- }
-
- if (conn->connection != DRM_MODE_CONNECTED) {
- if (!silent) {
- MP_ERR(vo, "Connector %d is disconnected\n", conn_id);
- }
- return false;
- }
-
- if (conn->count_modes == 0) {
- if (!silent) {
- MP_ERR(vo, "Connector %d has no valid modes\n", conn_id);
- }
- return false;
- }
-
- return true;
-}
-
-static int modeset_prepare_dev(struct vo *vo, int fd, int conn_id, int mode_id,
- struct modeset_dev **out)
-{
- struct modeset_dev *dev = NULL;
- drmModeConnector *conn = NULL;
-
- int ret = 0;
- *out = NULL;
-
- drmModeRes *res = drmModeGetResources(fd);
- if (!res) {
- MP_ERR(vo, "Cannot retrieve DRM resources: %s\n", mp_strerror(errno));
- ret = -errno;
- goto end;
- }
-
- if (conn_id == -1) {
- // get the first connected connector
- for (int i = 0; i < res->count_connectors; i++) {
- conn = drmModeGetConnector(fd, res->connectors[i]);
- if (is_connector_valid(vo, i, conn, true)) {
- conn_id = i;
- break;
- }
- if (conn) {
- drmModeFreeConnector(conn);
- conn = NULL;
- }
- }
- if (conn_id == -1) {
- MP_ERR(vo, "No connected connectors found\n");
- ret = -ENODEV;
- goto end;
- }
- }
-
- if (conn_id < 0 || conn_id >= res->count_connectors) {
- MP_ERR(vo, "Bad connector ID. Max valid connector ID = %u\n",
- res->count_connectors);
- ret = -ENODEV;
- goto end;
- }
-
- conn = drmModeGetConnector(fd, res->connectors[conn_id]);
- if (!is_connector_valid(vo, conn_id, conn, false)) {
- ret = -ENODEV;
- goto end;
- }
-
- if (mode_id < 0 || mode_id >= conn->count_modes) {
- MP_ERR(vo, "Bad mode ID (max = %d).\n", conn->count_modes - 1);
- MP_INFO(vo, "Available modes:\n");
- for (unsigned int i = 0; i < conn->count_modes; i++) {
- MP_INFO(vo, "Mode %d: %s (%dx%d)\n", i, conn->modes[i].name,
- conn->modes[i].hdisplay, conn->modes[i].vdisplay);
- }
- }
+ struct priv *p = vo->priv;
- dev = talloc_zero(vo->priv, struct modeset_dev);
- dev->conn = conn->connector_id;
- dev->front_buf = 0;
- dev->mode = conn->modes[mode_id];
+ p->front_buf = 0;
for (unsigned int i = 0; i < 2; i++) {
- dev->bufs[i].width = dev->mode.hdisplay;
- dev->bufs[i].height = dev->mode.vdisplay;
- }
-
- ret = modeset_find_crtc(vo, fd, res, conn, dev);
- if (ret) {
- MP_ERR(vo, "Connector %d has no valid CRTC\n", conn_id);
- goto end;
+ p->bufs[i].width = p->kms->mode.hdisplay;
+ p->bufs[i].height = p->kms->mode.vdisplay;
}
for (unsigned int i = 0; i < BUF_COUNT; i++) {
- ret = modeset_create_fb(vo, fd, &dev->bufs[i]);
+ int ret = fb_setup_single(vo, p->kms->fd, &p->bufs[i]);
if (ret) {
MP_ERR(vo, "Cannot create framebuffer for connector %d\n",
- conn_id);
+ p->kms->connector->connector_id);
for (unsigned int j = 0; j < i; j++) {
- modeset_destroy_fb(fd, &dev->bufs[j]);
+ fb_destroy(p->kms->fd, &p->bufs[j]);
}
- goto end;
+ return ret;
}
}
-end:
- if (conn) {
- drmModeFreeConnector(conn);
- conn = NULL;
- }
- if (res) {
- drmModeFreeResources(res);
- res = NULL;
- }
- if (ret == 0) {
- *out = dev;
- } else {
- talloc_free(dev);
- }
- return ret;
+ return 0;
}
-static void modeset_page_flipped(int fd, unsigned int frame, unsigned int sec,
+static void page_flipped(int fd, unsigned int frame, unsigned int sec,
unsigned int usec, void *data)
{
struct priv *p = data;
p->pflip_happening = false;
}
-
-
-static int setup_vo_crtc(struct vo *vo)
+static int crtc_setup(struct vo *vo)
{
struct priv *p = vo->priv;
if (p->active)
return 0;
- p->old_crtc = drmModeGetCrtc(p->fd, p->dev->crtc);
- int ret = drmModeSetCrtc(p->fd, p->dev->crtc,
- p->dev->bufs[p->dev->front_buf + BUF_COUNT - 1].fb,
- 0, 0, &p->dev->conn, 1, &p->dev->mode);
+ p->old_crtc = drmModeGetCrtc(p->kms->fd, p->kms->crtc_id);
+ int ret = drmModeSetCrtc(p->kms->fd, p->kms->crtc_id,
+ p->bufs[p->front_buf + BUF_COUNT - 1].fb,
+ 0,
+ 0,
+ &p->kms->connector->connector_id,
+ 1,
+ &p->kms->mode);
p->active = true;
return ret;
}
-static void release_vo_crtc(struct vo *vo)
+static void crtc_release(struct vo *vo)
{
struct priv *p = vo->priv;
@@ -381,7 +221,7 @@ static void release_vo_crtc(struct vo *vo)
// wait for current page flip
while (p->pflip_happening) {
- int ret = drmHandleEvent(p->fd, &p->ev);
+ int ret = drmHandleEvent(p->kms->fd, &p->ev);
if (ret) {
MP_ERR(vo, "drmHandleEvent failed: %i\n", ret);
break;
@@ -389,12 +229,12 @@ static void release_vo_crtc(struct vo *vo)
}
if (p->old_crtc) {
- drmModeSetCrtc(p->fd,
+ drmModeSetCrtc(p->kms->fd,
p->old_crtc->crtc_id,
p->old_crtc->buffer_id,
p->old_crtc->x,
p->old_crtc->y,
- &p->dev->conn,
+ &p->kms->connector->connector_id,
1,
&p->old_crtc->mode);
drmModeFreeCrtc(p->old_crtc);
@@ -405,13 +245,13 @@ static void release_vo_crtc(struct vo *vo)
static void release_vt(void *data)
{
struct vo *vo = data;
- release_vo_crtc(vo);
+ crtc_release(vo);
if (USE_MASTER) {
//this function enables support for switching to x, weston etc.
//however, for whatever reason, it can be called only by root users.
//until things change, this is commented.
struct priv *p = vo->priv;
- if (drmDropMaster(p->fd)) {
+ if (drmDropMaster(p->kms->fd)) {
MP_WARN(vo, "Failed to drop DRM master: %s\n", mp_strerror(errno));
}
}
@@ -422,12 +262,12 @@ static void acquire_vt(void *data)
struct vo *vo = data;
if (USE_MASTER) {
struct priv *p = vo->priv;
- if (drmSetMaster(p->fd)) {
+ if (drmSetMaster(p->kms->fd)) {
MP_WARN(vo, "Failed to acquire DRM master: %s\n", mp_strerror(errno));
}
}
- setup_vo_crtc(vo);
+ crtc_setup(vo);
}
@@ -486,7 +326,7 @@ static int reconfig(struct vo *vo, struct mp_image_params *params)
mp_image_params_guess_csp(&p->sws->dst);
mp_image_set_params(p->cur_frame, &p->sws->dst);
- struct modeset_buf *buf = p->dev->bufs;
+ struct framebuffer *buf = p->bufs;
for (unsigned int i = 0; i < BUF_COUNT; i++)
memset(buf[i].map, 0, buf[i].size);
@@ -515,7 +355,7 @@ static void draw_image(struct vo *vo, mp_image_t *mpi)
osd_draw_on_image(vo->osd, p->osd, 0, 0, p->cur_frame);
}
- struct modeset_buf *front_buf = &p->dev->bufs[p->dev->front_buf];
+ struct framebuffer *front_buf = &p->bufs[p->front_buf];
int w = p->dst.x1 - p->dst.x0;
int h = p->dst.y1 - p->dst.y0;
int x = (p->device_w - w) >> 1;
@@ -541,25 +381,25 @@ static void flip_page(struct vo *vo)
if (!p->active || p->pflip_happening)
return;
- int ret = drmModePageFlip(p->fd, p->dev->crtc,
- p->dev->bufs[p->dev->front_buf].fb,
+ int ret = drmModePageFlip(p->kms->fd, p->kms->crtc_id,
+ p->bufs[p->front_buf].fb,
DRM_MODE_PAGE_FLIP_EVENT, p);
if (ret) {
MP_WARN(vo, "Cannot flip page for connector\n");
} else {
- p->dev->front_buf++;
- p->dev->front_buf %= BUF_COUNT;
+ p->front_buf++;
+ p->front_buf %= BUF_COUNT;
p->pflip_happening = true;
}
// poll page flip finish event
const int timeout_ms = 3000;
struct pollfd fds[1] = {
- { .events = POLLIN, .fd = p->fd },
+ { .events = POLLIN, .fd = p->kms->fd },
};
poll(fds, 1, timeout_ms);
if (fds[0].revents & POLLIN) {
- ret = drmHandleEvent(p->fd, &p->ev);
+ ret = drmHandleEvent(p->kms->fd, &p->ev);
if (ret != 0) {
MP_ERR(vo, "drmHandleEvent failed: %i\n", ret);
return;
@@ -571,11 +411,13 @@ static void uninit(struct vo *vo)
{
struct priv *p = vo->priv;
- if (p->dev) {
- release_vo_crtc(vo);
- for (unsigned int i = 0; i < BUF_COUNT; i++)
- modeset_destroy_fb(p->fd, &p->dev->bufs[i]);
- drmModeFreeEncoder(p->dev->enc);
+ crtc_release(vo);
+ for (unsigned int i = 0; i < BUF_COUNT; i++)
+ fb_destroy(p->kms->fd, &p->bufs[i]);
+
+ if (p->kms) {
+ kms_destroy(p->kms);
+ p->kms = NULL;
}
if (p->vt_switcher_active)
@@ -583,17 +425,14 @@ static void uninit(struct vo *vo)
talloc_free(p->last_input);
talloc_free(p->cur_frame);
- talloc_free(p->dev);
- close(p->fd);
}
static int preinit(struct vo *vo)
{
struct priv *p = vo->priv;
p->sws = mp_sws_alloc(vo);
- p->fd = -1;
p->ev.version = DRM_EVENT_CONTEXT_VERSION;
- p->ev.page_flip_handler = modeset_page_flipped;
+ p->ev.page_flip_handler = page_flipped;
p->vt_switcher_active = vt_switcher_init(&p->vt_switcher, vo->log) == 0;
if (p->vt_switcher_active) {
@@ -603,18 +442,35 @@ static int preinit(struct vo *vo)
MP_WARN(vo, "Failed to set up VT switcher. Terminal switching will be unavailable.\n");
}
- if (modeset_open(vo, &p->fd, p->device_path))
+ p->kms = kms_create(vo->log);
+ if (!p->kms) {
+ MP_ERR(vo, "Failed to create KMS.\n");
+ goto err;
+ }
+
+ if (kms_setup(p->kms, p->device_path, p->connector_id, p->mode_id)) {
+ MP_ERR(vo, "Failed to configure KMS.\n");
+ goto err;
+ }
+
+ if (fb_setup_double_buffering(vo)) {
+ MP_ERR(vo, "Failed to set up double buffering.\n");
goto err;
+ }
- if (modeset_prepare_dev(vo, p->fd, p->connector_id, p->mode_id, &p->dev))
+ uint64_t has_dumb;
+ if (drmGetCap(p->kms->fd, DRM_CAP_DUMB_BUFFER, &has_dumb) < 0) {
+ MP_ERR(vo, "Device \"%s\" does not support dumb buffers.\n", p->device_path);
goto err;
+ }
- assert(p->dev);
- p->device_w = p->dev->bufs[0].width;
- p->device_h = p->dev->bufs[0].height;
+ p->device_w = p->bufs[0].width;
+ p->device_h = p->bufs[0].height;
- if (setup_vo_crtc(vo)) {
- MP_ERR(vo, "Cannot set CRTC for connector %u: %s\n", p->connector_id,
+ if (crtc_setup(vo)) {
+ MP_ERR(vo,
+ "Cannot set CRTC for connector %u: %s\n",
+ p->kms->connector->connector_id,
mp_strerror(errno));
goto err;
}