From a132c8dc8e9aed838aa76b384a6cf814a6fb6051 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Wed, 25 Mar 2020 10:33:45 +0100 Subject: [PATCH] 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 eb1cff356..44da0c022 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 057ad411b..217cf771a 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 3d8b70a82..a7407e1b6 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) )