From 847e89d31f103ebdca527eacbb78d590e60a4dbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonas=20=C3=85dahl?= Date: Sat, 23 May 2020 21:20:54 +0200 Subject: [PATCH] clutter/frame-clock: Handle reschedule then dispatch results in idle A frame clock dispatch doesn't necessarily result in a frame drawn, meaning we'll end up in the idle state. However, it may be the case that something still requires another frame, and will in that case have requested one to be scheduled. In order to not dead lock, try to reschedule directly if requested after dispatching, if we ended up in the idle state. https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1285 --- clutter/clutter/clutter-frame-clock.c | 1 + src/tests/clutter/conform/frame-clock.c | 63 +++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/clutter/clutter/clutter-frame-clock.c b/clutter/clutter/clutter-frame-clock.c index c325c63fe..1ea524aca 100644 --- a/clutter/clutter/clutter-frame-clock.c +++ b/clutter/clutter/clutter-frame-clock.c @@ -419,6 +419,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock, break; case CLUTTER_FRAME_RESULT_IDLE: frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; + maybe_reschedule_update (frame_clock); break; } break; diff --git a/src/tests/clutter/conform/frame-clock.c b/src/tests/clutter/conform/frame-clock.c index b865b132c..74bcc4228 100644 --- a/src/tests/clutter/conform/frame-clock.c +++ b/src/tests/clutter/conform/frame-clock.c @@ -628,6 +628,68 @@ frame_clock_inhibit (void) g_object_unref (test.frame_clock); } +typedef struct _RescheduleOnIdleFrameClockTest +{ + FrameClockTest base; +} RescheduleOnIdleFrameClockTest; + +static ClutterFrameResult +reschedule_on_idle_clock_frame (ClutterFrameClock *frame_clock, + int64_t frame_count, + int64_t time_us, + gpointer user_data) +{ + RescheduleOnIdleFrameClockTest *test = user_data; + GMainLoop *main_loop = test->base.main_loop; + + 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_schedule_update (frame_clock); + + return CLUTTER_FRAME_RESULT_IDLE; +} + +static const ClutterFrameListenerIface reschedule_on_idle_listener_iface = { + .frame = reschedule_on_idle_clock_frame, +}; + +static void +frame_clock_reschedule_on_idle (void) +{ + RescheduleOnIdleFrameClockTest test; + ClutterFrameClock *frame_clock; + FakeHwClock *fake_hw_clock; + GSource *source; + + test_frame_count = 10; + expected_frame_count = 0; + + test.base.main_loop = g_main_loop_new (NULL, FALSE); + frame_clock = clutter_frame_clock_new (refresh_rate, + &reschedule_on_idle_listener_iface, + &test); + fake_hw_clock = fake_hw_clock_new (frame_clock, NULL, NULL); + source = &fake_hw_clock->source; + g_source_attach (source, NULL); + test.base.fake_hw_clock = fake_hw_clock; + + clutter_frame_clock_schedule_update (frame_clock); + g_main_loop_run (test.base.main_loop); + + g_main_loop_unref (test.base.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) @@ -636,4 +698,5 @@ CLUTTER_TEST_SUITE ( 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) + CLUTTER_TEST_UNIT ("/frame-clock/reschedule-on-idle", frame_clock_reschedule_on_idle) )