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
3 // found in the LICENSE file.
4
5 #include "cc/resources/picture_layer_tiling_set.h"
6
7 #include <limits>
8
9 namespace cc {
10
11 namespace {
12
13 class LargestToSmallestScaleFunctor {
14 public:
operator ()(PictureLayerTiling * left,PictureLayerTiling * right)15 bool operator() (PictureLayerTiling* left, PictureLayerTiling* right) {
16 return left->contents_scale() > right->contents_scale();
17 }
18 };
19
20 } // namespace
21
22
PictureLayerTilingSet(PictureLayerTilingClient * client,const gfx::Size & layer_bounds)23 PictureLayerTilingSet::PictureLayerTilingSet(
24 PictureLayerTilingClient* client,
25 const gfx::Size& layer_bounds)
26 : client_(client),
27 layer_bounds_(layer_bounds) {
28 }
29
~PictureLayerTilingSet()30 PictureLayerTilingSet::~PictureLayerTilingSet() {
31 }
32
SetClient(PictureLayerTilingClient * client)33 void PictureLayerTilingSet::SetClient(PictureLayerTilingClient* client) {
34 client_ = client;
35 for (size_t i = 0; i < tilings_.size(); ++i)
36 tilings_[i]->SetClient(client_);
37 }
38
RemoveTilesInRegion(const Region & region)39 void PictureLayerTilingSet::RemoveTilesInRegion(const Region& region) {
40 for (size_t i = 0; i < tilings_.size(); ++i)
41 tilings_[i]->RemoveTilesInRegion(region);
42 }
43
SyncTilings(const PictureLayerTilingSet & other,const gfx::Size & new_layer_bounds,const Region & layer_invalidation,float minimum_contents_scale)44 bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other,
45 const gfx::Size& new_layer_bounds,
46 const Region& layer_invalidation,
47 float minimum_contents_scale) {
48 if (new_layer_bounds.IsEmpty()) {
49 RemoveAllTilings();
50 layer_bounds_ = new_layer_bounds;
51 return false;
52 }
53
54 tilings_.reserve(other.tilings_.size());
55
56 // Remove any tilings that aren't in |other| or don't meet the minimum.
57 for (size_t i = 0; i < tilings_.size(); ++i) {
58 float scale = tilings_[i]->contents_scale();
59 if (scale >= minimum_contents_scale && !!other.TilingAtScale(scale))
60 continue;
61 // Swap with the last element and remove it.
62 tilings_.swap(tilings_.begin() + i, tilings_.end() - 1);
63 tilings_.pop_back();
64 --i;
65 }
66
67 bool have_high_res_tiling = false;
68
69 // Add any missing tilings from |other| that meet the minimum.
70 for (size_t i = 0; i < other.tilings_.size(); ++i) {
71 float contents_scale = other.tilings_[i]->contents_scale();
72 if (contents_scale < minimum_contents_scale)
73 continue;
74 if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
75 this_tiling->set_resolution(other.tilings_[i]->resolution());
76
77 this_tiling->UpdateTilesToCurrentPile(layer_invalidation,
78 new_layer_bounds);
79 this_tiling->CreateMissingTilesInLiveTilesRect();
80 if (this_tiling->resolution() == HIGH_RESOLUTION)
81 have_high_res_tiling = true;
82
83 DCHECK(this_tiling->tile_size() ==
84 client_->CalculateTileSize(this_tiling->tiling_size()))
85 << "tile_size: " << this_tiling->tile_size().ToString()
86 << " tiling_size: " << this_tiling->tiling_size().ToString()
87 << " CalculateTileSize: "
88 << client_->CalculateTileSize(this_tiling->tiling_size()).ToString();
89 continue;
90 }
91 scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
92 contents_scale,
93 new_layer_bounds,
94 client_);
95 new_tiling->set_resolution(other.tilings_[i]->resolution());
96 if (new_tiling->resolution() == HIGH_RESOLUTION)
97 have_high_res_tiling = true;
98 tilings_.push_back(new_tiling.Pass());
99 }
100 tilings_.sort(LargestToSmallestScaleFunctor());
101
102 layer_bounds_ = new_layer_bounds;
103 return have_high_res_tiling;
104 }
105
AddTiling(float contents_scale)106 PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) {
107 for (size_t i = 0; i < tilings_.size(); ++i)
108 DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
109
110 tilings_.push_back(PictureLayerTiling::Create(contents_scale,
111 layer_bounds_,
112 client_));
113 PictureLayerTiling* appended = tilings_.back();
114
115 tilings_.sort(LargestToSmallestScaleFunctor());
116 return appended;
117 }
118
NumHighResTilings() const119 int PictureLayerTilingSet::NumHighResTilings() const {
120 int num_high_res = 0;
121 for (size_t i = 0; i < tilings_.size(); ++i) {
122 if (tilings_[i]->resolution() == HIGH_RESOLUTION)
123 num_high_res++;
124 }
125 return num_high_res;
126 }
127
TilingAtScale(float scale) const128 PictureLayerTiling* PictureLayerTilingSet::TilingAtScale(float scale) const {
129 for (size_t i = 0; i < tilings_.size(); ++i) {
130 if (tilings_[i]->contents_scale() == scale)
131 return tilings_[i];
132 }
133 return NULL;
134 }
135
RemoveAllTilings()136 void PictureLayerTilingSet::RemoveAllTilings() {
137 tilings_.clear();
138 }
139
Remove(PictureLayerTiling * tiling)140 void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) {
141 ScopedPtrVector<PictureLayerTiling>::iterator iter =
142 std::find(tilings_.begin(), tilings_.end(), tiling);
143 if (iter == tilings_.end())
144 return;
145 tilings_.erase(iter);
146 }
147
RemoveAllTiles()148 void PictureLayerTilingSet::RemoveAllTiles() {
149 for (size_t i = 0; i < tilings_.size(); ++i)
150 tilings_[i]->Reset();
151 }
152
CoverageIterator(const PictureLayerTilingSet * set,float contents_scale,const gfx::Rect & content_rect,float ideal_contents_scale)153 PictureLayerTilingSet::CoverageIterator::CoverageIterator(
154 const PictureLayerTilingSet* set,
155 float contents_scale,
156 const gfx::Rect& content_rect,
157 float ideal_contents_scale)
158 : set_(set),
159 contents_scale_(contents_scale),
160 ideal_contents_scale_(ideal_contents_scale),
161 current_tiling_(-1) {
162 missing_region_.Union(content_rect);
163
164 for (ideal_tiling_ = 0;
165 static_cast<size_t>(ideal_tiling_) < set_->tilings_.size();
166 ++ideal_tiling_) {
167 PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_];
168 if (tiling->contents_scale() < ideal_contents_scale_) {
169 if (ideal_tiling_ > 0)
170 ideal_tiling_--;
171 break;
172 }
173 }
174
175 DCHECK_LE(set_->tilings_.size(),
176 static_cast<size_t>(std::numeric_limits<int>::max()));
177
178 int num_tilings = set_->tilings_.size();
179 if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0)
180 ideal_tiling_--;
181
182 ++(*this);
183 }
184
~CoverageIterator()185 PictureLayerTilingSet::CoverageIterator::~CoverageIterator() {
186 }
187
geometry_rect() const188 gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const {
189 if (!tiling_iter_) {
190 if (!region_iter_.has_rect())
191 return gfx::Rect();
192 return region_iter_.rect();
193 }
194 return tiling_iter_.geometry_rect();
195 }
196
texture_rect() const197 gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const {
198 if (!tiling_iter_)
199 return gfx::RectF();
200 return tiling_iter_.texture_rect();
201 }
202
texture_size() const203 gfx::Size PictureLayerTilingSet::CoverageIterator::texture_size() const {
204 if (!tiling_iter_)
205 return gfx::Size();
206 return tiling_iter_.texture_size();
207 }
208
operator ->() const209 Tile* PictureLayerTilingSet::CoverageIterator::operator->() const {
210 if (!tiling_iter_)
211 return NULL;
212 return *tiling_iter_;
213 }
214
operator *() const215 Tile* PictureLayerTilingSet::CoverageIterator::operator*() const {
216 if (!tiling_iter_)
217 return NULL;
218 return *tiling_iter_;
219 }
220
CurrentTiling()221 PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() {
222 if (current_tiling_ < 0)
223 return NULL;
224 if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size())
225 return NULL;
226 return set_->tilings_[current_tiling_];
227 }
228
NextTiling() const229 int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
230 // Order returned by this method is:
231 // 1. Ideal tiling index
232 // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
233 // 3. Tiling index > Ideal in increasing order (lower res than ideal)
234 // 4. Tiling index > tilings.size() (invalid index)
235 if (current_tiling_ < 0)
236 return ideal_tiling_;
237 else if (current_tiling_ > ideal_tiling_)
238 return current_tiling_ + 1;
239 else if (current_tiling_)
240 return current_tiling_ - 1;
241 else
242 return ideal_tiling_ + 1;
243 }
244
245 PictureLayerTilingSet::CoverageIterator&
operator ++()246 PictureLayerTilingSet::CoverageIterator::operator++() {
247 bool first_time = current_tiling_ < 0;
248
249 if (!*this && !first_time)
250 return *this;
251
252 if (tiling_iter_)
253 ++tiling_iter_;
254
255 // Loop until we find a valid place to stop.
256 while (true) {
257 while (tiling_iter_ &&
258 (!*tiling_iter_ || !tiling_iter_->IsReadyToDraw())) {
259 missing_region_.Union(tiling_iter_.geometry_rect());
260 ++tiling_iter_;
261 }
262 if (tiling_iter_)
263 return *this;
264
265 // If the set of current rects for this tiling is done, go to the next
266 // tiling and set up to iterate through all of the remaining holes.
267 // This will also happen the first time through the loop.
268 if (!region_iter_.has_rect()) {
269 current_tiling_ = NextTiling();
270 current_region_.Swap(&missing_region_);
271 missing_region_.Clear();
272 region_iter_ = Region::Iterator(current_region_);
273
274 // All done and all filled.
275 if (!region_iter_.has_rect()) {
276 current_tiling_ = set_->tilings_.size();
277 return *this;
278 }
279
280 // No more valid tiles, return this checkerboard rect.
281 if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
282 return *this;
283 }
284
285 // Pop a rect off. If there are no more tilings, then these will be
286 // treated as geometry with null tiles that the caller can checkerboard.
287 gfx::Rect last_rect = region_iter_.rect();
288 region_iter_.next();
289
290 // Done, found next checkerboard rect to return.
291 if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
292 return *this;
293
294 // Construct a new iterator for the next tiling, but we need to loop
295 // again until we get to a valid one.
296 tiling_iter_ = PictureLayerTiling::CoverageIterator(
297 set_->tilings_[current_tiling_],
298 contents_scale_,
299 last_rect);
300 }
301
302 return *this;
303 }
304
operator bool() const305 PictureLayerTilingSet::CoverageIterator::operator bool() const {
306 return current_tiling_ < static_cast<int>(set_->tilings_.size()) ||
307 region_iter_.has_rect();
308 }
309
DidBecomeActive()310 void PictureLayerTilingSet::DidBecomeActive() {
311 for (size_t i = 0; i < tilings_.size(); ++i)
312 tilings_[i]->DidBecomeActive();
313 }
314
DidBecomeRecycled()315 void PictureLayerTilingSet::DidBecomeRecycled() {
316 for (size_t i = 0; i < tilings_.size(); ++i)
317 tilings_[i]->DidBecomeRecycled();
318 }
319
AsValueInto(base::debug::TracedValue * state) const320 void PictureLayerTilingSet::AsValueInto(base::debug::TracedValue* state) const {
321 for (size_t i = 0; i < tilings_.size(); ++i) {
322 state->BeginDictionary();
323 tilings_[i]->AsValueInto(state);
324 state->EndDictionary();
325 }
326 }
327
GPUMemoryUsageInBytes() const328 size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
329 size_t amount = 0;
330 for (size_t i = 0; i < tilings_.size(); ++i)
331 amount += tilings_[i]->GPUMemoryUsageInBytes();
332 return amount;
333 }
334
GetTilingRange(TilingRangeType type) const335 PictureLayerTilingSet::TilingRange PictureLayerTilingSet::GetTilingRange(
336 TilingRangeType type) const {
337 // Doesn't seem to be the case right now but if it ever becomes a performance
338 // problem to compute these ranges each time this function is called, we can
339 // compute them only when the tiling set has changed instead.
340 TilingRange high_res_range(0, 0);
341 TilingRange low_res_range(tilings_.size(), tilings_.size());
342 for (size_t i = 0; i < tilings_.size(); ++i) {
343 const PictureLayerTiling* tiling = tilings_[i];
344 if (tiling->resolution() == HIGH_RESOLUTION)
345 high_res_range = TilingRange(i, i + 1);
346 if (tiling->resolution() == LOW_RESOLUTION)
347 low_res_range = TilingRange(i, i + 1);
348 }
349
350 switch (type) {
351 case HIGHER_THAN_HIGH_RES:
352 return TilingRange(0, high_res_range.start);
353 case HIGH_RES:
354 return high_res_range;
355 case BETWEEN_HIGH_AND_LOW_RES:
356 return TilingRange(high_res_range.end, low_res_range.start);
357 case LOW_RES:
358 return low_res_range;
359 case LOWER_THAN_LOW_RES:
360 return TilingRange(low_res_range.end, tilings_.size());
361 }
362
363 NOTREACHED();
364 return TilingRange(0, 0);
365 }
366
367 } // namespace cc
368