summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAkemi <der.richter@gmx.de>2016-12-17 20:53:09 +0100
committerAkemi <der.richter@gmx.de>2017-01-11 14:20:32 +0100
commit449eb208f4d312c1bde616259d44d4d36112a603 (patch)
tree2a176c06502679eb87620f0503172488e7e4cee2
parent46b74a38f11e9ff2808fc151a329a260d4ac8d90 (diff)
downloadmpv-449eb208f4d312c1bde616259d44d4d36112a603.tar.bz2
mpv-449eb208f4d312c1bde616259d44d4d36112a603.tar.xz
cocoa: rate limit video output
the display refresh rate can't be estimated correctly in some cases and just increases till it turns off display-resample. cases are off-screen rendering (different space), mpv being completely hidden behind another window or the mission control view. this utilise the unused displaylink callback to limit the refresh rate to the actual display refresh rate.
-rw-r--r--video/out/cocoa_common.m65
1 files changed, 51 insertions, 14 deletions
diff --git a/video/out/cocoa_common.m b/video/out/cocoa_common.m
index 58b0df518f..0b10217f80 100644
--- a/video/out/cocoa_common.m
+++ b/video/out/cocoa_common.m
@@ -87,6 +87,11 @@ struct vo_cocoa_state {
uint32_t old_dwidth;
uint32_t old_dheight;
+ CVDisplayLinkRef link;
+ pthread_mutex_t sync_lock;
+ pthread_cond_t sync_wakeup;
+ uint64_t sync_counter;
+
pthread_mutex_t lock;
pthread_cond_t wakeup;
@@ -305,6 +310,26 @@ static void vo_cocoa_update_screen_info(struct vo *vo)
}
}
+static void vo_cocoa_init_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];
+
+ CVDisplayLinkCreateWithCGDisplay(did, &s->link);
+ CVDisplayLinkSetOutputCallback(s->link, &displayLinkCallback, vo);
+ CVDisplayLinkStart(s->link);
+}
+
+static void vo_cocoa_uninit_displaylink(struct vo_cocoa_state *s)
+{
+ if (CVDisplayLinkIsRunning(s->link))
+ CVDisplayLinkStop(s->link);
+ CVDisplayLinkRelease(s->link);
+}
+
void vo_cocoa_init(struct vo *vo)
{
struct vo_cocoa_state *s = talloc_zero(NULL, struct vo_cocoa_state);
@@ -321,6 +346,8 @@ void vo_cocoa_init(struct vo *vo)
}
pthread_mutex_init(&s->lock, NULL);
pthread_cond_init(&s->wakeup, NULL);
+ pthread_mutex_init(&s->sync_lock, NULL);
+ pthread_cond_init(&s->sync_wakeup, NULL);
vo->cocoa = s;
vo_cocoa_update_screen_info(vo);
cocoa_init_light_sensor(vo);
@@ -362,6 +389,10 @@ void vo_cocoa_uninit(struct vo *vo)
run_on_main_thread(vo, ^{
enable_power_management(s);
+ vo_cocoa_uninit_displaylink(s);
+ pthread_mutex_lock(&s->sync_lock);
+ pthread_cond_signal(&s->sync_wakeup);
+ pthread_mutex_unlock(&s->sync_lock);
cocoa_uninit_light_sensor(s);
cocoa_rm_screen_reconfiguration_observer(vo);
@@ -384,6 +415,8 @@ void vo_cocoa_uninit(struct vo *vo)
if (!s->embedded)
[s->blankCursor release];
+ pthread_cond_destroy(&s->sync_wakeup);
+ pthread_mutex_destroy(&s->sync_lock);
pthread_cond_destroy(&s->wakeup);
pthread_mutex_destroy(&s->lock);
talloc_free(s);
@@ -398,30 +431,19 @@ static void vo_cocoa_update_screen_fps(struct vo *vo)
NSNumber* sid = [sinfo objectForKey:@"NSScreenNumber"];
CGDirectDisplayID did = [sid longValue];
- CVDisplayLinkRef link;
- CVDisplayLinkCreateWithCGDisplay(did, &link);
- CVDisplayLinkSetOutputCallback(link, &displayLinkCallback, NULL);
- CVDisplayLinkStart(link);
- CVDisplayLinkSetCurrentCGDisplay(link, did);
-
- double display_period = CVDisplayLinkGetActualOutputVideoRefreshPeriod(link);
+ CVDisplayLinkSetCurrentCGDisplay(s->link, did);
+ double display_period = CVDisplayLinkGetActualOutputVideoRefreshPeriod(s->link);
if (display_period > 0) {
s->screen_fps = 1/display_period;
} else {
- // Fallback to using Nominal refresh rate from DisplayLink,
- // CVDisplayLinkGet *Actual* OutputVideoRefreshPeriod seems to
- // return 0 on some Apple devices. Use the nominal refresh period
- // instead.
- const CVTime t = CVDisplayLinkGetNominalOutputVideoRefreshPeriod(link);
+ 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);
}
}
- CVDisplayLinkRelease(link);
-
flag_events(vo, VO_EVENT_WIN_STATE);
}
@@ -429,6 +451,13 @@ static CVReturn displayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeSt
const CVTimeStamp* outputTime, CVOptionFlags flagsIn,
CVOptionFlags* flagsOut, void* displayLinkContext)
{
+ struct vo *vo = displayLinkContext;
+ struct vo_cocoa_state *s = vo->cocoa;
+
+ pthread_mutex_lock(&s->sync_lock);
+ s->sync_counter += 1;
+ pthread_cond_signal(&s->sync_wakeup);
+ pthread_mutex_unlock(&s->sync_lock);
return kCVReturnSuccess;
}
@@ -603,6 +632,7 @@ int vo_cocoa_config_window(struct vo *vo)
struct mp_vo_opts *opts = vo->opts;
run_on_main_thread(vo, ^{
+ vo_cocoa_init_displaylink(vo);
vo_cocoa_update_screen_fps(vo);
NSRect r = [s->current_screen frame];
@@ -700,6 +730,13 @@ void vo_cocoa_swap_buffers(struct vo *vo)
if (skip)
return;
+ pthread_mutex_lock(&s->sync_lock);
+ uint64_t old_counter = s->sync_counter;
+ while(old_counter == s->sync_counter) {
+ pthread_cond_wait(&s->sync_wakeup, &s->sync_lock);
+ }
+ pthread_mutex_unlock(&s->sync_lock);
+
pthread_mutex_lock(&s->lock);
s->frame_w = vo->dwidth;
s->frame_h = vo->dheight;