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.
5 #include "cc/resources/picture_pile_base.h"
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"
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;
24 const bool kDefaultClearCanvasSetting
= false;
26 const bool kDefaultClearCanvasSetting
= true;
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;
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();
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_
) {}
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();
88 picture_map_
[it
->first
] = it
->second
.CloneForThread(thread_index
);
92 PicturePileBase::~PicturePileBase() {
95 void PicturePileBase::SetTilingRect(const gfx::Rect
& new_tiling_rect
) {
96 if (tiling_rect() == new_tiling_rect
)
99 gfx::Rect old_tiling_rect
= tiling_rect();
100 tiling_
.SetTilingRect(new_tiling_rect
);
102 has_any_recordings_
= false;
104 // Don't waste time in Resize figuring out what these hints should be.
105 recorded_viewport_
= gfx::Rect();
107 if (new_tiling_rect
.origin() != old_tiling_rect
.origin()) {
108 picture_map_
.clear();
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();
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();
126 to_erase
.push_back(key
);
129 for (size_t i
= 0; i
< to_erase
.size(); ++i
)
130 picture_map_
.erase(to_erase
[i
]);
133 void PicturePileBase::SetMinContentsScale(float min_contents_scale
) {
134 DCHECK(min_contents_scale
);
135 if (min_contents_scale_
== min_contents_scale
)
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
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
;
155 void PicturePileBase::ComputeTileGridInfo(
156 const gfx::Size
& tile_grid_size
,
157 SkTileGridFactory::TileGridInfo
* 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
167 info
->fOffset
.set(-kTileGridBorderPixels
, -kTileGridBorderPixels
);
170 void PicturePileBase::SetTileGridSize(const gfx::Size
& tile_grid_size
) {
171 ComputeTileGridInfo(tile_grid_size
, &tile_grid_info_
);
174 void PicturePileBase::SetBufferPixels(int new_buffer_pixels
) {
175 if (new_buffer_pixels
== buffer_pixels())
179 tiling_
.SetBorderTexels(new_buffer_pixels
);
182 void PicturePileBase::Clear() {
183 picture_map_
.clear();
184 recorded_viewport_
= gfx::Rect();
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())
191 return !!found
->second
.GetPicture();
194 bool PicturePileBase::CanRaster(float contents_scale
,
195 const gfx::Rect
& content_rect
) {
196 if (tiling_
.tiling_rect().IsEmpty())
198 gfx::Rect layer_rect
= gfx::ScaleToEnclosingRect(
199 content_rect
, 1.f
/ contents_scale
);
200 layer_rect
.Intersect(tiling_
.tiling_rect());
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
));
209 return CanRasterSlowTileCheck(layer_rect
);
212 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
);
218 PictureMap::const_iterator map_iter
= picture_map_
.find(tile_iter
.index());
219 if (map_iter
== picture_map_
.end())
221 if (!map_iter
->second
.GetPicture())
227 gfx::Rect
PicturePileBase::PaddedRect(const PictureMapKey
& key
) {
228 gfx::Rect tile
= tiling_
.TileBounds(key
.first
, key
.second
);
229 return PadRect(tile
);
232 gfx::Rect
PicturePileBase::PadRect(const gfx::Rect
& rect
) {
233 gfx::Rect padded_rect
= rect
;
235 -buffer_pixels(), -buffer_pixels(), -buffer_pixels(), -buffer_pixels());
239 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
);
247 PictureMap::const_iterator map_iter
= picture_map_
.find(tile_iter
.index());
248 if (map_iter
== picture_map_
.end())
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());
257 return pictures
.PassAs
<base::Value
>();
260 PicturePileBase::PictureInfo::PictureInfo() : last_frame_number_(0) {}
262 PicturePileBase::PictureInfo::~PictureInfo() {}
264 void PicturePileBase::PictureInfo::AdvanceInvalidationHistory(
266 DCHECK_GE(frame_number
, last_frame_number_
);
267 if (frame_number
== last_frame_number_
)
270 invalidation_history_
<<= (frame_number
- last_frame_number_
);
271 last_frame_number_
= frame_number
;
274 bool PicturePileBase::PictureInfo::Invalidate(int frame_number
) {
275 AdvanceInvalidationHistory(frame_number
);
276 invalidation_history_
.set(0);
278 bool did_invalidate
= !!picture_
;
280 return did_invalidate
;
283 bool PicturePileBase::PictureInfo::NeedsRecording(int frame_number
,
284 int distance_to_visible
) {
285 AdvanceInvalidationHistory(frame_number
);
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
292 ((distance_to_visible
<= kFrequentInvalidationDistanceThreshold
) ||
293 (GetInvalidationFrequency() < kInvalidationFrequencyThreshold
));
296 void PicturePileBase::PictureInfo::SetPicture(scoped_refptr
<Picture
> picture
) {
300 Picture
* PicturePileBase::PictureInfo::GetPicture() const {
301 return picture_
.get();
304 PicturePileBase::PictureInfo
PicturePileBase::PictureInfo::CloneForThread(
305 int thread_index
) const {
306 PictureInfo info
= *this;
308 info
.picture_
= picture_
->GetCloneForDrawingOnThread(thread_index
);
312 float PicturePileBase::PictureInfo::GetInvalidationFrequency() const {
313 return invalidation_history_
.count() /
314 static_cast<float>(INVALIDATION_FRAMES_TRACKED
);