Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(198)

Side by Side Diff: cc/tiled_layer.cc

Issue 12603013: Part 10 of cc/ directory shuffles: layers (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « cc/tiled_layer.h ('k') | cc/tiled_layer_impl.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2011 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/tiled_layer.h"
6
7 #include "base/auto_reset.h"
8 #include "base/basictypes.h"
9 #include "build/build_config.h"
10 #include "cc/debug/overdraw_metrics.h"
11 #include "cc/layer_impl.h"
12 #include "cc/resources/layer_updater.h"
13 #include "cc/resources/prioritized_resource.h"
14 #include "cc/resources/priority_calculator.h"
15 #include "cc/tiled_layer_impl.h"
16 #include "cc/trees/layer_tree_host.h"
17 #include "third_party/khronos/GLES2/gl2.h"
18 #include "ui/gfx/rect_conversions.h"
19
20 namespace cc {
21
22 // Maximum predictive expansion of the visible area.
23 static const int kMaxPredictiveTilesCount = 2;
24
25 // Number of rows/columns of tiles to pre-paint.
26 // We should increase these further as all textures are
27 // prioritized and we insure performance doesn't suffer.
28 static const int kPrepaintRows = 4;
29 static const int kPrepaintColumns = 2;
30
31 class UpdatableTile : public LayerTilingData::Tile {
32 public:
33 static scoped_ptr<UpdatableTile> Create(
34 scoped_ptr<LayerUpdater::Resource> updater_resource) {
35 return make_scoped_ptr(new UpdatableTile(updater_resource.Pass()));
36 }
37
38 LayerUpdater::Resource* updater_resource() { return updater_resource_.get(); }
39 PrioritizedResource* managed_resource() {
40 return updater_resource_->texture();
41 }
42
43 bool is_dirty() const { return !dirty_rect.IsEmpty(); }
44
45 // Reset update state for the current frame. This should occur before painting
46 // for all layers. Since painting one layer can invalidate another layer after
47 // it has already painted, mark all non-dirty tiles as valid before painting
48 // such that invalidations during painting won't prevent them from being
49 // pushed.
50 void ResetUpdateState() {
51 update_rect = gfx::Rect();
52 occluded = false;
53 partial_update = false;
54 valid_for_frame = !is_dirty();
55 }
56
57 // This promises to update the tile and therefore also guarantees the tile
58 // will be valid for this frame. dirty_rect is copied into update_rect so we
59 // can continue to track re-entrant invalidations that occur during painting.
60 void MarkForUpdate() {
61 valid_for_frame = true;
62 update_rect = dirty_rect;
63 dirty_rect = gfx::Rect();
64 }
65
66 gfx::Rect dirty_rect;
67 gfx::Rect update_rect;
68 bool partial_update;
69 bool valid_for_frame;
70 bool occluded;
71
72 private:
73 explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updater_resource)
74 : partial_update(false),
75 valid_for_frame(false),
76 occluded(false),
77 updater_resource_(updater_resource.Pass()) {}
78
79 scoped_ptr<LayerUpdater::Resource> updater_resource_;
80
81 DISALLOW_COPY_AND_ASSIGN(UpdatableTile);
82 };
83
84 TiledLayer::TiledLayer()
85 : ContentsScalingLayer(),
86 texture_format_(GL_INVALID_ENUM),
87 skips_draw_(false),
88 failed_update_(false),
89 tiling_option_(AUTO_TILE) {
90 tiler_ =
91 LayerTilingData::Create(gfx::Size(), LayerTilingData::HAS_BORDER_TEXELS);
92 }
93
94 TiledLayer::~TiledLayer() {}
95
96 scoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
97 return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
98 }
99
100 void TiledLayer::UpdateTileSizeAndTilingOption() {
101 DCHECK(layer_tree_host());
102
103 gfx::Size default_tile_size = layer_tree_host()->settings().defaultTileSize;
104 gfx::Size max_untiled_layer_size =
105 layer_tree_host()->settings().maxUntiledLayerSize;
106 int layer_width = content_bounds().width();
107 int layer_height = content_bounds().height();
108
109 gfx::Size tile_size(std::min(default_tile_size.width(), layer_width),
110 std::min(default_tile_size.height(), layer_height));
111
112 // Tile if both dimensions large, or any one dimension large and the other
113 // extends into a second tile but the total layer area isn't larger than that
114 // of the largest possible untiled layer. This heuristic allows for long
115 // skinny layers (e.g. scrollbars) that are Nx1 tiles to minimize wasted
116 // texture space but still avoids creating very large tiles.
117 bool any_dimension_large = layer_width > max_untiled_layer_size.width() ||
118 layer_height > max_untiled_layer_size.height();
119 bool any_dimension_one_tile =
120 (layer_width <= default_tile_size.width() ||
121 layer_height <= default_tile_size.height()) &&
122 (layer_width * layer_height) <= (max_untiled_layer_size.width() *
123 max_untiled_layer_size.height());
124 bool auto_tiled = any_dimension_large && !any_dimension_one_tile;
125
126 bool is_tiled;
127 if (tiling_option_ == ALWAYS_TILE)
128 is_tiled = true;
129 else if (tiling_option_ == NEVER_TILE)
130 is_tiled = false;
131 else
132 is_tiled = auto_tiled;
133
134 gfx::Size requested_size = is_tiled ? tile_size : content_bounds();
135 const int max_size =
136 layer_tree_host()->GetRendererCapabilities().max_texture_size;
137 requested_size.ClampToMax(gfx::Size(max_size, max_size));
138 SetTileSize(requested_size);
139 }
140
141 void TiledLayer::UpdateBounds() {
142 gfx::Size old_bounds = tiler_->bounds();
143 gfx::Size new_bounds = content_bounds();
144 if (old_bounds == new_bounds)
145 return;
146 tiler_->SetBounds(new_bounds);
147
148 // Invalidate any areas that the new bounds exposes.
149 Region old_region = gfx::Rect(gfx::Point(), old_bounds);
150 Region new_region = gfx::Rect(gfx::Point(), new_bounds);
151 new_region.Subtract(old_region);
152 for (Region::Iterator new_rects(new_region);
153 new_rects.has_rect();
154 new_rects.next())
155 InvalidateContentRect(new_rects.rect());
156 }
157
158 void TiledLayer::SetTileSize(gfx::Size size) { tiler_->SetTileSize(size); }
159
160 void TiledLayer::SetBorderTexelOption(
161 LayerTilingData::BorderTexelOption border_texel_option) {
162 tiler_->SetBorderTexelOption(border_texel_option);
163 }
164
165 bool TiledLayer::DrawsContent() const {
166 if (!ContentsScalingLayer::DrawsContent())
167 return false;
168
169 bool has_more_than_one_tile =
170 tiler_->num_tiles_x() > 1 || tiler_->num_tiles_y() > 1;
171 if (tiling_option_ == NEVER_TILE && has_more_than_one_tile)
172 return false;
173
174 return true;
175 }
176
177 void TiledLayer::SetIsMask(bool is_mask) {
178 set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
179 }
180
181 void TiledLayer::PushPropertiesTo(LayerImpl* layer) {
182 ContentsScalingLayer::PushPropertiesTo(layer);
183
184 TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
185
186 tiled_layer->set_skips_draw(skips_draw_);
187 tiled_layer->SetTilingData(*tiler_);
188 std::vector<UpdatableTile*> invalid_tiles;
189
190 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
191 iter != tiler_->tiles().end();
192 ++iter) {
193 int i = iter->first.first;
194 int j = iter->first.second;
195 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
196 // FIXME: This should not ever be null.
197 if (!tile)
198 continue;
199
200 if (!tile->managed_resource()->haveBackingTexture()) {
201 // Evicted tiles get deleted from both layers
202 invalid_tiles.push_back(tile);
203 continue;
204 }
205
206 if (!tile->valid_for_frame) {
207 // Invalidated tiles are set so they can get different debug colors.
208 tiled_layer->PushInvalidTile(i, j);
209 continue;
210 }
211
212 tiled_layer->PushTileProperties(
213 i,
214 j,
215 tile->managed_resource()->resourceId(),
216 tile->opaque_rect(),
217 tile->managed_resource()->contentsSwizzled());
218 }
219 for (std::vector<UpdatableTile*>::const_iterator iter = invalid_tiles.begin();
220 iter != invalid_tiles.end();
221 ++iter)
222 tiler_->TakeTile((*iter)->i(), (*iter)->j());
223 }
224
225 bool TiledLayer::BlocksPendingCommit() const { return true; }
226
227 PrioritizedResourceManager* TiledLayer::ResourceManager() const {
228 if (!layer_tree_host())
229 return NULL;
230 return layer_tree_host()->contents_texture_manager();
231 }
232
233 const PrioritizedResource* TiledLayer::ResourceAtForTesting(int i,
234 int j) const {
235 UpdatableTile* tile = TileAt(i, j);
236 if (!tile)
237 return NULL;
238 return tile->managed_resource();
239 }
240
241 void TiledLayer::SetLayerTreeHost(LayerTreeHost* host) {
242 if (host && host != layer_tree_host()) {
243 for (LayerTilingData::TileMap::const_iterator
244 iter = tiler_->tiles().begin();
245 iter != tiler_->tiles().end();
246 ++iter) {
247 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
248 // FIXME: This should not ever be null.
249 if (!tile)
250 continue;
251 tile->managed_resource()->setTextureManager(
252 host->contents_texture_manager());
253 }
254 }
255 ContentsScalingLayer::SetLayerTreeHost(host);
256 }
257
258 UpdatableTile* TiledLayer::TileAt(int i, int j) const {
259 return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
260 }
261
262 UpdatableTile* TiledLayer::CreateTile(int i, int j) {
263 CreateUpdaterIfNeeded();
264
265 scoped_ptr<UpdatableTile> tile(
266 UpdatableTile::Create(Updater()->CreateResource(ResourceManager())));
267 tile->managed_resource()->setDimensions(tiler_->tile_size(), texture_format_);
268
269 UpdatableTile* added_tile = tile.get();
270 tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);
271
272 added_tile->dirty_rect = tiler_->TileRect(added_tile);
273
274 // Temporary diagnostic crash.
275 CHECK(added_tile);
276 CHECK(TileAt(i, j));
277
278 return added_tile;
279 }
280
281 void TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
282 InvalidateContentRect(LayerRectToContentRect(dirty_rect));
283 ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
284 }
285
286 void TiledLayer::InvalidateContentRect(gfx::Rect content_rect) {
287 UpdateBounds();
288 if (tiler_->is_empty() || content_rect.IsEmpty() || skips_draw_)
289 return;
290
291 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
292 iter != tiler_->tiles().end();
293 ++iter) {
294 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
295 DCHECK(tile);
296 // FIXME: This should not ever be null.
297 if (!tile)
298 continue;
299 gfx::Rect bound = tiler_->TileRect(tile);
300 bound.Intersect(content_rect);
301 tile->dirty_rect.Union(bound);
302 }
303 }
304
305 // Returns true if tile is dirty and only part of it needs to be updated.
306 bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
307 return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
308 tile->managed_resource()->haveBackingTexture();
309 }
310
311 bool TiledLayer::UpdateTiles(int left,
312 int top,
313 int right,
314 int bottom,
315 ResourceUpdateQueue* queue,
316 const OcclusionTracker* occlusion,
317 RenderingStats* stats,
318 bool* did_paint) {
319 *did_paint = false;
320 CreateUpdaterIfNeeded();
321
322 bool ignore_occlusions = !occlusion;
323 if (!HaveTexturesForTiles(left, top, right, bottom, ignore_occlusions)) {
324 failed_update_ = true;
325 return false;
326 }
327
328 gfx::Rect paint_rect =
329 MarkTilesForUpdate(left, top, right, bottom, ignore_occlusions);
330
331 if (occlusion)
332 occlusion->overdraw_metrics()->DidPaint(paint_rect);
333
334 if (paint_rect.IsEmpty())
335 return true;
336
337 *did_paint = true;
338 UpdateTileTextures(
339 paint_rect, left, top, right, bottom, queue, occlusion, stats);
340 return true;
341 }
342
343 void TiledLayer::MarkOcclusionsAndRequestTextures(
344 int left,
345 int top,
346 int right,
347 int bottom,
348 const OcclusionTracker* occlusion) {
349 // There is some difficult dependancies between occlusions, recording
350 // occlusion metrics and requesting memory so those are encapsulated in this
351 // function: - We only want to call RequestLate on unoccluded textures (to
352 // preserve memory for other layers when near OOM). - We only want to record
353 // occlusion metrics if all memory requests succeed.
354
355 int occluded_tile_count = 0;
356 bool succeeded = true;
357 for (int j = top; j <= bottom; ++j) {
358 for (int i = left; i <= right; ++i) {
359 UpdatableTile* tile = TileAt(i, j);
360 DCHECK(tile); // Did SetTexturePriorities get skipped?
361 // FIXME: This should not ever be null.
362 if (!tile)
363 continue;
364 // Did ResetUpdateState get skipped? Are we doing more than one occlusion
365 // pass?
366 DCHECK(!tile->occluded);
367 gfx::Rect visible_tile_rect = gfx::IntersectRects(
368 tiler_->tile_bounds(i, j), visible_content_rect());
369 if (occlusion && occlusion->Occluded(render_target(),
370 visible_tile_rect,
371 draw_transform(),
372 draw_transform_is_animating(),
373 is_clipped(),
374 clip_rect(),
375 NULL)) {
376 tile->occluded = true;
377 occluded_tile_count++;
378 } else {
379 succeeded &= tile->managed_resource()->requestLate();
380 }
381 }
382 }
383
384 if (!succeeded)
385 return;
386 if (occlusion)
387 occlusion->overdraw_metrics()->DidCullTilesForUpload(occluded_tile_count);
388 }
389
390 bool TiledLayer::HaveTexturesForTiles(int left,
391 int top,
392 int right,
393 int bottom,
394 bool ignore_occlusions) {
395 for (int j = top; j <= bottom; ++j) {
396 for (int i = left; i <= right; ++i) {
397 UpdatableTile* tile = TileAt(i, j);
398 DCHECK(tile); // Did SetTexturePriorites get skipped?
399 // FIXME: This should not ever be null.
400 if (!tile)
401 continue;
402
403 // Ensure the entire tile is dirty if we don't have the texture.
404 if (!tile->managed_resource()->haveBackingTexture())
405 tile->dirty_rect = tiler_->TileRect(tile);
406
407 // If using occlusion and the visible region of the tile is occluded,
408 // don't reserve a texture or update the tile.
409 if (tile->occluded && !ignore_occlusions)
410 continue;
411
412 if (!tile->managed_resource()->canAcquireBackingTexture())
413 return false;
414 }
415 }
416 return true;
417 }
418
419 gfx::Rect TiledLayer::MarkTilesForUpdate(int left,
420 int top,
421 int right,
422 int bottom,
423 bool ignore_occlusions) {
424 gfx::Rect paint_rect;
425 for (int j = top; j <= bottom; ++j) {
426 for (int i = left; i <= right; ++i) {
427 UpdatableTile* tile = TileAt(i, j);
428 DCHECK(tile); // Did SetTexturePriorites get skipped?
429 // FIXME: This should not ever be null.
430 if (!tile)
431 continue;
432 if (tile->occluded && !ignore_occlusions)
433 continue;
434 // FIXME: Decide if partial update should be allowed based on cost
435 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
436 if (tile->is_dirty() && layer_tree_host() &&
437 layer_tree_host()->buffered_updates()) {
438 // If we get a partial update, we use the same texture, otherwise return
439 // the current texture backing, so we don't update visible textures
440 // non-atomically. If the current backing is in-use, it won't be
441 // deleted until after the commit as the texture manager will not allow
442 // deletion or recycling of in-use textures.
443 if (TileOnlyNeedsPartialUpdate(tile) &&
444 layer_tree_host()->RequestPartialTextureUpdate()) {
445 tile->partial_update = true;
446 } else {
447 tile->dirty_rect = tiler_->TileRect(tile);
448 tile->managed_resource()->returnBackingTexture();
449 }
450 }
451
452 paint_rect.Union(tile->dirty_rect);
453 tile->MarkForUpdate();
454 }
455 }
456 return paint_rect;
457 }
458
459 void TiledLayer::UpdateTileTextures(gfx::Rect paint_rect,
460 int left,
461 int top,
462 int right,
463 int bottom,
464 ResourceUpdateQueue* queue,
465 const OcclusionTracker* occlusion,
466 RenderingStats* stats) {
467 // The update_rect should be in layer space. So we have to convert the
468 // paint_rect from content space to layer space.
469 float width_scale =
470 bounds().width() / static_cast<float>(content_bounds().width());
471 float height_scale =
472 bounds().height() / static_cast<float>(content_bounds().height());
473 update_rect_ = gfx::ScaleRect(paint_rect, width_scale, height_scale);
474
475 // Calling PrepareToUpdate() calls into WebKit to paint, which may have the
476 // side effect of disabling compositing, which causes our reference to the
477 // texture updater to be deleted. However, we can't free the memory backing
478 // the SkCanvas until the paint finishes, so we grab a local reference here to
479 // hold the updater alive until the paint completes.
480 scoped_refptr<LayerUpdater> protector(Updater());
481 gfx::Rect painted_opaque_rect;
482 Updater()->PrepareToUpdate(paint_rect,
483 tiler_->tile_size(),
484 1.f / width_scale,
485 1.f / height_scale,
486 &painted_opaque_rect,
487 stats);
488
489 for (int j = top; j <= bottom; ++j) {
490 for (int i = left; i <= right; ++i) {
491 UpdatableTile* tile = TileAt(i, j);
492 DCHECK(tile); // Did SetTexturePriorites get skipped?
493 // FIXME: This should not ever be null.
494 if (!tile)
495 continue;
496
497 gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
498
499 // Use update_rect as the above loop copied the dirty rect for this frame
500 // to update_rect.
501 gfx::Rect dirty_rect = tile->update_rect;
502 if (dirty_rect.IsEmpty())
503 continue;
504
505 // Save what was painted opaque in the tile. Keep the old area if the
506 // paint didn't touch it, and didn't paint some other part of the tile
507 // opaque.
508 gfx::Rect tile_painted_rect = gfx::IntersectRects(tile_rect, paint_rect);
509 gfx::Rect tile_painted_opaque_rect =
510 gfx::IntersectRects(tile_rect, painted_opaque_rect);
511 if (!tile_painted_rect.IsEmpty()) {
512 gfx::Rect paint_inside_tile_opaque_rect =
513 gfx::IntersectRects(tile->opaque_rect(), tile_painted_rect);
514 bool paint_inside_tile_opaque_rect_is_non_opaque =
515 !tile_painted_opaque_rect.Contains(paint_inside_tile_opaque_rect);
516 bool opaque_paint_not_inside_tile_opaque_rect =
517 !tile_painted_opaque_rect.IsEmpty() &&
518 !tile->opaque_rect().Contains(tile_painted_opaque_rect);
519
520 if (paint_inside_tile_opaque_rect_is_non_opaque ||
521 opaque_paint_not_inside_tile_opaque_rect)
522 tile->set_opaque_rect(tile_painted_opaque_rect);
523 }
524
525 // source_rect starts as a full-sized tile with border texels included.
526 gfx::Rect source_rect = tiler_->TileRect(tile);
527 source_rect.Intersect(dirty_rect);
528 // Paint rect not guaranteed to line up on tile boundaries, so
529 // make sure that source_rect doesn't extend outside of it.
530 source_rect.Intersect(paint_rect);
531
532 tile->update_rect = source_rect;
533
534 if (source_rect.IsEmpty())
535 continue;
536
537 const gfx::Point anchor = tiler_->TileRect(tile).origin();
538
539 // Calculate tile-space rectangle to upload into.
540 gfx::Vector2d dest_offset = source_rect.origin() - anchor;
541 CHECK_GE(dest_offset.x(), 0);
542 CHECK_GE(dest_offset.y(), 0);
543
544 // Offset from paint rectangle to this tile's dirty rectangle.
545 gfx::Vector2d paint_offset = source_rect.origin() - paint_rect.origin();
546 CHECK_GE(paint_offset.x(), 0);
547 CHECK_GE(paint_offset.y(), 0);
548 CHECK_LE(paint_offset.x() + source_rect.width(), paint_rect.width());
549 CHECK_LE(paint_offset.y() + source_rect.height(), paint_rect.height());
550
551 tile->updater_resource()->Update(
552 queue, source_rect, dest_offset, tile->partial_update, stats);
553 if (occlusion) {
554 occlusion->overdraw_metrics()->
555 DidUpload(gfx::Transform(), source_rect, tile->opaque_rect());
556 }
557
558 }
559 }
560 }
561
562 // This picks a small animated layer to be anything less than one viewport. This
563 // is specifically for page transitions which are viewport-sized layers. The
564 // extra tile of padding is due to these layers being slightly larger than the
565 // viewport in some cases.
566 bool TiledLayer::IsSmallAnimatedLayer() const {
567 if (!draw_transform_is_animating() && !screen_space_transform_is_animating())
568 return false;
569 gfx::Size viewport_size =
570 layer_tree_host() ? layer_tree_host()->device_viewport_size()
571 : gfx::Size();
572 gfx::Rect content_rect(gfx::Point(), content_bounds());
573 return content_rect.width() <=
574 viewport_size.width() + tiler_->tile_size().width() &&
575 content_rect.height() <=
576 viewport_size.height() + tiler_->tile_size().height();
577 }
578
579 namespace {
580 // FIXME: Remove this and make this based on distance once distance can be
581 // calculated for offscreen layers. For now, prioritize all small animated
582 // layers after 512 pixels of pre-painting.
583 void SetPriorityForTexture(gfx::Rect visible_rect,
584 gfx::Rect tile_rect,
585 bool draws_to_root,
586 bool is_small_animated_layer,
587 PrioritizedResource* texture) {
588 int priority = PriorityCalculator::LowestPriority();
589 if (!visible_rect.IsEmpty()) {
590 priority = PriorityCalculator::PriorityFromDistance(
591 visible_rect, tile_rect, draws_to_root);
592 }
593
594 if (is_small_animated_layer) {
595 priority = PriorityCalculator::max_priority(
596 priority, PriorityCalculator::SmallAnimatedLayerMinPriority());
597 }
598
599 if (priority != PriorityCalculator::LowestPriority())
600 texture->setRequestPriority(priority);
601 }
602 } // namespace
603
604 void TiledLayer::SetTexturePriorities(const PriorityCalculator& priority_calc) {
605 UpdateBounds();
606 ResetUpdateState();
607 UpdateScrollPrediction();
608
609 if (tiler_->has_empty_bounds())
610 return;
611
612 bool draws_to_root = !render_target()->parent();
613 bool small_animated_layer = IsSmallAnimatedLayer();
614
615 // Minimally create the tiles in the desired pre-paint rect.
616 gfx::Rect create_tiles_rect = IdlePaintRect();
617 if (small_animated_layer)
618 create_tiles_rect = gfx::Rect(gfx::Point(), content_bounds());
619 if (!create_tiles_rect.IsEmpty()) {
620 int left, top, right, bottom;
621 tiler_->ContentRectToTileIndices(
622 create_tiles_rect, &left, &top, &right, &bottom);
623 for (int j = top; j <= bottom; ++j) {
624 for (int i = left; i <= right; ++i) {
625 if (!TileAt(i, j))
626 CreateTile(i, j);
627 }
628 }
629 }
630
631 // Now update priorities on all tiles we have in the layer, no matter where
632 // they are.
633 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
634 iter != tiler_->tiles().end();
635 ++iter) {
636 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
637 // FIXME: This should not ever be null.
638 if (!tile)
639 continue;
640 gfx::Rect tile_rect = tiler_->TileRect(tile);
641 SetPriorityForTexture(predicted_visible_rect_,
642 tile_rect,
643 draws_to_root,
644 small_animated_layer,
645 tile->managed_resource());
646 }
647 }
648
649 Region TiledLayer::VisibleContentOpaqueRegion() const {
650 if (skips_draw_)
651 return Region();
652 if (contents_opaque())
653 return visible_content_rect();
654 return tiler_->OpaqueRegionInContentRect(visible_content_rect());
655 }
656
657 void TiledLayer::ResetUpdateState() {
658 skips_draw_ = false;
659 failed_update_ = false;
660
661 LayerTilingData::TileMap::const_iterator end = tiler_->tiles().end();
662 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
663 iter != end;
664 ++iter) {
665 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
666 // FIXME: This should not ever be null.
667 if (!tile)
668 continue;
669 tile->ResetUpdateState();
670 }
671 }
672
673 namespace {
674 gfx::Rect ExpandRectByDelta(gfx::Rect rect, gfx::Vector2d delta) {
675 int width = rect.width() + std::abs(delta.x());
676 int height = rect.height() + std::abs(delta.y());
677 int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0);
678 int y = rect.y() + ((delta.y() < 0) ? delta.y() : 0);
679 return gfx::Rect(x, y, width, height);
680 }
681 }
682
683 void TiledLayer::UpdateScrollPrediction() {
684 // This scroll prediction is very primitive and should be replaced by a
685 // a recursive calculation on all layers which uses actual scroll/animation
686 // velocities. To insure this doesn't miss-predict, we only use it to predict
687 // the visible_rect if:
688 // - content_bounds() hasn't changed.
689 // - visible_rect.size() hasn't changed.
690 // These two conditions prevent rotations, scales, pinch-zooms etc. where
691 // the prediction would be incorrect.
692 gfx::Vector2d delta = visible_content_rect().CenterPoint() -
693 previous_visible_rect_.CenterPoint();
694 predicted_scroll_ = -delta;
695 predicted_visible_rect_ = visible_content_rect();
696 if (previous_content_bounds_ == content_bounds() &&
697 previous_visible_rect_.size() == visible_content_rect().size()) {
698 // Only expand the visible rect in the major scroll direction, to prevent
699 // massive paints due to diagonal scrolls.
700 gfx::Vector2d major_scroll_delta =
701 (std::abs(delta.x()) > std::abs(delta.y())) ?
702 gfx::Vector2d(delta.x(), 0) :
703 gfx::Vector2d(0, delta.y());
704 predicted_visible_rect_ =
705 ExpandRectByDelta(visible_content_rect(), major_scroll_delta);
706
707 // Bound the prediction to prevent unbounded paints, and clamp to content
708 // bounds.
709 gfx::Rect bound = visible_content_rect();
710 bound.Inset(-tiler_->tile_size().width() * kMaxPredictiveTilesCount,
711 -tiler_->tile_size().height() * kMaxPredictiveTilesCount);
712 bound.Intersect(gfx::Rect(gfx::Point(), content_bounds()));
713 predicted_visible_rect_.Intersect(bound);
714 }
715 previous_content_bounds_ = content_bounds();
716 previous_visible_rect_ = visible_content_rect();
717 }
718
719 void TiledLayer::Update(ResourceUpdateQueue* queue,
720 const OcclusionTracker* occlusion,
721 RenderingStats* stats) {
722 DCHECK(!skips_draw_ && !failed_update_); // Did ResetUpdateState get skipped?
723 {
724 base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
725 true);
726
727 ContentsScalingLayer::Update(queue, occlusion, stats);
728 UpdateBounds();
729 }
730
731 if (tiler_->has_empty_bounds() || !DrawsContent())
732 return;
733
734 bool did_paint = false;
735
736 // Animation pre-paint. If the layer is small, try to paint it all
737 // immediately whether or not it is occluded, to avoid paint/upload
738 // hiccups while it is animating.
739 if (IsSmallAnimatedLayer()) {
740 int left, top, right, bottom;
741 tiler_->ContentRectToTileIndices(gfx::Rect(gfx::Point(), content_bounds()),
742 &left,
743 &top,
744 &right,
745 &bottom);
746 UpdateTiles(left, top, right, bottom, queue, NULL, stats, &did_paint);
747 if (did_paint)
748 return;
749 // This was an attempt to paint the entire layer so if we fail it's okay,
750 // just fallback on painting visible etc. below.
751 failed_update_ = false;
752 }
753
754 if (predicted_visible_rect_.IsEmpty())
755 return;
756
757 // Visible painting. First occlude visible tiles and paint the non-occluded
758 // tiles.
759 int left, top, right, bottom;
760 tiler_->ContentRectToTileIndices(
761 predicted_visible_rect_, &left, &top, &right, &bottom);
762 MarkOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
763 skips_draw_ = !UpdateTiles(
764 left, top, right, bottom, queue, occlusion, stats, &did_paint);
765 if (skips_draw_)
766 tiler_->reset();
767 if (skips_draw_ || did_paint)
768 return;
769
770 // If we have already painting everything visible. Do some pre-painting while
771 // idle.
772 gfx::Rect idle_paint_content_rect = IdlePaintRect();
773 if (idle_paint_content_rect.IsEmpty())
774 return;
775
776 // Prepaint anything that was occluded but inside the layer's visible region.
777 if (!UpdateTiles(left, top, right, bottom, queue, NULL, stats, &did_paint) ||
778 did_paint)
779 return;
780
781 int prepaint_left, prepaint_top, prepaint_right, prepaint_bottom;
782 tiler_->ContentRectToTileIndices(idle_paint_content_rect,
783 &prepaint_left,
784 &prepaint_top,
785 &prepaint_right,
786 &prepaint_bottom);
787
788 // Then expand outwards one row/column at a time until we find a dirty
789 // row/column to update. Increment along the major and minor scroll directions
790 // first.
791 gfx::Vector2d delta = -predicted_scroll_;
792 delta = gfx::Vector2d(delta.x() == 0 ? 1 : delta.x(),
793 delta.y() == 0 ? 1 : delta.y());
794 gfx::Vector2d major_delta =
795 (abs(delta.x()) > abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
796 : gfx::Vector2d(0, delta.y());
797 gfx::Vector2d minor_delta =
798 (abs(delta.x()) <= abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
799 : gfx::Vector2d(0, delta.y());
800 gfx::Vector2d deltas[4] = { major_delta, minor_delta, -major_delta,
801 -minor_delta };
802 for (int i = 0; i < 4; i++) {
803 if (deltas[i].y() > 0) {
804 while (bottom < prepaint_bottom) {
805 ++bottom;
806 if (!UpdateTiles(
807 left, bottom, right, bottom, queue, NULL, stats, &did_paint) ||
808 did_paint)
809 return;
810 }
811 }
812 if (deltas[i].y() < 0) {
813 while (top > prepaint_top) {
814 --top;
815 if (!UpdateTiles(
816 left, top, right, top, queue, NULL, stats, &did_paint) ||
817 did_paint)
818 return;
819 }
820 }
821 if (deltas[i].x() < 0) {
822 while (left > prepaint_left) {
823 --left;
824 if (!UpdateTiles(
825 left, top, left, bottom, queue, NULL, stats, &did_paint) ||
826 did_paint)
827 return;
828 }
829 }
830 if (deltas[i].x() > 0) {
831 while (right < prepaint_right) {
832 ++right;
833 if (!UpdateTiles(
834 right, top, right, bottom, queue, NULL, stats, &did_paint) ||
835 did_paint)
836 return;
837 }
838 }
839 }
840 }
841
842 bool TiledLayer::NeedsIdlePaint() {
843 // Don't trigger more paints if we failed (as we'll just fail again).
844 if (failed_update_ || visible_content_rect().IsEmpty() ||
845 tiler_->has_empty_bounds() || !DrawsContent())
846 return false;
847
848 gfx::Rect idle_paint_content_rect = IdlePaintRect();
849 if (idle_paint_content_rect.IsEmpty())
850 return false;
851
852 int left, top, right, bottom;
853 tiler_->ContentRectToTileIndices(
854 idle_paint_content_rect, &left, &top, &right, &bottom);
855
856 for (int j = top; j <= bottom; ++j) {
857 for (int i = left; i <= right; ++i) {
858 UpdatableTile* tile = TileAt(i, j);
859 DCHECK(tile); // Did SetTexturePriorities get skipped?
860 if (!tile)
861 continue;
862
863 bool updated = !tile->update_rect.IsEmpty();
864 bool can_acquire = tile->managed_resource()->canAcquireBackingTexture();
865 bool dirty =
866 tile->is_dirty() || !tile->managed_resource()->haveBackingTexture();
867 if (!updated && can_acquire && dirty)
868 return true;
869 }
870 }
871 return false;
872 }
873
874 gfx::Rect TiledLayer::IdlePaintRect() {
875 // Don't inflate an empty rect.
876 if (visible_content_rect().IsEmpty())
877 return gfx::Rect();
878
879 gfx::Rect prepaint_rect = visible_content_rect();
880 prepaint_rect.Inset(-tiler_->tile_size().width() * kPrepaintColumns,
881 -tiler_->tile_size().height() * kPrepaintRows);
882 gfx::Rect content_rect(content_bounds());
883 prepaint_rect.Intersect(content_rect);
884
885 return prepaint_rect;
886 }
887
888 } // namespace cc
OLDNEW
« no previous file with comments | « cc/tiled_layer.h ('k') | cc/tiled_layer_impl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698