Blame tests/conform/actor-offscreen-redirect.c

Packit 31ecd5
#define CLUTTER_DISABLE_DEPRECATION_WARNINGS
Packit 31ecd5
#include <clutter/clutter.h>
Packit 31ecd5
Packit 31ecd5
typedef struct _FooActor      FooActor;
Packit 31ecd5
typedef struct _FooActorClass FooActorClass;
Packit 31ecd5
Packit 31ecd5
struct _FooActorClass
Packit 31ecd5
{
Packit 31ecd5
  ClutterActorClass parent_class;
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
struct _FooActor
Packit 31ecd5
{
Packit 31ecd5
  ClutterActor parent;
Packit 31ecd5
Packit 31ecd5
  guint8 last_paint_opacity;
Packit 31ecd5
  int paint_count;
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
typedef struct
Packit 31ecd5
{
Packit 31ecd5
  ClutterActor *stage;
Packit 31ecd5
  FooActor *foo_actor;
Packit 31ecd5
  ClutterActor *parent_container;
Packit 31ecd5
  ClutterActor *container;
Packit 31ecd5
  ClutterActor *child;
Packit 31ecd5
  ClutterActor *unrelated_actor;
Packit 31ecd5
  gboolean was_painted;
Packit 31ecd5
} Data;
Packit 31ecd5
Packit 31ecd5
GType foo_actor_get_type (void) G_GNUC_CONST;
Packit 31ecd5
Packit 31ecd5
G_DEFINE_TYPE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR);
Packit 31ecd5
Packit 31ecd5
static gboolean group_has_overlaps;
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
foo_actor_paint (ClutterActor *actor)
Packit 31ecd5
{
Packit 31ecd5
  FooActor *foo_actor = (FooActor *) actor;
Packit 31ecd5
  ClutterActorBox allocation;
Packit 31ecd5
Packit 31ecd5
  foo_actor->last_paint_opacity = clutter_actor_get_paint_opacity (actor);
Packit 31ecd5
  foo_actor->paint_count++;
Packit 31ecd5
Packit 31ecd5
  clutter_actor_get_allocation_box (actor, &allocation);
Packit 31ecd5
Packit 31ecd5
  /* Paint a red rectangle with the right opacity */
Packit 31ecd5
  cogl_set_source_color4ub (255,
Packit 31ecd5
                            0,
Packit 31ecd5
                            0,
Packit 31ecd5
                            foo_actor->last_paint_opacity);
Packit 31ecd5
  cogl_rectangle (allocation.x1,
Packit 31ecd5
                  allocation.y1,
Packit 31ecd5
                  allocation.x2,
Packit 31ecd5
                  allocation.y2);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
foo_actor_get_paint_volume (ClutterActor *actor,
Packit 31ecd5
                            ClutterPaintVolume *volume)
Packit 31ecd5
{
Packit 31ecd5
  return clutter_paint_volume_set_from_allocation (volume, actor);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
foo_actor_has_overlaps (ClutterActor *actor)
Packit 31ecd5
{
Packit 31ecd5
  return FALSE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
foo_actor_class_init (FooActorClass *klass)
Packit 31ecd5
{
Packit 31ecd5
  ClutterActorClass *actor_class = (ClutterActorClass *) klass;
Packit 31ecd5
Packit 31ecd5
  actor_class->paint = foo_actor_paint;
Packit 31ecd5
  actor_class->get_paint_volume = foo_actor_get_paint_volume;
Packit 31ecd5
  actor_class->has_overlaps = foo_actor_has_overlaps;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
foo_actor_init (FooActor *self)
Packit 31ecd5
{
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
typedef struct _FooGroup      FooGroup;
Packit 31ecd5
typedef struct _FooGroupClass FooGroupClass;
Packit 31ecd5
Packit 31ecd5
struct _FooGroupClass
Packit 31ecd5
{
Packit 31ecd5
  ClutterActorClass parent_class;
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
struct _FooGroup
Packit 31ecd5
{
Packit 31ecd5
  ClutterActor parent;
Packit 31ecd5
};
Packit 31ecd5
Packit 31ecd5
GType foo_group_get_type (void);
Packit 31ecd5
Packit 31ecd5
G_DEFINE_TYPE (FooGroup, foo_group, CLUTTER_TYPE_ACTOR)
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
foo_group_has_overlaps (ClutterActor *actor)
Packit 31ecd5
{
Packit 31ecd5
  return group_has_overlaps;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
foo_group_class_init (FooGroupClass *klass)
Packit 31ecd5
{
Packit 31ecd5
  ClutterActorClass *actor_class = (ClutterActorClass *) klass;
Packit 31ecd5
Packit 31ecd5
  actor_class->has_overlaps = foo_group_has_overlaps;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
foo_group_init (FooGroup *self)
Packit 31ecd5
{
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
verify_results (Data *data,
Packit 31ecd5
                guint8 expected_color_red,
Packit 31ecd5
                guint8 expected_color_green,
Packit 31ecd5
                guint8 expected_color_blue,
Packit 31ecd5
                int expected_paint_count,
Packit 31ecd5
                int expected_paint_opacity)
Packit 31ecd5
{
Packit 31ecd5
  guchar *pixel;
Packit 31ecd5
Packit 31ecd5
  data->foo_actor->paint_count = 0;
Packit 31ecd5
Packit 31ecd5
  /* Read a pixel at the center of the to determine what color it
Packit 31ecd5
     painted. This should cause a redraw */
Packit 31ecd5
  pixel = clutter_stage_read_pixels (CLUTTER_STAGE (data->stage),
Packit 31ecd5
                                     50, 50, /* x/y */
Packit 31ecd5
                                     1, 1 /* width/height */);
Packit 31ecd5
Packit 31ecd5
  g_assert_cmpint (expected_paint_count, ==, data->foo_actor->paint_count);
Packit 31ecd5
  g_assert_cmpint (expected_paint_opacity,
Packit 31ecd5
                   ==,
Packit 31ecd5
                   data->foo_actor->last_paint_opacity);
Packit 31ecd5
Packit 31ecd5
  g_assert_cmpint (ABS ((int) expected_color_red - (int) pixel[0]), <=, 2);
Packit 31ecd5
  g_assert_cmpint (ABS ((int) expected_color_green - (int) pixel[1]), <=, 2);
Packit 31ecd5
  g_assert_cmpint (ABS ((int) expected_color_blue - (int) pixel[2]), <=, 2);
Packit 31ecd5
Packit 31ecd5
  g_free (pixel);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
verify_redraw (Data *data, int expected_paint_count)
Packit 31ecd5
{
Packit 31ecd5
  GMainLoop *main_loop = g_main_loop_new (NULL, TRUE);
Packit 31ecd5
  guint paint_handler;
Packit 31ecd5
Packit 31ecd5
  paint_handler = g_signal_connect_data (data->stage,
Packit 31ecd5
                                         "paint",
Packit 31ecd5
                                         G_CALLBACK (g_main_loop_quit),
Packit 31ecd5
                                         main_loop,
Packit 31ecd5
                                         NULL,
Packit 31ecd5
                                         G_CONNECT_SWAPPED | G_CONNECT_AFTER);
Packit 31ecd5
Packit 31ecd5
  /* Queue a redraw on the stage */
Packit 31ecd5
  clutter_actor_queue_redraw (data->stage);
Packit 31ecd5
Packit 31ecd5
  data->foo_actor->paint_count = 0;
Packit 31ecd5
Packit 31ecd5
  /* Wait for it to paint */
Packit 31ecd5
  g_main_loop_run (main_loop);
Packit 31ecd5
Packit 31ecd5
  g_signal_handler_disconnect (data->stage, paint_handler);
Packit 31ecd5
Packit 31ecd5
  g_assert_cmpint (data->foo_actor->paint_count, ==, expected_paint_count);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static gboolean
Packit 31ecd5
run_verify (gpointer user_data)
Packit 31ecd5
{
Packit 31ecd5
  Data *data = user_data;
Packit 31ecd5
Packit 31ecd5
  group_has_overlaps = FALSE;
Packit 31ecd5
Packit 31ecd5
  /* By default the actor shouldn't be redirected so the redraw should
Packit 31ecd5
     cause the actor to be painted */
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 0, 0,
Packit 31ecd5
                  1,
Packit 31ecd5
                  255);
Packit 31ecd5
Packit 31ecd5
  /* Make the actor semi-transparent and verify the paint opacity */
Packit 31ecd5
  clutter_actor_set_opacity (data->container, 127);
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 127, 127,
Packit 31ecd5
                  1,
Packit 31ecd5
                  127);
Packit 31ecd5
Packit 31ecd5
  /* With automatic redirect for opacity it shouldn't redirect if
Packit 31ecd5
   * has_overlaps returns FALSE; */
Packit 31ecd5
  clutter_actor_set_offscreen_redirect
Packit 31ecd5
    (data->container, CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY);
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 127, 127,
Packit 31ecd5
                  1,
Packit 31ecd5
                  127);
Packit 31ecd5
Packit 31ecd5
  /* We do a double check here to verify that the actor wasn't cached
Packit 31ecd5
   * during the last check. If it was cached then this check wouldn't
Packit 31ecd5
   * result in any foo-actor re-paint. */
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 127, 127,
Packit 31ecd5
                  1,
Packit 31ecd5
                  127);
Packit 31ecd5
Packit 31ecd5
  /* With automatic redirect for opacity it should redirect if
Packit 31ecd5
   * has_overlaps returns TRUE.
Packit 31ecd5
   * The first paint will still cause the actor to draw because
Packit 31ecd5
   * it needs to fill the cache first. It should be painted with full
Packit 31ecd5
   * opacity */
Packit 31ecd5
  group_has_overlaps = TRUE;
Packit 31ecd5
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 127, 127,
Packit 31ecd5
                  1,
Packit 31ecd5
                  255);
Packit 31ecd5
Packit 31ecd5
  /* The second time the actor is painted it should be cached */
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 127, 127,
Packit 31ecd5
                  0,
Packit 31ecd5
                  255);
Packit 31ecd5
Packit 31ecd5
  /* We should be able to change the opacity without causing the actor
Packit 31ecd5
     to redraw */
Packit 31ecd5
  clutter_actor_set_opacity (data->container, 64);
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 191, 191,
Packit 31ecd5
                  0,
Packit 31ecd5
                  255);
Packit 31ecd5
Packit 31ecd5
  /* Changing it back to fully opaque should cause it not to go
Packit 31ecd5
     through the FBO so it will draw */
Packit 31ecd5
  clutter_actor_set_opacity (data->container, 255);
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 0, 0,
Packit 31ecd5
                  1,
Packit 31ecd5
                  255);
Packit 31ecd5
Packit 31ecd5
  /* Tell it to always redirect through the FBO. This should cause a
Packit 31ecd5
     paint of the actor because the last draw didn't go through the
Packit 31ecd5
     FBO */
Packit 31ecd5
  clutter_actor_set_offscreen_redirect (data->container,
Packit 31ecd5
                                        CLUTTER_OFFSCREEN_REDIRECT_ALWAYS);
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 0, 0,
Packit 31ecd5
                  1,
Packit 31ecd5
                  255);
Packit 31ecd5
Packit 31ecd5
  /* We should be able to change the opacity without causing the actor
Packit 31ecd5
     to redraw */
Packit 31ecd5
  clutter_actor_set_opacity (data->container, 64);
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 191, 191,
Packit 31ecd5
                  0,
Packit 31ecd5
                  255);
Packit 31ecd5
Packit 31ecd5
  /* Even changing it back to fully opaque shouldn't cause a redraw */
Packit 31ecd5
  clutter_actor_set_opacity (data->container, 255);
Packit 31ecd5
  verify_results (data,
Packit 31ecd5
                  255, 0, 0,
Packit 31ecd5
                  0,
Packit 31ecd5
                  255);
Packit 31ecd5
Packit 31ecd5
  /* Queueing a redraw on the actor should cause a redraw */
Packit 31ecd5
  clutter_actor_queue_redraw (data->container);
Packit 31ecd5
  verify_redraw (data, 1);
Packit 31ecd5
Packit 31ecd5
  /* Queueing a redraw on a child should cause a redraw */
Packit 31ecd5
  clutter_actor_queue_redraw (data->child);
Packit 31ecd5
  verify_redraw (data, 1);
Packit 31ecd5
Packit 31ecd5
  /* Modifying the transformation on the parent should cause a
Packit 31ecd5
     redraw */
Packit 31ecd5
  clutter_actor_set_anchor_point (data->parent_container, 0, 1);
Packit 31ecd5
  verify_redraw (data, 1);
Packit 31ecd5
Packit 31ecd5
  /* Redrawing an unrelated actor shouldn't cause a redraw */
Packit 31ecd5
  clutter_actor_set_position (data->unrelated_actor, 0, 1);
Packit 31ecd5
  verify_redraw (data, 0);
Packit 31ecd5
Packit 31ecd5
  data->was_painted = TRUE;
Packit 31ecd5
Packit 31ecd5
  return G_SOURCE_REMOVE;
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
static void
Packit 31ecd5
actor_offscreen_redirect (void)
Packit 31ecd5
{
Packit 31ecd5
  Data data;
Packit 31ecd5
Packit 31ecd5
  if (!cogl_features_available (COGL_FEATURE_OFFSCREEN))
Packit 31ecd5
    return;
Packit 31ecd5
Packit 31ecd5
  data.stage = clutter_test_get_stage ();
Packit 31ecd5
  data.parent_container = clutter_actor_new ();
Packit 31ecd5
  data.container = g_object_new (foo_group_get_type (), NULL);
Packit 31ecd5
  data.foo_actor = g_object_new (foo_actor_get_type (), NULL);
Packit 31ecd5
  clutter_actor_set_size (CLUTTER_ACTOR (data.foo_actor), 100, 100);
Packit 31ecd5
Packit 31ecd5
  clutter_actor_add_child (data.container, CLUTTER_ACTOR (data.foo_actor));
Packit 31ecd5
  clutter_actor_add_child (data.parent_container, data.container);
Packit 31ecd5
  clutter_actor_add_child (data.stage, data.parent_container);
Packit 31ecd5
Packit 31ecd5
  data.child = clutter_actor_new ();
Packit 31ecd5
  clutter_actor_set_size (data.child, 1, 1);
Packit 31ecd5
  clutter_actor_add_child (data.container, data.child);
Packit 31ecd5
Packit 31ecd5
  data.unrelated_actor = clutter_actor_new ();
Packit 31ecd5
  clutter_actor_set_size (data.child, 1, 1);
Packit 31ecd5
  clutter_actor_add_child (data.stage, data.unrelated_actor);
Packit 31ecd5
Packit 31ecd5
  clutter_actor_show (data.stage);
Packit 31ecd5
Packit 31ecd5
  clutter_threads_add_repaint_func_full (CLUTTER_REPAINT_FLAGS_POST_PAINT,
Packit 31ecd5
                                         run_verify,
Packit 31ecd5
                                         &data,
Packit 31ecd5
                                         NULL);
Packit 31ecd5
Packit 31ecd5
  while (!data.was_painted)
Packit 31ecd5
    g_main_context_iteration (NULL, FALSE);
Packit 31ecd5
}
Packit 31ecd5
Packit 31ecd5
CLUTTER_TEST_SUITE (
Packit 31ecd5
  CLUTTER_TEST_UNIT ("/actor/offscreen/redirect", actor_offscreen_redirect)
Packit 31ecd5
)