Apply subcompositor optimizations for Firefox Nightly

* subcompositor.c (struct _View): Fix comment.
(struct _Subcompositor): New field `additional_damage'.
(MakeSubcompositor): Initialize that field.
(SubcompositorUpdateBounds, SubcompositorUpdateBoundsForInsert):
Only garbage subcompositor if bounds really changed.
(SkipSlug): Move definition earlier.
(ViewUnionInferiorBounds, DamageIncludingInferiors): New
functions.
(SubcompositorInsert, SubcompositorInsertBefore)
(SubcompositorInsertAfter, ViewInsert, ViewInsertAfter)
(ViewInsertBefore, ViewUnparent, ViewAfterSizeUpdate)
(ViewAttachBuffer, ViewMove, ViewMoveFractional, ViewUnskip)
(ViewSetScale, ViewSetTransform, ViewSetViewport)
(ViewClearViewport, SubcompositorComposite, SubcompositorRedraw)
(SubcompositorFree): Handle damage in a more detailed fashion;
try to avoid garbaging upon subsurface movement, mapping, or
unmapping.
* wp_viewporter.c (SetSource, SetDestination): Don't set pending
if things didn't actually change.
This commit is contained in:
hujianwei 2022-10-29 11:15:40 +00:00
parent a05a62d9d0
commit 6f3941866a
2 changed files with 365 additions and 122 deletions

View file

@ -261,7 +261,8 @@ struct _View
/* Buffer data. */ /* Buffer data. */
#ifndef TEST #ifndef TEST
/* Width and height of the view. Not valid until ViewAfterSizeUpdate! */ /* Width and height of the view. Not valid until
ViewAfterSizeUpdate! */
int width, height; int width, height;
/* The buffer associated with this view, or None if nothing is /* The buffer associated with this view, or None if nothing is
@ -350,6 +351,9 @@ struct _Subcompositor
/* Buffers used to store that damage. */ /* Buffers used to store that damage. */
pixman_region32_t prior_damage[2]; pixman_region32_t prior_damage[2];
/* Any additional damage to be applied to the subcompositor. */
pixman_region32_t additional_damage;
/* The damage region of previous updates. last_damage is what the /* The damage region of previous updates. last_damage is what the
damage region was 1 update ago, and before_damage is what the damage region was 1 update ago, and before_damage is what the
damage region was 2 updates ago. */ damage region was 2 updates ago. */
@ -469,6 +473,9 @@ MakeSubcompositor (void)
pixman_region32_init (&subcompositor->prior_damage[0]); pixman_region32_init (&subcompositor->prior_damage[0]);
pixman_region32_init (&subcompositor->prior_damage[1]); pixman_region32_init (&subcompositor->prior_damage[1]);
/* And the buffer used to store additional damage. */
pixman_region32_init (&subcompositor->additional_damage);
return subcompositor; return subcompositor;
} }
@ -541,6 +548,7 @@ SubcompositorUpdateBounds (Subcompositor *subcompositor, int doflags)
{ {
List *list; List *list;
int min_x, min_y, max_x, max_y; int min_x, min_y, max_x, max_y;
int old_min_x, old_min_y, old_max_x, old_max_y;
/* Updates were optimized out. */ /* Updates were optimized out. */
if (!doflags) if (!doflags)
@ -548,6 +556,10 @@ SubcompositorUpdateBounds (Subcompositor *subcompositor, int doflags)
list = subcompositor->inferiors->next; list = subcompositor->inferiors->next;
min_x = max_x = min_y = max_y = 0; min_x = max_x = min_y = max_y = 0;
old_min_x = subcompositor->min_x;
old_min_y = subcompositor->min_y;
old_max_x = subcompositor->max_x;
old_max_y = subcompositor->max_y;
while (list != subcompositor->inferiors) while (list != subcompositor->inferiors)
{ {
@ -593,6 +605,10 @@ SubcompositorUpdateBounds (Subcompositor *subcompositor, int doflags)
if (doflags & DoMaxY) if (doflags & DoMaxY)
subcompositor->max_y = max_y; subcompositor->max_y = max_y;
if (subcompositor->min_x != old_min_x
|| subcompositor->min_y != old_min_y
|| subcompositor->max_x != old_max_x
|| subcompositor->max_y != old_max_y)
SetGarbaged (subcompositor); SetGarbaged (subcompositor);
} }
@ -609,16 +625,36 @@ SubcompositorUpdateBoundsForInsert (Subcompositor *subcompositor,
/* Inserting a view cannot shrink the subcompositor. */ /* Inserting a view cannot shrink the subcompositor. */
if (view->abs_x < subcompositor->min_x) if (view->abs_x < subcompositor->min_x)
{
subcompositor->min_x = view->abs_x; subcompositor->min_x = view->abs_x;
/* Garbage the subcompositor for this change. */
SetGarbaged (subcompositor);
}
if (view->abs_x < view->subcompositor->min_y) if (view->abs_x < view->subcompositor->min_y)
{
subcompositor->min_y = view->abs_y; subcompositor->min_y = view->abs_y;
/* Garbage the subcompositor for this change. */
SetGarbaged (subcompositor);
}
if (view->subcompositor->max_x < ViewMaxX (view)) if (view->subcompositor->max_x < ViewMaxX (view))
{
subcompositor->max_x = ViewMaxX (view); subcompositor->max_x = ViewMaxX (view);
/* Garbage the subcompositor for this change. */
SetGarbaged (subcompositor);
}
if (view->subcompositor->max_y < ViewMaxY (view)) if (view->subcompositor->max_y < ViewMaxY (view))
{
subcompositor->max_y = ViewMaxY (view); subcompositor->max_y = ViewMaxY (view);
/* Garbage the subcompositor for this change. */
SetGarbaged (subcompositor);
}
} }
#endif #endif
@ -644,6 +680,101 @@ SubcompositorSetTarget (Subcompositor *compositor,
#endif #endif
#define SkipSlug(list, view, next) \
{ \
if (!list->view) \
goto next; \
\
if (IsViewUnmapped (list->view)) \
{ \
/* Skip the unmapped view. */ \
list = list->view->inferior; \
SetPartiallyMapped (subcompositor); \
goto next; \
} \
\
if (IsSkipped (list->view)) \
{ \
/* We must skip this view, as it represents (for \
instance) a subsurface that has been added, but not \
committed. */ \
SetPartiallyMapped (subcompositor); \
goto next; \
} \
\
if (!list->view->buffer) \
goto next; \
\
view = list->view; \
} \
static void
ViewUnionInferiorBounds (View *parent, pixman_region32_t *region)
{
List *list;
View *view;
Subcompositor *subcompositor;
/* Return the bounds of each of VIEW's inferiors in REGION. */
list = parent->link;
subcompositor = parent->subcompositor;
while (True)
{
SkipSlug (list, view, next);
/* Union the view bounds with the given region. */
pixman_region32_union_rect (region, region, view->abs_x,
view->abs_y, view->width,
view->height);
next:
if (list == parent->inferior)
/* Break if we are at the end of the list. */
break;
list = list->next;
}
}
static void
DamageIncludingInferiors (View *parent)
{
List *list;
View *view;
Subcompositor *subcompositor;
if (parent->subcompositor)
/* No subcompositor is attached... */
return;
pixman_region32_union_rect (&parent->damage, &parent->damage,
0, 0, parent->width, parent->height);
/* Now, damage each inferior. */
list = parent->link;
subcompositor = parent->subcompositor;
while (True)
{
SkipSlug (list, view, next);
/* Union the view damage with its bounds. */
pixman_region32_union_rect (&view->damage, &view->damage,
view->abs_x, view->abs_y,
view->width, view->height);
next:
if (list == parent->inferior)
/* Break if we are at the end of the list. */
break;
list = list->next;
}
}
TEST_STATIC void TEST_STATIC void
SubcompositorInsert (Subcompositor *compositor, View *view) SubcompositorInsert (Subcompositor *compositor, View *view)
{ {
@ -654,13 +785,14 @@ SubcompositorInsert (Subcompositor *compositor, View *view)
ListRelinkBefore (view->link, view->inferior, ListRelinkBefore (view->link, view->inferior,
compositor->last); compositor->last);
/* Now that the view hierarchy has been changed, garbage the
subcompositor. */
SetGarbaged (compositor);
#ifndef TEST #ifndef TEST
/* And update bounds. */ /* And update bounds. */
SubcompositorUpdateBoundsForInsert (compositor, view); SubcompositorUpdateBoundsForInsert (compositor, view);
/* Now, if the subcompositor is still not garbaged, damage each
inferior of the view. */
if (!IsGarbaged (compositor))
DamageIncludingInferiors (view);
#endif #endif
} }
@ -675,13 +807,14 @@ SubcompositorInsertBefore (Subcompositor *compositor, View *view,
/* Make view's inferiors part of the compositor. */ /* Make view's inferiors part of the compositor. */
ListRelinkBefore (view->link, view->inferior, sibling->link); ListRelinkBefore (view->link, view->inferior, sibling->link);
/* Now that the view hierarchy has been changed, garbage the
subcompositor. */
SetGarbaged (compositor);
#ifndef TEST #ifndef TEST
/* And update bounds. */ /* And update bounds. */
SubcompositorUpdateBoundsForInsert (compositor, view); SubcompositorUpdateBoundsForInsert (compositor, view);
/* Now, if the subcompositor is still not garbaged, damage each
inferior of the view. */
if (!IsGarbaged (compositor))
DamageIncludingInferiors (view);
#endif #endif
} }
@ -695,13 +828,14 @@ SubcompositorInsertAfter (Subcompositor *compositor, View *view,
/* Make view's inferiors part of the compositor. */ /* Make view's inferiors part of the compositor. */
ListRelinkAfter (view->link, view->inferior, sibling->inferior); ListRelinkAfter (view->link, view->inferior, sibling->inferior);
/* Now that the view hierarchy has been changed, garbage the
subcompositor. */
SetGarbaged (compositor);
#ifndef TEST #ifndef TEST
/* And update bounds. */ /* And update bounds. */
SubcompositorUpdateBoundsForInsert (compositor, view); SubcompositorUpdateBoundsForInsert (compositor, view);
/* Now, if the subcompositor is still not garbaged, damage each
inferior of the view. */
if (!IsGarbaged (compositor))
DamageIncludingInferiors (view);
#endif #endif
} }
@ -852,9 +986,6 @@ ViewInsert (View *view, View *child)
/* Now that the view hierarchy has been changed, garbage the /* Now that the view hierarchy has been changed, garbage the
subcompositor. */ subcompositor. */
if (view->subcompositor)
SetGarbaged (view->subcompositor);
#ifndef TEST #ifndef TEST
/* Also update the absolute positions of the child. */ /* Also update the absolute positions of the child. */
child->abs_x = view->abs_x + child->x; child->abs_x = view->abs_x + child->x;
@ -863,6 +994,12 @@ ViewInsert (View *view, View *child)
/* And update bounds. */ /* And update bounds. */
ViewUpdateBoundsForInsert (view); ViewUpdateBoundsForInsert (view);
/* Now, if the subcompositor is still not garbaged, damage each
inferior of the view. */
if (view->subcompositor
&& !IsGarbaged (view->subcompositor))
DamageIncludingInferiors (view);
#endif #endif
} }
@ -901,12 +1038,6 @@ ViewInsertAfter (View *view, View *child, View *sibling)
} }
} }
/* Now that the view hierarchy has been changed, garbage the
subcompositor. */
if (view->subcompositor)
SetGarbaged (view->subcompositor);
#ifndef TEST #ifndef TEST
/* Also update the absolute positions of the child. */ /* Also update the absolute positions of the child. */
child->abs_x = view->abs_x + child->x; child->abs_x = view->abs_x + child->x;
@ -915,6 +1046,12 @@ ViewInsertAfter (View *view, View *child, View *sibling)
/* And update bounds. */ /* And update bounds. */
ViewUpdateBoundsForInsert (view); ViewUpdateBoundsForInsert (view);
/* Now, if the subcompositor is still not garbaged, damage each
inferior of the view. */
if (view->subcompositor
&& !IsGarbaged (view->subcompositor))
DamageIncludingInferiors (view);
#endif #endif
} }
@ -931,12 +1068,6 @@ ViewInsertBefore (View *view, View *child, View *sibling)
ListRelinkBefore (child->link, child->inferior, ListRelinkBefore (child->link, child->inferior,
sibling->link); sibling->link);
/* Now that the view hierarchy has been changed, garbage the
subcompositor. */
if (view->subcompositor)
SetGarbaged (view->subcompositor);
#ifndef TEST #ifndef TEST
/* Also update the absolute positions of the child. */ /* Also update the absolute positions of the child. */
child->abs_x = view->abs_x + child->x; child->abs_x = view->abs_x + child->x;
@ -946,6 +1077,12 @@ ViewInsertBefore (View *view, View *child, View *sibling)
/* Update subcompositor bounds. Inserting a view cannot shrink /* Update subcompositor bounds. Inserting a view cannot shrink
anything. */ anything. */
ViewUpdateBoundsForInsert (view); ViewUpdateBoundsForInsert (view);
/* Now, if the subcompositor is still not garbaged, damage each
inferior of the view. */
if (view->subcompositor
&& !IsGarbaged (view->subcompositor))
DamageIncludingInferiors (view);
#endif #endif
/* Inserting inferiors before a sibling can never bump the inferior /* Inserting inferiors before a sibling can never bump the inferior
@ -969,6 +1106,22 @@ TEST_STATIC void
ViewUnparent (View *child) ViewUnparent (View *child)
{ {
View *parent; View *parent;
Bool mapped, attached;
pixman_region32_t damage;
/* See if the view is attached or not. */
attached = (ViewVisibilityState (child, &mapped)
&& mapped);
if (attached)
{
/* Init the damage region. */
pixman_region32_init (&damage);
/* And store what additional damage should be applied for this
unparent. */
ViewUnionInferiorBounds (child, &damage);
}
/* Parent is either the subcompositor or another view. */ /* Parent is either the subcompositor or another view. */
ListUnlink (child->self, child->self); ListUnlink (child->self, child->self);
@ -1015,11 +1168,19 @@ ViewUnparent (View *child)
#ifndef TEST #ifndef TEST
/* Update the bounds of the subcompositor. */ /* Update the bounds of the subcompositor. */
SubcompositorUpdateBounds (child->subcompositor, DoAll); SubcompositorUpdateBounds (child->subcompositor, DoAll);
#endif
/* Then, garbage the subcompositor. */ /* If the subcompositor is not garbaged, then apply additional
SetGarbaged (child->subcompositor); damage. */
if (attached && !IsGarbaged (child->subcompositor))
pixman_region32_union (&child->subcompositor->additional_damage,
&child->subcompositor->additional_damage,
&damage);
#endif
} }
if (attached)
/* Finalize the damage region. */
pixman_region32_fini (&damage);
} }
TEST_STATIC void TEST_STATIC void
@ -1244,12 +1405,16 @@ main (int argc, char **argv)
static void static void
ViewAfterSizeUpdate (View *view) ViewAfterSizeUpdate (View *view)
{ {
int doflags; int doflags, old_width, old_height;
Bool mapped; Bool mapped;
if (view->maybe_resized) if (view->maybe_resized)
view->maybe_resized (view); view->maybe_resized (view);
/* These are used to decide how to damage the subcompositor. */
old_width = view->width;
old_height = view->height;
/* Calculate view->width and view->height again. */ /* Calculate view->width and view->height again. */
view->width = ViewWidth (view); view->width = ViewWidth (view);
view->height = ViewHeight (view); view->height = ViewHeight (view);
@ -1267,6 +1432,7 @@ ViewAfterSizeUpdate (View *view)
if (view->subcompositor->max_x < ViewMaxX (view)) if (view->subcompositor->max_x < ViewMaxX (view))
{ {
view->subcompositor->max_x = ViewMaxX (view); view->subcompositor->max_x = ViewMaxX (view);
SetGarbaged (view->subcompositor);
/* We don't have to update max_x anymore. */ /* We don't have to update max_x anymore. */
doflags &= ~DoMaxX; doflags &= ~DoMaxX;
@ -1275,6 +1441,7 @@ ViewAfterSizeUpdate (View *view)
if (view->subcompositor->max_y < ViewMaxY (view)) if (view->subcompositor->max_y < ViewMaxY (view))
{ {
view->subcompositor->max_y = ViewMaxY (view); view->subcompositor->max_y = ViewMaxY (view);
SetGarbaged (view->subcompositor);
/* We don't have to update max_x anymore. */ /* We don't have to update max_x anymore. */
doflags &= ~DoMaxY; doflags &= ~DoMaxY;
@ -1282,6 +1449,16 @@ ViewAfterSizeUpdate (View *view)
/* Finally, update the bounds. */ /* Finally, update the bounds. */
SubcompositorUpdateBounds (view->subcompositor, doflags); SubcompositorUpdateBounds (view->subcompositor, doflags);
/* If the subcompositor is not garbaged and the view shrunk, damage
the subcompositor accordingly. */
if (!IsGarbaged (view->subcompositor)
&& (view->width < old_width
|| view->height < old_height))
pixman_region32_union_rect (&view->subcompositor->additional_damage,
&view->subcompositor->additional_damage,
view->abs_x, view->abs_y, old_width,
old_height);
} }
void void
@ -1292,30 +1469,18 @@ ViewAttachBuffer (View *view, ExtBuffer *buffer)
old = view->buffer; old = view->buffer;
view->buffer = buffer; view->buffer = buffer;
if (!old != !buffer) if (!view->buffer && old && view->subcompositor)
{ /* The view needs a size update, as it is now 0 by 0. */
/* TODO: just damage intersecting views before view->link if the ViewAfterSizeUpdate (view);
buffer was removed. */ else if (((buffer && !old)
if (view->subcompositor)
SetGarbaged (view->subcompositor);
}
if (((buffer && !old)
|| (old && !buffer) || (old && !buffer)
|| (buffer && old || (buffer && old
&& (XLBufferWidth (buffer) != XLBufferWidth (old) && (XLBufferWidth (buffer) != XLBufferWidth (old)
|| XLBufferHeight (buffer) != XLBufferHeight (old)))) || XLBufferHeight (buffer) != XLBufferHeight (old))))
&& !IsViewported (view)) && !IsViewported (view))
{
/* Recompute view and subcompositor bounds. */ /* Recompute view and subcompositor bounds. */
ViewAfterSizeUpdate (view); ViewAfterSizeUpdate (view);
if (view->subcompositor)
/* A new buffer was attached, so garbage the subcompositor as
well. */
SetGarbaged (view->subcompositor);
}
if (buffer && IsViewUnmapped (view)) if (buffer && IsViewUnmapped (view))
{ {
/* A buffer is now attached. Automatically map the view, should /* A buffer is now attached. Automatically map the view, should
@ -1324,9 +1489,11 @@ ViewAttachBuffer (View *view, ExtBuffer *buffer)
if (view->subcompositor) if (view->subcompositor)
{ {
/* Garbage the subcompositor and recompute bounds. */ /* Recompute subcompositor bounds. */
SetGarbaged (view->subcompositor);
SubcompositorUpdateBounds (view->subcompositor, DoAll); SubcompositorUpdateBounds (view->subcompositor, DoAll);
/* Garbage the subcompositor. */
SetGarbaged (view->subcompositor);
} }
} }
@ -1340,6 +1507,7 @@ ViewAttachBuffer (View *view, ExtBuffer *buffer)
void void
ViewMove (View *view, int x, int y) ViewMove (View *view, int x, int y)
{ {
pixman_region32_t damage;
int doflags; int doflags;
Bool mapped; Bool mapped;
@ -1347,6 +1515,8 @@ ViewMove (View *view, int x, int y)
if (x != view->x || y != view->y) if (x != view->x || y != view->y)
{ {
pixman_region32_init (&damage);
view->x = x; view->x = x;
view->y = y; view->y = y;
@ -1380,6 +1550,10 @@ ViewMove (View *view, int x, int y)
/* min_x has already been updated so there is no need to /* min_x has already been updated so there is no need to
recompute it later. */ recompute it later. */
doflags &= ~DoMinX; doflags &= ~DoMinX;
/* Also garbage the subcompositor since the bounds
changed. */
SetGarbaged (view->subcompositor);
} }
if (view->abs_y < view->subcompositor->min_x) if (view->abs_y < view->subcompositor->min_x)
@ -1389,6 +1563,10 @@ ViewMove (View *view, int x, int y)
/* min_y has already been updated so there is no need to /* min_y has already been updated so there is no need to
recompute it later. */ recompute it later. */
doflags &= ~DoMinY; doflags &= ~DoMinY;
/* Also garbage the subcompositor since the bounds
changed. */
SetGarbaged (view->subcompositor);
} }
/* If moving this biew bumps subcompositor.max_x and/or /* If moving this biew bumps subcompositor.max_x and/or
@ -1402,6 +1580,10 @@ ViewMove (View *view, int x, int y)
recompute it later. If a child is bigger, then recompute it later. If a child is bigger, then
ViewRecomputeChildren will handle it as well. */ ViewRecomputeChildren will handle it as well. */
doflags &= ~DoMaxX; doflags &= ~DoMaxX;
/* Also garbage the subcompositor since the bounds
changed. */
SetGarbaged (view->subcompositor);
} }
if (view->subcompositor->max_y < ViewMaxX (view)) if (view->subcompositor->max_y < ViewMaxX (view))
@ -1412,22 +1594,45 @@ ViewMove (View *view, int x, int y)
recompute it later. If a child is bigger, then recompute it later. If a child is bigger, then
ViewRecomputeChildren will handle it as well. */ ViewRecomputeChildren will handle it as well. */
doflags &= ~DoMaxY; doflags &= ~DoMaxY;
}
/* Also garbage the subcompositor since those values /* Also garbage the subcompositor since the bounds
changed. TODO: just damage intersecting views before changed. */
view->link. */
SetGarbaged (view->subcompositor); SetGarbaged (view->subcompositor);
} }
}
/* If the subcompositor is not garbaged, then damage the union
of the previous view bounds and the current view bounds. */
if (view->subcompositor)
{
if (!IsGarbaged (view->subcompositor))
ViewUnionInferiorBounds (view, &damage);
/* Update the subcompositor bounds. */
SubcompositorUpdateBounds (view->subcompositor, doflags);
/* Now calculate the absolute position for this view and all of /* Now calculate the absolute position for this view and all of
its children. N.B. that this operation can also update its children. N.B. that this operation can also update
subcompositor.min_x or subcompositor.min_y. */ subcompositor.min_x or subcompositor.min_y. */
ViewRecomputeChildren (view, &doflags); ViewRecomputeChildren (view, &doflags);
/* Update subcompositor bounds. */ /* If the subcompositor is still not garbaged, union damage
if (view->subcompositor) the rest of the way and apply it. */
SubcompositorUpdateBounds (view->subcompositor, doflags); if (!IsGarbaged (view->subcompositor))
{
ViewUnionInferiorBounds (view, &damage);
pixman_region32_union (&view->subcompositor->additional_damage,
&view->subcompositor->additional_damage,
&damage);
}
}
else
/* Now calculate the absolute position for this view and all
of its children. */
ViewRecomputeChildren (view, &doflags);
pixman_region32_fini (&damage);
} }
} }
@ -1436,13 +1641,18 @@ ViewMoveFractional (View *view, double x, double y)
{ {
XLAssert (x < 1.0 && y < 1.0); XLAssert (x < 1.0 && y < 1.0);
if (view->fract_x == x || view->fract_y == y)
return;
/* This does not necessitate adjustments to the view size, but does /* This does not necessitate adjustments to the view size, but does
require that the subcompositor be garbaged. */ require that the view be redrawn. */
view->fract_x = x; view->fract_x = x;
view->fract_y = y; view->fract_y = y;
if (view->subcompositor) if (view->subcompositor)
SetGarbaged (view->subcompositor); /* Damage the entire view. */
pixman_region32_union_rect (&view->damage, &view->damage,
0, 0, view->width, view->height);
} }
void void
@ -1508,12 +1718,10 @@ ViewUnskip (View *view)
ClearSkipped (view); ClearSkipped (view);
if (view->subcompositor && view->buffer) if (view->subcompositor && view->buffer)
{ /* Damage the whole view bounds. */
/* Garbage the subcompositor and recompute bounds, if something pixman_region32_union_rect (&view->damage, &view->damage,
is attached to the view. */ view->abs_x, view->abs_y,
SetGarbaged (view->subcompositor); view->width, view->height);
SubcompositorUpdateBounds (view->subcompositor, DoAll);
}
} }
void void
@ -1791,6 +1999,11 @@ ViewSetScale (View *view, int scale)
/* Recompute subcompositor bounds; they could've changed. */ /* Recompute subcompositor bounds; they could've changed. */
ViewAfterSizeUpdate (view); ViewAfterSizeUpdate (view);
/* The scale of the view changed, so prior damage cannot be trusted
any longer. */
pixman_region32_union_rect (&view->damage, &view->damage,
0, 0, view->width, view->height);
} }
void void
@ -1808,6 +2021,11 @@ ViewSetTransform (View *view, BufferTransform transform)
!= RotatesDimensions (old_transform)) != RotatesDimensions (old_transform))
/* Subcompositor bounds may have changed. */ /* Subcompositor bounds may have changed. */
ViewAfterSizeUpdate (view); ViewAfterSizeUpdate (view);
/* The transform of the view changed, so prior damage cannot be
trusted any longer. */
pixman_region32_union_rect (&view->damage, &view->damage,
0, 0, view->width, view->height);
} }
void void
@ -1827,9 +2045,10 @@ ViewSetViewport (View *view, double src_x, double src_y,
/* Update min_x and min_y. */ /* Update min_x and min_y. */
ViewAfterSizeUpdate (view); ViewAfterSizeUpdate (view);
/* Garbage the subcompositor as damage can no longer be trusted. */ /* The transform of the view changed, so prior damage cannot be
if (view->subcompositor) trusted any longer. */
SubcompositorGarbage (view->subcompositor); pixman_region32_union_rect (&view->damage, &view->damage,
0, 0, view->width, view->height);
} }
void void
@ -1840,9 +2059,10 @@ ViewClearViewport (View *view)
/* Update min_x and min_y. */ /* Update min_x and min_y. */
ViewAfterSizeUpdate (view); ViewAfterSizeUpdate (view);
/* Garbage the subcompositor as damage can no longer be trusted. */ /* The transform of the view changed, so prior damage cannot be
if (view->subcompositor) trusted any longer. */
SubcompositorGarbage (view->subcompositor); pixman_region32_union_rect (&view->damage, &view->damage,
0, 0, view->width, view->height);
} }
static void static void
@ -2066,35 +2286,6 @@ RenderCompletedCallback (void *data)
subcompositor->note_frame_data); subcompositor->note_frame_data);
} }
#define SkipSlug(list, view, next) \
{ \
if (!list->view) \
goto next; \
\
if (IsViewUnmapped (list->view)) \
{ \
/* Skip the unmapped view. */ \
list = list->view->inferior; \
SetPartiallyMapped (subcompositor); \
goto next; \
} \
\
if (IsSkipped (list->view)) \
{ \
/* We must skip this view, as it represents (for \
instance) a subsurface that has been added, but not \
committed. */ \
SetPartiallyMapped (subcompositor); \
goto next; \
} \
\
if (!list->view->buffer) \
goto next; \
\
view = list->view; \
\
}
/* Update ancillary data upon commit. This includes the input and /* Update ancillary data upon commit. This includes the input and
opaque regions. */ opaque regions. */
@ -2741,6 +2932,20 @@ SubcompositorComposite (Subcompositor *subcompositor)
{ {
SkipSlug (list, view, next); SkipSlug (list, view, next);
/* Subtract the view's opaque region from the output damage
region. */
if (pixman_region32_not_empty (&view->opaque))
{
/* Avoid reporting damage that will be covered up by views
above. */
pixman_region32_intersect_rect (&temp, &view->opaque,
0, 0, view->width,
view->height);
pixman_region32_translate (&temp, view->abs_x, view->abs_y);
pixman_region32_subtract (&damage, &damage, &temp);
}
/* Add the view's damage region to the output damage region. */ /* Add the view's damage region to the output damage region. */
pixman_region32_intersect_rect (&temp, &view->damage, 0, 0, pixman_region32_intersect_rect (&temp, &view->damage, 0, 0,
view->width, view->height); view->width, view->height);
@ -2751,18 +2956,34 @@ SubcompositorComposite (Subcompositor *subcompositor)
list = list->next; list = list->next;
} }
/* Add damage caused by i.e. movement. */
pixman_region32_union (&damage, &damage,
&subcompositor->additional_damage);
/* If there is no damage, just return without drawing anything. */ /* If there is no damage, just return without drawing anything. */
if (!pixman_region32_not_empty (&damage)) if (!pixman_region32_not_empty (&damage))
{
pixman_region32_fini (&damage);
pixman_region32_fini (&temp);
return True; return True;
}
if (age == -1 || age > 2) if (age == -1 || age > 2)
{
/* The target is too old. */ /* The target is too old. */
pixman_region32_fini (&damage);
pixman_region32_fini (&temp);
return False; return False;
}
if ((age > 0 && !subcompositor->last_damage) if ((age > 0 && !subcompositor->last_damage)
|| (age > 1 && !subcompositor->before_damage)) || (age > 1 && !subcompositor->before_damage))
{
/* Damage required for incremental update is missing. */ /* Damage required for incremental update is missing. */
pixman_region32_fini (&damage);
pixman_region32_fini (&temp);
return False; return False;
}
/* Copy the damage so StorePreviousDamage gets the damage before it /* Copy the damage so StorePreviousDamage gets the damage before it
was unioned. */ was unioned. */
@ -2789,6 +3010,10 @@ SubcompositorComposite (Subcompositor *subcompositor)
pixman_region32_fini (&damage); pixman_region32_fini (&damage);
if (rc)
/* Clear any additional damage applied. */
pixman_region32_clear (&subcompositor->additional_damage);
return rc; return rc;
} }
@ -2804,6 +3029,9 @@ SubcompositorRedraw (Subcompositor *subcompositor)
SubcompositorHeight (subcompositor)); SubcompositorHeight (subcompositor));
SubcompositorComposite1 (subcompositor, &damage, False); SubcompositorComposite1 (subcompositor, &damage, False);
pixman_region32_fini (&damage); pixman_region32_fini (&damage);
/* Clear any additional damage applied. */
pixman_region32_clear (&subcompositor->additional_damage);
} }
static void static void
@ -2946,6 +3174,9 @@ SubcompositorFree (Subcompositor *subcompositor)
pixman_region32_fini (&subcompositor->prior_damage[0]); pixman_region32_fini (&subcompositor->prior_damage[0]);
pixman_region32_fini (&subcompositor->prior_damage[1]); pixman_region32_fini (&subcompositor->prior_damage[1]);
/* Finalize the region used to store additional damage. */
pixman_region32_fini (&subcompositor->additional_damage);
/* Remove the presentation key. */ /* Remove the presentation key. */
if (subcompositor->present_key) if (subcompositor->present_key)
RenderCancelPresentationCallback (subcompositor->present_key); RenderCancelPresentationCallback (subcompositor->present_key);

View file

@ -117,6 +117,13 @@ SetSource (struct wl_client *client, struct wl_resource *resource,
wl_resource_post_error (resource, WP_VIEWPORT_ERROR_BAD_VALUE, wl_resource_post_error (resource, WP_VIEWPORT_ERROR_BAD_VALUE,
"invalid source rectangle specified"); "invalid source rectangle specified");
if (ext->surface->current_state.src_x == src_x
&& ext->surface->current_state.src_y == src_y
&& ext->surface->current_state.src_width == src_width
&& ext->surface->current_state.src_height == src_height)
/* No change happened. */
return;
ext->surface->pending_state.pending |= PendingViewportSrc; ext->surface->pending_state.pending |= PendingViewportSrc;
ext->surface->pending_state.src_x = src_x; ext->surface->pending_state.src_x = src_x;
ext->surface->pending_state.src_y = src_y; ext->surface->pending_state.src_y = src_y;
@ -148,6 +155,11 @@ SetDestination (struct wl_client *client, struct wl_resource *resource,
return; return;
} }
if (ext->surface->current_state.dest_width == width
&& ext->surface->current_state.dest_height == height)
/* No change happened. */
return;
ext->surface->pending_state.pending |= PendingViewportDest; ext->surface->pending_state.pending |= PendingViewportDest;
ext->surface->pending_state.dest_width = width; ext->surface->pending_state.dest_width = width;
ext->surface->pending_state.dest_height = height; ext->surface->pending_state.dest_height = height;