Index: cc/layers/tiled_layer.cc |
diff --git a/cc/layers/tiled_layer.cc b/cc/layers/tiled_layer.cc |
deleted file mode 100644 |
index 55143befe9305b55ef351dd7f7ae7d2ce77ce233..0000000000000000000000000000000000000000 |
--- a/cc/layers/tiled_layer.cc |
+++ /dev/null |
@@ -1,869 +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/layers/tiled_layer.h" |
- |
-#include <algorithm> |
-#include <vector> |
- |
-#include "base/auto_reset.h" |
-#include "base/basictypes.h" |
-#include "build/build_config.h" |
-#include "cc/base/simple_enclosed_region.h" |
-#include "cc/layers/layer_impl.h" |
-#include "cc/layers/tiled_layer_impl.h" |
-#include "cc/resources/layer_updater.h" |
-#include "cc/resources/prioritized_resource.h" |
-#include "cc/resources/priority_calculator.h" |
-#include "cc/trees/layer_tree_host.h" |
-#include "cc/trees/occlusion_tracker.h" |
-#include "ui/gfx/geometry/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_(RGBA_8888), |
- 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()); |
-} |
- |
-void TiledLayer::UpdateTileSizeAndTilingOption() { |
- DCHECK(layer_tree_host()); |
- |
- gfx::Size default_tile_size = layer_tree_host()->settings().default_tile_size; |
- gfx::Size max_untiled_layer_size = |
- layer_tree_host()->settings().max_untiled_layer_size; |
- 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.SetToMin(gfx::Size(max_size, max_size)); |
- SetTileSize(requested_size); |
-} |
- |
-void TiledLayer::UpdateBounds() { |
- gfx::Size old_tiling_size = tiler_->tiling_size(); |
- gfx::Size new_tiling_size = content_bounds(); |
- if (old_tiling_size == new_tiling_size) |
- return; |
- tiler_->SetTilingSize(new_tiling_size); |
- |
- // Invalidate any areas that the new bounds exposes. |
- Region new_region = |
- SubtractRegions(gfx::Rect(new_tiling_size), gfx::Rect(old_tiling_size)); |
- for (Region::Iterator new_rects(new_region); new_rects.has_rect(); |
- new_rects.next()) |
- InvalidateContentRect(new_rects.rect()); |
- UpdateDrawsContent(HasDrawableContent()); |
-} |
- |
-void TiledLayer::SetTileSize(const gfx::Size& size) { |
- tiler_->SetTileSize(size); |
- UpdateDrawsContent(HasDrawableContent()); |
-} |
- |
-void TiledLayer::SetBorderTexelOption( |
- LayerTilingData::BorderTexelOption border_texel_option) { |
- tiler_->SetBorderTexelOption(border_texel_option); |
- UpdateDrawsContent(HasDrawableContent()); |
-} |
- |
-bool TiledLayer::HasDrawableContent() const { |
- bool has_more_than_one_tile = |
- (tiler_->num_tiles_x() > 1) || (tiler_->num_tiles_y() > 1); |
- |
- return !(tiling_option_ == NEVER_TILE && has_more_than_one_tile) && |
- ContentsScalingLayer::HasDrawableContent(); |
-} |
- |
-void TiledLayer::ReduceMemoryUsage() { |
- if (Updater()) |
- Updater()->ReduceMemoryUsage(); |
-} |
- |
-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); |
- // TODO(enne): This should not ever be null. |
- if (!tile) |
- continue; |
- |
- if (!tile->managed_resource()->have_backing_texture()) { |
- // 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()->resource_id(), |
- tile->managed_resource()->contents_swizzled()); |
- } |
- for (std::vector<UpdatableTile*>::const_iterator iter = invalid_tiles.begin(); |
- iter != invalid_tiles.end(); |
- ++iter) |
- tiler_->TakeTile((*iter)->i(), (*iter)->j()); |
- |
- // TiledLayer must push properties every frame, since viewport state and |
- // occlusion from anywhere in the tree can change what the layer decides to |
- // push to the impl tree. |
- needs_push_properties_ = true; |
-} |
- |
-PrioritizedResourceManager* TiledLayer::ResourceManager() { |
- if (!layer_tree_host()) |
- return nullptr; |
- return layer_tree_host()->contents_texture_manager(); |
-} |
- |
-const PrioritizedResource* TiledLayer::ResourceAtForTesting(int i, |
- int j) const { |
- UpdatableTile* tile = TileAt(i, j); |
- if (!tile) |
- return nullptr; |
- 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); |
- // TODO(enne): 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.Pass(), 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::Rect& dirty_rect) { |
- InvalidateContentRect(LayerRectToContentRect(dirty_rect)); |
- ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect); |
-} |
- |
-void TiledLayer::InvalidateContentRect(const 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); |
- // TODO(enne): 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()->have_backing_texture(); |
-} |
- |
-bool TiledLayer::UpdateTiles(int left, |
- int top, |
- int right, |
- int bottom, |
- ResourceUpdateQueue* queue, |
- const OcclusionTracker<Layer>* occlusion, |
- bool* updated) { |
- CreateUpdaterIfNeeded(); |
- |
- bool ignore_occlusions = !occlusion; |
- if (!HaveTexturesForTiles(left, top, right, bottom, ignore_occlusions)) { |
- failed_update_ = true; |
- return false; |
- } |
- |
- gfx::Rect update_rect; |
- gfx::Rect paint_rect; |
- MarkTilesForUpdate( |
- &update_rect, &paint_rect, left, top, right, bottom, ignore_occlusions); |
- |
- if (paint_rect.IsEmpty()) |
- return true; |
- |
- *updated = true; |
- UpdateTileTextures( |
- update_rect, paint_rect, left, top, right, bottom, queue, occlusion); |
- return true; |
-} |
- |
-void TiledLayer::MarkOcclusionsAndRequestTextures( |
- int left, |
- int top, |
- int right, |
- int bottom, |
- const OcclusionTracker<Layer>* occlusion) { |
- 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? |
- // TODO(enne): 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 (!draw_transform_is_animating() && occlusion && |
- occlusion->GetCurrentOcclusionForLayer(draw_transform()) |
- .IsOccluded(visible_tile_rect)) { |
- tile->occluded = true; |
- occluded_tile_count++; |
- } else { |
- succeeded &= tile->managed_resource()->RequestLate(); |
- } |
- } |
- } |
-} |
- |
-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? |
- // TODO(enne): 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()->have_backing_texture()) |
- 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()->can_acquire_backing_texture()) |
- return false; |
- } |
- } |
- return true; |
-} |
- |
-void TiledLayer::MarkTilesForUpdate(gfx::Rect* update_rect, |
- gfx::Rect* paint_rect, |
- 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? |
- // TODO(enne): This should not ever be null. |
- if (!tile) |
- continue; |
- if (tile->occluded && !ignore_occlusions) |
- continue; |
- |
- // Prepare update rect from original dirty rects. |
- update_rect->Union(tile->dirty_rect); |
- |
- // TODO(reveman): 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()->AlwaysUsePartialTextureUpdates()) { |
- // 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(); |
- } |
- } |
-} |
- |
-void TiledLayer::UpdateTileTextures(const gfx::Rect& update_rect, |
- const gfx::Rect& paint_rect, |
- int left, |
- int top, |
- int right, |
- int bottom, |
- ResourceUpdateQueue* queue, |
- const OcclusionTracker<Layer>* occlusion) { |
- // 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 = 1 / draw_properties().contents_scale_x; |
- float height_scale = 1 / draw_properties().contents_scale_y; |
- update_rect_ = |
- gfx::ScaleToEnclosingRect(update_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()); |
- Updater()->PrepareToUpdate(content_bounds(), |
- paint_rect, |
- tiler_->tile_size(), |
- 1.f / width_scale, |
- 1.f / height_scale); |
- |
- 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? |
- // TODO(enne): 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; |
- |
- // 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); |
- } |
- } |
-} |
- |
-// 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(content_bounds()); |
- return content_rect.width() <= |
- viewport_size.width() + tiler_->tile_size().width() && |
- content_rect.height() <= |
- viewport_size.height() + tiler_->tile_size().height(); |
-} |
- |
-namespace { |
-// TODO(epenner): 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(const gfx::Rect& visible_rect, |
- const 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->set_request_priority(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(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); |
- // TODO(enne): 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()); |
- } |
-} |
- |
-SimpleEnclosedRegion TiledLayer::VisibleContentOpaqueRegion() const { |
- if (skips_draw_) |
- return SimpleEnclosedRegion(); |
- return Layer::VisibleContentOpaqueRegion(); |
-} |
- |
-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); |
- // TODO(enne): This should not ever be null. |
- if (!tile) |
- continue; |
- tile->ResetUpdateState(); |
- } |
-} |
- |
-namespace { |
-gfx::Rect ExpandRectByDelta(const gfx::Rect& rect, const 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(content_bounds())); |
- predicted_visible_rect_.Intersect(bound); |
- } |
- previous_content_bounds_ = content_bounds(); |
- previous_visible_rect_ = visible_content_rect(); |
-} |
- |
-bool TiledLayer::Update(ResourceUpdateQueue* queue, |
- const OcclusionTracker<Layer>* occlusion) { |
- DCHECK(!skips_draw_ && !failed_update_); // Did ResetUpdateState get skipped? |
- |
- // Tiled layer always causes commits to wait for activation, as it does |
- // not support pending trees. |
- SetNextCommitWaitsForActivation(); |
- |
- bool updated = false; |
- |
- { |
- base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_, |
- true); |
- |
- updated |= ContentsScalingLayer::Update(queue, occlusion); |
- UpdateBounds(); |
- } |
- |
- if (tiler_->has_empty_bounds() || !DrawsContent()) |
- return 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(content_bounds()), |
- &left, |
- &top, |
- &right, |
- &bottom); |
- UpdateTiles(left, top, right, bottom, queue, nullptr, &updated); |
- if (updated) |
- return updated; |
- // 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 updated; |
- |
- // 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, &updated); |
- if (skips_draw_) |
- tiler_->reset(); |
- if (skips_draw_ || updated) |
- return true; |
- |
- // 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 updated; |
- |
- // Prepaint anything that was occluded but inside the layer's visible region. |
- if (!UpdateTiles(left, top, right, bottom, queue, nullptr, &updated) || |
- updated) |
- return updated; |
- |
- 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 = |
- (std::abs(delta.x()) > std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0) |
- : gfx::Vector2d(0, delta.y()); |
- gfx::Vector2d minor_delta = |
- (std::abs(delta.x()) <= std::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, nullptr, &updated) || |
- updated) |
- return updated; |
- } |
- } |
- if (deltas[i].y() < 0) { |
- while (top > prepaint_top) { |
- --top; |
- if (!UpdateTiles(left, top, right, top, queue, nullptr, &updated) || |
- updated) |
- return updated; |
- } |
- } |
- if (deltas[i].x() < 0) { |
- while (left > prepaint_left) { |
- --left; |
- if (!UpdateTiles(left, top, left, bottom, queue, nullptr, &updated) || |
- updated) |
- return updated; |
- } |
- } |
- if (deltas[i].x() > 0) { |
- while (right < prepaint_right) { |
- ++right; |
- if (!UpdateTiles(right, top, right, bottom, queue, nullptr, &updated) || |
- updated) |
- return updated; |
- } |
- } |
- } |
- return updated; |
-} |
- |
-void TiledLayer::OnOutputSurfaceCreated() { |
- // Ensure that all textures are of the right format. |
- for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin(); |
- iter != tiler_->tiles().end(); |
- ++iter) { |
- UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second); |
- if (!tile) |
- continue; |
- PrioritizedResource* resource = tile->managed_resource(); |
- resource->SetDimensions(resource->size(), texture_format_); |
- } |
-} |
- |
-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()->can_acquire_backing_texture(); |
- bool dirty = |
- tile->is_dirty() || !tile->managed_resource()->have_backing_texture(); |
- 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 |