| 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
|
|
|