1
0
mirror of https://github.com/mpv-player/mpv synced 2025-03-20 18:28:01 +00:00

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.
This commit is contained in:
Akemi 2017-01-27 20:41:40 +01:00
parent 8bbdecea83
commit f39a1cb1b0

View File

@ -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