diff --git a/clutter/clutter-actor.c b/clutter/clutter-actor.c index ed76d930a..90bf3d64c 100644 --- a/clutter/clutter-actor.c +++ b/clutter/clutter-actor.c @@ -2730,20 +2730,16 @@ needs_flatten_effect (ClutterActor *self) CLUTTER_DEBUG_DISABLE_OFFSCREEN_REDIRECT)) return FALSE; - switch (priv->offscreen_redirect) + if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_ALWAYS) + return TRUE; + else if (priv->offscreen_redirect & CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY) { - case CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY: - if (!clutter_actor_has_overlaps (self)) - return FALSE; - /* flow through */ - case CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY: - return clutter_actor_get_paint_opacity (self) < 255; - - case CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: - return TRUE; + if (clutter_actor_get_paint_opacity (self) < 255 && + clutter_actor_has_overlaps (self)) + return TRUE; } - g_assert_not_reached (); + return FALSE; } static void @@ -3823,11 +3819,9 @@ clutter_actor_real_get_paint_volume (ClutterActor *self, static gboolean clutter_actor_real_has_overlaps (ClutterActor *self) { - /* By default we'll assume that all actors need an offscreen - redirect to get the correct opacity. This effectively favours - accuracy over efficiency. Actors such as ClutterTexture that - would never need an offscreen redirect can override this to - return FALSE. */ + /* By default we'll assume that all actors need an offscreen redirect to get + * the correct opacity. Actors such as ClutterTexture that would never need + * an offscreen redirect can override this to return FALSE. */ return TRUE; } @@ -4225,18 +4219,21 @@ clutter_actor_class_init (ClutterActorClass *klass) /** * ClutterActor:offscreen-redirect: * - * Whether to flatten the actor into a single image. See + * Determines the conditions in which the actor will be redirected + * to an offscreen framebuffer while being painted. For example this + * can be used to cache an actor in a framebuffer or for improved + * handling of transparent actors. See * clutter_actor_set_offscreen_redirect() for details. * * Since: 1.8 */ - pspec = g_param_spec_enum ("offscreen-redirect", - P_("Offscreen redirect"), - P_("Whether to flatten the actor into a " - "single image"), - CLUTTER_TYPE_OFFSCREEN_REDIRECT, - CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY, - CLUTTER_PARAM_READWRITE); + pspec = g_param_spec_flags ("offscreen-redirect", + P_("Offscreen redirect"), + P_("Flags controlling when to flatten the " + "actor into a single image"), + CLUTTER_TYPE_OFFSCREEN_REDIRECT, + 0, + CLUTTER_PARAM_READWRITE); obj_props[PROP_OFFSCREEN_REDIRECT] = pspec; g_object_class_install_property (object_class, PROP_OFFSCREEN_REDIRECT, @@ -5288,7 +5285,6 @@ clutter_actor_init (ClutterActor *self) priv->parent_actor = NULL; priv->has_clip = FALSE; priv->opacity = 0xff; - priv->offscreen_redirect = CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY; priv->id = _clutter_context_acquire_id (self); priv->pick_id = -1; priv->scale_x = 1.0; @@ -7598,15 +7594,16 @@ clutter_actor_get_opacity (ClutterActor *self) /** * clutter_actor_set_offscreen_redirect: * @self: A #ClutterActor - * @redirect: New offscreen redirect value for the actor. + * @redirect: New offscreen redirect flags for the actor. * - * Sets whether to redirect the actor into an offscreen image. The - * offscreen image is used to flatten the actor into a single image - * while painting for two main reasons. Firstly, when the actor is - * painted a second time without any of its contents changing it can - * simply repaint the cached image without descending further down the - * actor hierarchy. Secondly, it will make the opacity look correct - * even if there are overlapping primitives in the actor. + * Defines the circumstances where the actor should be redirected into + * an offscreen image. The offscreen image is used to flatten the + * actor into a single image while painting for two main reasons. + * Firstly, when the actor is painted a second time without any of its + * contents changing it can simply repaint the cached image without + * descending further down the actor hierarchy. Secondly, it will make + * the opacity look correct even if there are overlapping primitives + * in the actor. * * Caching the actor could in some cases be a performance win and in * some cases be a performance lose so it is important to determine @@ -7643,13 +7640,15 @@ clutter_actor_get_opacity (ClutterActor *self) * * * - * The default behaviour is - * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY. This will end up - * redirecting actors whenever they are semi-transparent unless their - * has_overlaps() virtual returns %FALSE. This should mean that - * generally all actors will be rendered with the correct opacity and - * certain actors that don't need the offscreen redirect (such as - * #ClutterTexture) will paint directly for efficiency. + * The default value for this property is 0, so we effectively will + * never redirect an actor offscreen by default. This means that there + * are times that transparent actors may look glassy as described + * above. The reason this is the default is because there is a + * performance trade off between quality and performance here. In many + * cases the default form of glassy opacity looks good enough, but if + * it's not you will need to set the + * %CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY flag to enable + * redirection for opacity. * * Custom actors that don't contain any overlapping primitives are * recommended to override the has_overlaps() virtual to return %FALSE @@ -12408,8 +12407,9 @@ clutter_actor_get_paint_box (ClutterActor *self, * Asks the actor's implementation whether it may contain overlapping * primitives. * - * Clutter uses this to determine whether the painting should be redirected - * to an offscreen buffer to correctly implement the opacity property. + * For example; Clutter may use this to determine whether the painting + * should be redirected to an offscreen buffer to correctly implement + * the opacity property. * * Custom actors can override the default response by implementing the * #ClutterActor has_overlaps virtual function. See diff --git a/clutter/clutter-actor.h b/clutter/clutter-actor.h index bdeeda5b9..25f56238a 100644 --- a/clutter/clutter-actor.h +++ b/clutter/clutter-actor.h @@ -121,21 +121,17 @@ typedef enum * @CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY: Only redirect * the actor if it is semi-transparent and its has_overlaps() * virtual returns %TRUE. This is the default. - * @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY: Always redirect the - * actor if it is semi-transparent regardless of the return value of - * its has_overlaps() virtual. * @CLUTTER_OFFSCREEN_REDIRECT_ALWAYS: Always redirect the actor to an * offscreen buffer even if it is fully opaque. * - * Possible values to pass to clutter_actor_set_offscreen_redirect(). + * Possible flags to pass to clutter_actor_set_offscreen_redirect(). * * Since: 1.8 */ typedef enum { - CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY, - CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY, - CLUTTER_OFFSCREEN_REDIRECT_ALWAYS + CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY = 1<<0, + CLUTTER_OFFSCREEN_REDIRECT_ALWAYS = 1<<1 } ClutterOffscreenRedirect; /** diff --git a/tests/conform/test-offscreen-redirect.c b/tests/conform/test-offscreen-redirect.c index 3e25c9884..0952fa315 100644 --- a/tests/conform/test-offscreen-redirect.c +++ b/tests/conform/test-offscreen-redirect.c @@ -32,6 +32,8 @@ GType foo_actor_get_type (void) G_GNUC_CONST; G_DEFINE_TYPE (FooActor, foo_actor, CLUTTER_TYPE_ACTOR); +static gboolean group_has_overlaps; + static void foo_actor_paint (ClutterActor *actor) { @@ -100,7 +102,7 @@ G_DEFINE_TYPE (FooGroup, foo_group, CLUTTER_TYPE_GROUP); static gboolean foo_group_has_overlaps (ClutterActor *actor) { - return FALSE; + return group_has_overlaps; } static void @@ -177,6 +179,8 @@ timeout_cb (gpointer user_data) { Data *data = user_data; + group_has_overlaps = FALSE; + /* By default the actor shouldn't be redirected so the redraw should cause the actor to be painted */ verify_results (data, @@ -191,12 +195,30 @@ timeout_cb (gpointer user_data) 1, 127); - /* Enable offscreen for opacity so it should now paint through the - fbo. The first paint will still cause the actor to draw because - it needs to fill the cache first. It should be painted with full - opacity */ + /* With automatic redirect for opacity it shouldn't redirect if + * has_overlaps returns FALSE; */ clutter_actor_set_offscreen_redirect - (data->container, CLUTTER_OFFSCREEN_REDIRECT_ALWAYS_FOR_OPACITY); + (data->container, CLUTTER_OFFSCREEN_REDIRECT_AUTOMATIC_FOR_OPACITY); + verify_results (data, + 255, 127, 127, + 1, + 127); + + /* We do a double check here to verify that the actor wasn't cached + * during the last check. If it was cached then this check wouldn't + * result in any foo-actor re-paint. */ + verify_results (data, + 255, 127, 127, + 1, + 127); + + /* With automatic redirect for opacity it should redirect if + * has_overlaps returns TRUE. + * The first paint will still cause the actor to draw because + * it needs to fill the cache first. It should be painted with full + * opacity */ + group_has_overlaps = TRUE; + verify_results (data, 255, 127, 127, 1,