[mutter] clutter/frame-clock: Handle immediate present feedback
- From: Georges Basile Stavracas Neto <gbsneto src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [mutter] clutter/frame-clock: Handle immediate present feedback
- Date: Thu, 2 Jul 2020 20:49:52 +0000 (UTC)
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]