[mutter] frame-clock: Add API to inhibit/uninhibit updates



commit a132c8dc8e9aed838aa76b384a6cf814a6fb6051
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Wed Mar 25 10:33:45 2020 +0100

    frame-clock: Add API to inhibit/uninhibit updates
    
    Equivalent to pause/resume, but ref counted.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285

 clutter/clutter/clutter-frame-clock.c   | 86 +++++++++++++++++++++++++++------
 clutter/clutter/clutter-frame-clock.h   |  6 +++
 src/tests/clutter/conform/frame-clock.c | 80 ++++++++++++++++++++++++++++++
 3 files changed, 157 insertions(+), 15 deletions(-)
---
diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c
index eb1cff356c..44da0c0222 100644
--- a/clutter/clutter/clutter-frame-clock.c
+++ b/clutter/clutter/clutter-frame-clock.c
@@ -78,11 +78,32 @@ struct _ClutterFrameClock
 
   gboolean pending_reschedule;
   gboolean pending_reschedule_now;
+
+  int inhibit_count;
 };
 
 G_DEFINE_TYPE (ClutterFrameClock, clutter_frame_clock,
                G_TYPE_OBJECT)
 
+static void
+maybe_reschedule_update (ClutterFrameClock *frame_clock)
+{
+  if (frame_clock->pending_reschedule)
+    {
+      frame_clock->pending_reschedule = FALSE;
+
+      if (frame_clock->pending_reschedule_now)
+        {
+          frame_clock->pending_reschedule_now = FALSE;
+          clutter_frame_clock_schedule_update_now (frame_clock);
+        }
+      else
+        {
+          clutter_frame_clock_schedule_update (frame_clock);
+        }
+    }
+}
+
 void
 clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
                                       int64_t            presentation_time_us)
@@ -111,21 +132,7 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
     case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
     case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
       frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
-
-      if (frame_clock->pending_reschedule)
-        {
-          frame_clock->pending_reschedule = FALSE;
-
-          if (frame_clock->pending_reschedule_now)
-            {
-              frame_clock->pending_reschedule_now = FALSE;
-              clutter_frame_clock_schedule_update_now (frame_clock);
-            }
-          else
-            {
-              clutter_frame_clock_schedule_update (frame_clock);
-            }
-        }
+      maybe_reschedule_update (frame_clock);
       break;
     }
 }
@@ -194,11 +201,54 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
   *out_next_presentation_time_us = next_presentation_time_us;
 }
 
+void
+clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock)
+{
+  frame_clock->inhibit_count++;
+
+  if (frame_clock->inhibit_count == 1)
+    {
+      switch (frame_clock->state)
+        {
+        case CLUTTER_FRAME_CLOCK_STATE_INIT:
+        case CLUTTER_FRAME_CLOCK_STATE_IDLE:
+          break;
+        case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
+          frame_clock->pending_reschedule = TRUE;
+          frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
+          break;
+        case CLUTTER_FRAME_CLOCK_STATE_DISPATCHING:
+        case CLUTTER_FRAME_CLOCK_STATE_PENDING_PRESENTED:
+          break;
+        }
+
+      g_source_set_ready_time (frame_clock->source, -1);
+    }
+}
+
+void
+clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock)
+{
+  g_return_if_fail (frame_clock->inhibit_count > 0);
+
+  frame_clock->inhibit_count--;
+
+  if (frame_clock->inhibit_count == 0)
+    maybe_reschedule_update (frame_clock);
+}
+
 void
 clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock)
 {
   int64_t next_update_time_us = -1;
 
+  if (frame_clock->inhibit_count > 0)
+    {
+      frame_clock->pending_reschedule = TRUE;
+      frame_clock->pending_reschedule_now = TRUE;
+      return;
+    }
+
   switch (frame_clock->state)
     {
     case CLUTTER_FRAME_CLOCK_STATE_INIT:
@@ -226,6 +276,12 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
 {
   int64_t next_update_time_us = -1;
 
+  if (frame_clock->inhibit_count > 0)
+    {
+      frame_clock->pending_reschedule = TRUE;
+      return;
+    }
+
   switch (frame_clock->state)
     {
     case CLUTTER_FRAME_CLOCK_STATE_INIT:
diff --git a/clutter/clutter/clutter-frame-clock.h b/clutter/clutter/clutter-frame-clock.h
index 057ad411bd..217cf771aa 100644
--- a/clutter/clutter/clutter-frame-clock.h
+++ b/clutter/clutter/clutter-frame-clock.h
@@ -61,4 +61,10 @@ void clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock);
 CLUTTER_EXPORT
 void clutter_frame_clock_schedule_update_now (ClutterFrameClock *frame_clock);
 
+CLUTTER_EXPORT
+void clutter_frame_clock_inhibit (ClutterFrameClock *frame_clock);
+
+CLUTTER_EXPORT
+void clutter_frame_clock_uninhibit (ClutterFrameClock *frame_clock);
+
 #endif /* CLUTTER_FRAME_CLOCK_H */
diff --git a/src/tests/clutter/conform/frame-clock.c b/src/tests/clutter/conform/frame-clock.c
index 3d8b70a82d..a7407e1b63 100644
--- a/src/tests/clutter/conform/frame-clock.c
+++ b/src/tests/clutter/conform/frame-clock.c
@@ -524,6 +524,85 @@ frame_clock_before_frame (void)
   g_object_unref (frame_clock);
 }
 
+typedef struct _InhibitTest
+{
+  GMainLoop *main_loop;
+  ClutterFrameClock *frame_clock;
+
+  gboolean frame_count;
+  gboolean pending_inhibit;
+  gboolean pending_quit;
+} InhibitTest;
+
+static ClutterFrameResult
+inhibit_frame_clock_frame (ClutterFrameClock *frame_clock,
+                           int64_t            frame_count,
+                           gpointer           user_data)
+{
+  InhibitTest *test = user_data;
+
+  g_assert_cmpint (frame_count, ==, test->frame_count);
+
+  test->frame_count++;
+
+  clutter_frame_clock_notify_presented (frame_clock, g_get_monotonic_time ());
+  clutter_frame_clock_schedule_update (frame_clock);
+
+  if (test->pending_inhibit)
+    {
+      test->pending_inhibit = FALSE;
+      clutter_frame_clock_inhibit (frame_clock);
+    }
+
+  clutter_frame_clock_schedule_update (frame_clock);
+
+  if (test->pending_quit)
+    g_main_loop_quit (test->main_loop);
+
+  return CLUTTER_FRAME_RESULT_PENDING_PRESENTED;
+}
+
+static const ClutterFrameListenerIface inhibit_frame_listener_iface = {
+  .frame = inhibit_frame_clock_frame,
+};
+
+static gboolean
+uninhibit_timeout (gpointer user_data)
+{
+  InhibitTest *test = user_data;
+
+  g_assert_cmpint (test->frame_count, ==, 1);
+
+  clutter_frame_clock_uninhibit (test->frame_clock);
+  test->pending_quit = TRUE;
+
+  return G_SOURCE_REMOVE;
+}
+
+static void
+frame_clock_inhibit (void)
+{
+  InhibitTest test = { 0 };
+
+  expected_frame_count = 0;
+
+  test.main_loop = g_main_loop_new (NULL, FALSE);
+  test.frame_clock = clutter_frame_clock_new (refresh_rate,
+                                              &inhibit_frame_listener_iface,
+                                              &test);
+
+  test.pending_inhibit = TRUE;
+
+  clutter_frame_clock_schedule_update (test.frame_clock);
+  g_timeout_add (100, uninhibit_timeout, &test);
+  g_main_loop_run (test.main_loop);
+
+  g_assert_cmpint (test.frame_count, ==, 2);
+
+  g_main_loop_unref (test.main_loop);
+  g_object_unref (test.frame_clock);
+}
+
 CLUTTER_TEST_SUITE (
   CLUTTER_TEST_UNIT ("/frame-clock/schedule-update", frame_clock_schedule_update)
   CLUTTER_TEST_UNIT ("/frame-clock/immediate-present", frame_clock_immediate_present)
@@ -531,4 +610,5 @@ CLUTTER_TEST_SUITE (
   CLUTTER_TEST_UNIT ("/frame-clock/no-damage", frame_clock_no_damage)
   CLUTTER_TEST_UNIT ("/frame-clock/schedule-update-now", frame_clock_schedule_update_now)
   CLUTTER_TEST_UNIT ("/frame-clock/before-frame", frame_clock_before_frame)
+  CLUTTER_TEST_UNIT ("/frame-clock/inhibit", frame_clock_inhibit)
 )


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