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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « cc/tiled_layer.h ('k') | cc/tiled_layer_impl.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: cc/tiled_layer.cc
diff --git a/cc/tiled_layer.cc b/cc/tiled_layer.cc
deleted file mode 100644
index 6058a769dfe98e1f05434f84993966e08963fdfb..0000000000000000000000000000000000000000
--- a/cc/tiled_layer.cc
+++ /dev/null
@@ -1,888 +0,0 @@
-// Copyright 2011 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/tiled_layer.h"
-
-#include "base/auto_reset.h"
-#include "base/basictypes.h"
-#include "build/build_config.h"
-#include "cc/debug/overdraw_metrics.h"
-#include "cc/layer_impl.h"
-#include "cc/resources/layer_updater.h"
-#include "cc/resources/prioritized_resource.h"
-#include "cc/resources/priority_calculator.h"
-#include "cc/tiled_layer_impl.h"
-#include "cc/trees/layer_tree_host.h"
-#include "third_party/khronos/GLES2/gl2.h"
-#include "ui/gfx/rect_conversions.h"
-
-namespace cc {
-
-// Maximum predictive expansion of the visible area.
-static const int kMaxPredictiveTilesCount = 2;
-
-// Number of rows/columns of tiles to pre-paint.
-// We should increase these further as all textures are
-// prioritized and we insure performance doesn't suffer.
-static const int kPrepaintRows = 4;
-static const int kPrepaintColumns = 2;
-
-class UpdatableTile : public LayerTilingData::Tile {
- public:
- static scoped_ptr<UpdatableTile> Create(
- scoped_ptr<LayerUpdater::Resource> updater_resource) {
- return make_scoped_ptr(new UpdatableTile(updater_resource.Pass()));
- }
-
- LayerUpdater::Resource* updater_resource() { return updater_resource_.get(); }
- PrioritizedResource* managed_resource() {
- return updater_resource_->texture();
- }
-
- bool is_dirty() const { return !dirty_rect.IsEmpty(); }
-
- // Reset update state for the current frame. This should occur before painting
- // for all layers. Since painting one layer can invalidate another layer after
- // it has already painted, mark all non-dirty tiles as valid before painting
- // such that invalidations during painting won't prevent them from being
- // pushed.
- void ResetUpdateState() {
- update_rect = gfx::Rect();
- occluded = false;
- partial_update = false;
- valid_for_frame = !is_dirty();
- }
-
- // This promises to update the tile and therefore also guarantees the tile
- // will be valid for this frame. dirty_rect is copied into update_rect so we
- // can continue to track re-entrant invalidations that occur during painting.
- void MarkForUpdate() {
- valid_for_frame = true;
- update_rect = dirty_rect;
- dirty_rect = gfx::Rect();
- }
-
- gfx::Rect dirty_rect;
- gfx::Rect update_rect;
- bool partial_update;
- bool valid_for_frame;
- bool occluded;
-
- private:
- explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updater_resource)
- : partial_update(false),
- valid_for_frame(false),
- occluded(false),
- updater_resource_(updater_resource.Pass()) {}
-
- scoped_ptr<LayerUpdater::Resource> updater_resource_;
-
- DISALLOW_COPY_AND_ASSIGN(UpdatableTile);
-};
-
-TiledLayer::TiledLayer()
- : ContentsScalingLayer(),
- texture_format_(GL_INVALID_ENUM),
- skips_draw_(false),
- failed_update_(false),
- tiling_option_(AUTO_TILE) {
- tiler_ =
- LayerTilingData::Create(gfx::Size(), LayerTilingData::HAS_BORDER_TEXELS);
-}
-
-TiledLayer::~TiledLayer() {}
-
-scoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
- return TiledLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
-}
-
-void TiledLayer::UpdateTileSizeAndTilingOption() {
- DCHECK(layer_tree_host());
-
- gfx::Size default_tile_size = layer_tree_host()->settings().defaultTileSize;
- gfx::Size max_untiled_layer_size =
- layer_tree_host()->settings().maxUntiledLayerSize;
- int layer_width = content_bounds().width();
- int layer_height = content_bounds().height();
-
- gfx::Size tile_size(std::min(default_tile_size.width(), layer_width),
- std::min(default_tile_size.height(), layer_height));
-
- // Tile if both dimensions large, or any one dimension large and the other
- // extends into a second tile but the total layer area isn't larger than that
- // of the largest possible untiled layer. This heuristic allows for long
- // skinny layers (e.g. scrollbars) that are Nx1 tiles to minimize wasted
- // texture space but still avoids creating very large tiles.
- bool any_dimension_large = layer_width > max_untiled_layer_size.width() ||
- layer_height > max_untiled_layer_size.height();
- bool any_dimension_one_tile =
- (layer_width <= default_tile_size.width() ||
- layer_height <= default_tile_size.height()) &&
- (layer_width * layer_height) <= (max_untiled_layer_size.width() *
- max_untiled_layer_size.height());
- bool auto_tiled = any_dimension_large && !any_dimension_one_tile;
-
- bool is_tiled;
- if (tiling_option_ == ALWAYS_TILE)
- is_tiled = true;
- else if (tiling_option_ == NEVER_TILE)
- is_tiled = false;
- else
- is_tiled = auto_tiled;
-
- gfx::Size requested_size = is_tiled ? tile_size : content_bounds();
- const int max_size =
- layer_tree_host()->GetRendererCapabilities().max_texture_size;
- requested_size.ClampToMax(gfx::Size(max_size, max_size));
- SetTileSize(requested_size);
-}
-
-void TiledLayer::UpdateBounds() {
- gfx::Size old_bounds = tiler_->bounds();
- gfx::Size new_bounds = content_bounds();
- if (old_bounds == new_bounds)
- return;
- tiler_->SetBounds(new_bounds);
-
- // Invalidate any areas that the new bounds exposes.
- Region old_region = gfx::Rect(gfx::Point(), old_bounds);
- Region new_region = gfx::Rect(gfx::Point(), new_bounds);
- new_region.Subtract(old_region);
- for (Region::Iterator new_rects(new_region);
- new_rects.has_rect();
- new_rects.next())
- InvalidateContentRect(new_rects.rect());
-}
-
-void TiledLayer::SetTileSize(gfx::Size size) { tiler_->SetTileSize(size); }
-
-void TiledLayer::SetBorderTexelOption(
- LayerTilingData::BorderTexelOption border_texel_option) {
- tiler_->SetBorderTexelOption(border_texel_option);
-}
-
-bool TiledLayer::DrawsContent() const {
- if (!ContentsScalingLayer::DrawsContent())
- return false;
-
- bool has_more_than_one_tile =
- tiler_->num_tiles_x() > 1 || tiler_->num_tiles_y() > 1;
- if (tiling_option_ == NEVER_TILE && has_more_than_one_tile)
- return false;
-
- return true;
-}
-
-void TiledLayer::SetIsMask(bool is_mask) {
- set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
-}
-
-void TiledLayer::PushPropertiesTo(LayerImpl* layer) {
- ContentsScalingLayer::PushPropertiesTo(layer);
-
- TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
-
- tiled_layer->set_skips_draw(skips_draw_);
- tiled_layer->SetTilingData(*tiler_);
- std::vector<UpdatableTile*> invalid_tiles;
-
- for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
- iter != tiler_->tiles().end();
- ++iter) {
- int i = iter->first.first;
- int j = iter->first.second;
- UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
-
- if (!tile->managed_resource()->haveBackingTexture()) {
- // Evicted tiles get deleted from both layers
- invalid_tiles.push_back(tile);
- continue;
- }
-
- if (!tile->valid_for_frame) {
- // Invalidated tiles are set so they can get different debug colors.
- tiled_layer->PushInvalidTile(i, j);
- continue;
- }
-
- tiled_layer->PushTileProperties(
- i,
- j,
- tile->managed_resource()->resourceId(),
- tile->opaque_rect(),
- tile->managed_resource()->contentsSwizzled());
- }
- for (std::vector<UpdatableTile*>::const_iterator iter = invalid_tiles.begin();
- iter != invalid_tiles.end();
- ++iter)
- tiler_->TakeTile((*iter)->i(), (*iter)->j());
-}
-
-bool TiledLayer::BlocksPendingCommit() const { return true; }
-
-PrioritizedResourceManager* TiledLayer::ResourceManager() const {
- if (!layer_tree_host())
- return NULL;
- return layer_tree_host()->contents_texture_manager();
-}
-
-const PrioritizedResource* TiledLayer::ResourceAtForTesting(int i,
- int j) const {
- UpdatableTile* tile = TileAt(i, j);
- if (!tile)
- return NULL;
- return tile->managed_resource();
-}
-
-void TiledLayer::SetLayerTreeHost(LayerTreeHost* host) {
- if (host && host != layer_tree_host()) {
- for (LayerTilingData::TileMap::const_iterator
- iter = tiler_->tiles().begin();
- iter != tiler_->tiles().end();
- ++iter) {
- UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
- tile->managed_resource()->setTextureManager(
- host->contents_texture_manager());
- }
- }
- ContentsScalingLayer::SetLayerTreeHost(host);
-}
-
-UpdatableTile* TiledLayer::TileAt(int i, int j) const {
- return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
-}
-
-UpdatableTile* TiledLayer::CreateTile(int i, int j) {
- CreateUpdaterIfNeeded();
-
- scoped_ptr<UpdatableTile> tile(
- UpdatableTile::Create(Updater()->CreateResource(ResourceManager())));
- tile->managed_resource()->setDimensions(tiler_->tile_size(), texture_format_);
-
- UpdatableTile* added_tile = tile.get();
- tiler_->AddTile(tile.PassAs<LayerTilingData::Tile>(), i, j);
-
- added_tile->dirty_rect = tiler_->TileRect(added_tile);
-
- // Temporary diagnostic crash.
- CHECK(added_tile);
- CHECK(TileAt(i, j));
-
- return added_tile;
-}
-
-void TiledLayer::SetNeedsDisplayRect(const gfx::RectF& dirty_rect) {
- InvalidateContentRect(LayerRectToContentRect(dirty_rect));
- ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
-}
-
-void TiledLayer::InvalidateContentRect(gfx::Rect content_rect) {
- UpdateBounds();
- if (tiler_->is_empty() || content_rect.IsEmpty() || skips_draw_)
- return;
-
- for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
- iter != tiler_->tiles().end();
- ++iter) {
- UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
- DCHECK(tile);
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
- gfx::Rect bound = tiler_->TileRect(tile);
- bound.Intersect(content_rect);
- tile->dirty_rect.Union(bound);
- }
-}
-
-// Returns true if tile is dirty and only part of it needs to be updated.
-bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
- return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
- tile->managed_resource()->haveBackingTexture();
-}
-
-bool TiledLayer::UpdateTiles(int left,
- int top,
- int right,
- int bottom,
- ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion,
- RenderingStats* stats,
- bool* did_paint) {
- *did_paint = false;
- CreateUpdaterIfNeeded();
-
- bool ignore_occlusions = !occlusion;
- if (!HaveTexturesForTiles(left, top, right, bottom, ignore_occlusions)) {
- failed_update_ = true;
- return false;
- }
-
- gfx::Rect paint_rect =
- MarkTilesForUpdate(left, top, right, bottom, ignore_occlusions);
-
- if (occlusion)
- occlusion->overdraw_metrics()->DidPaint(paint_rect);
-
- if (paint_rect.IsEmpty())
- return true;
-
- *did_paint = true;
- UpdateTileTextures(
- paint_rect, left, top, right, bottom, queue, occlusion, stats);
- return true;
-}
-
-void TiledLayer::MarkOcclusionsAndRequestTextures(
- int left,
- int top,
- int right,
- int bottom,
- const OcclusionTracker* occlusion) {
- // There is some difficult dependancies between occlusions, recording
- // occlusion metrics and requesting memory so those are encapsulated in this
- // function: - We only want to call RequestLate on unoccluded textures (to
- // preserve memory for other layers when near OOM). - We only want to record
- // occlusion metrics if all memory requests succeed.
-
- int occluded_tile_count = 0;
- bool succeeded = true;
- for (int j = top; j <= bottom; ++j) {
- for (int i = left; i <= right; ++i) {
- UpdatableTile* tile = TileAt(i, j);
- DCHECK(tile); // Did SetTexturePriorities get skipped?
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
- // Did ResetUpdateState get skipped? Are we doing more than one occlusion
- // pass?
- DCHECK(!tile->occluded);
- gfx::Rect visible_tile_rect = gfx::IntersectRects(
- tiler_->tile_bounds(i, j), visible_content_rect());
- if (occlusion && occlusion->Occluded(render_target(),
- visible_tile_rect,
- draw_transform(),
- draw_transform_is_animating(),
- is_clipped(),
- clip_rect(),
- NULL)) {
- tile->occluded = true;
- occluded_tile_count++;
- } else {
- succeeded &= tile->managed_resource()->requestLate();
- }
- }
- }
-
- if (!succeeded)
- return;
- if (occlusion)
- occlusion->overdraw_metrics()->DidCullTilesForUpload(occluded_tile_count);
-}
-
-bool TiledLayer::HaveTexturesForTiles(int left,
- int top,
- int right,
- int bottom,
- bool ignore_occlusions) {
- for (int j = top; j <= bottom; ++j) {
- for (int i = left; i <= right; ++i) {
- UpdatableTile* tile = TileAt(i, j);
- DCHECK(tile); // Did SetTexturePriorites get skipped?
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
-
- // Ensure the entire tile is dirty if we don't have the texture.
- if (!tile->managed_resource()->haveBackingTexture())
- tile->dirty_rect = tiler_->TileRect(tile);
-
- // If using occlusion and the visible region of the tile is occluded,
- // don't reserve a texture or update the tile.
- if (tile->occluded && !ignore_occlusions)
- continue;
-
- if (!tile->managed_resource()->canAcquireBackingTexture())
- return false;
- }
- }
- return true;
-}
-
-gfx::Rect TiledLayer::MarkTilesForUpdate(int left,
- int top,
- int right,
- int bottom,
- bool ignore_occlusions) {
- gfx::Rect paint_rect;
- for (int j = top; j <= bottom; ++j) {
- for (int i = left; i <= right; ++i) {
- UpdatableTile* tile = TileAt(i, j);
- DCHECK(tile); // Did SetTexturePriorites get skipped?
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
- if (tile->occluded && !ignore_occlusions)
- continue;
- // FIXME: Decide if partial update should be allowed based on cost
- // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
- if (tile->is_dirty() && layer_tree_host() &&
- layer_tree_host()->buffered_updates()) {
- // If we get a partial update, we use the same texture, otherwise return
- // the current texture backing, so we don't update visible textures
- // non-atomically. If the current backing is in-use, it won't be
- // deleted until after the commit as the texture manager will not allow
- // deletion or recycling of in-use textures.
- if (TileOnlyNeedsPartialUpdate(tile) &&
- layer_tree_host()->RequestPartialTextureUpdate()) {
- tile->partial_update = true;
- } else {
- tile->dirty_rect = tiler_->TileRect(tile);
- tile->managed_resource()->returnBackingTexture();
- }
- }
-
- paint_rect.Union(tile->dirty_rect);
- tile->MarkForUpdate();
- }
- }
- return paint_rect;
-}
-
-void TiledLayer::UpdateTileTextures(gfx::Rect paint_rect,
- int left,
- int top,
- int right,
- int bottom,
- ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion,
- RenderingStats* stats) {
- // The update_rect should be in layer space. So we have to convert the
- // paint_rect from content space to layer space.
- float width_scale =
- bounds().width() / static_cast<float>(content_bounds().width());
- float height_scale =
- bounds().height() / static_cast<float>(content_bounds().height());
- update_rect_ = gfx::ScaleRect(paint_rect, width_scale, height_scale);
-
- // Calling PrepareToUpdate() calls into WebKit to paint, which may have the
- // side effect of disabling compositing, which causes our reference to the
- // texture updater to be deleted. However, we can't free the memory backing
- // the SkCanvas until the paint finishes, so we grab a local reference here to
- // hold the updater alive until the paint completes.
- scoped_refptr<LayerUpdater> protector(Updater());
- gfx::Rect painted_opaque_rect;
- Updater()->PrepareToUpdate(paint_rect,
- tiler_->tile_size(),
- 1.f / width_scale,
- 1.f / height_scale,
- &painted_opaque_rect,
- stats);
-
- for (int j = top; j <= bottom; ++j) {
- for (int i = left; i <= right; ++i) {
- UpdatableTile* tile = TileAt(i, j);
- DCHECK(tile); // Did SetTexturePriorites get skipped?
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
-
- gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
-
- // Use update_rect as the above loop copied the dirty rect for this frame
- // to update_rect.
- gfx::Rect dirty_rect = tile->update_rect;
- if (dirty_rect.IsEmpty())
- continue;
-
- // Save what was painted opaque in the tile. Keep the old area if the
- // paint didn't touch it, and didn't paint some other part of the tile
- // opaque.
- gfx::Rect tile_painted_rect = gfx::IntersectRects(tile_rect, paint_rect);
- gfx::Rect tile_painted_opaque_rect =
- gfx::IntersectRects(tile_rect, painted_opaque_rect);
- if (!tile_painted_rect.IsEmpty()) {
- gfx::Rect paint_inside_tile_opaque_rect =
- gfx::IntersectRects(tile->opaque_rect(), tile_painted_rect);
- bool paint_inside_tile_opaque_rect_is_non_opaque =
- !tile_painted_opaque_rect.Contains(paint_inside_tile_opaque_rect);
- bool opaque_paint_not_inside_tile_opaque_rect =
- !tile_painted_opaque_rect.IsEmpty() &&
- !tile->opaque_rect().Contains(tile_painted_opaque_rect);
-
- if (paint_inside_tile_opaque_rect_is_non_opaque ||
- opaque_paint_not_inside_tile_opaque_rect)
- tile->set_opaque_rect(tile_painted_opaque_rect);
- }
-
- // source_rect starts as a full-sized tile with border texels included.
- gfx::Rect source_rect = tiler_->TileRect(tile);
- source_rect.Intersect(dirty_rect);
- // Paint rect not guaranteed to line up on tile boundaries, so
- // make sure that source_rect doesn't extend outside of it.
- source_rect.Intersect(paint_rect);
-
- tile->update_rect = source_rect;
-
- if (source_rect.IsEmpty())
- continue;
-
- const gfx::Point anchor = tiler_->TileRect(tile).origin();
-
- // Calculate tile-space rectangle to upload into.
- gfx::Vector2d dest_offset = source_rect.origin() - anchor;
- CHECK_GE(dest_offset.x(), 0);
- CHECK_GE(dest_offset.y(), 0);
-
- // Offset from paint rectangle to this tile's dirty rectangle.
- gfx::Vector2d paint_offset = source_rect.origin() - paint_rect.origin();
- CHECK_GE(paint_offset.x(), 0);
- CHECK_GE(paint_offset.y(), 0);
- CHECK_LE(paint_offset.x() + source_rect.width(), paint_rect.width());
- CHECK_LE(paint_offset.y() + source_rect.height(), paint_rect.height());
-
- tile->updater_resource()->Update(
- queue, source_rect, dest_offset, tile->partial_update, stats);
- if (occlusion) {
- occlusion->overdraw_metrics()->
- DidUpload(gfx::Transform(), source_rect, tile->opaque_rect());
- }
-
- }
- }
-}
-
-// This picks a small animated layer to be anything less than one viewport. This
-// is specifically for page transitions which are viewport-sized layers. The
-// extra tile of padding is due to these layers being slightly larger than the
-// viewport in some cases.
-bool TiledLayer::IsSmallAnimatedLayer() const {
- if (!draw_transform_is_animating() && !screen_space_transform_is_animating())
- return false;
- gfx::Size viewport_size =
- layer_tree_host() ? layer_tree_host()->device_viewport_size()
- : gfx::Size();
- gfx::Rect content_rect(gfx::Point(), content_bounds());
- return content_rect.width() <=
- viewport_size.width() + tiler_->tile_size().width() &&
- content_rect.height() <=
- viewport_size.height() + tiler_->tile_size().height();
-}
-
-namespace {
-// FIXME: Remove this and make this based on distance once distance can be
-// calculated for offscreen layers. For now, prioritize all small animated
-// layers after 512 pixels of pre-painting.
-void SetPriorityForTexture(gfx::Rect visible_rect,
- gfx::Rect tile_rect,
- bool draws_to_root,
- bool is_small_animated_layer,
- PrioritizedResource* texture) {
- int priority = PriorityCalculator::LowestPriority();
- if (!visible_rect.IsEmpty()) {
- priority = PriorityCalculator::PriorityFromDistance(
- visible_rect, tile_rect, draws_to_root);
- }
-
- if (is_small_animated_layer) {
- priority = PriorityCalculator::max_priority(
- priority, PriorityCalculator::SmallAnimatedLayerMinPriority());
- }
-
- if (priority != PriorityCalculator::LowestPriority())
- texture->setRequestPriority(priority);
-}
-} // namespace
-
-void TiledLayer::SetTexturePriorities(const PriorityCalculator& priority_calc) {
- UpdateBounds();
- ResetUpdateState();
- UpdateScrollPrediction();
-
- if (tiler_->has_empty_bounds())
- return;
-
- bool draws_to_root = !render_target()->parent();
- bool small_animated_layer = IsSmallAnimatedLayer();
-
- // Minimally create the tiles in the desired pre-paint rect.
- gfx::Rect create_tiles_rect = IdlePaintRect();
- if (small_animated_layer)
- create_tiles_rect = gfx::Rect(gfx::Point(), content_bounds());
- if (!create_tiles_rect.IsEmpty()) {
- int left, top, right, bottom;
- tiler_->ContentRectToTileIndices(
- create_tiles_rect, &left, &top, &right, &bottom);
- for (int j = top; j <= bottom; ++j) {
- for (int i = left; i <= right; ++i) {
- if (!TileAt(i, j))
- CreateTile(i, j);
- }
- }
- }
-
- // Now update priorities on all tiles we have in the layer, no matter where
- // they are.
- for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
- iter != tiler_->tiles().end();
- ++iter) {
- UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
- gfx::Rect tile_rect = tiler_->TileRect(tile);
- SetPriorityForTexture(predicted_visible_rect_,
- tile_rect,
- draws_to_root,
- small_animated_layer,
- tile->managed_resource());
- }
-}
-
-Region TiledLayer::VisibleContentOpaqueRegion() const {
- if (skips_draw_)
- return Region();
- if (contents_opaque())
- return visible_content_rect();
- return tiler_->OpaqueRegionInContentRect(visible_content_rect());
-}
-
-void TiledLayer::ResetUpdateState() {
- skips_draw_ = false;
- failed_update_ = false;
-
- LayerTilingData::TileMap::const_iterator end = tiler_->tiles().end();
- for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
- iter != end;
- ++iter) {
- UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
- // FIXME: This should not ever be null.
- if (!tile)
- continue;
- tile->ResetUpdateState();
- }
-}
-
-namespace {
-gfx::Rect ExpandRectByDelta(gfx::Rect rect, gfx::Vector2d delta) {
- int width = rect.width() + std::abs(delta.x());
- int height = rect.height() + std::abs(delta.y());
- int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0);
- int y = rect.y() + ((delta.y() < 0) ? delta.y() : 0);
- return gfx::Rect(x, y, width, height);
-}
-}
-
-void TiledLayer::UpdateScrollPrediction() {
- // This scroll prediction is very primitive and should be replaced by a
- // a recursive calculation on all layers which uses actual scroll/animation
- // velocities. To insure this doesn't miss-predict, we only use it to predict
- // the visible_rect if:
- // - content_bounds() hasn't changed.
- // - visible_rect.size() hasn't changed.
- // These two conditions prevent rotations, scales, pinch-zooms etc. where
- // the prediction would be incorrect.
- gfx::Vector2d delta = visible_content_rect().CenterPoint() -
- previous_visible_rect_.CenterPoint();
- predicted_scroll_ = -delta;
- predicted_visible_rect_ = visible_content_rect();
- if (previous_content_bounds_ == content_bounds() &&
- previous_visible_rect_.size() == visible_content_rect().size()) {
- // Only expand the visible rect in the major scroll direction, to prevent
- // massive paints due to diagonal scrolls.
- gfx::Vector2d major_scroll_delta =
- (std::abs(delta.x()) > std::abs(delta.y())) ?
- gfx::Vector2d(delta.x(), 0) :
- gfx::Vector2d(0, delta.y());
- predicted_visible_rect_ =
- ExpandRectByDelta(visible_content_rect(), major_scroll_delta);
-
- // Bound the prediction to prevent unbounded paints, and clamp to content
- // bounds.
- gfx::Rect bound = visible_content_rect();
- bound.Inset(-tiler_->tile_size().width() * kMaxPredictiveTilesCount,
- -tiler_->tile_size().height() * kMaxPredictiveTilesCount);
- bound.Intersect(gfx::Rect(gfx::Point(), content_bounds()));
- predicted_visible_rect_.Intersect(bound);
- }
- previous_content_bounds_ = content_bounds();
- previous_visible_rect_ = visible_content_rect();
-}
-
-void TiledLayer::Update(ResourceUpdateQueue* queue,
- const OcclusionTracker* occlusion,
- RenderingStats* stats) {
- DCHECK(!skips_draw_ && !failed_update_); // Did ResetUpdateState get skipped?
- {
- base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
- true);
-
- ContentsScalingLayer::Update(queue, occlusion, stats);
- UpdateBounds();
- }
-
- if (tiler_->has_empty_bounds() || !DrawsContent())
- return;
-
- bool did_paint = false;
-
- // Animation pre-paint. If the layer is small, try to paint it all
- // immediately whether or not it is occluded, to avoid paint/upload
- // hiccups while it is animating.
- if (IsSmallAnimatedLayer()) {
- int left, top, right, bottom;
- tiler_->ContentRectToTileIndices(gfx::Rect(gfx::Point(), content_bounds()),
- &left,
- &top,
- &right,
- &bottom);
- UpdateTiles(left, top, right, bottom, queue, NULL, stats, &did_paint);
- if (did_paint)
- return;
- // This was an attempt to paint the entire layer so if we fail it's okay,
- // just fallback on painting visible etc. below.
- failed_update_ = false;
- }
-
- if (predicted_visible_rect_.IsEmpty())
- return;
-
- // Visible painting. First occlude visible tiles and paint the non-occluded
- // tiles.
- int left, top, right, bottom;
- tiler_->ContentRectToTileIndices(
- predicted_visible_rect_, &left, &top, &right, &bottom);
- MarkOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
- skips_draw_ = !UpdateTiles(
- left, top, right, bottom, queue, occlusion, stats, &did_paint);
- if (skips_draw_)
- tiler_->reset();
- if (skips_draw_ || did_paint)
- return;
-
- // If we have already painting everything visible. Do some pre-painting while
- // idle.
- gfx::Rect idle_paint_content_rect = IdlePaintRect();
- if (idle_paint_content_rect.IsEmpty())
- return;
-
- // Prepaint anything that was occluded but inside the layer's visible region.
- if (!UpdateTiles(left, top, right, bottom, queue, NULL, stats, &did_paint) ||
- did_paint)
- return;
-
- int prepaint_left, prepaint_top, prepaint_right, prepaint_bottom;
- tiler_->ContentRectToTileIndices(idle_paint_content_rect,
- &prepaint_left,
- &prepaint_top,
- &prepaint_right,
- &prepaint_bottom);
-
- // Then expand outwards one row/column at a time until we find a dirty
- // row/column to update. Increment along the major and minor scroll directions
- // first.
- gfx::Vector2d delta = -predicted_scroll_;
- delta = gfx::Vector2d(delta.x() == 0 ? 1 : delta.x(),
- delta.y() == 0 ? 1 : delta.y());
- gfx::Vector2d major_delta =
- (abs(delta.x()) > abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
- : gfx::Vector2d(0, delta.y());
- gfx::Vector2d minor_delta =
- (abs(delta.x()) <= abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
- : gfx::Vector2d(0, delta.y());
- gfx::Vector2d deltas[4] = { major_delta, minor_delta, -major_delta,
- -minor_delta };
- for (int i = 0; i < 4; i++) {
- if (deltas[i].y() > 0) {
- while (bottom < prepaint_bottom) {
- ++bottom;
- if (!UpdateTiles(
- left, bottom, right, bottom, queue, NULL, stats, &did_paint) ||
- did_paint)
- return;
- }
- }
- if (deltas[i].y() < 0) {
- while (top > prepaint_top) {
- --top;
- if (!UpdateTiles(
- left, top, right, top, queue, NULL, stats, &did_paint) ||
- did_paint)
- return;
- }
- }
- if (deltas[i].x() < 0) {
- while (left > prepaint_left) {
- --left;
- if (!UpdateTiles(
- left, top, left, bottom, queue, NULL, stats, &did_paint) ||
- did_paint)
- return;
- }
- }
- if (deltas[i].x() > 0) {
- while (right < prepaint_right) {
- ++right;
- if (!UpdateTiles(
- right, top, right, bottom, queue, NULL, stats, &did_paint) ||
- did_paint)
- return;
- }
- }
- }
-}
-
-bool TiledLayer::NeedsIdlePaint() {
- // Don't trigger more paints if we failed (as we'll just fail again).
- if (failed_update_ || visible_content_rect().IsEmpty() ||
- tiler_->has_empty_bounds() || !DrawsContent())
- return false;
-
- gfx::Rect idle_paint_content_rect = IdlePaintRect();
- if (idle_paint_content_rect.IsEmpty())
- return false;
-
- int left, top, right, bottom;
- tiler_->ContentRectToTileIndices(
- idle_paint_content_rect, &left, &top, &right, &bottom);
-
- for (int j = top; j <= bottom; ++j) {
- for (int i = left; i <= right; ++i) {
- UpdatableTile* tile = TileAt(i, j);
- DCHECK(tile); // Did SetTexturePriorities get skipped?
- if (!tile)
- continue;
-
- bool updated = !tile->update_rect.IsEmpty();
- bool can_acquire = tile->managed_resource()->canAcquireBackingTexture();
- bool dirty =
- tile->is_dirty() || !tile->managed_resource()->haveBackingTexture();
- if (!updated && can_acquire && dirty)
- return true;
- }
- }
- return false;
-}
-
-gfx::Rect TiledLayer::IdlePaintRect() {
- // Don't inflate an empty rect.
- if (visible_content_rect().IsEmpty())
- return gfx::Rect();
-
- gfx::Rect prepaint_rect = visible_content_rect();
- prepaint_rect.Inset(-tiler_->tile_size().width() * kPrepaintColumns,
- -tiler_->tile_size().height() * kPrepaintRows);
- gfx::Rect content_rect(content_bounds());
- prepaint_rect.Intersect(content_rect);
-
- return prepaint_rect;
-}
-
-} // namespace cc
« 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