Home | History | Annotate | Download | only in trees
      1 // Copyright 2011 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "cc/trees/damage_tracker.h"
      6 
      7 #include <algorithm>
      8 
      9 #include "cc/base/math_util.h"
     10 #include "cc/layers/heads_up_display_layer_impl.h"
     11 #include "cc/layers/layer_impl.h"
     12 #include "cc/layers/render_surface_impl.h"
     13 #include "cc/output/filter_operations.h"
     14 #include "cc/trees/layer_tree_host_common.h"
     15 #include "cc/trees/layer_tree_impl.h"
     16 
     17 namespace cc {
     18 
     19 scoped_ptr<DamageTracker> DamageTracker::Create() {
     20   return make_scoped_ptr(new DamageTracker());
     21 }
     22 
     23 DamageTracker::DamageTracker()
     24     : current_rect_history_(new RectMap),
     25       next_rect_history_(new RectMap) {}
     26 
     27 DamageTracker::~DamageTracker() {}
     28 
     29 static inline void ExpandRectWithFilters(
     30     gfx::RectF* rect, const FilterOperations& filters) {
     31   int top, right, bottom, left;
     32   filters.GetOutsets(&top, &right, &bottom, &left);
     33   rect->Inset(-left, -top, -right, -bottom);
     34 }
     35 
     36 static inline void ExpandDamageRectInsideRectWithFilters(
     37     gfx::RectF* damage_rect,
     38     const gfx::RectF& pre_filter_rect,
     39     const FilterOperations& filters) {
     40   gfx::RectF expanded_damage_rect = *damage_rect;
     41   ExpandRectWithFilters(&expanded_damage_rect, filters);
     42   gfx::RectF filter_rect = pre_filter_rect;
     43   ExpandRectWithFilters(&filter_rect, filters);
     44 
     45   expanded_damage_rect.Intersect(filter_rect);
     46   damage_rect->Union(expanded_damage_rect);
     47 }
     48 
     49 void DamageTracker::UpdateDamageTrackingState(
     50     const LayerImplList& layer_list,
     51     int target_surface_layer_id,
     52     bool target_surface_property_changed_only_from_descendant,
     53     gfx::Rect target_surface_content_rect,
     54     LayerImpl* target_surface_mask_layer,
     55     const FilterOperations& filters,
     56     SkImageFilter* filter) {
     57   //
     58   // This function computes the "damage rect" of a target surface, and updates
     59   // the state that is used to correctly track damage across frames. The damage
     60   // rect is the region of the surface that may have changed and needs to be
     61   // redrawn. This can be used to scissor what is actually drawn, to save GPU
     62   // computation and bandwidth.
     63   //
     64   // The surface's damage rect is computed as the union of all possible changes
     65   // that have happened to the surface since the last frame was drawn. This
     66   // includes:
     67   //   - any changes for existing layers/surfaces that contribute to the target
     68   //     surface
     69   //   - layers/surfaces that existed in the previous frame, but no longer exist
     70   //
     71   // The basic algorithm for computing the damage region is as follows:
     72   //
     73   //   1. compute damage caused by changes in active/new layers
     74   //       for each layer in the layer_list:
     75   //           if the layer is actually a render_surface:
     76   //               add the surface's damage to our target surface.
     77   //           else
     78   //               add the layer's damage to the target surface.
     79   //
     80   //   2. compute damage caused by the target surface's mask, if it exists.
     81   //
     82   //   3. compute damage caused by old layers/surfaces that no longer exist
     83   //       for each leftover layer:
     84   //           add the old layer/surface bounds to the target surface damage.
     85   //
     86   //   4. combine all partial damage rects to get the full damage rect.
     87   //
     88   // Additional important points:
     89   //
     90   // - This algorithm is implicitly recursive; it assumes that descendant
     91   //   surfaces have already computed their damage.
     92   //
     93   // - Changes to layers/surfaces indicate "damage" to the target surface; If a
     94   //   layer is not changed, it does NOT mean that the layer can skip drawing.
     95   //   All layers that overlap the damaged region still need to be drawn. For
     96   //   example, if a layer changed its opacity, then layers underneath must be
     97   //   re-drawn as well, even if they did not change.
     98   //
     99   // - If a layer/surface property changed, the old bounds and new bounds may
    100   //   overlap... i.e. some of the exposed region may not actually be exposing
    101   //   anything. But this does not artificially inflate the damage rect. If the
    102   //   layer changed, its entire old bounds would always need to be redrawn,
    103   //   regardless of how much it overlaps with the layer's new bounds, which
    104   //   also need to be entirely redrawn.
    105   //
    106   // - See comments in the rest of the code to see what exactly is considered a
    107   //   "change" in a layer/surface.
    108   //
    109   // - To correctly manage exposed rects, two RectMaps are maintained:
    110   //
    111   //      1. The "current" map contains all the layer bounds that contributed to
    112   //         the previous frame (even outside the previous damaged area). If a
    113   //         layer changes or does not exist anymore, those regions are then
    114   //         exposed and damage the target surface. As the algorithm progresses,
    115   //         entries are removed from the map until it has only leftover layers
    116   //         that no longer exist.
    117   //
    118   //      2. The "next" map starts out empty, and as the algorithm progresses,
    119   //         every layer/surface that contributes to the surface is added to the
    120   //         map.
    121   //
    122   //      3. After the damage rect is computed, the two maps are swapped, so
    123   //         that the damage tracker is ready for the next frame.
    124   //
    125 
    126   // These functions cannot be bypassed with early-exits, even if we know what
    127   // the damage will be for this frame, because we need to update the damage
    128   // tracker state to correctly track the next frame.
    129   gfx::RectF damage_from_active_layers =
    130       TrackDamageFromActiveLayers(layer_list, target_surface_layer_id);
    131   gfx::RectF damage_from_surface_mask =
    132       TrackDamageFromSurfaceMask(target_surface_mask_layer);
    133   gfx::RectF damage_from_leftover_rects = TrackDamageFromLeftoverRects();
    134 
    135   gfx::RectF damage_rect_for_this_update;
    136 
    137   if (target_surface_property_changed_only_from_descendant) {
    138     damage_rect_for_this_update = target_surface_content_rect;
    139   } else {
    140     // TODO(shawnsingh): can we clamp this damage to the surface's content rect?
    141     // (affects performance, but not correctness)
    142     damage_rect_for_this_update = damage_from_active_layers;
    143     damage_rect_for_this_update.Union(damage_from_surface_mask);
    144     damage_rect_for_this_update.Union(damage_from_leftover_rects);
    145 
    146     if (filters.HasFilterThatMovesPixels()) {
    147       ExpandRectWithFilters(&damage_rect_for_this_update, filters);
    148     } else if (filter) {
    149       // TODO(senorblanco):  Once SkImageFilter reports its outsets, use
    150       // those here to limit damage.
    151       damage_rect_for_this_update = target_surface_content_rect;
    152     }
    153   }
    154 
    155   // Damage accumulates until we are notified that we actually did draw on that
    156   // frame.
    157   current_damage_rect_.Union(damage_rect_for_this_update);
    158 
    159   // The next history map becomes the current map for the next frame. Note this
    160   // must happen every frame to correctly track changes, even if damage
    161   // accumulates over multiple frames before actually being drawn.
    162   swap(current_rect_history_, next_rect_history_);
    163 }
    164 
    165 gfx::RectF DamageTracker::RemoveRectFromCurrentFrame(int layer_id,
    166                                                      bool* layer_is_new) {
    167   RectMap::iterator iter = current_rect_history_->find(layer_id);
    168   *layer_is_new = iter == current_rect_history_->end();
    169   if (*layer_is_new)
    170     return gfx::RectF();
    171 
    172   gfx::RectF ret = iter->second;
    173   current_rect_history_->erase(iter);
    174   return ret;
    175 }
    176 
    177 void DamageTracker::SaveRectForNextFrame(int layer_id,
    178                                          const gfx::RectF& target_space_rect) {
    179   // This layer should not yet exist in next frame's history.
    180   DCHECK_GT(layer_id, 0);
    181   DCHECK(next_rect_history_->find(layer_id) == next_rect_history_->end());
    182   (*next_rect_history_)[layer_id] = target_space_rect;
    183 }
    184 
    185 gfx::RectF DamageTracker::TrackDamageFromActiveLayers(
    186     const LayerImplList& layer_list,
    187     int target_surface_layer_id) {
    188   gfx::RectF damage_rect = gfx::RectF();
    189 
    190   for (size_t layer_index = 0; layer_index < layer_list.size(); ++layer_index) {
    191     // Visit layers in back-to-front order.
    192     LayerImpl* layer = layer_list[layer_index];
    193 
    194     // We skip damage from the HUD layer because (a) the HUD layer damages the
    195     // whole frame and (b) we don't want HUD layer damage to be shown by the
    196     // HUD damage rect visualization.
    197     if (layer == layer->layer_tree_impl()->hud_layer())
    198       continue;
    199 
    200     if (LayerTreeHostCommon::RenderSurfaceContributesToTarget<LayerImpl>(
    201             layer, target_surface_layer_id))
    202       ExtendDamageForRenderSurface(layer, &damage_rect);
    203     else
    204       ExtendDamageForLayer(layer, &damage_rect);
    205   }
    206 
    207   return damage_rect;
    208 }
    209 
    210 gfx::RectF DamageTracker::TrackDamageFromSurfaceMask(
    211     LayerImpl* target_surface_mask_layer) {
    212   gfx::RectF damage_rect = gfx::RectF();
    213 
    214   if (!target_surface_mask_layer)
    215     return damage_rect;
    216 
    217   // Currently, if there is any change to the mask, we choose to damage the
    218   // entire surface. This could potentially be optimized later, but it is not
    219   // expected to be a common case.
    220   if (target_surface_mask_layer->LayerPropertyChanged() ||
    221       !target_surface_mask_layer->update_rect().IsEmpty()) {
    222     damage_rect = gfx::RectF(gfx::PointF(),
    223                              target_surface_mask_layer->bounds());
    224   }
    225 
    226   return damage_rect;
    227 }
    228 
    229 gfx::RectF DamageTracker::TrackDamageFromLeftoverRects() {
    230   // After computing damage for all active layers, any leftover items in the
    231   // current rect history correspond to layers/surfaces that no longer exist.
    232   // So, these regions are now exposed on the target surface.
    233 
    234   gfx::RectF damage_rect = gfx::RectF();
    235 
    236   for (RectMap::iterator it = current_rect_history_->begin();
    237        it != current_rect_history_->end();
    238        ++it)
    239     damage_rect.Union(it->second);
    240 
    241   current_rect_history_->clear();
    242 
    243   return damage_rect;
    244 }
    245 
    246 static bool LayerNeedsToRedrawOntoItsTargetSurface(LayerImpl* layer) {
    247   // If the layer does NOT own a surface but has SurfacePropertyChanged,
    248   // this means that its target surface is affected and needs to be redrawn.
    249   // However, if the layer DOES own a surface, then the SurfacePropertyChanged
    250   // flag should not be used here, because that flag represents whether the
    251   // layer's surface has changed.
    252   if (layer->render_surface())
    253     return layer->LayerPropertyChanged();
    254   return layer->LayerPropertyChanged() || layer->LayerSurfacePropertyChanged();
    255 }
    256 
    257 void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
    258                                          gfx::RectF* target_damage_rect) {
    259   // There are two ways that a layer can damage a region of the target surface:
    260   //   1. Property change (e.g. opacity, position, transforms):
    261   //        - the entire region of the layer itself damages the surface.
    262   //        - the old layer region also damages the surface, because this region
    263   //          is now exposed.
    264   //        - note that in many cases the old and new layer rects may overlap,
    265   //          which is fine.
    266   //
    267   //   2. Repaint/update: If a region of the layer that was repainted/updated,
    268   //      that region damages the surface.
    269   //
    270   // Property changes take priority over update rects.
    271   //
    272   // This method is called when we want to consider how a layer contributes to
    273   // its target RenderSurface, even if that layer owns the target RenderSurface
    274   // itself. To consider how a layer's target surface contributes to the
    275   // ancestor surface, ExtendDamageForRenderSurface() must be called instead.
    276 
    277   bool layer_is_new = false;
    278   gfx::RectF old_rect_in_target_space =
    279       RemoveRectFromCurrentFrame(layer->id(), &layer_is_new);
    280 
    281   gfx::RectF rect_in_target_space = MathUtil::MapClippedRect(
    282       layer->draw_transform(),
    283       gfx::RectF(gfx::PointF(), layer->content_bounds()));
    284   SaveRectForNextFrame(layer->id(), rect_in_target_space);
    285 
    286   if (layer_is_new || LayerNeedsToRedrawOntoItsTargetSurface(layer)) {
    287     // If a layer is new or has changed, then its entire layer rect affects the
    288     // target surface.
    289     target_damage_rect->Union(rect_in_target_space);
    290 
    291     // The layer's old region is now exposed on the target surface, too.
    292     // Note old_rect_in_target_space is already in target space.
    293     target_damage_rect->Union(old_rect_in_target_space);
    294   } else if (!layer->update_rect().IsEmpty()) {
    295     // If the layer properties haven't changed, then the the target surface is
    296     // only affected by the layer's update area, which could be empty.
    297     gfx::RectF update_content_rect =
    298         layer->LayerRectToContentRect(layer->update_rect());
    299     gfx::RectF update_rect_in_target_space =
    300         MathUtil::MapClippedRect(layer->draw_transform(), update_content_rect);
    301     target_damage_rect->Union(update_rect_in_target_space);
    302   }
    303 }
    304 
    305 void DamageTracker::ExtendDamageForRenderSurface(
    306     LayerImpl* layer, gfx::RectF* target_damage_rect) {
    307   // There are two ways a "descendant surface" can damage regions of the "target
    308   // surface":
    309   //   1. Property change:
    310   //        - a surface's geometry can change because of
    311   //            - changes to descendants (i.e. the subtree) that affect the
    312   //              surface's content rect
    313   //            - changes to ancestor layers that propagate their property
    314   //              changes to their entire subtree.
    315   //        - just like layers, both the old surface rect and new surface rect
    316   //          will damage the target surface in this case.
    317   //
    318   //   2. Damage rect: This surface may have been damaged by its own layer_list
    319   //      as well, and that damage should propagate to the target surface.
    320   //
    321 
    322   RenderSurfaceImpl* render_surface = layer->render_surface();
    323 
    324   bool surface_is_new = false;
    325   gfx::RectF old_surface_rect = RemoveRectFromCurrentFrame(layer->id(),
    326                                                            &surface_is_new);
    327 
    328   // The drawableContextRect() already includes the replica if it exists.
    329   gfx::RectF surface_rect_in_target_space =
    330       render_surface->DrawableContentRect();
    331   SaveRectForNextFrame(layer->id(), surface_rect_in_target_space);
    332 
    333   gfx::RectF damage_rect_in_local_space;
    334   if (surface_is_new ||
    335       render_surface->SurfacePropertyChanged() ||
    336       layer->LayerSurfacePropertyChanged()) {
    337     // The entire surface contributes damage.
    338     damage_rect_in_local_space = render_surface->content_rect();
    339 
    340     // The surface's old region is now exposed on the target surface, too.
    341     target_damage_rect->Union(old_surface_rect);
    342   } else {
    343     // Only the surface's damage_rect will damage the target surface.
    344     damage_rect_in_local_space =
    345         render_surface->damage_tracker()->current_damage_rect();
    346   }
    347 
    348   // If there was damage, transform it to target space, and possibly contribute
    349   // its reflection if needed.
    350   if (!damage_rect_in_local_space.IsEmpty()) {
    351     const gfx::Transform& draw_transform = render_surface->draw_transform();
    352     gfx::RectF damage_rect_in_target_space =
    353         MathUtil::MapClippedRect(draw_transform, damage_rect_in_local_space);
    354     target_damage_rect->Union(damage_rect_in_target_space);
    355 
    356     if (layer->replica_layer()) {
    357       const gfx::Transform& replica_draw_transform =
    358           render_surface->replica_draw_transform();
    359       target_damage_rect->Union(MathUtil::MapClippedRect(
    360           replica_draw_transform, damage_rect_in_local_space));
    361     }
    362   }
    363 
    364   // If there was damage on the replica's mask, then the target surface receives
    365   // that damage as well.
    366   if (layer->replica_layer() && layer->replica_layer()->mask_layer()) {
    367     LayerImpl* replica_mask_layer = layer->replica_layer()->mask_layer();
    368 
    369     bool replica_is_new = false;
    370     RemoveRectFromCurrentFrame(replica_mask_layer->id(), &replica_is_new);
    371 
    372     const gfx::Transform& replica_draw_transform =
    373         render_surface->replica_draw_transform();
    374     gfx::RectF replica_mask_layer_rect = MathUtil::MapClippedRect(
    375         replica_draw_transform,
    376         gfx::RectF(gfx::PointF(), replica_mask_layer->bounds()));
    377     SaveRectForNextFrame(replica_mask_layer->id(), replica_mask_layer_rect);
    378 
    379     // In the current implementation, a change in the replica mask damages the
    380     // entire replica region.
    381     if (replica_is_new ||
    382         replica_mask_layer->LayerPropertyChanged() ||
    383         !replica_mask_layer->update_rect().IsEmpty())
    384       target_damage_rect->Union(replica_mask_layer_rect);
    385   }
    386 
    387   // If the layer has a background filter, this may cause pixels in our surface
    388   // to be expanded, so we will need to expand any damage at or below this
    389   // layer. We expand the damage from this layer too, as we need to readback
    390   // those pixels from the surface with only the contents of layers below this
    391   // one in them. This means we need to redraw any pixels in the surface being
    392   // used for the blur in this layer this frame.
    393   if (layer->background_filters().HasFilterThatMovesPixels()) {
    394     ExpandDamageRectInsideRectWithFilters(target_damage_rect,
    395                                           surface_rect_in_target_space,
    396                                           layer->background_filters());
    397   }
    398 }
    399 
    400 }  // namespace cc
    401