diff options
Diffstat (limited to 'chromium/cc/resources/picture_pile.cc')
-rw-r--r-- | chromium/cc/resources/picture_pile.cc | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/chromium/cc/resources/picture_pile.cc b/chromium/cc/resources/picture_pile.cc new file mode 100644 index 00000000000..17283ddd263 --- /dev/null +++ b/chromium/cc/resources/picture_pile.cc @@ -0,0 +1,177 @@ +// Copyright 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "cc/resources/picture_pile.h" + +#include <algorithm> +#include <vector> + +#include "cc/base/region.h" +#include "cc/debug/benchmark_instrumentation.h" +#include "cc/resources/picture_pile_impl.h" + +namespace { +// Maximum number of pictures that can overlap before we collapse them into +// a larger one. +const size_t kMaxOverlapping = 2; +// Maximum percentage area of the base picture another picture in the picture +// list can be. If higher, we destroy the list and recreate from scratch. +const float kResetThreshold = 0.7f; +// Layout pixel buffer around the visible layer rect to record. Any base +// picture that intersects the visible layer rect expanded by this distance +// will be recorded. +const int kPixelDistanceToRecord = 8000; +} // namespace + +namespace cc { + +PicturePile::PicturePile() { +} + +PicturePile::~PicturePile() { +} + +bool PicturePile::Update( + ContentLayerClient* painter, + SkColor background_color, + bool contents_opaque, + const Region& invalidation, + gfx::Rect visible_layer_rect, + RenderingStatsInstrumentation* stats_instrumentation) { + background_color_ = background_color; + contents_opaque_ = contents_opaque; + + gfx::Rect interest_rect = visible_layer_rect; + interest_rect.Inset( + -kPixelDistanceToRecord, + -kPixelDistanceToRecord, + -kPixelDistanceToRecord, + -kPixelDistanceToRecord); + bool modified_pile = false; + for (Region::Iterator i(invalidation); i.has_rect(); i.next()) { + gfx::Rect invalidation = i.rect(); + // Split this inflated invalidation across tile boundaries and apply it + // to all tiles that it touches. + for (TilingData::Iterator iter(&tiling_, invalidation); + iter; ++iter) { + gfx::Rect tile = + tiling_.TileBoundsWithBorder(iter.index_x(), iter.index_y()); + if (!tile.Intersects(interest_rect)) { + // This invalidation touches a tile outside the interest rect, so + // just remove the entire picture list. + picture_list_map_.erase(iter.index()); + modified_pile = true; + continue; + } + + gfx::Rect tile_invalidation = gfx::IntersectRects(invalidation, tile); + if (tile_invalidation.IsEmpty()) + continue; + PictureListMap::iterator find = picture_list_map_.find(iter.index()); + if (find == picture_list_map_.end()) + continue; + PictureList& pic_list = find->second; + // Leave empty pic_lists empty in case there are multiple invalidations. + if (!pic_list.empty()) { + // Inflate all recordings from invalidations with a margin so that when + // scaled down to at least min_contents_scale, any final pixel touched + // by an invalidation can be fully rasterized by this picture. + tile_invalidation.Inset(-buffer_pixels(), -buffer_pixels()); + + DCHECK_GE(tile_invalidation.width(), buffer_pixels() * 2 + 1); + DCHECK_GE(tile_invalidation.height(), buffer_pixels() * 2 + 1); + + InvalidateRect(pic_list, tile_invalidation); + modified_pile = true; + } + } + } + + int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); + + // Walk through all pictures in the rect of interest and record. + for (TilingData::Iterator iter(&tiling_, interest_rect); iter; ++iter) { + // Create a picture in this list if it doesn't exist. + PictureList& pic_list = picture_list_map_[iter.index()]; + if (pic_list.empty()) { + // Inflate the base picture with a margin, similar to invalidations, so + // that when scaled down to at least min_contents_scale, the enclosed + // rect still includes content all the way to the edge of the layer. + gfx::Rect tile = tiling_.TileBounds(iter.index_x(), iter.index_y()); + tile.Inset( + -buffer_pixels(), + -buffer_pixels(), + -buffer_pixels(), + -buffer_pixels()); + scoped_refptr<Picture> base_picture = Picture::Create(tile); + pic_list.push_back(base_picture); + } + + for (PictureList::iterator pic = pic_list.begin(); + pic != pic_list.end(); ++pic) { + if (!(*pic)->HasRecording()) { + modified_pile = true; + TRACE_EVENT0(benchmark_instrumentation::kCategory, + benchmark_instrumentation::kRecordLoop); + for (int i = 0; i < repeat_count; i++) + (*pic)->Record(painter, tile_grid_info_, stats_instrumentation); + (*pic)->GatherPixelRefs(tile_grid_info_, stats_instrumentation); + (*pic)->CloneForDrawing(num_raster_threads_); + } + } + } + + UpdateRecordedRegion(); + + return modified_pile; +} + +class FullyContainedPredicate { + public: + explicit FullyContainedPredicate(gfx::Rect rect) : layer_rect_(rect) {} + bool operator()(const scoped_refptr<Picture>& picture) { + return picture->LayerRect().IsEmpty() || + layer_rect_.Contains(picture->LayerRect()); + } + gfx::Rect layer_rect_; +}; + +void PicturePile::InvalidateRect( + PictureList& picture_list, + gfx::Rect invalidation) { + DCHECK(!picture_list.empty()); + DCHECK(!invalidation.IsEmpty()); + + std::vector<PictureList::iterator> overlaps; + for (PictureList::iterator i = picture_list.begin(); + i != picture_list.end(); ++i) { + if ((*i)->LayerRect().Contains(invalidation) && !(*i)->HasRecording()) + return; + if ((*i)->LayerRect().Intersects(invalidation) && i != picture_list.begin()) + overlaps.push_back(i); + } + + gfx::Rect picture_rect = invalidation; + if (overlaps.size() >= kMaxOverlapping) { + for (size_t j = 0; j < overlaps.size(); j++) + picture_rect.Union((*overlaps[j])->LayerRect()); + } + + Picture* base_picture = picture_list.front().get(); + int max_pixels = kResetThreshold * base_picture->LayerRect().size().GetArea(); + if (picture_rect.size().GetArea() > max_pixels) { + // This picture list will be entirely recreated, so clear it. + picture_list.clear(); + return; + } + + FullyContainedPredicate pred(picture_rect); + picture_list.erase(std::remove_if(picture_list.begin(), + picture_list.end(), + pred), + picture_list.end()); + picture_list.push_back(Picture::Create(picture_rect)); +} + +} // namespace cc |