meta-shaped-texture: Don't queue redraws for obscured regions

When we get a damage event we update the window by calling
meta_shaped_texture_update_area which queues a redraw on the actor.
We can avoid that for obscured regions by comparing the damage area to
our visible area.

This patch causes _NET_WM_FRAME_DRAWN messages to be not sent in some cases
where they should be sent; they will be added back in a later commit.

https://bugzilla.gnome.org/show_bug.cgi?id=703332
This commit is contained in:
Adel Gadllah 2013-08-27 16:45:15 +02:00 committed by Jasper St. Pierre
parent 0089b5769c
commit f08921bd0c
5 changed files with 166 additions and 54 deletions

View File

@ -738,19 +738,38 @@ queue_damage_redraw_with_clip (MetaShapedTexture *stex,
clutter_actor_queue_redraw_with_clip (self, &clip); clutter_actor_queue_redraw_with_clip (self, &clip);
} }
void /**
* meta_shaped_texture_update_area:
* @stex: #MetaShapedTexture
* @x: the x coordinate of the damaged area
* @y: the y coordinate of the damaged area
* @width: the width of the damaged area
* @height: the height of the damaged area
* @unobscured_region: The unobscured region of the window or %NULL if
* there is no valid one (like when the actor is transformed or
* has a mapped clone)
*
* Repairs the damaged area indicated by @x, @y, @width and @height
* and queues a redraw for the intersection @visibible_region and
* the damage area. If @visibible_region is %NULL a redraw will always
* get queued.
*
* Return value: Whether a redraw have been queued or not
*/
gboolean
meta_shaped_texture_update_area (MetaShapedTexture *stex, meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x, int x,
int y, int y,
int width, int width,
int height) int height,
cairo_region_t *unobscured_region)
{ {
MetaShapedTexturePrivate *priv; MetaShapedTexturePrivate *priv;
priv = stex->priv; priv = stex->priv;
if (priv->texture == NULL) if (priv->texture == NULL)
return; return FALSE;
switch (priv->type) switch (priv->type)
{ {
@ -765,7 +784,34 @@ meta_shaped_texture_update_area (MetaShapedTexture *stex,
meta_texture_tower_update_area (priv->paint_tower, x, y, width, height); meta_texture_tower_update_area (priv->paint_tower, x, y, width, height);
queue_damage_redraw_with_clip (stex, x, y, width, height); if (unobscured_region)
{
cairo_region_t *intersection;
if (cairo_region_is_empty (unobscured_region))
return FALSE;
intersection = cairo_region_copy (unobscured_region);
cairo_region_intersect_rectangle (intersection, &clip);
if (!cairo_region_is_empty (intersection))
{
cairo_rectangle_int_t damage_rect;
cairo_region_get_extents (intersection, &damage_rect);
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &damage_rect);
cairo_region_destroy (intersection);
return TRUE;
}
cairo_region_destroy (intersection);
return FALSE;
}
clutter_actor_queue_redraw_with_clip (CLUTTER_ACTOR (stex), &clip);
return TRUE;
} }
/** /**

View File

@ -70,11 +70,14 @@ void meta_window_actor_queue_frame_drawn (MetaWindowActor *self,
cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self); cairo_region_t *meta_window_actor_get_obscured_region (MetaWindowActor *self);
void meta_window_actor_set_visible_region (MetaWindowActor *self, void meta_window_actor_set_clip_region (MetaWindowActor *self,
cairo_region_t *visible_region); cairo_region_t *clip_region);
void meta_window_actor_set_visible_region_beneath (MetaWindowActor *self, void meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region); cairo_region_t *beneath_region);
void meta_window_actor_reset_visible_regions (MetaWindowActor *self); void meta_window_actor_reset_clip_regions (MetaWindowActor *self);
void meta_window_actor_set_unobscured_region (MetaWindowActor *self,
cairo_region_t *unobscured_region);
void meta_window_actor_effect_completed (MetaWindowActor *actor, void meta_window_actor_effect_completed (MetaWindowActor *actor,
gulong event); gulong event);

View File

@ -77,6 +77,9 @@ struct _MetaWindowActorPrivate
/* The region we should clip to when painting the shadow */ /* The region we should clip to when painting the shadow */
cairo_region_t *shadow_clip; cairo_region_t *shadow_clip;
/* The region that is visible, used to optimize out redraws */
cairo_region_t *unobscured_region;
/* Extracted size-invariant shape used for shadows */ /* Extracted size-invariant shape used for shadows */
MetaWindowShape *shadow_shape; MetaWindowShape *shadow_shape;
@ -445,6 +448,7 @@ meta_window_actor_dispose (GObject *object)
meta_window_actor_detach_x11_pixmap (self); meta_window_actor_detach_x11_pixmap (self);
} }
g_clear_pointer (&priv->unobscured_region, cairo_region_destroy);
g_clear_pointer (&priv->shape_region, cairo_region_destroy); g_clear_pointer (&priv->shape_region, cairo_region_destroy);
g_clear_pointer (&priv->input_region, cairo_region_destroy); g_clear_pointer (&priv->input_region, cairo_region_destroy);
g_clear_pointer (&priv->opaque_region, cairo_region_destroy); g_clear_pointer (&priv->opaque_region, cairo_region_destroy);
@ -948,7 +952,8 @@ meta_window_actor_damage_all (MetaWindowActor *self)
meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor), meta_shaped_texture_update_area (META_SHAPED_TEXTURE (priv->actor),
0, 0, 0, 0,
cogl_texture_get_width (texture), cogl_texture_get_width (texture),
cogl_texture_get_height (texture)); cogl_texture_get_height (texture),
clutter_actor_has_mapped_clones (priv->actor) ? NULL : priv->unobscured_region);
priv->needs_damage_all = FALSE; priv->needs_damage_all = FALSE;
priv->repaint_scheduled = TRUE; priv->repaint_scheduled = TRUE;
@ -1734,39 +1739,66 @@ see_region (cairo_region_t *region,
#endif #endif
/** /**
* meta_window_actor_set_visible_region: * meta_window_actor_set_unobscured_region:
* @self: a #MetaWindowActor * @self: a #MetaWindowActor
* @visible_region: the region of the screen that isn't completely * @unobscured_region: the region of the screen that isn't completely
* obscured.
*
* Provides a hint as to what areas of the window need to queue
* redraws when damaged. Regions not in @unobscured_region are completely obscured.
* Unlike meta_window_actor_set_clip_region(), the region here
* doesn't take into account any clipping that is in effect while drawing.
*/
void
meta_window_actor_set_unobscured_region (MetaWindowActor *self,
cairo_region_t *unobscured_region)
{
MetaWindowActorPrivate *priv = self->priv;
if (priv->unobscured_region)
cairo_region_destroy (priv->unobscured_region);
if (unobscured_region)
priv->unobscured_region = cairo_region_copy (unobscured_region);
else
priv->unobscured_region = NULL;
}
/**
* meta_window_actor_set_clip_region:
* @self: a #MetaWindowActor
* @clip_region: the region of the screen that isn't completely
* obscured. * obscured.
* *
* Provides a hint as to what areas of the window need to be * Provides a hint as to what areas of the window need to be
* drawn. Regions not in @visible_region are completely obscured. * drawn. Regions not in @clip_region are completely obscured or
* not drawn in this frame.
* This will be set before painting then unset afterwards. * This will be set before painting then unset afterwards.
*/ */
void void
meta_window_actor_set_visible_region (MetaWindowActor *self, meta_window_actor_set_clip_region (MetaWindowActor *self,
cairo_region_t *visible_region) cairo_region_t *clip_region)
{ {
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor), meta_shaped_texture_set_clip_region (META_SHAPED_TEXTURE (priv->actor),
visible_region); clip_region);
} }
/** /**
* meta_window_actor_set_visible_region_beneath: * meta_window_actor_set_clip_region_beneath:
* @self: a #MetaWindowActor * @self: a #MetaWindowActor
* @visible_region: the region of the screen that isn't completely * @clip_region: the region of the screen that isn't completely
* obscured beneath the main window texture. * obscured beneath the main window texture.
* *
* Provides a hint as to what areas need to be drawn *beneath* * Provides a hint as to what areas need to be drawn *beneath*
* the main window texture. This is the relevant visible region * the main window texture. This is the relevant clip region
* when drawing the shadow, properly accounting for areas of the * when drawing the shadow, properly accounting for areas of the
* shadow hid by the window itself. This will be set before painting * shadow hid by the window itself. This will be set before painting
* then unset afterwards. * then unset afterwards.
*/ */
void void
meta_window_actor_set_visible_region_beneath (MetaWindowActor *self, meta_window_actor_set_clip_region_beneath (MetaWindowActor *self,
cairo_region_t *beneath_region) cairo_region_t *beneath_region)
{ {
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
@ -1786,14 +1818,14 @@ meta_window_actor_set_visible_region_beneath (MetaWindowActor *self,
} }
/** /**
* meta_window_actor_reset_visible_regions: * meta_window_actor_reset_clip_regions:
* @self: a #MetaWindowActor * @self: a #MetaWindowActor
* *
* Unsets the regions set by meta_window_actor_set_visible_region() and * Unsets the regions set by meta_window_actor_set_clip_region() and
* meta_window_actor_set_visible_region_beneath() * meta_window_actor_set_clip_region_beneath()
*/ */
void void
meta_window_actor_reset_visible_regions (MetaWindowActor *self) meta_window_actor_reset_clip_regions (MetaWindowActor *self)
{ {
MetaWindowActorPrivate *priv = self->priv; MetaWindowActorPrivate *priv = self->priv;
@ -2019,7 +2051,8 @@ meta_window_actor_process_x11_damage (MetaWindowActor *self,
event->area.x, event->area.x,
event->area.y, event->area.y,
event->area.width, event->area.width,
event->area.height); event->area.height,
clutter_actor_has_mapped_clones (priv->actor) ? NULL : priv->unobscured_region);
priv->repaint_scheduled = TRUE; priv->repaint_scheduled = TRUE;
} }

View File

@ -90,17 +90,30 @@ painting_untransformed (MetaWindowGroup *window_group,
static void static void
meta_window_group_paint (ClutterActor *actor) meta_window_group_paint (ClutterActor *actor)
{ {
cairo_region_t *visible_region; cairo_region_t *clip_region;
ClutterActor *stage; cairo_region_t *unobscured_region;
ClutterActorIter iter; ClutterActorIter iter;
ClutterActor *child; ClutterActor *child;
cairo_rectangle_int_t visible_rect; cairo_rectangle_int_t visible_rect, clip_rect;
int paint_x_origin, paint_y_origin; int paint_x_origin, paint_y_origin;
int actor_x_origin, actor_y_origin; int actor_x_origin, actor_y_origin;
int paint_x_offset, paint_y_offset; int paint_x_offset, paint_y_offset;
MetaWindowGroup *window_group = META_WINDOW_GROUP (actor); MetaWindowGroup *window_group = META_WINDOW_GROUP (actor);
MetaCompScreen *info; MetaCompScreen *info = meta_screen_get_compositor_data (window_group->screen);
ClutterActor *stage = clutter_actor_get_stage (actor);
/* Start off by treating all windows as completely unobscured, so damage anywhere
* in a window queues redraws, but confine it more below. */
clutter_actor_iter_init (&iter, actor);
while (clutter_actor_iter_next (&iter, &child))
{
if (META_IS_WINDOW_ACTOR (child))
{
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
meta_window_actor_set_unobscured_region (window_actor, NULL);
}
}
/* Normally we expect an actor to be drawn at it's position on the screen. /* 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 * However, if we're inside the paint of a ClutterClone, that won't be the
@ -125,17 +138,22 @@ meta_window_group_paint (ClutterActor *actor)
paint_x_offset = paint_x_origin - actor_x_origin; paint_x_offset = paint_x_origin - actor_x_origin;
paint_y_offset = paint_y_origin - actor_y_origin; paint_y_offset = paint_y_origin - actor_y_origin;
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));
unobscured_region = cairo_region_create_rectangle (&visible_rect);
/* Get the clipped redraw bounds from Clutter so that we can avoid /* Get the clipped redraw bounds from Clutter so that we can avoid
* painting shadows on windows that don't need to be painted in this * painting shadows on windows that don't need to be painted in this
* frame. In the case of a multihead setup with mismatched monitor * frame. In the case of a multihead setup with mismatched monitor
* sizes, we could intersect this with an accurate union of the * sizes, we could intersect this with an accurate union of the
* monitors to avoid painting shadows that are visible only in the * monitors to avoid painting shadows that are visible only in the
* holes. */ * holes. */
stage = clutter_actor_get_stage (actor);
clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage), clutter_stage_get_redraw_clip_bounds (CLUTTER_STAGE (stage),
&visible_rect); &clip_rect);
visible_region = cairo_region_create_rectangle (&visible_rect); clip_region = cairo_region_create_rectangle (&clip_rect);
if (!meta_is_wayland_compositor ()) if (!meta_is_wayland_compositor ())
{ {
@ -146,7 +164,8 @@ meta_window_group_paint (ClutterActor *actor)
MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window); MetaWindow *window = meta_window_actor_get_meta_window (info->unredirected_window);
meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect); meta_window_get_outer_rect (window, (MetaRectangle *)&unredirected_rect);
cairo_region_subtract_rectangle (visible_region, &unredirected_rect); cairo_region_subtract_rectangle (unobscured_region, &unredirected_rect);
cairo_region_subtract_rectangle (clip_region, &unredirected_rect);
} }
} }
@ -195,20 +214,28 @@ meta_window_group_paint (ClutterActor *actor)
x += paint_x_offset; x += paint_x_offset;
y += paint_y_offset; y += paint_y_offset;
/* Temporarily move to the coordinate system of the actor */
cairo_region_translate (visible_region, - x, - y);
meta_window_actor_set_visible_region (window_actor, visible_region); /* Temporarily move to the coordinate system of the actor */
cairo_region_translate (unobscured_region, - x, - y);
cairo_region_translate (clip_region, - x, - y);
meta_window_actor_set_unobscured_region (window_actor, unobscured_region);
meta_window_actor_set_clip_region (window_actor, clip_region);
if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff) if (clutter_actor_get_paint_opacity (CLUTTER_ACTOR (window_actor)) == 0xff)
{ {
cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor); cairo_region_t *obscured_region = meta_window_actor_get_obscured_region (window_actor);
if (obscured_region) if (obscured_region)
cairo_region_subtract (visible_region, obscured_region); {
cairo_region_subtract (unobscured_region, obscured_region);
cairo_region_subtract (clip_region, obscured_region);
}
} }
meta_window_actor_set_visible_region_beneath (window_actor, visible_region); meta_window_actor_set_clip_region_beneath (window_actor, clip_region);
cairo_region_translate (visible_region, x, y);
cairo_region_translate (unobscured_region, x, y);
cairo_region_translate (clip_region, x, y);
} }
else if (META_IS_BACKGROUND_ACTOR (child) || else if (META_IS_BACKGROUND_ACTOR (child) ||
META_IS_BACKGROUND_GROUP (child)) META_IS_BACKGROUND_GROUP (child))
@ -221,17 +248,19 @@ meta_window_group_paint (ClutterActor *actor)
x += paint_x_offset; x += paint_x_offset;
y += paint_y_offset; y += paint_y_offset;
cairo_region_translate (visible_region, - x, - y); cairo_region_translate (clip_region, - x, - y);
if (META_IS_BACKGROUND_GROUP (child)) if (META_IS_BACKGROUND_GROUP (child))
meta_background_group_set_visible_region (META_BACKGROUND_GROUP (child), visible_region); meta_background_group_set_clip_region (META_BACKGROUND_GROUP (child), clip_region);
else else
meta_background_actor_set_visible_region (META_BACKGROUND_ACTOR (child), visible_region); meta_background_actor_set_clip_region (META_BACKGROUND_ACTOR (child), clip_region);
cairo_region_translate (visible_region, x, y);
cairo_region_translate (clip_region, x, y);
} }
} }
cairo_region_destroy (visible_region); cairo_region_destroy (unobscured_region);
cairo_region_destroy (clip_region);
CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor); CLUTTER_ACTOR_CLASS (meta_window_group_parent_class)->paint (actor);
@ -244,7 +273,7 @@ meta_window_group_paint (ClutterActor *actor)
if (META_IS_WINDOW_ACTOR (child)) if (META_IS_WINDOW_ACTOR (child))
{ {
MetaWindowActor *window_actor = META_WINDOW_ACTOR (child); MetaWindowActor *window_actor = META_WINDOW_ACTOR (child);
meta_window_actor_reset_visible_regions (window_actor); meta_window_actor_reset_clip_regions (window_actor);
} }
else if (META_IS_BACKGROUND_ACTOR (child)) else if (META_IS_BACKGROUND_ACTOR (child))
{ {

View File

@ -67,11 +67,12 @@ GType meta_shaped_texture_get_type (void) G_GNUC_CONST;
void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex, void meta_shaped_texture_set_create_mipmaps (MetaShapedTexture *stex,
gboolean create_mipmaps); gboolean create_mipmaps);
void meta_shaped_texture_update_area (MetaShapedTexture *stex, gboolean meta_shaped_texture_update_area (MetaShapedTexture *stex,
int x, int x,
int y, int y,
int width, int width,
int height); int height,
cairo_region_t *unobscured_region);
CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex); CoglTexture * meta_shaped_texture_get_texture (MetaShapedTexture *stex);