| Index: cc/trees/damage_tracker.cc
|
| diff --git a/cc/trees/damage_tracker.cc b/cc/trees/damage_tracker.cc
|
| index 49bb634c1f6252425c37d7af4c41ddda9a61c8e1..9895458c99a73c5f732e6b4d561f98a57ff0f0d1 100644
|
| --- a/cc/trees/damage_tracker.cc
|
| +++ b/cc/trees/damage_tracker.cc
|
| @@ -21,8 +21,7 @@ scoped_ptr<DamageTracker> DamageTracker::Create() {
|
| }
|
|
|
| DamageTracker::DamageTracker()
|
| - : current_rect_history_(new RectMap),
|
| - next_rect_history_(new RectMap) {}
|
| + : mailboxId_(0) {}
|
|
|
| DamageTracker::~DamageTracker() {}
|
|
|
| @@ -105,23 +104,23 @@ void DamageTracker::UpdateDamageTrackingState(
|
| // - See comments in the rest of the code to see what exactly is considered a
|
| // "change" in a layer/surface.
|
| //
|
| - // - To correctly manage exposed rects, two RectMaps are maintained:
|
| + // - To correctly manage exposed rects, SortedRectMap is maintained:
|
| //
|
| - // 1. The "current" map contains all the layer bounds that contributed to
|
| + // 1. All existing rects from the previous frame are marked as
|
| + // not updated.
|
| + // 2. The map contains all the layer bounds that contributed to
|
| // the previous frame (even outside the previous damaged area). If a
|
| // layer changes or does not exist anymore, those regions are then
|
| // exposed and damage the target surface. As the algorithm progresses,
|
| - // entries are removed from the map until it has only leftover layers
|
| - // that no longer exist.
|
| + // entries are updated in the map until only leftover layers
|
| + // that no longer exist stay marked not updated.
|
| //
|
| - // 2. The "next" map starts out empty, and as the algorithm progresses,
|
| - // every layer/surface that contributes to the surface is added to the
|
| - // map.
|
| - //
|
| - // 3. After the damage rect is computed, the two maps are swapped, so
|
| - // that the damage tracker is ready for the next frame.
|
| + // 3. After the damage rect is computed, the leftover not marked regions
|
| + // in a map are used to compute are damaged by deleted layers and
|
| + // erased from map.
|
| //
|
|
|
| + PrepareRectHistoryForUpdate();
|
| // These functions cannot be bypassed with early-exits, even if we know what
|
| // the damage will be for this frame, because we need to update the damage
|
| // tracker state to correctly track the next frame.
|
| @@ -154,31 +153,23 @@ void DamageTracker::UpdateDamageTrackingState(
|
| // Damage accumulates until we are notified that we actually did draw on that
|
| // frame.
|
| current_damage_rect_.Union(damage_rect_for_this_update);
|
| -
|
| - // The next history map becomes the current map for the next frame. Note this
|
| - // must happen every frame to correctly track changes, even if damage
|
| - // accumulates over multiple frames before actually being drawn.
|
| - swap(current_rect_history_, next_rect_history_);
|
| }
|
|
|
| -gfx::RectF DamageTracker::RemoveRectFromCurrentFrame(int layer_id,
|
| - bool* layer_is_new) {
|
| - RectMap::iterator iter = current_rect_history_->find(layer_id);
|
| - *layer_is_new = iter == current_rect_history_->end();
|
| - if (*layer_is_new)
|
| - return gfx::RectF();
|
| +DamageTracker::RectMapData& DamageTracker::RectDataForLayer(
|
| + int layer_id,
|
| + bool* layer_is_new) {
|
|
|
| - gfx::RectF ret = iter->second;
|
| - current_rect_history_->erase(iter);
|
| - return ret;
|
| -}
|
| + RectMapData data(layer_id);
|
| +
|
| + SortedRectMap::iterator it = std::lower_bound(rect_history_.begin(),
|
| + rect_history_.end(), data);
|
| +
|
| + if (it == rect_history_.end() || it->layer_id_ != layer_id) {
|
| + *layer_is_new = true;
|
| + it = rect_history_.insert(it, data);
|
| + }
|
|
|
| -void DamageTracker::SaveRectForNextFrame(int layer_id,
|
| - const gfx::RectF& target_space_rect) {
|
| - // This layer should not yet exist in next frame's history.
|
| - DCHECK_GT(layer_id, 0);
|
| - DCHECK(next_rect_history_->find(layer_id) == next_rect_history_->end());
|
| - (*next_rect_history_)[layer_id] = target_space_rect;
|
| + return *it;
|
| }
|
|
|
| gfx::RectF DamageTracker::TrackDamageFromActiveLayers(
|
| @@ -225,19 +216,46 @@ gfx::RectF DamageTracker::TrackDamageFromSurfaceMask(
|
| return damage_rect;
|
| }
|
|
|
| +void DamageTracker::PrepareRectHistoryForUpdate() {
|
| + mailboxId_++;
|
| +}
|
| +
|
| gfx::RectF DamageTracker::TrackDamageFromLeftoverRects() {
|
| // After computing damage for all active layers, any leftover items in the
|
| // current rect history correspond to layers/surfaces that no longer exist.
|
| // So, these regions are now exposed on the target surface.
|
|
|
| gfx::RectF damage_rect = gfx::RectF();
|
| + SortedRectMap::iterator cur_pos = rect_history_.begin();
|
| + SortedRectMap::iterator copy_pos = cur_pos;
|
| +
|
| + // Loop below basically implements std::remove_if loop with and extra
|
| + // processing (adding deleted rect to damage_rect) for deleted items.
|
| + // cur_pos iterator runs through all elements of the vector, but copy_pos
|
| + // always points to the element after the last not deleted element. If new
|
| + // not deleted element found then it is copied to the *copy_pos and copy_pos
|
| + // moved to the next position.
|
| + // If there are no deleted elements then copy_pos iterator is in sync with
|
| + // cur_pos and no copy happens.
|
| + while (cur_pos < rect_history_.end()) {
|
| + if (cur_pos->mailboxId_ == mailboxId_) {
|
| + if (cur_pos != copy_pos)
|
| + *copy_pos = *cur_pos;
|
| +
|
| + ++copy_pos;
|
| + } else {
|
| + damage_rect.Union(cur_pos->rect_);
|
| + }
|
| +
|
| + ++cur_pos;
|
| + }
|
|
|
| - for (RectMap::iterator it = current_rect_history_->begin();
|
| - it != current_rect_history_->end();
|
| - ++it)
|
| - damage_rect.Union(it->second);
|
| + if (copy_pos != rect_history_.end())
|
| + rect_history_.erase(copy_pos, rect_history_.end());
|
|
|
| - current_rect_history_->clear();
|
| + // If the vector has excessive storage, shrink it
|
| + if (rect_history_.capacity() > rect_history_.size() * 4)
|
| + SortedRectMap(rect_history_).swap(rect_history_);
|
|
|
| return damage_rect;
|
| }
|
| @@ -263,13 +281,13 @@ void DamageTracker::ExtendDamageForLayer(LayerImpl* layer,
|
| // ancestor surface, ExtendDamageForRenderSurface() must be called instead.
|
|
|
| bool layer_is_new = false;
|
| - gfx::RectF old_rect_in_target_space =
|
| - RemoveRectFromCurrentFrame(layer->id(), &layer_is_new);
|
| + RectMapData& data = RectDataForLayer(layer->id(), &layer_is_new);
|
| + gfx::RectF old_rect_in_target_space = data.rect_;
|
|
|
| gfx::RectF rect_in_target_space = MathUtil::MapClippedRect(
|
| layer->draw_transform(),
|
| gfx::RectF(gfx::PointF(), layer->content_bounds()));
|
| - SaveRectForNextFrame(layer->id(), rect_in_target_space);
|
| + data.Update(rect_in_target_space, mailboxId_);
|
|
|
| if (layer_is_new || layer->LayerPropertyChanged()) {
|
| // If a layer is new or has changed, then its entire layer rect affects the
|
| @@ -310,13 +328,13 @@ void DamageTracker::ExtendDamageForRenderSurface(
|
| RenderSurfaceImpl* render_surface = layer->render_surface();
|
|
|
| bool surface_is_new = false;
|
| - gfx::RectF old_surface_rect = RemoveRectFromCurrentFrame(layer->id(),
|
| - &surface_is_new);
|
| + RectMapData& data = RectDataForLayer(layer->id(), &surface_is_new);
|
| + gfx::RectF old_surface_rect = data.rect_;
|
|
|
| // The drawableContextRect() already includes the replica if it exists.
|
| gfx::RectF surface_rect_in_target_space =
|
| render_surface->DrawableContentRect();
|
| - SaveRectForNextFrame(layer->id(), surface_rect_in_target_space);
|
| + data.Update(surface_rect_in_target_space, mailboxId_);
|
|
|
| gfx::RectF damage_rect_in_local_space;
|
| if (surface_is_new || render_surface->SurfacePropertyChanged()) {
|
| @@ -353,14 +371,15 @@ void DamageTracker::ExtendDamageForRenderSurface(
|
| LayerImpl* replica_mask_layer = layer->replica_layer()->mask_layer();
|
|
|
| bool replica_is_new = false;
|
| - RemoveRectFromCurrentFrame(replica_mask_layer->id(), &replica_is_new);
|
| + RectMapData& data =
|
| + RectDataForLayer(replica_mask_layer->id(), &replica_is_new);
|
|
|
| const gfx::Transform& replica_draw_transform =
|
| render_surface->replica_draw_transform();
|
| gfx::RectF replica_mask_layer_rect = MathUtil::MapClippedRect(
|
| replica_draw_transform,
|
| gfx::RectF(gfx::PointF(), replica_mask_layer->bounds()));
|
| - SaveRectForNextFrame(replica_mask_layer->id(), replica_mask_layer_rect);
|
| + data.Update(replica_mask_layer_rect, mailboxId_);
|
|
|
| // In the current implementation, a change in the replica mask damages the
|
| // entire replica region.
|
|
|