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: 15 bool operator() (PictureLayerTiling* left, PictureLayerTiling* right) { 16 return left->contents_scale() > right->contents_scale(); 17 } 18 }; 19 20 } // namespace 21 22 23 PictureLayerTilingSet::PictureLayerTilingSet( 24 PictureLayerTilingClient* client, 25 const gfx::Size& layer_bounds) 26 : client_(client), 27 layer_bounds_(layer_bounds) { 28 } 29 30 PictureLayerTilingSet::~PictureLayerTilingSet() { 31 } 32 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 39 void PictureLayerTilingSet::RemoveTilesInRegion(const Region& region) { 40 for (size_t i = 0; i < tilings_.size(); ++i) 41 tilings_[i]->RemoveTilesInRegion(region); 42 } 43 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 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 119 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 128 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 136 void PictureLayerTilingSet::RemoveAllTilings() { 137 tilings_.clear(); 138 } 139 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 148 void PictureLayerTilingSet::RemoveAllTiles() { 149 for (size_t i = 0; i < tilings_.size(); ++i) 150 tilings_[i]->Reset(); 151 } 152 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 185 PictureLayerTilingSet::CoverageIterator::~CoverageIterator() { 186 } 187 188 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 197 gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const { 198 if (!tiling_iter_) 199 return gfx::RectF(); 200 return tiling_iter_.texture_rect(); 201 } 202 203 gfx::Size PictureLayerTilingSet::CoverageIterator::texture_size() const { 204 if (!tiling_iter_) 205 return gfx::Size(); 206 return tiling_iter_.texture_size(); 207 } 208 209 Tile* PictureLayerTilingSet::CoverageIterator::operator->() const { 210 if (!tiling_iter_) 211 return NULL; 212 return *tiling_iter_; 213 } 214 215 Tile* PictureLayerTilingSet::CoverageIterator::operator*() const { 216 if (!tiling_iter_) 217 return NULL; 218 return *tiling_iter_; 219 } 220 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 229 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& 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 305 PictureLayerTilingSet::CoverageIterator::operator bool() const { 306 return current_tiling_ < static_cast<int>(set_->tilings_.size()) || 307 region_iter_.has_rect(); 308 } 309 310 void PictureLayerTilingSet::DidBecomeActive() { 311 for (size_t i = 0; i < tilings_.size(); ++i) 312 tilings_[i]->DidBecomeActive(); 313 } 314 315 void PictureLayerTilingSet::DidBecomeRecycled() { 316 for (size_t i = 0; i < tilings_.size(); ++i) 317 tilings_[i]->DidBecomeRecycled(); 318 } 319 320 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 328 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 335 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