[gtk/wip/chergert/for-4-6: 13/56] macos: use video mode for refresh rate and interval




commit df2fb3b5209dcb0740a0af6d8fde5b490e310169
Author: Christian Hergert <christian hergert me>
Date:   Sun Feb 27 23:17:40 2022 -0800

    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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]