• 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       show_debug_picture_borders_(false),
47       clear_canvas_with_debug_color_(kDefaultClearCanvasSetting),
48       num_raster_threads_(0),
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       show_debug_picture_borders_(other->show_debug_picture_borders_),
67       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
68       num_raster_threads_(other->num_raster_threads_),
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       show_debug_picture_borders_(other->show_debug_picture_borders_),
82       clear_canvas_with_debug_color_(other->clear_canvas_with_debug_color_),
83       num_raster_threads_(other->num_raster_threads_),
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 
Resize(gfx::Size new_size)95 void PicturePileBase::Resize(gfx::Size new_size) {
96   if (size() == new_size)
97     return;
98 
99   gfx::Size old_size = size();
100   tiling_.SetTotalSize(new_size);
101 
102   has_any_recordings_ = false;
103 
104   // Find all tiles that contain any pixels outside the new size.
105   std::vector<PictureMapKey> to_erase;
106   int min_toss_x = tiling_.FirstBorderTileXIndexFromSrcCoord(
107       std::min(old_size.width(), new_size.width()));
108   int min_toss_y = tiling_.FirstBorderTileYIndexFromSrcCoord(
109       std::min(old_size.height(), new_size.height()));
110   for (PictureMap::const_iterator it = picture_map_.begin();
111        it != picture_map_.end();
112        ++it) {
113     const PictureMapKey& key = it->first;
114     if (key.first < min_toss_x && key.second < min_toss_y) {
115       has_any_recordings_ |= !!it->second.GetPicture();
116       continue;
117     }
118     to_erase.push_back(key);
119   }
120 
121   for (size_t i = 0; i < to_erase.size(); ++i)
122     picture_map_.erase(to_erase[i]);
123 
124   // Don't waste time in Resize figuring out what these hints should be.
125   recorded_viewport_ = gfx::Rect();
126 }
127 
SetMinContentsScale(float min_contents_scale)128 void PicturePileBase::SetMinContentsScale(float min_contents_scale) {
129   DCHECK(min_contents_scale);
130   if (min_contents_scale_ == min_contents_scale)
131     return;
132 
133   // Picture contents are played back scaled. When the final contents scale is
134   // less than 1 (i.e. low res), then multiple recorded pixels will be used
135   // to raster one final pixel.  To avoid splitting a final pixel across
136   // pictures (which would result in incorrect rasterization due to blending), a
137   // buffer margin is added so that any picture can be snapped to integral
138   // final pixels.
139   //
140   // For example, if a 1/4 contents scale is used, then that would be 3 buffer
141   // pixels, since that's the minimum number of pixels to add so that resulting
142   // content can be snapped to a four pixel aligned grid.
143   int buffer_pixels = static_cast<int>(ceil(1 / min_contents_scale) - 1);
144   buffer_pixels = std::max(0, buffer_pixels);
145   SetBufferPixels(buffer_pixels);
146   min_contents_scale_ = min_contents_scale;
147 }
148 
149 // static
ComputeTileGridInfo(gfx::Size tile_grid_size,SkTileGridPicture::TileGridInfo * info)150 void PicturePileBase::ComputeTileGridInfo(
151     gfx::Size tile_grid_size,
152     SkTileGridPicture::TileGridInfo* info) {
153   DCHECK(info);
154   info->fTileInterval.set(tile_grid_size.width() - 2 * kTileGridBorderPixels,
155                           tile_grid_size.height() - 2 * kTileGridBorderPixels);
156   DCHECK_GT(info->fTileInterval.width(), 0);
157   DCHECK_GT(info->fTileInterval.height(), 0);
158   info->fMargin.set(kTileGridBorderPixels, kTileGridBorderPixels);
159   // Offset the tile grid coordinate space to take into account the fact
160   // that the top-most and left-most tiles do not have top and left borders
161   // respectively.
162   info->fOffset.set(-kTileGridBorderPixels, -kTileGridBorderPixels);
163 }
164 
SetTileGridSize(gfx::Size tile_grid_size)165 void PicturePileBase::SetTileGridSize(gfx::Size tile_grid_size) {
166   ComputeTileGridInfo(tile_grid_size, &tile_grid_info_);
167 }
168 
SetBufferPixels(int new_buffer_pixels)169 void PicturePileBase::SetBufferPixels(int new_buffer_pixels) {
170   if (new_buffer_pixels == buffer_pixels())
171     return;
172 
173   Clear();
174   tiling_.SetBorderTexels(new_buffer_pixels);
175 }
176 
Clear()177 void PicturePileBase::Clear() {
178   picture_map_.clear();
179   recorded_viewport_ = gfx::Rect();
180 }
181 
HasRecordingAt(int x,int y)182 bool PicturePileBase::HasRecordingAt(int x, int y) {
183   PictureMap::const_iterator found = picture_map_.find(PictureMapKey(x, y));
184   if (found == picture_map_.end())
185     return false;
186   return !!found->second.GetPicture();
187 }
188 
CanRaster(float contents_scale,gfx::Rect content_rect)189 bool PicturePileBase::CanRaster(float contents_scale, gfx::Rect content_rect) {
190   if (tiling_.total_size().IsEmpty())
191     return false;
192   gfx::Rect layer_rect = gfx::ScaleToEnclosingRect(
193       content_rect, 1.f / contents_scale);
194   layer_rect.Intersect(gfx::Rect(tiling_.total_size()));
195 
196   // Common case inside of viewport to avoid the slower map lookups.
197   if (recorded_viewport_.Contains(layer_rect)) {
198     // Sanity check that there are no false positives in recorded_viewport_.
199     DCHECK(CanRasterSlowTileCheck(layer_rect));
200     return true;
201   }
202 
203   return CanRasterSlowTileCheck(layer_rect);
204 }
205 
CanRasterSlowTileCheck(const gfx::Rect & layer_rect) const206 bool PicturePileBase::CanRasterSlowTileCheck(
207     const gfx::Rect& layer_rect) const {
208   bool include_borders = false;
209   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
210        tile_iter;
211        ++tile_iter) {
212     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
213     if (map_iter == picture_map_.end())
214       return false;
215     if (!map_iter->second.GetPicture())
216       return false;
217   }
218   return true;
219 }
220 
PaddedRect(const PictureMapKey & key)221 gfx::Rect PicturePileBase::PaddedRect(const PictureMapKey& key) {
222   gfx::Rect tile = tiling_.TileBounds(key.first, key.second);
223   return PadRect(tile);
224 }
225 
PadRect(gfx::Rect rect)226 gfx::Rect PicturePileBase::PadRect(gfx::Rect rect) {
227   gfx::Rect padded_rect = rect;
228   padded_rect.Inset(
229       -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
230   return padded_rect;
231 }
232 
AsValue() const233 scoped_ptr<base::Value> PicturePileBase::AsValue() const {
234   scoped_ptr<base::ListValue> pictures(new base::ListValue());
235   gfx::Rect layer_rect(tiling_.total_size());
236   std::set<void*> appended_pictures;
237   bool include_borders = true;
238   for (TilingData::Iterator tile_iter(&tiling_, layer_rect, include_borders);
239        tile_iter;
240        ++tile_iter) {
241     PictureMap::const_iterator map_iter = picture_map_.find(tile_iter.index());
242     if (map_iter == picture_map_.end())
243       continue;
244 
245     Picture* picture = map_iter->second.GetPicture();
246     if (picture && (appended_pictures.count(picture) == 0)) {
247       appended_pictures.insert(picture);
248       pictures->Append(TracedValue::CreateIDRef(picture).release());
249     }
250   }
251   return pictures.PassAs<base::Value>();
252 }
253 
PictureInfo()254 PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
255 
~PictureInfo()256 PicturePileBase::PictureInfo::~PictureInfo() {}
257 
AdvanceInvalidationHistory(int frame_number)258 void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
259     int frame_number) {
260   DCHECK_GE(frame_number, last_frame_number_);
261   if (frame_number == last_frame_number_)
262     return;
263 
264   invalidation_history_ <<= (frame_number - last_frame_number_);
265   last_frame_number_ = frame_number;
266 }
267 
Invalidate(int frame_number)268 bool PicturePileBase::PictureInfo::Invalidate(int frame_number) {
269   AdvanceInvalidationHistory(frame_number);
270   invalidation_history_.set(0);
271 
272   bool did_invalidate = !!picture_;
273   picture_ = NULL;
274   return did_invalidate;
275 }
276 
NeedsRecording(int frame_number,int distance_to_visible)277 bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number,
278                                                   int distance_to_visible) {
279   AdvanceInvalidationHistory(frame_number);
280 
281   // We only need recording if we don't have a picture. Furthermore, we only
282   // need a recording if we're within frequent invalidation distance threshold
283   // or the invalidation is not frequent enough (below invalidation frequency
284   // threshold).
285   return !picture_ &&
286          ((distance_to_visible <= kFrequentInvalidationDistanceThreshold) ||
287           (GetInvalidationFrequency() < kInvalidationFrequencyThreshold));
288 }
289 
SetPicture(scoped_refptr<Picture> picture)290 void PicturePileBase::PictureInfo::SetPicture(scoped_refptr<Picture> picture) {
291   picture_ = picture;
292 }
293 
GetPicture() const294 Picture* PicturePileBase::PictureInfo::GetPicture() const {
295   return picture_.get();
296 }
297 
CloneForThread(int thread_index) const298 PicturePileBase::PictureInfo PicturePileBase::PictureInfo::CloneForThread(
299     int thread_index) const {
300   PictureInfo info = *this;
301   if (picture_.get())
302     info.picture_ = picture_->GetCloneForDrawingOnThread(thread_index);
303   return info;
304 }
305 
GetInvalidationFrequency() const306 float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
307   return invalidation_history_.count() /
308          static_cast<float>(INVALIDATION_FRAMES_TRACKED);
309 }
310 
311 }  // namespace cc
312