• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 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/resources/picture_pile_base.h"
6 
7 #include <algorithm>
8 #include <set>
9 #include <vector>
10 
11 #include "base/logging.h"
12 #include "base/values.h"
13 #include "cc/base/math_util.h"
14 #include "cc/debug/traced_value.h"
15 #include "third_party/skia/include/core/SkColor.h"
16 #include "ui/gfx/rect_conversions.h"
17 
18 namespace {
19 // Dimensions of the tiles in this picture pile as well as the dimensions of
20 // the base picture in each tile.
21 const int kBasePictureSize = 512;
22 const int kTileGridBorderPixels = 1;
23 #ifdef NDEBUG
24 const bool kDefaultClearCanvasSetting = false;
25 #else
26 const bool kDefaultClearCanvasSetting = true;
27 #endif
28 
29 // Invalidation frequency settings. kInvalidationFrequencyThreshold is a value
30 // between 0 and 1 meaning invalidation frequency between 0% and 100% that
31 // indicates when to stop invalidating offscreen regions.
32 // kFrequentInvalidationDistanceThreshold defines what it means to be
33 // "offscreen" in terms of distance to visible in css pixels.
34 const float kInvalidationFrequencyThreshold = 0.75f;
35 const int kFrequentInvalidationDistanceThreshold = 512;
36 
37 }  // namespace
38 
39 namespace cc {
40 
PicturePileBase()41 PicturePileBase::PicturePileBase()
42     : min_contents_scale_(0),
43       background_color_(SkColorSetARGBInline(0, 0, 0, 0)),
44       slow_down_raster_scale_factor_for_debug_(0),
45       contents_opaque_(false),
46       contents_fill_bounds_completely_(false),
47       show_debug_picture_borders_(false),
48       clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
49       has_any_recordings_(false) {
50   tiling_.SetMaxTextureSize(gfx::Size(kBasePictureSize, kBasePictureSize));
51   tile_grid_info_.fTileInterval.setEmpty();
52   tile_grid_info_.fMargin.setEmpty();
53   tile_grid_info_.fOffset.setZero();
54 }
55 
PicturePileBase(const PicturePileBase * other)56 PicturePileBase::PicturePileBase(const PicturePileBase* other)
57     : picture_map_(other->picture_map_),
58       tiling_(other->tiling_),
59       recorded_viewport_(other->recorded_viewport_),
60       min_contents_scale_(other->min_contents_scale_),
61       tile_grid_info_(other->tile_grid_info_),
62       background_color_(other->background_color_),
63       slow_down_raster_scale_factor_for_debug_(
64           other->slow_down_raster_scale_factor_for_debug_),
65       contents_opaque_(other->contents_opaque_),
66       contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
67       show_debug_picture_borders_(other->show_debug_picture_borders_),
68       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
69       has_any_recordings_(other->has_any_recordings_) {}
70 
PicturePileBase(const PicturePileBase * other,unsigned thread_index)71 PicturePileBase::PicturePileBase(const PicturePileBase* other,
72                                  unsigned thread_index)
73     : tiling_(other->tiling_),
74       recorded_viewport_(other->recorded_viewport_),
75       min_contents_scale_(other->min_contents_scale_),
76       tile_grid_info_(other->tile_grid_info_),
77       background_color_(other->background_color_),
78       slow_down_raster_scale_factor_for_debug_(
79           other->slow_down_raster_scale_factor_for_debug_),
80       contents_opaque_(other->contents_opaque_),
81       contents_fill_bounds_completely_(other->contents_fill_bounds_completely_),
82       show_debug_picture_borders_(other->show_debug_picture_borders_),
83       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
84       has_any_recordings_(other->has_any_recordings_) {
85   for (PictureMap::const_iterator it = other->picture_map_.begin();
86        it != other->picture_map_.end();
87        ++it) {
88     picture_map_[it->first] = it->second.CloneForThread(thread_index);
89   }
90 }
91 
~PicturePileBase()92 PicturePileBase::~PicturePileBase() {
93 }
94 
SetTilingRect(const gfx::Rect & new_tiling_rect)95 void PicturePileBase::SetTilingRect(const gfx::Rect& new_tiling_rect) {
96   if (tiling_rect() == new_tiling_rect)
97     return;
98 
99   gfx::Rect old_tiling_rect = tiling_rect();
100   tiling_.SetTilingRect(new_tiling_rect);
101 
102   has_any_recordings_ = false;
103 
104   // Don't waste time in Resize figuring out what these hints should be.
105   recorded_viewport_ = gfx::Rect();
106 
107   if (new_tiling_rect.origin() != old_tiling_rect.origin()) {
108     picture_map_.clear();
109     return;
110   }
111 
112   // Find all tiles that contain any pixels outside the new rect.
113   std::vector<PictureMapKey> to_erase;
114   int min_toss_x = tiling_.FirstBorderTileXIndexFromSrcCoord(
115       std::min(old_tiling_rect.right(), new_tiling_rect.right()));
116   int min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord(
117       std::min(old_tiling_rect.bottom(), new_tiling_rect.bottom()));
118   for (PictureMap::const_iterator it = picture_map_.begin();
119        it != picture_map_.end();
120        ++it) {
121     const PictureMapKey& key = it->first;
122     if (key.first < min_toss_x && key.second < min_toss_y) {
123       has_any_recordings_ |= !!it->second.GetPicture();
124       continue;
125     }
126     to_erase.push_back(key);
127   }
128 
129   for (size_t i = 0; i < to_erase.size(); ++i)
130     picture_map_.erase(to_erase[i]);
131 }
132 
SetMinContentsScale(float min_contents_scale)133 void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
134   DCHECK(min_contents_scale);
135   if (min_contents_scale_ == min_contents_scale)
136     return;
137 
138   // Picture contents are played back scaled. When the final contents scale is
139   // less than 1 (i.e. low res), then multiple recorded pixels will be used
140   // to raster one final pixel.  To avoid splitting a final pixel across
141   // pictures (which would result in incorrect rasterization due to blending), a
142   // buffer margin is added so that any picture can be snapped to integral
143   // final pixels.
144   //
145   // For example, if a 1/4 contents scale is used, then that would be 3 buffer
146   // pixels, since that's the minimum number of pixels to add so that resulting
147   // content can be snapped to a four pixel aligned grid.
148   int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
149   buffer_pixels = std::max(0, buffer_pixels);
150   SetBufferPixels(buffer_pixels);
151   min_contents_scale_ = min_contents_scale;
152 }
153 
154 // static
ComputeTileGridInfo(const gfx::Size & tile_grid_size,SkTileGridFactory::TileGridInfo * info)155 void PicturePileBase::ComputeTileGridInfo(
156     const gfx::Size& tile_grid_size,
157     SkTileGridFactory::TileGridInfo* info) {
158   DCHECK(info);
159   info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
160                           tile_grid_size.height() - 2 * kTileGridBorderPixels);
161   DCHECK_GT(info->fTileInterval.width(), 0);
162   DCHECK_GT(info->fTileInterval.height(), 0);
163   info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
164   // Offset the tile grid coordinate space to take into account the fact
165   // that the top-most and left-most tiles do not have top and left borders
166   // respectively.
167   info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
168 }
169 
SetTileGridSize(const gfx::Size & tile_grid_size)170 void PicturePileBase::SetTileGridSize(const gfx::Size& tile_grid_size) {
171   ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
172 }
173 
SetBufferPixels(int new_buffer_pixels)174 void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
175   if (new_buffer_pixels == buffer_pixels())
176     return;
177 
178   Clear();
179   tiling_.SetBorderTexels(new_buffer_pixels);
180 }
181 
Clear()182 void PicturePileBase::Clear() {
183   picture_map_.clear();
184   recorded_viewport_ = gfx::Rect();
185 }
186 
HasRecordingAt(int x,int y)187 bool PicturePileBase::HasRecordingAt(int x, int y) {
188   PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
189   if (found == picture_map_.end())
190     return false;
191   return !!found->second.GetPicture();
192 }
193 
CanRaster(float contents_scale,const gfx::Rect & content_rect)194 bool PicturePileBase::CanRaster(float contents_scale,
195                                 const gfx::Rect& content_rect) {
196   if (tiling_.tiling_rect().IsEmpty())
197     return false;
198   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
199       content_rect, 1.f / contents_scale);
200   layer_rect.Intersect(tiling_.tiling_rect());
201 
202   // Common case inside of viewport to avoid the slower map lookups.
203   if (recorded_viewport_.Contains(layer_rect)) {
204     // Sanity check that there are no false positives in recorded_viewport_.
205     DCHECK(CanRasterSlowTileCheck(layer_rect));
206     return true;
207   }
208 
209   return CanRasterSlowTileCheck(layer_rect);
210 }
211 
CanRasterSlowTileCheck(const gfx::Rect & layer_rect) const212 bool PicturePileBase::CanRasterSlowTileCheck(
213     const gfx::Rect& layer_rect) const {
214   bool include_borders = false;
215   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
216        tile_iter;
217        ++tile_iter) {
218     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
219     if (map_iter == picture_map_.end())
220       return false;
221     if (!map_iter->second.GetPicture())
222       return false;
223   }
224   return true;
225 }
226 
PaddedRect(const PictureMapKey & key)227 gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) {
228   gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
229   return PadRect(tile);
230 }
231 
PadRect(const gfx::Rect & rect)232 gfx::Rect PicturePileBase::PadRect(const gfx::Rect& rect) {
233   gfx::Rect padded_rect = rect;
234   padded_rect.Inset(
235       -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
236   return padded_rect;
237 }
238 
AsValue() const239 scoped_ptr<base::Value> PicturePileBase::AsValue() const {
240   scoped_ptr<base::ListValue> pictures(new base::ListValue());
241   gfx::Rect tiling_rect(tiling_.tiling_rect());
242   std::set<void*> appended_pictures;
243   bool include_borders = true;
244   for (TilingData::Iterator tile_iter(&tiling_, tiling_rect, include_borders);
245        tile_iter;
246        ++tile_iter) {
247     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
248     if (map_iter == picture_map_.end())
249       continue;
250 
251     Picture* picture = map_iter->second.GetPicture();
252     if (picture && (appended_pictures.count(picture) == 0)) {
253       appended_pictures.insert(picture);
254       pictures->Append(TracedValue::CreateIDRef(picture).release());
255     }
256   }
257   return pictures.PassAs<base::Value>();
258 }
259 
PictureInfo()260 PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
261 
~PictureInfo()262 PicturePileBase::PictureInfo::~PictureInfo() {}
263 
AdvanceInvalidationHistory(int frame_number)264 void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
265     int frame_number) {
266   DCHECK_GE(frame_number, last_frame_number_);
267   if (frame_number == last_frame_number_)
268     return;
269 
270   invalidation_history_ <<= (frame_number - last_frame_number_);
271   last_frame_number_ = frame_number;
272 }
273 
Invalidate(int frame_number)274 bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
275   AdvanceInvalidationHistory(frame_number);
276   invalidation_history_.set(0);
277 
278   bool did_invalidate = !!picture_;
279   picture_ = NULL;
280   return did_invalidate;
281 }
282 
NeedsRecording(int frame_number,int distance_to_visible)283 bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
284                                                   int distance_to_visible) {
285   AdvanceInvalidationHistory(frame_number);
286 
287   // We only need recording if we don't have a picture. Furthermore, we only
288   // need a recording if we're within frequent invalidation distance threshold
289   // or the invalidation is not frequent enough (below invalidation frequency
290   // threshold).
291   return !picture_ &&
292          ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
293           (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
294 }
295 
SetPicture(scoped_refptr<Picture> picture)296 void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
297   picture_ = picture;
298 }
299 
GetPicture() const300 Picture* PicturePileBase::PictureInfo::GetPicture() const {
301   return picture_.get();
302 }
303 
CloneForThread(int thread_index) const304 PicturePileBase::PictureInfo PicturePileBase::PictureInfo::CloneForThread(
305     int thread_index) const {
306   PictureInfo info = *this;
307   if (picture_.get())
308     info.picture_ = picture_->GetCloneForDrawingOnThread(thread_index);
309   return info;
310 }
311 
GetInvalidationFrequency() const312 float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
313   return invalidation_history_.count() /
314          static_cast<float>(INVALIDATION_FRAMES_TRACKED);
315 }
316 
317 }  // namespace cc
318