[mutter] clutter/frame-clock: Handle immediate present feedback



commit e743b36cfc119f7bfa94866d39f01a1e5a8cb9d8
Author: Jonas Ã…dahl <jadahl gmail com>
Date:   Fri Mar 20 16:03:34 2020 +0100

    clutter/frame-clock: Handle immediate present feedback
    
    In certain scenarios, the frame clock needs to handle present feedback
    long before the assumed presentation time happens. To avoid scheduling
    the next frame to soon, avoid scheduling one if we were presented half a
    frame interval within the last expected presentation time.
    
    https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285

 clutter/clutter/clutter-frame-clock.c   | 25 +++++++++++-
 src/tests/clutter/conform/frame-clock.c | 72 +++++++++++++++++++++++++++++++++
 2 files changed, 95 insertions(+), 2 deletions(-)
---
diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c
index a05436ae4d..3248b4dcc1 100644
--- a/clutter/clutter/clutter-frame-clock.c
+++ b/clutter/clutter/clutter-frame-clock.c
@@ -72,6 +72,9 @@ struct _ClutterFrameClock
   ClutterFrameClockState state;
   int64_t last_presentation_time_us;
 
+  gboolean is_next_presentation_time_valid;
+  int64_t next_presentation_time_us;
+
   gboolean pending_reschedule;
 };
 
@@ -120,7 +123,8 @@ clutter_frame_clock_notify_presented (ClutterFrameClock *frame_clock,
 
 static void
 calculate_next_update_time_us (ClutterFrameClock *frame_clock,
-                               int64_t           *out_next_update_time_us)
+                               int64_t           *out_next_update_time_us,
+                               int64_t           *out_next_presentation_time_us)
 {
   int64_t last_presentation_time_us;
   int64_t now_us;
@@ -128,6 +132,8 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
   int64_t refresh_interval_us;
   int64_t min_render_time_allowed_us;
   int64_t max_render_time_allowed_us;
+  int64_t last_next_presentation_time_us;
+  int64_t time_since_last_next_presentation_time_us;
   int64_t next_presentation_time_us;
   int64_t next_update_time_us;
 
@@ -159,12 +165,24 @@ calculate_next_update_time_us (ClutterFrameClock *frame_clock,
       next_presentation_time_us = logical_clock_phase_us + hw_clock_offset_us;
     }
 
+  /* Skip one interval if we got an early presented event. */
+  last_next_presentation_time_us = frame_clock->next_presentation_time_us;
+  time_since_last_next_presentation_time_us =
+      next_presentation_time_us - last_next_presentation_time_us;
+  if (frame_clock->is_next_presentation_time_valid &&
+      time_since_last_next_presentation_time_us < (refresh_interval_us / 2))
+    {
+      next_presentation_time_us =
+        frame_clock->next_presentation_time_us + refresh_interval_us;
+    }
+
   while (next_presentation_time_us < now_us + min_render_time_allowed_us)
     next_presentation_time_us += refresh_interval_us;
 
   next_update_time_us = next_presentation_time_us - max_render_time_allowed_us;
 
   *out_next_update_time_us = next_update_time_us;
+  *out_next_presentation_time_us = next_presentation_time_us;
 }
 
 void
@@ -178,7 +196,10 @@ clutter_frame_clock_schedule_update (ClutterFrameClock *frame_clock)
       next_update_time_us = g_get_monotonic_time ();
       break;
     case CLUTTER_FRAME_CLOCK_STATE_IDLE:
-      calculate_next_update_time_us (frame_clock, &next_update_time_us);
+      calculate_next_update_time_us (frame_clock,
+                                     &next_update_time_us,
+                                     &frame_clock->next_presentation_time_us);
+      frame_clock->is_next_presentation_time_valid = TRUE;
       break;
     case CLUTTER_FRAME_CLOCK_STATE_SCHEDULED:
       return;
diff --git a/src/tests/clutter/conform/frame-clock.c b/src/tests/clutter/conform/frame-clock.c
index cf548e2c4e..63927ce0b9 100644
--- a/src/tests/clutter/conform/frame-clock.c
+++ b/src/tests/clutter/conform/frame-clock.c
@@ -158,6 +158,78 @@ frame_clock_schedule_update (void)
   g_source_unref (source);
 }
 
+static gboolean
+schedule_update_idle (gpointer user_data)
+{
+  ClutterFrameClock *frame_clock = user_data;
+
+  clutter_frame_clock_schedule_update (frame_clock);
+
+  return G_SOURCE_REMOVE;
+}
+
+static ClutterFrameResult
+immediate_frame_clock_frame (ClutterFrameClock *frame_clock,
+                             int64_t            frame_count,
+                             gpointer           user_data)
+{
+  GMainLoop *main_loop = user_data;
+
+  g_assert_cmpint (frame_count, ==, expected_frame_count);
+
+  expected_frame_count++;
+
+  if (test_frame_count == 0)
+    {
+      g_main_loop_quit (main_loop);
+      return CLUTTER_FRAME_RESULT_IDLE;
+    }
+
+  test_frame_count--;
+
+  clutter_frame_clock_notify_presented (frame_clock, g_get_monotonic_time ());
+  g_idle_add (schedule_update_idle, frame_clock);
+
+  return CLUTTER_FRAME_RESULT_PENDING_PRESENTED;
+}
+
+static const ClutterFrameListenerIface immediate_frame_listener_iface = {
+  .frame = immediate_frame_clock_frame,
+};
+
+static void
+frame_clock_immediate_present (void)
+{
+  GMainLoop *main_loop;
+  ClutterFrameClock *frame_clock;
+  int64_t before_us;
+  int64_t after_us;
+
+  test_frame_count = 10;
+  expected_frame_count = 0;
+
+  main_loop = g_main_loop_new (NULL, FALSE);
+  frame_clock = clutter_frame_clock_new (refresh_rate,
+                                         &immediate_frame_listener_iface,
+                                         main_loop);
+
+  before_us = g_get_monotonic_time ();
+
+  clutter_frame_clock_schedule_update (frame_clock);
+  g_main_loop_run (main_loop);
+
+  after_us = g_get_monotonic_time ();
+
+  /* The initial frame will only be delayed by 2 ms, so we are checking one
+   * less.
+   */
+  g_assert_cmpint (after_us - before_us, >, 9 * refresh_interval_us);
+
+  g_main_loop_unref (main_loop);
+  g_object_unref (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)
 )


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