From dac0b7d609740f0f330c59bd9696c55302ec434f Mon Sep 17 00:00:00 2001 From: Christian Hergert Date: Sun, 27 Feb 2022 23:17:40 -0800 Subject: [PATCH] macos: use video mode for refresh rate and interval Using the mode allows better detection of refresh rate and refresh interval for the CVDisplayLink bridge to GdkFrameClock. Using it can help ensure that our 144hz displays can actually reach that rather than falling back to just 60hz. This will also need future commits to rework the displaylink source to be per-monitor. --- gdk/macos/gdkdisplaylinksource.c | 61 ++++++++++++++++++++++---------- gdk/macos/gdkdisplaylinksource.h | 4 ++- 2 files changed, 46 insertions(+), 19 deletions(-) diff --git a/gdk/macos/gdkdisplaylinksource.c b/gdk/macos/gdkdisplaylinksource.c index 8b2f1a013f..fe75eb3a55 100644 --- a/gdk/macos/gdkdisplaylinksource.c +++ b/gdk/macos/gdkdisplaylinksource.c @@ -65,7 +65,7 @@ gdk_display_link_source_dispatch (GSource *source, impl->needs_dispatch = FALSE; - if (callback != NULL) + if (!impl->paused && callback != NULL) ret = callback (user_data); return ret; @@ -76,7 +76,9 @@ gdk_display_link_source_finalize (GSource *source) { GdkDisplayLinkSource *impl = (GdkDisplayLinkSource *)source; - CVDisplayLinkStop (impl->display_link); + if (!impl->paused) + CVDisplayLinkStop (impl->display_link); + CVDisplayLinkRelease (impl->display_link); } @@ -90,12 +92,18 @@ static GSourceFuncs gdk_display_link_source_funcs = { void gdk_display_link_source_pause (GdkDisplayLinkSource *source) { + g_return_if_fail (source->paused == FALSE); + + source->paused = TRUE; CVDisplayLinkStop (source->display_link); } void gdk_display_link_source_unpause (GdkDisplayLinkSource *source) { + g_return_if_fail (source->paused == TRUE); + + source->paused = FALSE; CVDisplayLinkStart (source->display_link); } @@ -160,16 +168,16 @@ gdk_display_link_source_frame_cb (CVDisplayLinkRef display_link, * Returns: (transfer full): A newly created `GSource` */ GSource * -gdk_display_link_source_new (CGDirectDisplayID display_id) +gdk_display_link_source_new (CGDirectDisplayID display_id, + CGDisplayModeRef mode) { GdkDisplayLinkSource *impl; GSource *source; - CVReturn ret; - double period; source = g_source_new (&gdk_display_link_source_funcs, sizeof *impl); impl = (GdkDisplayLinkSource *)source; impl->display_id = display_id; + impl->paused = TRUE; /* Create DisplayLink for timing information for the display in * question so that we can produce graphics for that display at whatever @@ -178,21 +186,34 @@ gdk_display_link_source_new (CGDirectDisplayID display_id) if (CVDisplayLinkCreateWithCGDisplay (display_id, &impl->display_link) != kCVReturnSuccess) { g_warning ("Failed to initialize CVDisplayLink!"); - return source; + goto failure; } - /* - * Determine our nominal period between frames. - */ - period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link); - if (period == 0.0) - period = 1.0 / 60.0; - impl->refresh_interval = period * 1000000L; - impl->refresh_rate = 1.0 / period * 1000L; - - /* - * Wire up our callback to be executed within the high-priority thread. - */ + impl->refresh_rate = CGDisplayModeGetRefreshRate (mode) * 1000.0; + + if (impl->refresh_rate == 0) + { + const CVTime time = CVDisplayLinkGetNominalOutputVideoRefreshPeriod (impl->display_link); + if (!(time.flags & kCVTimeIsIndefinite)) + impl->refresh_rate = (double)time.timeScale / (double)time.timeValue * 1000.0; + } + + if (impl->refresh_rate != 0) + { + impl->refresh_interval = 1000000.0 / (double)impl->refresh_rate * 1000.0; + } + else + { + double period = CVDisplayLinkGetActualOutputVideoRefreshPeriod (impl->display_link); + + if (period == 0.0) + period = 1.0 / 60.0; + + impl->refresh_rate = 1.0 / period * 1000L; + impl->refresh_interval = period * 1000000L; + } + + /* Wire up our callback to be executed within the high-priority thread. */ CVDisplayLinkSetOutputCallback (impl->display_link, gdk_display_link_source_frame_cb, source); @@ -200,6 +221,10 @@ gdk_display_link_source_new (CGDirectDisplayID display_id) g_source_set_static_name (source, "[gdk] quartz frame clock"); return source; + +failure: + g_source_unref (source); + return NULL; } static gint64 diff --git a/gdk/macos/gdkdisplaylinksource.h b/gdk/macos/gdkdisplaylinksource.h index bff1c91475..6f465907a2 100644 --- a/gdk/macos/gdkdisplaylinksource.h +++ b/gdk/macos/gdkdisplaylinksource.h @@ -36,12 +36,14 @@ typedef struct CVDisplayLinkRef display_link; gint64 refresh_interval; guint refresh_rate; + guint paused : 1; volatile gint64 presentation_time; volatile guint needs_dispatch; } GdkDisplayLinkSource; -GSource *gdk_display_link_source_new (CGDirectDisplayID display_id); +GSource *gdk_display_link_source_new (CGDirectDisplayID display_id, + CGDisplayModeRef mode); void gdk_display_link_source_pause (GdkDisplayLinkSource *source); void gdk_display_link_source_unpause (GdkDisplayLinkSource *source); -- 2.30.2