OLD | NEW |
---|---|
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 1 // Copyright 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/resources/picture_pile.h" | 5 #include "cc/resources/picture_pile.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "cc/base/region.h" | 11 #include "cc/base/region.h" |
12 #include "cc/debug/rendering_stats_instrumentation.h" | 12 #include "cc/debug/rendering_stats_instrumentation.h" |
13 #include "cc/resources/picture_pile_impl.h" | 13 #include "cc/resources/picture_pile_impl.h" |
14 | 14 |
15 namespace { | 15 namespace { |
16 // Layout pixel buffer around the visible layer rect to record. Any base | 16 // Layout pixel buffer around the visible layer rect to record. Any base |
17 // picture that intersects the visible layer rect expanded by this distance | 17 // picture that intersects the visible layer rect expanded by this distance |
18 // will be recorded. | 18 // will be recorded. |
19 const int kPixelDistanceToRecord = 8000; | 19 const int kPixelDistanceToRecord = 8000; |
20 } // namespace | 20 } // namespace |
21 | 21 |
22 namespace cc { | 22 namespace cc { |
23 | 23 |
24 PicturePile::PicturePile() { | 24 PicturePile::PicturePile() { |
25 } | 25 } |
26 | 26 |
27 PicturePile::~PicturePile() { | 27 PicturePile::~PicturePile() { |
28 } | 28 } |
29 | 29 |
30 static bool rect_sort_y(const gfx::Rect &r1, const gfx::Rect &r2) { | |
31 return r1.y() < r2.y(); | |
32 } | |
33 | |
34 static bool rect_sort_x(const gfx::Rect &r1, const gfx::Rect &r2) { | |
35 return r1.x() < r2.x(); | |
36 } | |
37 | |
38 class TileClustering { | |
vmpstr
2013/11/20 18:02:32
Why is this a separate class? Since all of the int
humper
2013/11/20 20:47:13
No particular reason; I had initially imagined it
| |
39 public: | |
40 TileClustering(const std::vector<gfx::Rect> &tiles, float thresh) | |
vmpstr
2013/11/20 18:02:32
nit: spacing (vector<...>& tiles) and don't abbrev
humper
2013/11/20 20:47:13
Done.
| |
41 : total_record_area(0), | |
42 invalid_record_area(0), | |
43 clustering_threshold(thresh) { | |
44 gfx::Rect cur_record_rect; | |
45 int total_area = 0, invalid_area = 0; | |
46 | |
47 for (std::vector<gfx::Rect>::iterator it = tiles.begin(); | |
humper
2013/11/21 18:49:29
Heh, that's what I get for not testing before doin
| |
48 it != tiles.end(); | |
49 it++) { | |
50 gfx::Rect invalid_tile = *it; | |
51 | |
52 // consider adding the invalid tile to the current record | |
53 // rectangle. Only add it if the amount of empty space created is | |
54 // below a density threshold. | |
55 | |
56 int tile_area = invalid_tile.width() * invalid_tile.height(); | |
57 | |
58 gfx::Rect proposed_union = cur_record_rect; | |
59 proposed_union.Union(invalid_tile); | |
60 int proposed_area = proposed_union.width() * proposed_union.height(); | |
61 float proposed_density = | |
62 static_cast<float>(invalid_area + tile_area) / | |
63 static_cast<float>(proposed_area); | |
64 | |
65 if (proposed_density >= clustering_threshold) { | |
vmpstr
2013/11/20 18:02:32
What happens in the case where we have a full row
humper
2013/11/20 20:47:13
This is partially an artifact of the greedy cluste
| |
66 // okay to add this invalid tile to the current recording rectangle | |
67 | |
68 cur_record_rect = proposed_union; | |
69 total_area = proposed_area; | |
70 invalid_area += tile_area; | |
71 invalid_record_area += tile_area; | |
72 } else { | |
73 // adding this invalid tile to the current recording rectangle | |
74 // would exceed our badness threshold, so put the current rectangle | |
75 // in the list of recording rects, and start a new one. | |
76 | |
77 record_rects.push_back(cur_record_rect); | |
78 total_record_area += total_area; | |
79 cur_record_rect = invalid_tile; | |
80 invalid_area = tile_area; | |
81 total_area = tile_area; | |
82 } | |
83 } | |
84 | |
85 if (!cur_record_rect.IsEmpty()) { | |
86 record_rects.push_back(cur_record_rect); | |
87 total_record_area += total_area; | |
88 } | |
89 } | |
90 std::vector<gfx::Rect> getRecordRects() const { | |
91 return record_rects; | |
92 } | |
93 | |
94 float density() const { | |
95 if (total_record_area == 0) | |
96 return 1; | |
97 return static_cast<float>(invalid_record_area) / | |
98 static_cast<float>(total_record_area); | |
99 } | |
100 | |
101 private: | |
102 std::vector<gfx::Rect> record_rects; | |
vmpstr
2013/11/20 18:02:32
nit: we typically name private members with a trai
humper
2013/11/20 20:47:13
Done.
| |
103 int total_record_area; | |
104 int invalid_record_area; | |
105 float clustering_threshold; | |
106 }; | |
107 | |
30 bool PicturePile::Update( | 108 bool PicturePile::Update( |
31 ContentLayerClient* painter, | 109 ContentLayerClient* painter, |
32 SkColor background_color, | 110 SkColor background_color, |
33 bool contents_opaque, | 111 bool contents_opaque, |
34 const Region& invalidation, | 112 const Region& invalidation, |
35 gfx::Rect visible_layer_rect, | 113 gfx::Rect visible_layer_rect, |
36 RenderingStatsInstrumentation* stats_instrumentation) { | 114 RenderingStatsInstrumentation* stats_instrumentation) { |
37 background_color_ = background_color; | 115 background_color_ = background_color; |
38 contents_opaque_ = contents_opaque; | 116 contents_opaque_ = contents_opaque; |
39 | 117 |
(...skipping 14 matching lines...) Expand all Loading... | |
54 const PictureMapKey& key = iter.index(); | 132 const PictureMapKey& key = iter.index(); |
55 | 133 |
56 PictureMap::iterator picture_it = picture_map_.find(key); | 134 PictureMap::iterator picture_it = picture_map_.find(key); |
57 if (picture_it == picture_map_.end()) | 135 if (picture_it == picture_map_.end()) |
58 continue; | 136 continue; |
59 | 137 |
60 invalidated = picture_it->second.Invalidate() || invalidated; | 138 invalidated = picture_it->second.Invalidate() || invalidated; |
61 } | 139 } |
62 } | 140 } |
63 | 141 |
64 gfx::Rect record_rect; | 142 // make a list of all invalid tiles; we will attempt to |
143 // cluster these into multiple invalidation regions. | |
144 | |
vmpstr
2013/11/20 18:02:32
nit: remove this line (and most trailing blank lin
humper
2013/11/20 20:47:13
Done.
| |
145 std::vector<gfx::Rect> invalid_tiles; | |
146 | |
65 for (TilingData::Iterator it(&tiling_, interest_rect); | 147 for (TilingData::Iterator it(&tiling_, interest_rect); |
66 it; ++it) { | 148 it; ++it) { |
67 const PictureMapKey& key = it.index(); | 149 const PictureMapKey& key = it.index(); |
68 const PictureInfo& info = picture_map_[key]; | 150 const PictureInfo& info = picture_map_[key]; |
69 if (!info.picture.get()) { | 151 if (!info.picture.get()) { |
70 gfx::Rect tile = PaddedRect(key); | 152 gfx::Rect tile = tiling_.TileBounds(key.first, key.second); |
71 record_rect.Union(tile); | 153 invalid_tiles.push_back(tile); |
72 } | 154 } |
73 } | 155 } |
74 | 156 |
75 if (record_rect.IsEmpty()) { | 157 std::vector<gfx::Rect> record_rects; |
158 | |
159 if (invalid_tiles.size() == 1) { | |
vmpstr
2013/11/20 18:02:32
Maybe make this a helper function, something along
humper
2013/11/20 20:47:13
will do.
| |
160 // special case for common single-invalidation update | |
161 record_rects = invalid_tiles; | |
162 } else { | |
163 // sort the invalid tiles by y coordinate. | |
164 | |
165 std::vector<gfx::Rect> invalid_tiles_vertical = invalid_tiles; | |
166 std::sort(invalid_tiles_vertical.begin(), | |
vmpstr
2013/11/20 18:02:32
Assuming that the sort totally ignores the other c
humper
2013/11/20 20:47:13
better sort would help with this, although groupin
| |
167 invalid_tiles_vertical.end(), | |
168 rect_sort_y); | |
169 // Note: density here is somewhat arbitrary; need a way to set | |
170 // this from the command line so we can write a benchmark script | |
171 // and find a sweet spot. | |
172 TileClustering vertical_clustering(invalid_tiles_vertical, 0.5); | |
vmpstr
2013/11/20 18:02:32
nit: Make density a constant at the top please, an
humper
2013/11/20 20:47:13
Yeah, absolutely -- wasn't sure the best way to ma
| |
173 | |
174 std::vector<gfx::Rect> invalid_tiles_horizontal = invalid_tiles; | |
175 std::sort(invalid_tiles_vertical.begin(), | |
176 invalid_tiles_vertical.end(), | |
177 rect_sort_x); | |
178 TileClustering horizontal_clustering(invalid_tiles_vertical, 0.5); | |
enne (OOO)
2013/11/20 19:15:33
Is it expensive to sort and walk through all the i
humper
2013/11/20 20:47:13
Not abandoned, just not done yet. There are a cou
| |
179 | |
180 if (vertical_clustering.density() < horizontal_clustering.density()) { | |
181 record_rects = horizontal_clustering.getRecordRects(); | |
182 } else { | |
183 record_rects = vertical_clustering.getRecordRects(); | |
184 } | |
185 } | |
186 | |
187 if (record_rects.empty()) { | |
76 if (invalidated) | 188 if (invalidated) |
77 UpdateRecordedRegion(); | 189 UpdateRecordedRegion(); |
78 return invalidated; | 190 return invalidated; |
79 } | 191 } |
80 | 192 |
81 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); | 193 for (std::vector<gfx::Rect>::iterator it = record_rects.begin(); |
82 scoped_refptr<Picture> picture = Picture::Create(record_rect); | 194 it != record_rects.end(); |
195 it++) { | |
196 gfx::Rect record_rect = *it; | |
197 record_rect.Inset(-buffer_pixels(), -buffer_pixels(), | |
198 -buffer_pixels(), -buffer_pixels()); | |
83 | 199 |
84 { | 200 int repeat_count = std::max(1, slow_down_raster_scale_factor_for_debug_); |
85 base::TimeDelta best_duration = base::TimeDelta::FromInternalValue( | 201 scoped_refptr<Picture> picture = Picture::Create(record_rect); |
86 std::numeric_limits<int64>::max()); | 202 |
87 for (int i = 0; i < repeat_count; i++) { | 203 { |
88 base::TimeTicks start_time = stats_instrumentation->StartRecording(); | 204 base::TimeDelta best_duration = base::TimeDelta::FromInternalValue( |
89 picture->Record(painter, tile_grid_info_); | 205 std::numeric_limits<int64>::max()); |
90 base::TimeDelta duration = | 206 for (int i = 0; i < repeat_count; i++) { |
91 stats_instrumentation->EndRecording(start_time); | 207 base::TimeTicks start_time = stats_instrumentation->StartRecording(); |
92 best_duration = std::min(duration, best_duration); | 208 picture->Record(painter, tile_grid_info_); |
209 base::TimeDelta duration = | |
210 stats_instrumentation->EndRecording(start_time); | |
211 best_duration = std::min(duration, best_duration); | |
212 } | |
213 int recorded_pixel_count = | |
214 picture->LayerRect().width() * picture->LayerRect().height(); | |
215 stats_instrumentation->AddRecord(best_duration, recorded_pixel_count); | |
216 if (num_raster_threads_ > 1) | |
217 picture->GatherPixelRefs(tile_grid_info_); | |
218 picture->CloneForDrawing(num_raster_threads_); | |
93 } | 219 } |
94 int recorded_pixel_count = | |
95 picture->LayerRect().width() * picture->LayerRect().height(); | |
96 stats_instrumentation->AddRecord(best_duration, recorded_pixel_count); | |
97 if (num_raster_threads_ > 1) | |
98 picture->GatherPixelRefs(tile_grid_info_); | |
99 picture->CloneForDrawing(num_raster_threads_); | |
100 } | |
101 | 220 |
102 for (TilingData::Iterator it(&tiling_, record_rect); | 221 for (TilingData::Iterator it(&tiling_, record_rect); |
103 it; ++it) { | 222 it; ++it) { |
104 const PictureMapKey& key = it.index(); | 223 const PictureMapKey& key = it.index(); |
105 gfx::Rect tile = PaddedRect(key); | 224 gfx::Rect tile = PaddedRect(key); |
106 if (record_rect.Contains(tile)) { | 225 if (record_rect.Contains(tile)) { |
107 PictureInfo& info = picture_map_[key]; | 226 PictureInfo& info = picture_map_[key]; |
108 info.picture = picture; | 227 info.picture = picture; |
228 } | |
109 } | 229 } |
110 } | 230 } |
111 | 231 |
112 UpdateRecordedRegion(); | 232 UpdateRecordedRegion(); |
113 return true; | 233 return true; |
114 } | 234 } |
115 | 235 |
116 } // namespace cc | 236 } // namespace cc |
OLD | NEW |