summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Kindestam <antonki@kth.se>2019-12-07 18:23:42 +0100
committerAnton Kindestam <antonki@kth.se>2019-12-07 18:34:25 +0100
commitd5cabf73489fe165562adea765ed7f53fd264e53 (patch)
tree42ebb44b8d924489c1b0556b3ba5805d8880cfff
parent83b742df77e9edd0fb2290567097c5d5dc0c2c55 (diff)
downloadmpv-d5cabf73489fe165562adea765ed7f53fd264e53.tar.bz2
mpv-d5cabf73489fe165562adea765ed7f53fd264e53.tar.xz
drm: avoid division by 0 in drm_pflip_cb with bad drivers
Seems like some drivers only increment msc every other page flip when running in interlaced mode (I'm looking at you nouveau). I.e. it seems to be incremented at the frame rate, rather than the field rate. Obviously we can't work with this, so shame the driver and bail. On intel this isn't an issue, as msc is incremented at field rate there. This means presentation feedback won't work correctly in interlaced modes with those drivers, but who in their right mind uses an interlaced mode these days, anyway?
-rw-r--r--video/out/drm_common.c9
-rw-r--r--video/out/drm_common.h1
-rw-r--r--video/out/opengl/context_drm_egl.c1
-rw-r--r--video/out/vo_drm.c1
4 files changed, 12 insertions, 0 deletions
diff --git a/video/out/drm_common.c b/video/out/drm_common.c
index 9c56227b9e..084cf22768 100644
--- a/video/out/drm_common.c
+++ b/video/out/drm_common.c
@@ -944,6 +944,15 @@ void drm_pflip_cb(int fd, unsigned int msc, unsigned int sec,
const uint64_t ust = (sec * 1000000LL) + usec;
const unsigned int msc_since_last_flip = msc - vsync->msc;
+ if (ready && msc == vsync->msc) {
+ // Seems like some drivers only increment msc every other page flip when
+ // running in interlaced mode (I'm looking at you nouveau). Obviously we
+ // can't work with this, so shame the driver and bail.
+ mp_err(closure->log,
+ "Got the same msc value twice: (msc: %u, vsync->msc: %u). This shouldn't happen. Possibly broken driver/interlaced mode?\n",
+ msc, vsync->msc);
+ goto fail;
+ }
vsync->ust = ust;
vsync->msc = msc;
diff --git a/video/out/drm_common.h b/video/out/drm_common.h
index 6ddd0994e3..aa08312ad2 100644
--- a/video/out/drm_common.h
+++ b/video/out/drm_common.h
@@ -66,6 +66,7 @@ struct drm_pflip_cb_closure {
struct drm_vsync_tuple *vsync; // vsync tuple of the latest page flip. drm_pflip_cb updates this
struct vo_vsync_info *vsync_info; // where the drm_pflip_cb routine writes its output
bool *waiting_for_flip; // drm_pflip_cb writes false here before returning
+ struct mp_log *log; // Needed to print error messages that shame bad drivers
};
bool vt_switcher_init(struct vt_switcher *s, struct mp_log *log);
diff --git a/video/out/opengl/context_drm_egl.c b/video/out/opengl/context_drm_egl.c
index 736db7a4ec..3b5dac64da 100644
--- a/video/out/opengl/context_drm_egl.c
+++ b/video/out/opengl/context_drm_egl.c
@@ -459,6 +459,7 @@ static void queue_flip(struct ra_ctx *ctx, struct gbm_frame *frame)
data->vsync = &p->vsync;
data->vsync_info = &p->vsync_info;
data->waiting_for_flip = &p->waiting_for_flip;
+ data->log = ctx->log;
if (atomic_ctx) {
drm_object_set_property(atomic_ctx->request, atomic_ctx->draw_plane, "FB_ID", p->fb->id);
diff --git a/video/out/vo_drm.c b/video/out/vo_drm.c
index be5b0c52d9..7eee6c66c1 100644
--- a/video/out/vo_drm.c
+++ b/video/out/vo_drm.c
@@ -489,6 +489,7 @@ static void queue_flip(struct vo *vo, struct kms_frame *frame)
data->vsync = &p->vsync;
data->vsync_info = &p->vsync_info;
data->waiting_for_flip = &p->waiting_for_flip;
+ data->log = vo->log;
ret = drmModePageFlip(p->kms->fd, p->kms->crtc_id,
p->cur_fb->fb,