conform: Use a repaint function

Timeouts and idles are subject to the whims of the load of the machine
running the tests, as we found out with the new installed tests and
OSTree-based VM running the conformance test suite continuously.

We should be able to use a repaint function and a blocking loop that
either is terminated because we hit g_assert(), or because a flag gets
toggled once we know that the Stage has been at least painted once.

The currently enabled tests using clutter_stage_read_pixels() have been
updated to this approach.

https://bugzilla.gnome.org/show_bug.cgi?id=703476
This commit is contained in:
Emmanuele Bassi 2013-07-02 22:00:23 +01:00
parent e352047499
commit f1971844b9
3 changed files with 72 additions and 96 deletions

View File

@ -16,7 +16,6 @@ struct _TestState
gint in_validation; gint in_validation;
guint is_running : 1; guint is_running : 1;
guint success : 1;
}; };
static TestState * static TestState *
@ -169,38 +168,28 @@ validate_state (ClutterActor *stage,
clutter_actor_get_allocation_box (actor, &box); clutter_actor_get_allocation_box (actor, &box);
g_assert (check_color_at (stage, actor, color, box.x1 + 2, box.y1 + 2)); check_color_at (stage, actor, color, box.x1 + 2, box.y1 + 2);
g_assert (check_color_at (stage, actor, color, box.x2 - 2, box.y2 - 2)); check_color_at (stage, actor, color, box.x2 - 2, box.y2 - 2);
} }
test_state_pop_validation (state); test_state_pop_validation (state);
state->success = TRUE; state->is_running = FALSE;
clutter_main_quit ();
}
static gboolean
queue_redraw (gpointer data_)
{
TestState *state = data_;
clutter_actor_queue_redraw (state->stage);
return TRUE;
} }
static gboolean static gboolean
test_state_run (TestState *state) test_state_run (TestState *state)
{ {
state->is_running = TRUE;
g_signal_connect_after (state->stage, "paint", G_CALLBACK (validate_state), state); g_signal_connect_after (state->stage, "paint", G_CALLBACK (validate_state), state);
state->id = clutter_threads_add_idle (queue_redraw, state);
clutter_main (); while (state->is_running)
{
clutter_actor_queue_redraw (state->stage);
return state->success; g_main_context_iteration (NULL, FALSE);
}
return TRUE;
} }
void void

View File

@ -26,6 +26,7 @@ typedef struct
ClutterActor *container; ClutterActor *container;
ClutterActor *child; ClutterActor *child;
ClutterActor *unrelated_actor; ClutterActor *unrelated_actor;
gboolean was_painted;
} Data; } Data;
GType foo_actor_get_type (void) G_GNUC_CONST; GType foo_actor_get_type (void) G_GNUC_CONST;
@ -89,15 +90,15 @@ typedef struct _FooGroupClass FooGroupClass;
struct _FooGroupClass struct _FooGroupClass
{ {
ClutterGroupClass parent_class; ClutterActorClass parent_class;
}; };
struct _FooGroup struct _FooGroup
{ {
ClutterGroup parent; ClutterActor parent;
}; };
G_DEFINE_TYPE (FooGroup, foo_group, CLUTTER_TYPE_GROUP); G_DEFINE_TYPE (FooGroup, foo_group, CLUTTER_TYPE_ACTOR)
static gboolean static gboolean
foo_group_has_overlaps (ClutterActor *actor) foo_group_has_overlaps (ClutterActor *actor)
@ -175,7 +176,7 @@ verify_redraw (Data *data, int expected_paint_count)
} }
static gboolean static gboolean
timeout_cb (gpointer user_data) run_verify (gpointer user_data)
{ {
Data *data = user_data; Data *data = user_data;
@ -288,7 +289,7 @@ timeout_cb (gpointer user_data)
clutter_actor_set_position (data->unrelated_actor, 0, 1); clutter_actor_set_position (data->unrelated_actor, 0, 1);
verify_redraw (data, 0); verify_redraw (data, 0);
clutter_main_quit (); data->was_painted = TRUE;
return G_SOURCE_REMOVE; return G_SOURCE_REMOVE;
} }
@ -297,52 +298,43 @@ void
actor_offscreen_redirect (TestConformSimpleFixture *fixture, actor_offscreen_redirect (TestConformSimpleFixture *fixture,
gconstpointer test_data) gconstpointer test_data)
{ {
if (cogl_features_available (COGL_FEATURE_OFFSCREEN))
{
Data data; Data data;
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
{
if (g_test_verbose ())
g_print ("Offscreen buffers are not available, skipping test.\n");
return;
}
data.stage = clutter_stage_new (); data.stage = clutter_stage_new ();
data.parent_container = clutter_actor_new ();
data.parent_container = clutter_group_new ();
data.container = g_object_new (foo_group_get_type (), NULL); data.container = g_object_new (foo_group_get_type (), NULL);
data.foo_actor = g_object_new (foo_actor_get_type (), NULL); data.foo_actor = g_object_new (foo_actor_get_type (), NULL);
clutter_actor_set_size (CLUTTER_ACTOR (data.foo_actor), 100, 100); clutter_actor_set_size (CLUTTER_ACTOR (data.foo_actor), 100, 100);
clutter_container_add_actor (CLUTTER_CONTAINER (data.container), clutter_actor_add_child (data.container, CLUTTER_ACTOR (data.foo_actor));
CLUTTER_ACTOR (data.foo_actor)); clutter_actor_add_child (data.parent_container, data.container);
clutter_actor_add_child (data.stage, data.parent_container);
clutter_container_add_actor (CLUTTER_CONTAINER (data.parent_container), data.child = clutter_actor_new ();
data.container);
clutter_container_add_actor (CLUTTER_CONTAINER (data.stage),
data.parent_container);
data.child = clutter_rectangle_new ();
clutter_actor_set_size (data.child, 1, 1); clutter_actor_set_size (data.child, 1, 1);
clutter_container_add_actor (CLUTTER_CONTAINER (data.container), clutter_actor_add_child (data.container, data.child);
data.child);
data.unrelated_actor = clutter_rectangle_new (); data.unrelated_actor = clutter_actor_new ();
clutter_actor_set_size (data.child, 1, 1); clutter_actor_set_size (data.child, 1, 1);
clutter_container_add_actor (CLUTTER_CONTAINER (data.stage), clutter_actor_add_child (data.stage, data.unrelated_actor);
data.unrelated_actor);
clutter_actor_show (data.stage); clutter_actor_show (data.stage);
/* Start the test after a short delay to allow the stage to clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
render its initial frames without affecting the results */ run_verify,
g_timeout_add_full (G_PRIORITY_LOW, 250, timeout_cb, &data, NULL); &data,
NULL);
clutter_main (); while (!data.was_painted)
g_main_context_iteration (NULL, FALSE);
clutter_actor_destroy (data.stage); clutter_actor_destroy (data.stage);
if (g_test_verbose ())
g_print ("OK\n");
}
else if (g_test_verbose ())
g_print ("Skipping\n");
} }

View File

@ -24,6 +24,7 @@ typedef struct _TestState
{ {
ClutterActor *stage; ClutterActor *stage;
guint frame; guint frame;
gboolean was_painted;
} TestState; } TestState;
static ClutterActor * static ClutterActor *
@ -137,16 +138,12 @@ validate_result (TestState *state)
g_print ("Testing onscreen clone with path clip...\n"); g_print ("Testing onscreen clone with path clip...\n");
validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 1); validate_part (state, SOURCE_SIZE, ypos * SOURCE_SIZE, 1);
ypos++; ypos++;
/* Comment this out if you want visual feedback of what this test
* paints.
*/
clutter_main_quit ();
} }
static void static gboolean
on_paint (ClutterActor *actor, TestState *state) on_paint (gpointer data)
{ {
TestState *state = data;
int frame_num; int frame_num;
/* XXX: validate_result calls clutter_stage_read_pixels which will result in /* XXX: validate_result calls clutter_stage_read_pixels which will result in
@ -155,14 +152,10 @@ on_paint (ClutterActor *actor, TestState *state)
frame_num = state->frame++; frame_num = state->frame++;
if (frame_num == 1) if (frame_num == 1)
validate_result (state); validate_result (state);
}
static gboolean state->was_painted = TRUE;
queue_redraw (gpointer stage)
{
clutter_actor_queue_redraw (CLUTTER_ACTOR (stage));
return G_SOURCE_CONTINUE; return G_SOURCE_REMOVE;
} }
void void
@ -174,7 +167,12 @@ texture_fbo (TestConformSimpleFixture *fixture,
int ypos = 0; int ypos = 0;
if (!cogl_features_available (COGL_FEATURE_OFFSCREEN)) if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
{
if (g_test_verbose ())
g_print ("Offscreen buffers are not available, skipping.\n");
return; return;
}
state.frame = 0; state.frame = 0;
@ -224,18 +222,15 @@ texture_fbo (TestConformSimpleFixture *fixture,
clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL); clutter_container_add (CLUTTER_CONTAINER (state.stage), actor, NULL);
ypos++; ypos++;
/* We force continuous redrawing of the stage, since we need to skip clutter_actor_show (state.stage);
* the first few frames, and we wont be doing anything else that
* will trigger redrawing. */
clutter_threads_add_idle (queue_redraw, state.stage);
g_signal_connect_after (state.stage, "paint", G_CALLBACK (on_paint), &state);
clutter_actor_show_all (state.stage); clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
on_paint,
&state,
NULL);
clutter_main (); while (!state.was_painted)
g_main_context_iteration (NULL, FALSE);
clutter_actor_destroy (state.stage); clutter_actor_destroy (state.stage);
if (g_test_verbose ())
g_print ("OK\n");
} }