diff --git a/src/compositor/meta-cullable.c b/src/compositor/meta-cullable.c index e306c56e2..8b60e36de 100644 --- a/src/compositor/meta-cullable.c +++ b/src/compositor/meta-cullable.c @@ -23,8 +23,10 @@ #include "config.h" +#include "clutter/clutter-mutter.h" #include "compositor/clutter-utils.h" #include "compositor/meta-cullable.h" +#include "compositor/region-utils.h" G_DEFINE_INTERFACE (MetaCullable, meta_cullable, CLUTTER_TYPE_ACTOR); @@ -44,6 +46,16 @@ has_active_effects (ClutterActor *actor) return FALSE; } +static cairo_region_t * +region_apply_transform_expand_maybe_ref (cairo_region_t *region, + graphene_matrix_t *transform) +{ + if (cairo_region_is_empty (region)) + return cairo_region_reference (region); + + return meta_region_apply_matrix_transform_expand (region, transform); +} + /** * SECTION:meta-cullable * @title: MetaCullable @@ -86,7 +98,6 @@ meta_cullable_cull_out_children (MetaCullable *cullable, clutter_actor_iter_init (&iter, actor); while (clutter_actor_iter_prev (&iter, &child)) { - float x, y; gboolean needs_culling; if (!META_IS_CULLABLE (child)) @@ -116,21 +127,60 @@ meta_cullable_cull_out_children (MetaCullable *cullable, if (needs_culling && has_active_effects (child)) needs_culling = FALSE; - if (needs_culling && !meta_cullable_is_untransformed (META_CULLABLE (child))) - needs_culling = FALSE; - if (needs_culling) { - clutter_actor_get_position (child, &x, &y); + cairo_region_t *actor_unobscured_region, *actor_clip_region; + cairo_region_t *reduced_unobscured_region, *reduced_clip_region; + graphene_matrix_t actor_transform, inverted_actor_transform; - /* Temporarily move to the coordinate system of the actor */ - cairo_region_translate (unobscured_region, - x, - y); - cairo_region_translate (clip_region, - x, - y); + clutter_actor_get_transform (child, &actor_transform); - meta_cullable_cull_out (META_CULLABLE (child), unobscured_region, clip_region); + if (graphene_matrix_is_identity (&actor_transform)) + { + /* No transformation needed, simply pass through to child */ + meta_cullable_cull_out (META_CULLABLE (child), + unobscured_region, + clip_region); + continue; + } - cairo_region_translate (unobscured_region, x, y); - cairo_region_translate (clip_region, x, y); + if (!graphene_matrix_inverse (&actor_transform, + &inverted_actor_transform) || + !graphene_matrix_is_2d (&actor_transform)) + { + meta_cullable_cull_out (META_CULLABLE (child), NULL, NULL); + continue; + } + + actor_unobscured_region = + region_apply_transform_expand_maybe_ref (unobscured_region, + &inverted_actor_transform); + actor_clip_region = + region_apply_transform_expand_maybe_ref (clip_region, + &inverted_actor_transform); + + g_assert (actor_unobscured_region && actor_clip_region); + + meta_cullable_cull_out (META_CULLABLE (child), + actor_unobscured_region, + actor_clip_region); + + reduced_unobscured_region = + region_apply_transform_expand_maybe_ref (actor_unobscured_region, + &actor_transform); + reduced_clip_region = + region_apply_transform_expand_maybe_ref (actor_clip_region, + &actor_transform); + + g_assert (reduced_unobscured_region && reduced_clip_region); + + cairo_region_intersect (unobscured_region, reduced_unobscured_region); + cairo_region_intersect (clip_region, reduced_clip_region); + + cairo_region_destroy (actor_unobscured_region); + cairo_region_destroy (actor_clip_region); + cairo_region_destroy (reduced_unobscured_region); + cairo_region_destroy (reduced_clip_region); } else { @@ -165,23 +215,9 @@ meta_cullable_reset_culling_children (MetaCullable *cullable) } } -static gboolean -meta_cullable_default_is_untransformed (MetaCullable *cullable) -{ - float width, height; - graphene_point3d_t verts[4]; - - clutter_actor_get_size (CLUTTER_ACTOR (cullable), &width, &height); - clutter_actor_get_abs_allocation_vertices (CLUTTER_ACTOR (cullable), verts); - - return meta_actor_vertices_are_untransformed (verts, width, height, - NULL); -} - static void meta_cullable_default_init (MetaCullableInterface *iface) { - iface->is_untransformed = meta_cullable_default_is_untransformed; } /** @@ -216,19 +252,6 @@ meta_cullable_cull_out (MetaCullable *cullable, META_CULLABLE_GET_IFACE (cullable)->cull_out (cullable, unobscured_region, clip_region); } -/** - * meta_cullable_is_untransformed: - * @cullable: The #MetaCullable - * - * Check if a cullable is "untransformed" - which actually means transformed by - * at most a integer-translation. - */ -gboolean -meta_cullable_is_untransformed (MetaCullable *cullable) -{ - return META_CULLABLE_GET_IFACE (cullable)->is_untransformed (cullable); -} - /** * meta_cullable_reset_culling: * @cullable: The #MetaCullable diff --git a/src/compositor/meta-cullable.h b/src/compositor/meta-cullable.h index 471681da3..4087bc44e 100644 --- a/src/compositor/meta-cullable.h +++ b/src/compositor/meta-cullable.h @@ -36,17 +36,15 @@ struct _MetaCullableInterface { GTypeInterface g_iface; - void (* cull_out) (MetaCullable *cullable, - cairo_region_t *unobscured_region, - cairo_region_t *clip_region); - gboolean (* is_untransformed) (MetaCullable *cullable); + void (* cull_out) (MetaCullable *cullable, + cairo_region_t *unobscured_region, + cairo_region_t *clip_region); void (* reset_culling) (MetaCullable *cullable); }; void meta_cullable_cull_out (MetaCullable *cullable, cairo_region_t *unobscured_region, cairo_region_t *clip_region); -gboolean meta_cullable_is_untransformed (MetaCullable *cullable); void meta_cullable_reset_culling (MetaCullable *cullable); /* Utility methods for implementations */ diff --git a/src/compositor/meta-surface-actor.c b/src/compositor/meta-surface-actor.c index 1bc58667a..e140261f4 100644 --- a/src/compositor/meta-surface-actor.c +++ b/src/compositor/meta-surface-actor.c @@ -77,43 +77,6 @@ effective_unobscured_region (MetaSurfaceActor *surface_actor) return priv->unobscured_region; } -static cairo_region_t* -get_scaled_region (MetaSurfaceActor *surface_actor, - cairo_region_t *region, - ScalePerspectiveType scale_perspective) -{ - MetaWindowActor *window_actor; - cairo_region_t *scaled_region = NULL; - int geometry_scale; - float x, y; - - window_actor = meta_window_actor_from_actor (CLUTTER_ACTOR (surface_actor)); - geometry_scale = meta_window_actor_get_geometry_scale (window_actor); - - clutter_actor_get_position (CLUTTER_ACTOR (surface_actor), &x, &y); - cairo_region_translate (region, x, y); - - switch (scale_perspective) - { - case IN_STAGE_PERSPECTIVE: - scaled_region = meta_region_scale_double (region, - geometry_scale, - META_ROUNDING_STRATEGY_GROW); - break; - case IN_ACTOR_PERSPECTIVE: - scaled_region = meta_region_scale_double (region, - 1.0 / geometry_scale, - META_ROUNDING_STRATEGY_GROW); - break; - } - - g_assert (scaled_region != NULL); - cairo_region_translate (region, -x, -y); - cairo_region_translate (scaled_region, -x, -y); - - return scaled_region; -} - static void set_unobscured_region (MetaSurfaceActor *surface_actor, cairo_region_t *unobscured_region) @@ -141,9 +104,7 @@ set_unobscured_region (MetaSurfaceActor *surface_actor, .height = height, }; - priv->unobscured_region = get_scaled_region (surface_actor, - unobscured_region, - IN_ACTOR_PERSPECTIVE); + priv->unobscured_region = cairo_region_copy (unobscured_region); cairo_region_intersect_rectangle (priv->unobscured_region, &bounds); } @@ -160,14 +121,12 @@ set_clip_region (MetaSurfaceActor *surface_actor, if (clip_region && !cairo_region_is_empty (clip_region)) { - cairo_region_t *region; + cairo_region_t *clip_region_copy; - region = get_scaled_region (surface_actor, - clip_region, - IN_ACTOR_PERSPECTIVE); - meta_shaped_texture_set_clip_region (stex, region); + clip_region_copy = cairo_region_copy (clip_region); + meta_shaped_texture_set_clip_region (stex, clip_region_copy); - cairo_region_destroy (region); + cairo_region_destroy (clip_region_copy); } else { @@ -293,47 +252,19 @@ meta_surface_actor_cull_out (MetaCullable *cullable, if (opacity == 0xff) { cairo_region_t *opaque_region; - cairo_region_t *scaled_opaque_region; opaque_region = meta_shaped_texture_get_opaque_region (priv->texture); if (!opaque_region) return; - scaled_opaque_region = get_scaled_region (surface_actor, - opaque_region, - IN_STAGE_PERSPECTIVE); - if (unobscured_region) - cairo_region_subtract (unobscured_region, scaled_opaque_region); + cairo_region_subtract (unobscured_region, opaque_region); if (clip_region) - cairo_region_subtract (clip_region, scaled_opaque_region); - - cairo_region_destroy (scaled_opaque_region); + cairo_region_subtract (clip_region, opaque_region); } } -static gboolean -meta_surface_actor_is_untransformed (MetaCullable *cullable) -{ - ClutterActor *actor = CLUTTER_ACTOR (cullable); - MetaWindowActor *window_actor; - float width, height; - graphene_point3d_t verts[4]; - int geometry_scale; - - clutter_actor_get_size (actor, &width, &height); - clutter_actor_get_abs_allocation_vertices (actor, verts); - - window_actor = meta_window_actor_from_actor (actor); - geometry_scale = meta_window_actor_get_geometry_scale (window_actor); - - return meta_actor_vertices_are_untransformed (verts, - width * geometry_scale, - height * geometry_scale, - NULL); -} - static void meta_surface_actor_reset_culling (MetaCullable *cullable) { @@ -346,7 +277,6 @@ static void cullable_iface_init (MetaCullableInterface *iface) { iface->cull_out = meta_surface_actor_cull_out; - iface->is_untransformed = meta_surface_actor_is_untransformed; iface->reset_culling = meta_surface_actor_reset_culling; } diff --git a/src/compositor/meta-window-actor-wayland.c b/src/compositor/meta-window-actor-wayland.c index a74a19aba..b465a793b 100644 --- a/src/compositor/meta-window-actor-wayland.c +++ b/src/compositor/meta-window-actor-wayland.c @@ -87,29 +87,6 @@ surface_container_cull_out (MetaCullable *cullable, meta_cullable_cull_out_children (cullable, unobscured_region, clip_region); } -static gboolean -surface_container_is_untransformed (MetaCullable *cullable) -{ - MetaSurfaceContainerActorWayland *surface_container = - META_SURFACE_CONTAINER_ACTOR_WAYLAND (cullable); - ClutterActor *actor = CLUTTER_ACTOR (cullable); - MetaWindowActor *window_actor; - float width, height; - graphene_point3d_t verts[4]; - int geometry_scale; - - clutter_actor_get_size (actor, &width, &height); - clutter_actor_get_abs_allocation_vertices (actor, verts); - - window_actor = surface_container->window_actor; - geometry_scale = meta_window_actor_get_geometry_scale (window_actor); - - return meta_actor_vertices_are_untransformed (verts, - width * geometry_scale, - height * geometry_scale, - NULL); -} - static void surface_container_reset_culling (MetaCullable *cullable) { @@ -120,7 +97,6 @@ static void surface_container_cullable_iface_init (MetaCullableInterface *iface) { iface->cull_out = surface_container_cull_out; - iface->is_untransformed = surface_container_is_untransformed; iface->reset_culling = surface_container_reset_culling; } diff --git a/src/compositor/meta-window-group.c b/src/compositor/meta-window-group.c index f5d8b9a62..2889bbc10 100644 --- a/src/compositor/meta-window-group.c +++ b/src/compositor/meta-window-group.c @@ -9,6 +9,7 @@ #include "compositor/meta-cullable.h" #include "compositor/meta-window-actor-private.h" #include "compositor/meta-window-group-private.h" +#include "compositor/region-utils.h" #include "core/display-private.h" #include "core/window-private.h" @@ -62,62 +63,63 @@ meta_window_group_paint (ClutterActor *actor, cairo_region_t *clip_region; cairo_region_t *unobscured_region; cairo_rectangle_int_t visible_rect; - int paint_x_origin, paint_y_origin; int screen_width, screen_height; + graphene_matrix_t stage_to_actor; redraw_clip = clutter_paint_context_get_redraw_clip (paint_context); if (!redraw_clip) - { - parent_actor_class->paint (actor, paint_context); - return; - } + goto fail; meta_display_get_size (window_group->display, &screen_width, &screen_height); /* Normally we expect an actor to be drawn at it's position on the screen. * However, if we're inside the paint of a ClutterClone, that won't be the - * case and we need to compensate. We look at the position of the window - * group under the current model-view matrix and the position of the actor. - * If they are both simply integer translations, then we can compensate - * easily, otherwise we give up. - * - * Possible cleanup: work entirely in paint space - we can compute the - * combination of the model-view matrix with the local matrix for each child - * actor and get a total transformation for that actor for how we are - * painting currently, and never worry about how actors are positioned - * on the stage. + * case and we need to compensate. */ if (clutter_actor_is_in_clone_paint (actor)) { CoglFramebuffer *fb; ClutterStageView *view; - MetaTransforms trans; + graphene_matrix_t eye_to_actor, actor_to_eye, stage_to_eye; fb = clutter_paint_context_get_framebuffer (paint_context); view = clutter_paint_context_get_stage_view (paint_context); + if (!view || - fb != clutter_stage_view_get_framebuffer (view) || - !meta_actor_painting_untransformed (fb, - screen_width, - screen_height, - screen_width, - screen_height, - &trans) || - !meta_cullable_is_untransformed (META_CULLABLE (actor))) + fb != clutter_stage_view_get_framebuffer (view)) { - parent_actor_class->paint (actor, paint_context); - return; + goto fail; } - paint_x_origin = trans.x_origin; - paint_y_origin = trans.y_origin; + cogl_framebuffer_get_modelview_matrix (fb, &actor_to_eye); + + /* We need to obtain the transformation matrix from eye coordinates + * to cloned actor coordinates to be able to deduce the transformation + * matrix from stage to cloned actor coordinates, which is needed to + * calculate the redraw clip for the current actor. + * If we cannot do this because the cloned actor modelview matrix is + * non-invertible, give up on culling. + */ + if (!graphene_matrix_inverse (&actor_to_eye, &eye_to_actor)) + goto fail; + + clutter_actor_get_transform (stage, &stage_to_eye); + graphene_matrix_multiply (&stage_to_eye, &eye_to_actor, + &stage_to_actor); } else { - paint_x_origin = 0; - paint_y_origin = 0; + graphene_matrix_t actor_to_stage; + + clutter_actor_get_relative_transformation_matrix (actor, stage, + &actor_to_stage); + if (!graphene_matrix_inverse (&actor_to_stage, &stage_to_actor)) + goto fail; } + if (!graphene_matrix_is_2d (&stage_to_actor)) + goto fail; + visible_rect.x = visible_rect.y = 0; visible_rect.width = clutter_actor_get_width (CLUTTER_ACTOR (stage)); visible_rect.height = clutter_actor_get_height (CLUTTER_ACTOR (stage)); @@ -129,9 +131,8 @@ meta_window_group_paint (ClutterActor *actor, * multihead setup with mismatched monitor sizes, we could intersect this * with an accurate union of the monitors to avoid painting shadows that are * visible only in the holes. */ - clip_region = cairo_region_copy (redraw_clip); - - cairo_region_translate (clip_region, -paint_x_origin, -paint_y_origin); + clip_region = meta_region_apply_matrix_transform_expand (redraw_clip, + &stage_to_actor); meta_cullable_cull_out (META_CULLABLE (window_group), unobscured_region, clip_region); @@ -141,6 +142,11 @@ meta_window_group_paint (ClutterActor *actor, parent_actor_class->paint (actor, paint_context); meta_cullable_reset_culling (META_CULLABLE (window_group)); + + return; + +fail: + parent_actor_class->paint (actor, paint_context); } /* Adapted from clutter_actor_update_default_paint_volume() */ diff --git a/src/compositor/region-utils.c b/src/compositor/region-utils.c index e00f123d3..892d59fc1 100644 --- a/src/compositor/region-utils.c +++ b/src/compositor/region-utils.c @@ -472,3 +472,36 @@ meta_region_to_cairo_path (cairo_region_t *region, cairo_rectangle (cr, rect.x, rect.y, rect.width, rect.height); } } + +cairo_region_t * +meta_region_apply_matrix_transform_expand (const cairo_region_t *region, + graphene_matrix_t *transform) +{ + int n_rects, i; + cairo_rectangle_int_t *rects; + cairo_region_t *transformed_region; + + if (graphene_matrix_is_identity (transform)) + return cairo_region_copy (region); + + n_rects = cairo_region_num_rectangles (region); + META_REGION_CREATE_RECTANGLE_ARRAY_SCOPED (n_rects, rects); + for (i = 0; i < n_rects; i++) + { + graphene_rect_t transformed_rect, rect; + cairo_rectangle_int_t int_rect; + + cairo_region_get_rectangle (region, i, &int_rect); + rect = meta_rectangle_to_graphene_rect (&int_rect); + + graphene_matrix_transform_bounds (transform, &rect, &transformed_rect); + + meta_rectangle_from_graphene_rect (&transformed_rect, + META_ROUNDING_STRATEGY_GROW, + &rects[i]); + } + + transformed_region = cairo_region_create_rectangles (rects, n_rects); + + return transformed_region; +} diff --git a/src/compositor/region-utils.h b/src/compositor/region-utils.h index a3b89f994..cf7315192 100644 --- a/src/compositor/region-utils.h +++ b/src/compositor/region-utils.h @@ -119,4 +119,8 @@ cairo_region_t * meta_region_crop_and_scale (cairo_region_t *region, void meta_region_to_cairo_path (cairo_region_t *region, cairo_t *cr); +cairo_region_t * +meta_region_apply_matrix_transform_expand (const cairo_region_t *region, + graphene_matrix_t *transform); + #endif /* __META_REGION_UTILS_H__ */