From b35ad080ced79b39aa1c8d0264241463a4a58015 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20M=C3=BCllner?= Date: Fri, 28 Oct 2016 12:58:39 +0200 Subject: [PATCH] window-actor: Use different shape_regions/masks based on focus state We now update the frame mask and -shape on every focus change, which is expensive and wasteful if we recompute the same two regions over and over again. To address this, use different regions/masks based on the focus state, so that we'll be able to re-use a previously computed one if possible. https://bugzilla.gnome.org/show_bug.cgi?id=744667 --- src/compositor/meta-window-actor.c | 57 ++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 15 deletions(-) diff --git a/src/compositor/meta-window-actor.c b/src/compositor/meta-window-actor.c index c3df284ff..73d017ae0 100644 --- a/src/compositor/meta-window-actor.c +++ b/src/compositor/meta-window-actor.c @@ -67,8 +67,12 @@ struct _MetaWindowActorPrivate MetaShadow *focused_shadow; MetaShadow *unfocused_shadow; + CoglTexture *focused_mask; + CoglTexture *unfocused_mask; + /* A region that matches the shape of the window, including frame bounds */ - cairo_region_t *shape_region; + cairo_region_t *focused_shape_region; + cairo_region_t *unfocused_shape_region; /* The region we should clip to when painting the shadow */ cairo_region_t *shadow_clip; @@ -458,7 +462,8 @@ meta_window_actor_constructed (GObject *object) /* Start off with an empty shape region to maintain the invariant * that it's always set */ - priv->shape_region = cairo_region_create (); + priv->focused_shape_region = cairo_region_create (); + priv->unfocused_shape_region = cairo_region_create (); } static void @@ -479,9 +484,13 @@ meta_window_actor_dispose (GObject *object) priv->send_frame_messages_timer = 0; } - g_clear_pointer (&priv->shape_region, cairo_region_destroy); + g_clear_pointer (&priv->focused_shape_region, cairo_region_destroy); + g_clear_pointer (&priv->unfocused_shape_region, cairo_region_destroy); g_clear_pointer (&priv->shadow_clip, cairo_region_destroy); + g_clear_pointer (&priv->focused_mask, cogl_object_unref); + g_clear_pointer (&priv->unfocused_mask, cogl_object_unref); + g_clear_pointer (&priv->shadow_class, g_free); g_clear_pointer (&priv->focused_shadow, meta_shadow_unref); g_clear_pointer (&priv->unfocused_shadow, meta_shadow_unref); @@ -622,8 +631,10 @@ meta_window_actor_get_shape_bounds (MetaWindowActor *self, cairo_rectangle_int_t *bounds) { MetaWindowActorPrivate *priv = self->priv; - - cairo_region_get_extents (priv->shape_region, bounds); + gboolean appears_focused = meta_window_appears_focused (priv->window); + cairo_region_t *shape_region = appears_focused ? priv->focused_shape_region + : priv->unfocused_shape_region; + cairo_region_get_extents (shape_region, bounds); } static void @@ -1586,7 +1597,12 @@ check_needs_shadow (MetaWindowActor *self) if (*shadow_location == NULL && should_have_shadow) { if (priv->shadow_shape == NULL) - priv->shadow_shape = meta_window_shape_new (priv->shape_region); + { + cairo_region_t *shape_region; + shape_region = appears_focused ? priv->focused_shape_region + : priv->unfocused_shape_region; + priv->shadow_shape = meta_window_shape_new (shape_region); + } MetaShadowFactory *factory = meta_shadow_factory_get_default (); const char *shadow_class = meta_window_actor_get_shadow_class (self); @@ -1679,10 +1695,11 @@ build_and_scan_frame_mask (MetaWindowActor *self, guchar *mask_data; guint tex_width, tex_height; MetaShapedTexture *stex; - CoglTexture *paint_tex, *mask_texture; + CoglTexture *paint_tex, *mask_texture, **mask_ptr; int stride; cairo_t *cr; cairo_surface_t *surface; + gboolean appears_focused = meta_window_appears_focused (priv->window); stex = meta_surface_actor_get_texture (priv->surface); g_return_if_fail (stex); @@ -1763,8 +1780,10 @@ build_and_scan_frame_mask (MetaWindowActor *self, } meta_shaped_texture_set_mask_texture (stex, mask_texture); - if (mask_texture) - cogl_object_unref (mask_texture); + + mask_ptr = appears_focused ? &priv->focused_mask : &priv->unfocused_mask; + g_clear_pointer (mask_ptr, cogl_object_unref); + *mask_ptr = mask_texture; g_free (mask_data); } @@ -1773,8 +1792,12 @@ static void meta_window_actor_update_shape_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - cairo_region_t *region = NULL; + cairo_region_t *region = NULL, **shape_region; cairo_rectangle_int_t client_area; + gboolean appears_focused = meta_window_appears_focused (priv->window); + + shape_region = appears_focused ? &priv->focused_shape_region + : &priv->unfocused_shape_region; meta_window_get_client_area_rect (priv->window, &client_area); @@ -1798,8 +1821,8 @@ meta_window_actor_update_shape_region (MetaWindowActor *self) if ((priv->window->shape_region != NULL) || (priv->window->frame != NULL)) build_and_scan_frame_mask (self, &client_area, region); - g_clear_pointer (&priv->shape_region, cairo_region_destroy); - priv->shape_region = region; + g_clear_pointer (shape_region, cairo_region_destroy); + *shape_region = region; g_clear_pointer (&priv->shadow_shape, meta_window_shape_unref); @@ -1833,8 +1856,12 @@ static void meta_window_actor_update_opaque_region (MetaWindowActor *self) { MetaWindowActorPrivate *priv = self->priv; - cairo_region_t *opaque_region; + cairo_region_t *opaque_region, *shape_region; gboolean argb32 = is_argb32 (self); + gboolean appears_focused = meta_window_appears_focused (priv->window); + + shape_region = appears_focused ? priv->focused_shape_region + : priv->unfocused_shape_region; if (argb32 && priv->window->opaque_region != NULL) { @@ -1854,12 +1881,12 @@ meta_window_actor_update_opaque_region (MetaWindowActor *self) */ opaque_region = cairo_region_copy (priv->window->opaque_region); cairo_region_translate (opaque_region, client_area.x, client_area.y); - cairo_region_intersect (opaque_region, priv->shape_region); + cairo_region_intersect (opaque_region, shape_region); } else if (argb32) opaque_region = NULL; else - opaque_region = cairo_region_reference (priv->shape_region); + opaque_region = cairo_region_reference (shape_region); meta_surface_actor_set_opaque_region (priv->surface, opaque_region); cairo_region_destroy (opaque_region);