surface-actor: Keep track of ignored damage

We ignore all damage while a surface is frozen and queue a full
update instead once it's thawed. While not super efficient, this
isn't overly bad for the intended case of catching up with any
updates that happened during a compositor effect. However when
extended frame sync is used, surfaces are also frozen while the
client is drawing a frame, in which case the current behavior is
pretty damaging (pun intended), as we end up redrawing the entire
window each frame. To address this, keep track of the actual damage
we ignore and apply it when the surface is thawed.

https://bugzilla.gnome.org/show_bug.cgi?id=767798
This commit is contained in:
Florian Müllner 2016-06-17 17:45:20 +02:00
parent 989ec7fc60
commit 53a9411255

View File

@ -25,7 +25,7 @@ struct _MetaSurfaceActorPrivate
cairo_region_t *input_region;
/* Freeze/thaw accounting */
guint needs_damage_all : 1;
cairo_region_t *pending_damage;
guint frozen : 1;
};
@ -261,9 +261,8 @@ meta_surface_actor_process_damage (MetaSurfaceActor *self,
* here on the off chance that this will stop the corresponding
* texture_from_pixmap from being update.
*
* needs_damage_all tracks that some unknown damage happened while the
* window was frozen so that when the window becomes unfrozen we can
* issue a full window update to cover any lost damage.
* pending_damage tracks any damage that happened while the window was
* frozen so that when can apply it when the window becomes unfrozen.
*
* It should be noted that this is an unreliable mechanism since it's
* quite likely that drivers will aim to provide a zero-copy
@ -271,7 +270,12 @@ meta_surface_actor_process_damage (MetaSurfaceActor *self,
* any drawing done to the window is always immediately reflected in the
* texture regardless of damage event handling.
*/
priv->needs_damage_all = TRUE;
cairo_rectangle_int_t rect = { .x = x, .y = y, .width = width, .height = height };
if (!priv->pending_damage)
priv->pending_damage = cairo_region_create_rectangle (&rect);
else
cairo_region_union_rectangle (priv->pending_damage, &rect);
return;
}
@ -332,16 +336,21 @@ meta_surface_actor_set_frozen (MetaSurfaceActor *self,
priv->frozen = frozen;
if (!frozen && priv->needs_damage_all)
if (!frozen && priv->pending_damage)
{
/* Since we ignore damage events while a window is frozen for certain effects
* we may need to issue an update_area() covering the whole pixmap if we
* don't know what real damage has happened. */
int i, n_rects = cairo_region_num_rectangles (priv->pending_damage);
cairo_rectangle_int_t rect;
meta_surface_actor_process_damage (self, 0, 0,
clutter_actor_get_width (CLUTTER_ACTOR (priv->texture)),
clutter_actor_get_height (CLUTTER_ACTOR (priv->texture)));
priv->needs_damage_all = FALSE;
/* Since we ignore damage events while a window is frozen for certain effects
* we need to apply the tracked damage now. */
for (i = 0; i < n_rects; i++)
{
cairo_region_get_rectangle (priv->pending_damage, i, &rect);
meta_surface_actor_process_damage (self, rect.x, rect.y,
rect.width, rect.height);
}
g_clear_pointer (&priv->pending_damage, cairo_region_destroy);
}
}