mirror of
https://github.com/brl/mutter.git
synced 2024-11-27 18:40:40 -05:00
372737e282
This fixes the interpolate test to not use the wall clock, but the monotonic clock. It also cleans up the timestamp granularity naming, so that the different granularity is clearer, as in the test, different timestamps have different granularity. Part-of: <https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/1751>
212 lines
5.9 KiB
C
212 lines
5.9 KiB
C
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
|
|
#include <stdlib.h>
|
|
#include <glib.h>
|
|
#include <clutter/clutter.h>
|
|
|
|
#include "tests/clutter-test-utils.h"
|
|
|
|
#define TEST_TIMELINE_DURATION 3000
|
|
|
|
/*
|
|
* Make the test tolarate being half a second off track in each direction,
|
|
* the thing we're testing for will still be tested for.
|
|
*/
|
|
#define TEST_ERROR_TOLERANCE 500
|
|
|
|
typedef struct _TestState
|
|
{
|
|
ClutterTimeline *timeline;
|
|
int64_t start_time_us;
|
|
int new_frame_counter;
|
|
int expected_frame;
|
|
int completion_count;
|
|
int cycle_frame_counter;
|
|
} TestState;
|
|
|
|
|
|
static void
|
|
new_frame_cb (ClutterTimeline *timeline,
|
|
int frame_num,
|
|
TestState *state)
|
|
{
|
|
int64_t current_time_us;
|
|
int current_frame_ms;
|
|
long msec_diff;
|
|
int loop_overflow = 0;
|
|
|
|
current_time_us = g_get_monotonic_time ();
|
|
current_frame_ms = clutter_timeline_get_elapsed_time (state->timeline);
|
|
msec_diff = us2ms (current_time_us - state->start_time_us);
|
|
|
|
/* If we expect to have interpolated past the end of the timeline
|
|
* we keep track of the overflow so we can determine when
|
|
* the next timeout will happen. We then clip expected_frames
|
|
* to TEST_TIMELINE_DURATION since clutter-timeline
|
|
* semantics guaranty this frame is always signaled before
|
|
* looping */
|
|
if (state->expected_frame > TEST_TIMELINE_DURATION)
|
|
{
|
|
loop_overflow = state->expected_frame - TEST_TIMELINE_DURATION;
|
|
state->expected_frame = TEST_TIMELINE_DURATION;
|
|
}
|
|
|
|
switch (state->cycle_frame_counter)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
if (current_frame_ms >= (state->expected_frame - TEST_ERROR_TOLERANCE) &&
|
|
current_frame_ms <= (state->expected_frame + TEST_ERROR_TOLERANCE))
|
|
{
|
|
g_test_message ("elapsed milliseconds=%-5li "
|
|
"expected frame=%-4i actual frame=%-4i (OK)",
|
|
msec_diff,
|
|
state->expected_frame,
|
|
current_frame_ms);
|
|
}
|
|
else
|
|
{
|
|
g_test_message ("elapsed milliseconds=%-5li "
|
|
"expected frame=%-4i actual frame=%-4i (FAILED)",
|
|
msec_diff,
|
|
state->expected_frame,
|
|
current_frame_ms);
|
|
g_test_fail ();
|
|
}
|
|
break;
|
|
case 2:
|
|
g_assert_cmpint (current_frame_ms, ==, TEST_TIMELINE_DURATION);
|
|
break;
|
|
default:
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
/* We already tested that we interpolated when looping, lets stop now. */
|
|
if (state->completion_count == 1 &&
|
|
state->cycle_frame_counter == 0)
|
|
{
|
|
clutter_timeline_stop (timeline);
|
|
return;
|
|
}
|
|
|
|
switch (state->cycle_frame_counter)
|
|
{
|
|
case 0:
|
|
{
|
|
/*
|
|
* First frame, sleep so we're about in the middle of the cycle,
|
|
* before the end of the timeline cycle.
|
|
*/
|
|
int delay_ms = ms (1500);
|
|
|
|
state->expected_frame = current_frame_ms + delay_ms;
|
|
g_test_message ("Sleeping for 1.5 seconds "
|
|
"so next frame should be (%d + %d) = %d",
|
|
current_frame_ms,
|
|
delay_ms,
|
|
state->expected_frame);
|
|
g_usleep (ms2us (delay_ms));
|
|
break;
|
|
}
|
|
case 1:
|
|
{
|
|
/*
|
|
* Second frame, we're about in the middle of the cycle; sleep one cycle,
|
|
* and check that we end up in the middle again.
|
|
*/
|
|
int delay_ms = TEST_TIMELINE_DURATION;
|
|
|
|
state->expected_frame = current_frame_ms + delay_ms;
|
|
g_test_message ("Sleeping for %d seconds "
|
|
"so next frame should be (%d + %d) = %d, "
|
|
"which is %d into the next cycle",
|
|
TEST_TIMELINE_DURATION / 1000,
|
|
current_frame_ms,
|
|
delay_ms,
|
|
state->expected_frame,
|
|
state->expected_frame - TEST_TIMELINE_DURATION);
|
|
g_usleep (ms2us (delay_ms));
|
|
|
|
g_assert_cmpint (state->expected_frame, >, TEST_TIMELINE_DURATION);
|
|
|
|
state->expected_frame += loop_overflow;
|
|
state->expected_frame -= TEST_TIMELINE_DURATION;
|
|
g_test_message ("End of timeline reached: "
|
|
"Wrapping expected frame too %d",
|
|
state->expected_frame);
|
|
break;
|
|
}
|
|
case 2:
|
|
case 3:
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
state->new_frame_counter++;
|
|
state->cycle_frame_counter++;
|
|
}
|
|
|
|
static void
|
|
completed_cb (ClutterTimeline *timeline,
|
|
TestState *state)
|
|
{
|
|
state->completion_count++;
|
|
state->cycle_frame_counter = 0;
|
|
|
|
if (state->completion_count >= 2)
|
|
g_assert_not_reached ();
|
|
}
|
|
|
|
static void
|
|
stopped_cb (ClutterTimeline *timeline,
|
|
gboolean is_finished,
|
|
TestState *state)
|
|
{
|
|
g_assert_cmpint (state->completion_count, ==, 1);
|
|
|
|
clutter_test_quit ();
|
|
}
|
|
|
|
static void
|
|
timeline_interpolation (void)
|
|
{
|
|
ClutterActor *stage;
|
|
TestState state;
|
|
|
|
stage = clutter_test_get_stage ();
|
|
|
|
state.timeline =
|
|
clutter_timeline_new_for_actor (stage, TEST_TIMELINE_DURATION);
|
|
clutter_timeline_set_repeat_count (state.timeline, -1);
|
|
g_signal_connect (state.timeline,
|
|
"new-frame",
|
|
G_CALLBACK (new_frame_cb),
|
|
&state);
|
|
g_signal_connect (state.timeline,
|
|
"completed",
|
|
G_CALLBACK (completed_cb),
|
|
&state);
|
|
g_signal_connect (state.timeline,
|
|
"stopped",
|
|
G_CALLBACK (stopped_cb),
|
|
&state);
|
|
|
|
state.completion_count = 0;
|
|
state.new_frame_counter = 0;
|
|
state.cycle_frame_counter = 0;
|
|
state.expected_frame = 0;
|
|
|
|
clutter_actor_show (stage);
|
|
|
|
state.start_time_us = g_get_monotonic_time ();
|
|
clutter_timeline_start (state.timeline);
|
|
|
|
clutter_test_main ();
|
|
|
|
g_object_unref (state.timeline);
|
|
}
|
|
|
|
CLUTTER_TEST_SUITE (
|
|
CLUTTER_TEST_UNIT ("/timeline/interpolate", timeline_interpolation)
|
|
)
|