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