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
This commit is contained in:
Jonas Ådahl 2020-05-23 21:20:54 +02:00
parent f9eb140e62
commit 847e89d31f
2 changed files with 64 additions and 0 deletions

View File

@ -419,6 +419,7 @@ clutter_frame_clock_dispatch (ClutterFrameClock *frame_clock,
break; break;
case CLUTTER_FRAME_RESULT_IDLE: case CLUTTER_FRAME_RESULT_IDLE:
frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE; frame_clock->state = CLUTTER_FRAME_CLOCK_STATE_IDLE;
maybe_reschedule_update (frame_clock);
break; break;
} }
break; break;

View File

@ -628,6 +628,68 @@ frame_clock_inhibit (void)
g_object_unref (test.frame_clock); 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_SUITE (
CLUTTER_TEST_UNIT ("/frame-clock/schedule-update", frame_clock_schedule_update) CLUTTER_TEST_UNIT ("/frame-clock/schedule-update", frame_clock_schedule_update)
CLUTTER_TEST_UNIT ("/frame-clock/immediate-present", frame_clock_immediate_present) 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/schedule-update-now", frame_clock_schedule_update_now)
CLUTTER_TEST_UNIT ("/frame-clock/before-frame", frame_clock_before_frame) 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/inhibit", frame_clock_inhibit)
CLUTTER_TEST_UNIT ("/frame-clock/reschedule-on-idle", frame_clock_reschedule_on_idle)
) )