]> Pileus Git - ~andy/gtk/commitdiff
Add gdk_frame_timings_get/set_slept_before()
authorOwen W. Taylor <otaylor@fishsoup.net>
Wed, 14 Nov 2012 21:08:08 +0000 (16:08 -0500)
committerOwen W. Taylor <otaylor@fishsoup.net>
Thu, 14 Feb 2013 22:19:50 +0000 (17:19 -0500)
Add functions that tell us whether the main loop slept before we drew
a frame. Blocking with the frame clock frozen doesn't count as sleeping.
We'll use this to advertise to the compositor whether we
are drawing as fast as possible (and it should do the same) or timing
frames carefully (and it should do the same.)

https://bugzilla.gnome.org/show_bug.cgi?id=685460

gdk/gdkframeclockidle.c
gdk/gdkframetimings.c
gdk/gdkframetimings.h

index 37a6733620f28c8f32633678bc6a3f0dd8e2cfb7..f6e2d339b9aa3f55857761d1d14a30cdeafcf3c1 100644 (file)
@@ -39,6 +39,7 @@ struct _GdkFrameClockIdlePrivate
   guint64 timer_base;
   guint64 frame_time;
   guint64 min_next_frame_time;
+  gint64 sleep_serial;
 
   guint flush_idle_id;
   guint paint_idle_id;
@@ -60,6 +61,58 @@ G_DEFINE_TYPE_WITH_CODE (GdkFrameClockIdle, gdk_frame_clock_idle, G_TYPE_OBJECT,
                         G_IMPLEMENT_INTERFACE (GDK_TYPE_FRAME_CLOCK,
                                                gdk_frame_clock_idle_interface_init))
 
+static gint64 sleep_serial;
+static gint64 sleep_source_prepare_time;
+static GSource *sleep_source;
+
+gboolean
+sleep_source_prepare (GSource *source,
+                      gint    *timeout)
+{
+  sleep_source_prepare_time = g_source_get_time (source);
+  *timeout = -1;
+  return FALSE;
+}
+
+gboolean
+sleep_source_check (GSource *source)
+{
+  if (g_source_get_time (source) != sleep_source_prepare_time)
+    sleep_serial++;
+
+  return FALSE;
+}
+
+gboolean
+sleep_source_dispatch (GSource     *source,
+                       GSourceFunc  callback,
+                       gpointer     user_data)
+{
+  return TRUE;
+}
+
+static GSourceFuncs sleep_source_funcs = {
+  sleep_source_prepare,
+  sleep_source_check,
+  sleep_source_dispatch,
+  NULL /* finalize */
+};
+
+static gint64
+get_sleep_serial (void)
+{
+  if (sleep_source == NULL)
+    {
+      sleep_source = g_source_new (&sleep_source_funcs, sizeof (GSource));
+
+      g_source_set_priority (sleep_source, G_PRIORITY_HIGH);
+      g_source_attach (sleep_source, NULL);
+      g_source_unref (sleep_source);
+    }
+
+  return sleep_serial;
+}
+
 static void
 gdk_frame_clock_idle_class_init (GdkFrameClockIdleClass *klass)
 {
@@ -244,6 +297,9 @@ gdk_frame_clock_paint_idle (void *data)
               timings = gdk_frame_history_get_timings (priv->history, frame_counter);
               gdk_frame_timings_set_frame_time (timings, priv->frame_time);
 
+              gdk_frame_timings_set_slept_before (timings,
+                                                  priv->sleep_serial != get_sleep_serial ());
+
               priv->phase = GDK_FRAME_CLOCK_PHASE_BEFORE_PAINT;
 
               /* We always emit ::before-paint and ::after-paint if
@@ -322,6 +378,9 @@ gdk_frame_clock_paint_idle (void *data)
       priv->min_next_frame_time = 0;
     }
 
+  if (priv->freeze_count == 0)
+    priv->sleep_serial = get_sleep_serial ();
+
   return FALSE;
 }
 
@@ -383,6 +442,8 @@ gdk_frame_clock_idle_thaw (GdkFrameClock *clock)
        * run and do it for us. */
       if (priv->paint_idle_id == 0)
         priv->phase = GDK_FRAME_CLOCK_PHASE_NONE;
+
+      priv->sleep_serial = get_sleep_serial ();
     }
 }
 
index d9354ede4f7ecab0efbf52424e57e267248e6bfb..a51912baa6e31c959a002a090ab1d274969a1ffd 100644 (file)
@@ -23,13 +23,15 @@ struct _GdkFrameTimings
 {
   guint ref_count;
 
-  gboolean complete;
   gint64 frame_counter;
   guint64 cookie;
   gint64 frame_time;
   gint64 drawn_time;
   gint64 presentation_time;
   gint64 refresh_interval;
+
+  guint complete : 1;
+  guint slept_before : 1;
 };
 
 G_DEFINE_BOXED_TYPE (GdkFrameTimings, gdk_frame_timings,
@@ -111,6 +113,23 @@ gdk_frame_timings_set_complete (GdkFrameTimings *timings,
   timings->complete = complete;
 }
 
+gboolean
+gdk_frame_timings_get_slept_before (GdkFrameTimings *timings)
+{
+  g_return_val_if_fail (timings != NULL, FALSE);
+
+  return timings->slept_before;
+}
+
+void
+gdk_frame_timings_set_slept_before (GdkFrameTimings *timings,
+                                    gboolean         slept_before)
+{
+  g_return_if_fail (timings != NULL);
+
+  timings->slept_before = slept_before;
+}
+
 gint64
 gdk_frame_timings_get_frame_time (GdkFrameTimings *timings)
 {
index 7fddbd4a6da117b0023147f422e9a2520f3dd876..53dbffbd068c78ac418f35b435984f5a607c79af 100644 (file)
@@ -45,6 +45,10 @@ gboolean         gdk_frame_timings_get_complete          (GdkFrameTimings *timin
 void             gdk_frame_timings_set_complete          (GdkFrameTimings *timings,
                                                           gboolean         complete);
 
+gboolean         gdk_frame_timings_get_slept_before      (GdkFrameTimings *timings);
+void             gdk_frame_timings_set_slept_before      (GdkFrameTimings *timings,
+                                                          gboolean         slept_before);
+
 gint64           gdk_frame_timings_get_frame_time        (GdkFrameTimings *timings);
 void             gdk_frame_timings_set_frame_time        (GdkFrameTimings *timings,
                                                           gint64           frame_time);