diff --git a/src/tests/clutter-test-utils.h b/src/tests/clutter-test-utils.h index 62e8e9fdc..9655fd113 100644 --- a/src/tests/clutter-test-utils.h +++ b/src/tests/clutter-test-utils.h @@ -168,6 +168,18 @@ gboolean clutter_test_check_color_at_point (ClutterActor const ClutterColor *color, ClutterColor *result); +static inline uint64_t +us (uint64_t us) +{ + return us; +} + +static inline uint64_t +ms2us (uint64_t ms) +{ + return us (ms * 1000); +} + G_END_DECLS #endif /* __CLUTTER_TEST_UTILS_H__ */ diff --git a/src/tests/clutter/conform/frame-clock-timeline.c b/src/tests/clutter/conform/frame-clock-timeline.c new file mode 100644 index 000000000..66ef030f2 --- /dev/null +++ b/src/tests/clutter/conform/frame-clock-timeline.c @@ -0,0 +1,113 @@ +#include "clutter-frame-clock.h" +#include "clutter/clutter.h" +#include "tests/clutter-test-utils.h" + +static const float refresh_rate = 60.0; + +static ClutterFrameResult +timeline_frame_clock_frame (ClutterFrameClock *frame_clock, + int64_t frame_count, + int64_t time_us, + gpointer user_data) +{ + clutter_frame_clock_notify_presented (frame_clock, g_get_monotonic_time ()); + clutter_frame_clock_schedule_update (frame_clock); + + return CLUTTER_FRAME_RESULT_PENDING_PRESENTED; +} + +static const ClutterFrameListenerIface timeline_frame_listener_iface = { + .frame = timeline_frame_clock_frame, +}; + +static void +on_marker_reached (ClutterTimeline *timeline, + const char *marker_name, + unsigned int frame_number, + gboolean *marker_reached) +{ + *marker_reached = TRUE; +} + +static void +on_timeline_new_frame (ClutterTimeline *timeline, + int time_ms, + int *frame_counter) +{ + (*frame_counter)++; +} + +static void +on_timeline_completed (ClutterTimeline *timeline, + GMainLoop *main_loop) +{ + g_main_loop_quit (main_loop); +} + +static void +frame_clock_timeline_basic (void) +{ + GMainLoop *main_loop; + ClutterFrameClock *frame_clock; + ClutterTimeline *timeline; + gboolean marker1_reached; + int frame_counter; + int64_t before_us; + int64_t after_us; + + main_loop = g_main_loop_new (NULL, FALSE); + frame_clock = clutter_frame_clock_new (refresh_rate, + &timeline_frame_listener_iface, + NULL); + g_object_add_weak_pointer (G_OBJECT (frame_clock), (gpointer *) &frame_clock); + + timeline = g_object_new (CLUTTER_TYPE_TIMELINE, + "duration", 1000, + "frame-clock", frame_clock, + NULL); + g_object_add_weak_pointer (G_OBJECT (timeline), (gpointer *) &timeline); + + clutter_timeline_add_marker_at_time (timeline, "marker1", 500); + + marker1_reached = FALSE; + frame_counter = 0; + + g_signal_connect (timeline, "marker-reached::marker1", + G_CALLBACK (on_marker_reached), + &marker1_reached); + g_signal_connect (timeline, "new-frame", + G_CALLBACK (on_timeline_new_frame), + &frame_counter); + g_signal_connect (timeline, "completed", + G_CALLBACK (on_timeline_completed), + main_loop); + + clutter_timeline_start (timeline); + + before_us = g_get_monotonic_time (); + + g_main_loop_run (main_loop); + + after_us = g_get_monotonic_time (); + + g_assert_cmpint (after_us - before_us, + >=, + ms2us (clutter_timeline_get_duration (timeline))); + + g_assert_true (marker1_reached); + + /* Just check that we got at least a few frames. Require too high and we'll be + * flaky. + */ + g_assert_cmpint (frame_counter, >, 20); + + g_main_loop_unref (main_loop); + g_object_unref (timeline); + g_assert_null (timeline); + g_object_unref (frame_clock); + g_assert_null (frame_clock); +} + +CLUTTER_TEST_SUITE ( + CLUTTER_TEST_UNIT ("/frame-clock/timeline/basic", frame_clock_timeline_basic) +) diff --git a/src/tests/clutter/conform/meson.build b/src/tests/clutter/conform/meson.build index 07b82ddfd..9758598b9 100644 --- a/src/tests/clutter/conform/meson.build +++ b/src/tests/clutter/conform/meson.build @@ -32,6 +32,7 @@ clutter_conform_tests_general_tests = [ 'binding-pool', 'color', 'frame-clock', + 'frame-clock-timeline', 'interval', 'script-parser', 'timeline',