picture_layer_tiling_set.cc revision 424c4d7b64af9d0d8fd9624f381f469654d5e3d2
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
9namespace cc {
10
11namespace {
12
13class 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
23PictureLayerTilingSet::PictureLayerTilingSet(
24    PictureLayerTilingClient* client,
25    gfx::Size layer_bounds)
26    : client_(client),
27      layer_bounds_(layer_bounds) {
28}
29
30PictureLayerTilingSet::~PictureLayerTilingSet() {
31}
32
33void PictureLayerTilingSet::SetClient(PictureLayerTilingClient* client) {
34  client_ = client;
35  for (size_t i = 0; i < tilings_.size(); ++i)
36    tilings_[i]->SetClient(client_);
37}
38
39void PictureLayerTilingSet::SyncTilings(
40    const PictureLayerTilingSet& other,
41    gfx::Size new_layer_bounds,
42    const Region& layer_invalidation,
43    float minimum_contents_scale) {
44  if (new_layer_bounds.IsEmpty()) {
45    RemoveAllTilings();
46    layer_bounds_ = new_layer_bounds;
47    return;
48  }
49
50  tilings_.reserve(other.tilings_.size());
51
52  // Remove any tilings that aren't in |other| or don't meet the minimum.
53  for (size_t i = 0; i < tilings_.size(); ++i) {
54    float scale = tilings_[i]->contents_scale();
55    if (scale >= minimum_contents_scale && !!other.TilingAtScale(scale))
56      continue;
57    // Swap with the last element and remove it.
58    tilings_.swap(tilings_.begin() + i, tilings_.end() - 1);
59    tilings_.pop_back();
60    --i;
61  }
62
63  // Add any missing tilings from |other| that meet the minimum.
64  for (size_t i = 0; i < other.tilings_.size(); ++i) {
65    float contents_scale = other.tilings_[i]->contents_scale();
66    if (contents_scale < minimum_contents_scale)
67      continue;
68    if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) {
69      this_tiling->set_resolution(other.tilings_[i]->resolution());
70
71      // These two calls must come before updating the pile, because they may
72      // destroy tiles that the new pile cannot raster.
73      this_tiling->SetLayerBounds(new_layer_bounds);
74      this_tiling->Invalidate(layer_invalidation);
75
76      this_tiling->UpdateTilesToCurrentPile();
77      this_tiling->CreateMissingTilesInLiveTilesRect();
78
79      DCHECK(this_tiling->tile_size() ==
80             client_->CalculateTileSize(this_tiling->ContentRect().size()));
81      continue;
82    }
83    scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create(
84        contents_scale,
85        new_layer_bounds,
86        client_);
87    new_tiling->set_resolution(other.tilings_[i]->resolution());
88    tilings_.push_back(new_tiling.Pass());
89  }
90  tilings_.sort(LargestToSmallestScaleFunctor());
91
92  layer_bounds_ = new_layer_bounds;
93}
94
95void PictureLayerTilingSet::SetCanUseLCDText(bool can_use_lcd_text) {
96  for (size_t i = 0; i < tilings_.size(); ++i)
97    tilings_[i]->SetCanUseLCDText(can_use_lcd_text);
98}
99
100PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) {
101  for (size_t i = 0; i < tilings_.size(); ++i)
102    DCHECK_NE(tilings_[i]->contents_scale(), contents_scale);
103
104  tilings_.push_back(PictureLayerTiling::Create(contents_scale,
105                                                layer_bounds_,
106                                                client_));
107  PictureLayerTiling* appended = tilings_.back();
108
109  tilings_.sort(LargestToSmallestScaleFunctor());
110  return appended;
111}
112
113int PictureLayerTilingSet::NumHighResTilings() const {
114  int num_high_res = 0;
115  for (size_t i = 0; i < tilings_.size(); ++i) {
116    if (tilings_[i]->resolution() == HIGH_RESOLUTION)
117      num_high_res++;
118  }
119  return num_high_res;
120}
121
122PictureLayerTiling* PictureLayerTilingSet::TilingAtScale(float scale) const {
123  for (size_t i = 0; i < tilings_.size(); ++i) {
124    if (tilings_[i]->contents_scale() == scale)
125      return tilings_[i];
126  }
127  return NULL;
128}
129
130void PictureLayerTilingSet::RemoveAllTilings() {
131  tilings_.clear();
132}
133
134void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) {
135  ScopedPtrVector<PictureLayerTiling>::iterator iter =
136    std::find(tilings_.begin(), tilings_.end(), tiling);
137  if (iter == tilings_.end())
138    return;
139  tilings_.erase(iter);
140}
141
142void PictureLayerTilingSet::RemoveAllTiles() {
143  for (size_t i = 0; i < tilings_.size(); ++i)
144    tilings_[i]->Reset();
145}
146
147PictureLayerTilingSet::CoverageIterator::CoverageIterator(
148    const PictureLayerTilingSet* set,
149    float contents_scale,
150    gfx::Rect content_rect,
151    float ideal_contents_scale)
152    : set_(set),
153      contents_scale_(contents_scale),
154      ideal_contents_scale_(ideal_contents_scale),
155      current_tiling_(-1) {
156  missing_region_.Union(content_rect);
157
158  for (ideal_tiling_ = 0;
159       static_cast<size_t>(ideal_tiling_) < set_->tilings_.size();
160       ++ideal_tiling_) {
161    PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_];
162    if (tiling->contents_scale() < ideal_contents_scale_) {
163      if (ideal_tiling_ > 0)
164        ideal_tiling_--;
165      break;
166    }
167  }
168
169  DCHECK_LE(set_->tilings_.size(),
170            static_cast<size_t>(std::numeric_limits<int>::max()));
171
172  int num_tilings = set_->tilings_.size();
173  if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0)
174    ideal_tiling_--;
175
176  ++(*this);
177}
178
179PictureLayerTilingSet::CoverageIterator::~CoverageIterator() {
180}
181
182gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const {
183  if (!tiling_iter_) {
184    if (!region_iter_.has_rect())
185      return gfx::Rect();
186    return region_iter_.rect();
187  }
188  return tiling_iter_.geometry_rect();
189}
190
191gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const {
192  if (!tiling_iter_)
193    return gfx::RectF();
194  return tiling_iter_.texture_rect();
195}
196
197gfx::Size PictureLayerTilingSet::CoverageIterator::texture_size() const {
198  if (!tiling_iter_)
199    return gfx::Size();
200  return tiling_iter_.texture_size();
201}
202
203Tile* PictureLayerTilingSet::CoverageIterator::operator->() const {
204  if (!tiling_iter_)
205    return NULL;
206  return *tiling_iter_;
207}
208
209Tile* PictureLayerTilingSet::CoverageIterator::operator*() const {
210  if (!tiling_iter_)
211    return NULL;
212  return *tiling_iter_;
213}
214
215PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() {
216  if (current_tiling_ < 0)
217    return NULL;
218  if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size())
219    return NULL;
220  return set_->tilings_[current_tiling_];
221}
222
223int PictureLayerTilingSet::CoverageIterator::NextTiling() const {
224  // Order returned by this method is:
225  // 1. Ideal tiling index
226  // 2. Tiling index < Ideal in decreasing order (higher res than ideal)
227  // 3. Tiling index > Ideal in increasing order (lower res than ideal)
228  // 4. Tiling index > tilings.size() (invalid index)
229  if (current_tiling_ < 0)
230    return ideal_tiling_;
231  else if (current_tiling_ > ideal_tiling_)
232    return current_tiling_ + 1;
233  else if (current_tiling_)
234    return current_tiling_ - 1;
235  else
236    return ideal_tiling_ + 1;
237}
238
239PictureLayerTilingSet::CoverageIterator&
240PictureLayerTilingSet::CoverageIterator::operator++() {
241  bool first_time = current_tiling_ < 0;
242
243  if (!*this && !first_time)
244    return *this;
245
246  if (tiling_iter_)
247    ++tiling_iter_;
248
249  // Loop until we find a valid place to stop.
250  while (true) {
251    while (tiling_iter_ &&
252           (!*tiling_iter_ || !tiling_iter_->IsReadyToDraw())) {
253      missing_region_.Union(tiling_iter_.geometry_rect());
254      ++tiling_iter_;
255    }
256    if (tiling_iter_)
257      return *this;
258
259    // If the set of current rects for this tiling is done, go to the next
260    // tiling and set up to iterate through all of the remaining holes.
261    // This will also happen the first time through the loop.
262    if (!region_iter_.has_rect()) {
263      current_tiling_ = NextTiling();
264      current_region_.Swap(&missing_region_);
265      missing_region_.Clear();
266      region_iter_ = Region::Iterator(current_region_);
267
268      // All done and all filled.
269      if (!region_iter_.has_rect()) {
270        current_tiling_ = set_->tilings_.size();
271        return *this;
272      }
273
274      // No more valid tiles, return this checkerboard rect.
275      if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
276        return *this;
277    }
278
279    // Pop a rect off.  If there are no more tilings, then these will be
280    // treated as geometry with null tiles that the caller can checkerboard.
281    gfx::Rect last_rect = region_iter_.rect();
282    region_iter_.next();
283
284    // Done, found next checkerboard rect to return.
285    if (current_tiling_ >= static_cast<int>(set_->tilings_.size()))
286      return *this;
287
288    // Construct a new iterator for the next tiling, but we need to loop
289    // again until we get to a valid one.
290    tiling_iter_ = PictureLayerTiling::CoverageIterator(
291        set_->tilings_[current_tiling_],
292        contents_scale_,
293        last_rect);
294  }
295
296  return *this;
297}
298
299PictureLayerTilingSet::CoverageIterator::operator bool() const {
300  return current_tiling_ < static_cast<int>(set_->tilings_.size()) ||
301      region_iter_.has_rect();
302}
303
304void PictureLayerTilingSet::UpdateTilePriorities(
305    WhichTree tree,
306    gfx::Size device_viewport,
307    gfx::Rect viewport_in_content_space,
308    gfx::Rect visible_content_rect,
309    gfx::Size last_layer_bounds,
310    gfx::Size current_layer_bounds,
311    float last_layer_contents_scale,
312    float current_layer_contents_scale,
313    const gfx::Transform& last_screen_transform,
314    const gfx::Transform& current_screen_transform,
315    double current_frame_time_in_seconds,
316    size_t max_tiles_for_interest_area) {
317  gfx::Rect viewport_in_layer_space = gfx::ScaleToEnclosingRect(
318      viewport_in_content_space,
319      1.f / current_layer_contents_scale);
320  gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
321      visible_content_rect,
322      1.f / current_layer_contents_scale);
323
324  for (size_t i = 0; i < tilings_.size(); ++i) {
325    tilings_[i]->UpdateTilePriorities(
326        tree,
327        device_viewport,
328        viewport_in_layer_space,
329        visible_layer_rect,
330        last_layer_bounds,
331        current_layer_bounds,
332        last_layer_contents_scale,
333        current_layer_contents_scale,
334        last_screen_transform,
335        current_screen_transform,
336        current_frame_time_in_seconds,
337        max_tiles_for_interest_area);
338  }
339}
340
341void PictureLayerTilingSet::DidBecomeActive() {
342  for (size_t i = 0; i < tilings_.size(); ++i)
343    tilings_[i]->DidBecomeActive();
344}
345
346scoped_ptr<base::Value> PictureLayerTilingSet::AsValue() const {
347  scoped_ptr<base::ListValue> state(new base::ListValue());
348  for (size_t i = 0; i < tilings_.size(); ++i)
349    state->Append(tilings_[i]->AsValue().release());
350  return state.PassAs<base::Value>();
351}
352
353size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const {
354  size_t amount = 0;
355  for (size_t i = 0; i < tilings_.size(); ++i)
356    amount += tilings_[i]->GPUMemoryUsageInBytes();
357  return amount;
358}
359
360}  // namespace cc
361