summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkemi <der.richter@gmx.de>2017-01-27 20:41:40 +0100
committerAkemi <der.richter@gmx.de>2017-02-02 16:22:27 +0100
commitf39a1cb1b0214ee3fb0640e11c1eeea6b3af47eb (patch)
treeb507937a560341c2304559ef3fa13727c4767875
parent8bbdecea8358e1a00630f095d9859bef9bc1535d (diff)
downloadmpv-f39a1cb1b0214ee3fb0640e11c1eeea6b3af47eb.tar.bz2
mpv-f39a1cb1b0214ee3fb0640e11c1eeea6b3af47eb.tar.xz
cocoa: fix displaylink refresh rate retrieval
we are dealing with several problems here, which weren't apparent because we always initialised a new displaylink for the display refresh rate retrieval, previously to commit 449eb20 and bug 9490b62. just changing the display with CVDisplayLinkSetCurrentCGDisplay can cause inconsistent refresh rates and discontinuity in timestamps. this can either lead to bogus values for the Actual display refresh rate or retrieving the refresh rate of the previous display if we immediately try to get a new value. since the Actual refresh rate is computed i assume that it at least needs one refresh period to actual return something useful. furthermore when changing the screen and updating the displaylink, it seems that the retrieved refresh rates for the screen mpv wasn't opened on are being estimated in a sub-optimal way. as an example, when moving my window to my second screen the Actual refresh rate was always a constant 60Hz, even though it is supposed to fluctuate a little bit. though if mpv was started on the secondary screen the Actual refresh rate fluctuated around 59.94Hz like expected. in that case my primary screen always reported a constant 60Hz instead. for the first problem we moved the actual retrieval of the refresh rate to the very last moment when mpv actual requests a new value and not when the refresh rate changed. we only update the displaylink itself when a possible refresh rate change is detected. this gives the displaylink some time to calculate the new refresh rate. for the second problem, instead of setting the new display we completely uninitialise the old dislaylink and create a new one for the new screen. this gives us properly estimated refresh rates. additionally we also optimised the display refresh rate fallback heuristic. it will never be 0 anymore and we prevent it from returning bogus values with a simple threshold for the difference of the Actual and Nominal refresh rate.
-rw-r--r--video/out/cocoa_common.m52
1 files changed, 29 insertions, 23 deletions
diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m
index 7eeb7163a1..5dda9c578c 100644
--- a/video/out/cocoa_common.m
+++ b/video/out/cocoa_common.m
@@ -69,7 +69,6 @@ struct vo_cocoa_state {
NSOpenGLContext *nsgl_ctx;
NSScreen *current_screen;
- double screen_fps;
NSInteger window_level;
int fullscreen;
@@ -428,28 +427,39 @@ void vo_cocoa_uninit(struct vo *vo)
});
}
-static void vo_cocoa_update_screen_fps(struct vo *vo)
+static void vo_cocoa_update_displaylink(struct vo *vo)
{
struct vo_cocoa_state *s = vo->cocoa;
- NSDictionary* sinfo = [s->current_screen deviceDescription];
- NSNumber* sid = [sinfo objectForKey:@"NSScreenNumber"];
- CGDirectDisplayID did = [sid longValue];
+ vo_cocoa_uninit_displaylink(s);
+ vo_cocoa_init_displaylink(vo);
- CVDisplayLinkSetCurrentCGDisplay(s->link, did);
- double display_period = CVDisplayLinkGetActualOutputVideoRefreshPeriod(s->link);
+ flag_events(vo, VO_EVENT_WIN_STATE);
+}
- if (display_period > 0) {
- s->screen_fps = 1/display_period;
- } else {
- const CVTime t = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(s->link);
- if (!(t.flags & kCVTimeIsIndefinite)) {
- s->screen_fps = (t.timeScale / (double) t.timeValue);
- MP_VERBOSE(vo, "Falling back to %f for display sync.\n", s->screen_fps);
+static double vo_cocoa_update_screen_fps(struct vo *vo)
+{
+ struct vo_cocoa_state *s = vo->cocoa;
+ double actual_fps = CVDisplayLinkGetActualOutputVideoRefreshPeriod(s->link);
+ const CVTime t = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(s->link);
+
+ if (!(t.flags & kCVTimeIsIndefinite)) {
+ double nominal_fps = (t.timeScale / (double) t.timeValue);
+
+ if (actual_fps > 0)
+ actual_fps = 1/actual_fps;
+
+ if (fabs(actual_fps - nominal_fps) > 0.1) {
+ MP_VERBOSE(vo, "Falling back to nominal display "
+ "refresh rate: %fHz\n", nominal_fps);
+ return nominal_fps;
+ } else {
+ return actual_fps;
}
}
- flag_events(vo, VO_EVENT_WIN_STATE);
+ MP_WARN(vo, "Falling back to standard display refresh rate: 60Hz\n");
+ return 60.0;
}
static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now,
@@ -609,7 +619,7 @@ static void cocoa_screen_reconfiguration_observer(
if (flags & kCGDisplaySetModeFlag) {
struct vo *vo = ctx;
MP_WARN(vo, "detected display mode change, updating screen info\n");
- vo_cocoa_update_screen_fps(vo);
+ vo_cocoa_update_displaylink(vo);
}
}
@@ -640,8 +650,6 @@ int vo_cocoa_config_window(struct vo *vo)
struct mp_vo_opts *opts = vo->opts;
run_on_main_thread(vo, ^{
- vo_cocoa_update_screen_fps(vo);
-
NSRect r = [s->current_screen frame];
struct mp_rect screenrc = {0, 0, r.size.width, r.size.height};
struct vo_win_geometry geo;
@@ -844,10 +852,8 @@ static int vo_cocoa_control_on_main_thread(struct vo *vo, int request, void *arg
vo_cocoa_control_get_icc_profile(vo, arg);
return VO_TRUE;
case VOCTRL_GET_DISPLAY_FPS:
- if (s->screen_fps > 0.0) {
- *(double *)arg = s->screen_fps;
- return VO_TRUE;
- }
+ *(double *)arg = vo_cocoa_update_screen_fps(vo);
+ return VO_TRUE;
break;
case VOCTRL_GET_AMBIENT_LUX:
if (s->light_sensor != IO_OBJECT_NULL) {
@@ -965,7 +971,7 @@ int vo_cocoa_control(struct vo *vo, int *events, int request, void *arg)
- (void)windowDidChangeScreen:(NSNotification *)notification
{
vo_cocoa_update_screen_info(self.vout);
- vo_cocoa_update_screen_fps(self.vout);
+ vo_cocoa_update_displaylink(self.vout);
}
- (void)windowDidEnterFullScreen:(NSNotification *)notification