#include <algorithm>
#include <limits>
+#include <set>
+#include "base/debug/trace_event_argument.h"
#include "base/time/time.h"
#include "cc/base/math_util.h"
#include "cc/base/util.h"
#include "cc/debug/micro_benchmark_impl.h"
#include "cc/debug/traced_value.h"
#include "cc/layers/append_quads_data.h"
-#include "cc/layers/quad_sink.h"
+#include "cc/layers/solid_color_layer_impl.h"
+#include "cc/output/begin_frame_args.h"
#include "cc/quads/checkerboard_draw_quad.h"
#include "cc/quads/debug_border_draw_quad.h"
#include "cc/quads/picture_draw_quad.h"
#include "cc/quads/solid_color_draw_quad.h"
#include "cc/quads/tile_draw_quad.h"
#include "cc/resources/tile_manager.h"
+#include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/occlusion_tracker.h"
#include "ui/gfx/quad_f.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size_conversions.h"
// When creating a new tiling during pinch, snap to an existing
// tiling's scale if the desired scale is within this ratio.
-const float kSnapToExistingTilingRatio = 0.2f;
+const float kSnapToExistingTilingRatio = 1.2f;
// Estimate skewport 60 frames ahead for pre-rasterization on the CPU.
const float kCpuSkewportTargetTimeInFrames = 60.0f;
// Don't pre-rasterize on the GPU (except for kBackflingGuardDistancePixels in
// TileManager::BinFromTilePriority).
const float kGpuSkewportTargetTimeInFrames = 0.0f;
+
} // namespace
namespace cc {
+PictureLayerImpl::Pair::Pair() : active(NULL), pending(NULL) {
+}
+
+PictureLayerImpl::Pair::Pair(PictureLayerImpl* active_layer,
+ PictureLayerImpl* pending_layer)
+ : active(active_layer), pending(pending_layer) {
+}
+
+PictureLayerImpl::Pair::~Pair() {
+}
+
PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* tree_impl, int id)
: LayerImpl(tree_impl, id),
twin_layer_(NULL),
pile_(PicturePileImpl::Create()),
- is_mask_(false),
ideal_page_scale_(0.f),
ideal_device_scale_(0.f),
ideal_source_scale_(0.f),
raster_contents_scale_(0.f),
low_res_raster_contents_scale_(0.f),
raster_source_scale_is_fixed_(false),
- was_animating_transform_to_screen_(false),
- is_using_lcd_text_(tree_impl->settings().can_use_lcd_text),
+ was_screen_space_transform_animating_(false),
needs_post_commit_initialization_(true),
- should_update_tile_priorities_(false),
- should_use_low_res_tiling_(tree_impl->settings().create_low_res_tiling),
- layer_needs_to_register_itself_(true) {
+ should_update_tile_priorities_(false) {
+ layer_tree_impl()->RegisterPictureLayerImpl(this);
}
PictureLayerImpl::~PictureLayerImpl() {
- if (!layer_needs_to_register_itself_)
- layer_tree_impl()->tile_manager()->UnregisterPictureLayerImpl(this);
+ layer_tree_impl()->UnregisterPictureLayerImpl(this);
}
const char* PictureLayerImpl::LayerTypeAsString() const {
LayerImpl::PushPropertiesTo(base_layer);
// When the pending tree pushes to the active tree, the pending twin
- // disappears.
+ // becomes recycled.
layer_impl->twin_layer_ = NULL;
twin_layer_ = NULL;
- layer_impl->SetIsMask(is_mask_);
layer_impl->pile_ = pile_;
+ DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
// Tilings would be expensive to push, so we swap.
layer_impl->tilings_.swap(tilings_);
-
- // Ensure that we don't have any tiles that are out of date.
- if (tilings_)
- tilings_->RemoveTilesInRegion(invalidation_);
-
layer_impl->tilings_->SetClient(layer_impl);
if (tilings_)
tilings_->SetClient(this);
+ // Ensure that the recycle tree doesn't have any unshared tiles.
+ if (tilings_ && pile_->is_solid_color())
+ tilings_->RemoveAllTilings();
+
+ // Remove invalidated tiles from what will become a recycle tree.
+ if (tilings_)
+ tilings_->RemoveTilesInRegion(invalidation_);
+
layer_impl->raster_page_scale_ = raster_page_scale_;
layer_impl->raster_device_scale_ = raster_device_scale_;
layer_impl->raster_source_scale_ = raster_source_scale_;
layer_impl->raster_contents_scale_ = raster_contents_scale_;
layer_impl->low_res_raster_contents_scale_ = low_res_raster_contents_scale_;
-
- layer_impl->UpdateLCDTextStatus(is_using_lcd_text_);
layer_impl->needs_post_commit_initialization_ = false;
// The invalidation on this soon-to-be-recycled layer must be cleared to
needs_push_properties_ = true;
}
-void PictureLayerImpl::AppendQuads(QuadSink* quad_sink,
- AppendQuadsData* append_quads_data) {
+void PictureLayerImpl::AppendQuads(
+ RenderPass* render_pass,
+ const OcclusionTracker<LayerImpl>& occlusion_tracker,
+ AppendQuadsData* append_quads_data) {
DCHECK(!needs_post_commit_initialization_);
- gfx::Rect rect(visible_content_rect());
- gfx::Rect content_rect(content_bounds());
- SharedQuadState* shared_quad_state = quad_sink->CreateSharedQuadState();
- PopulateSharedQuadState(shared_quad_state);
+ SharedQuadState* shared_quad_state =
+ render_pass->CreateAndAppendSharedQuadState();
+
+ if (pile_->is_solid_color()) {
+ PopulateSharedQuadState(shared_quad_state);
+
+ AppendDebugBorderQuad(
+ render_pass, content_bounds(), shared_quad_state, append_quads_data);
+
+ SolidColorLayerImpl::AppendSolidQuads(
+ render_pass,
+ occlusion_tracker,
+ shared_quad_state,
+ content_bounds(),
+ draw_properties().target_space_transform,
+ pile_->solid_color());
+ return;
+ }
+
+ float max_contents_scale = MaximumTilingContentsScale();
+ gfx::Transform scaled_draw_transform = draw_transform();
+ scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
+ SK_MScalar1 / max_contents_scale);
+ gfx::Size scaled_content_bounds =
+ gfx::ToCeiledSize(gfx::ScaleSize(content_bounds(), max_contents_scale));
+
+ gfx::Rect scaled_visible_content_rect =
+ gfx::ScaleToEnclosingRect(visible_content_rect(), max_contents_scale);
+ scaled_visible_content_rect.Intersect(gfx::Rect(scaled_content_bounds));
+
+ Occlusion occlusion =
+ occlusion_tracker.GetCurrentOcclusionForLayer(scaled_draw_transform);
+
+ shared_quad_state->SetAll(scaled_draw_transform,
+ scaled_content_bounds,
+ scaled_visible_content_rect,
+ draw_properties().clip_rect,
+ draw_properties().is_clipped,
+ draw_properties().opacity,
+ blend_mode(),
+ sorting_context_id_);
if (current_draw_mode_ == DRAW_MODE_RESOURCELESS_SOFTWARE) {
AppendDebugBorderQuad(
- quad_sink,
+ render_pass,
+ scaled_content_bounds,
shared_quad_state,
append_quads_data,
DebugColors::DirectPictureBorderColor(),
DebugColors::DirectPictureBorderWidth(layer_tree_impl()));
- gfx::Rect geometry_rect = rect;
+ gfx::Rect geometry_rect = scaled_visible_content_rect;
gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
gfx::Rect visible_geometry_rect =
- quad_sink->UnoccludedContentRect(geometry_rect, draw_transform());
+ occlusion.GetUnoccludedContentRect(geometry_rect);
if (visible_geometry_rect.IsEmpty())
return;
- gfx::Size texture_size = rect.size();
+ gfx::Size texture_size = scaled_visible_content_rect.size();
gfx::RectF texture_rect = gfx::RectF(texture_size);
- gfx::Rect quad_content_rect = rect;
- float contents_scale = contents_scale_x();
+ gfx::Rect quad_content_rect = scaled_visible_content_rect;
- scoped_ptr<PictureDrawQuad> quad = PictureDrawQuad::Create();
+ PictureDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
quad->SetNew(shared_quad_state,
geometry_rect,
opaque_rect,
texture_size,
RGBA_8888,
quad_content_rect,
- contents_scale,
+ max_contents_scale,
pile_);
- quad_sink->Append(quad.PassAs<DrawQuad>());
- append_quads_data->num_missing_tiles++;
return;
}
- AppendDebugBorderQuad(quad_sink, shared_quad_state, append_quads_data);
+ AppendDebugBorderQuad(
+ render_pass, scaled_content_bounds, shared_quad_state, append_quads_data);
if (ShowDebugBorders()) {
for (PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(), contents_scale_x(), rect, ideal_contents_scale_);
+ tilings_.get(),
+ max_contents_scale,
+ scaled_visible_content_rect,
+ ideal_contents_scale_);
iter;
++iter) {
SkColor color;
} else if (iter->priority(ACTIVE_TREE).resolution == LOW_RESOLUTION) {
color = DebugColors::LowResTileBorderColor();
width = DebugColors::LowResTileBorderWidth(layer_tree_impl());
- } else if (iter->contents_scale() > contents_scale_x()) {
+ } else if (iter->contents_scale() > max_contents_scale) {
color = DebugColors::ExtraHighResTileBorderColor();
width = DebugColors::ExtraHighResTileBorderWidth(layer_tree_impl());
} else {
width = DebugColors::MissingTileBorderWidth(layer_tree_impl());
}
- scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
- DebugBorderDrawQuad::Create();
+ DebugBorderDrawQuad* debug_border_quad =
+ render_pass->CreateAndAppendDrawQuad<DebugBorderDrawQuad>();
gfx::Rect geometry_rect = iter.geometry_rect();
gfx::Rect visible_geometry_rect = geometry_rect;
debug_border_quad->SetNew(shared_quad_state,
visible_geometry_rect,
color,
width);
- quad_sink->Append(debug_border_quad.PassAs<DrawQuad>());
}
}
// unused can be considered for removal.
std::vector<PictureLayerTiling*> seen_tilings;
- for (PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(), contents_scale_x(), rect, ideal_contents_scale_);
+ // Ignore missing tiles outside of viewport for tile priority. This is
+ // normally the same as draw viewport but can be independently overridden by
+ // embedders like Android WebView with SetExternalDrawConstraints.
+ gfx::Rect scaled_viewport_for_tile_priority = gfx::ScaleToEnclosingRect(
+ GetViewportForTilePriorityInContentSpace(), max_contents_scale);
+
+ size_t missing_tile_count = 0u;
+ size_t on_demand_missing_tile_count = 0u;
+ for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
+ max_contents_scale,
+ scaled_visible_content_rect,
+ ideal_contents_scale_);
iter;
++iter) {
gfx::Rect geometry_rect = iter.geometry_rect();
+ gfx::Rect opaque_rect = contents_opaque() ? geometry_rect : gfx::Rect();
gfx::Rect visible_geometry_rect =
- quad_sink->UnoccludedContentRect(geometry_rect, draw_transform());
+ occlusion.GetUnoccludedContentRect(geometry_rect);
if (visible_geometry_rect.IsEmpty())
continue;
append_quads_data->visible_content_area +=
visible_geometry_rect.width() * visible_geometry_rect.height();
- if (!*iter || !iter->IsReadyToDraw()) {
+ bool has_draw_quad = false;
+ if (*iter && iter->IsReadyToDraw()) {
+ const ManagedTileState::TileVersion& tile_version =
+ iter->GetTileVersionForDrawing();
+ switch (tile_version.mode()) {
+ case ManagedTileState::TileVersion::RESOURCE_MODE: {
+ gfx::RectF texture_rect = iter.texture_rect();
+
+ // The raster_contents_scale_ is the best scale that the layer is
+ // trying to produce, even though it may not be ideal. Since that's
+ // the best the layer can promise in the future, consider those as
+ // complete. But if a tile is ideal scale, we don't want to consider
+ // it incomplete and trying to replace it with a tile at a worse
+ // scale.
+ if (iter->contents_scale() != raster_contents_scale_ &&
+ iter->contents_scale() != ideal_contents_scale_ &&
+ geometry_rect.Intersects(scaled_viewport_for_tile_priority)) {
+ append_quads_data->num_incomplete_tiles++;
+ }
+
+ TileDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<TileDrawQuad>();
+ quad->SetNew(shared_quad_state,
+ geometry_rect,
+ opaque_rect,
+ visible_geometry_rect,
+ tile_version.get_resource_id(),
+ texture_rect,
+ iter.texture_size(),
+ tile_version.contents_swizzled());
+ has_draw_quad = true;
+ break;
+ }
+ case ManagedTileState::TileVersion::PICTURE_PILE_MODE: {
+ if (!layer_tree_impl()
+ ->GetRendererCapabilities()
+ .allow_rasterize_on_demand) {
+ ++on_demand_missing_tile_count;
+ break;
+ }
+
+ gfx::RectF texture_rect = iter.texture_rect();
+
+ ResourceProvider* resource_provider =
+ layer_tree_impl()->resource_provider();
+ ResourceFormat format =
+ resource_provider->memory_efficient_texture_format();
+ PictureDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<PictureDrawQuad>();
+ quad->SetNew(shared_quad_state,
+ geometry_rect,
+ opaque_rect,
+ visible_geometry_rect,
+ texture_rect,
+ iter.texture_size(),
+ format,
+ iter->content_rect(),
+ iter->contents_scale(),
+ pile_);
+ has_draw_quad = true;
+ break;
+ }
+ case ManagedTileState::TileVersion::SOLID_COLOR_MODE: {
+ SolidColorDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
+ quad->SetNew(shared_quad_state,
+ geometry_rect,
+ visible_geometry_rect,
+ tile_version.get_solid_color(),
+ false);
+ has_draw_quad = true;
+ break;
+ }
+ }
+ }
+
+ if (!has_draw_quad) {
if (draw_checkerboard_for_missing_tiles()) {
- scoped_ptr<CheckerboardDrawQuad> quad = CheckerboardDrawQuad::Create();
+ CheckerboardDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<CheckerboardDrawQuad>();
SkColor color = DebugColors::DefaultCheckerboardColor();
quad->SetNew(
shared_quad_state, geometry_rect, visible_geometry_rect, color);
- quad_sink->Append(quad.PassAs<DrawQuad>());
} else {
SkColor color = SafeOpaqueBackgroundColor();
- scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
+ SolidColorDrawQuad* quad =
+ render_pass->CreateAndAppendDrawQuad<SolidColorDrawQuad>();
quad->SetNew(shared_quad_state,
geometry_rect,
visible_geometry_rect,
color,
false);
- quad_sink->Append(quad.PassAs<DrawQuad>());
}
- append_quads_data->num_missing_tiles++;
- append_quads_data->had_incomplete_tile = true;
+ if (geometry_rect.Intersects(scaled_viewport_for_tile_priority)) {
+ append_quads_data->num_missing_tiles++;
+ ++missing_tile_count;
+ }
append_quads_data->approximated_visible_content_area +=
visible_geometry_rect.width() * visible_geometry_rect.height();
continue;
}
- const ManagedTileState::TileVersion& tile_version =
- iter->GetTileVersionForDrawing();
- scoped_ptr<DrawQuad> draw_quad;
- switch (tile_version.mode()) {
- case ManagedTileState::TileVersion::RESOURCE_MODE: {
- gfx::RectF texture_rect = iter.texture_rect();
- gfx::Rect opaque_rect = iter->opaque_rect();
- opaque_rect.Intersect(geometry_rect);
-
- if (iter->contents_scale() != ideal_contents_scale_)
- append_quads_data->had_incomplete_tile = true;
-
- scoped_ptr<TileDrawQuad> quad = TileDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- visible_geometry_rect,
- tile_version.get_resource_id(),
- texture_rect,
- iter.texture_size(),
- tile_version.contents_swizzled());
- draw_quad = quad.PassAs<DrawQuad>();
- break;
- }
- case ManagedTileState::TileVersion::PICTURE_PILE_MODE: {
- gfx::RectF texture_rect = iter.texture_rect();
- gfx::Rect opaque_rect = iter->opaque_rect();
- opaque_rect.Intersect(geometry_rect);
-
- ResourceProvider* resource_provider =
- layer_tree_impl()->resource_provider();
- ResourceFormat format =
- resource_provider->memory_efficient_texture_format();
- scoped_ptr<PictureDrawQuad> quad = PictureDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- opaque_rect,
- visible_geometry_rect,
- texture_rect,
- iter.texture_size(),
- format,
- iter->content_rect(),
- iter->contents_scale(),
- pile_);
- draw_quad = quad.PassAs<DrawQuad>();
- break;
- }
- case ManagedTileState::TileVersion::SOLID_COLOR_MODE: {
- scoped_ptr<SolidColorDrawQuad> quad = SolidColorDrawQuad::Create();
- quad->SetNew(shared_quad_state,
- geometry_rect,
- visible_geometry_rect,
- tile_version.get_solid_color(),
- false);
- draw_quad = quad.PassAs<DrawQuad>();
- break;
- }
- }
-
- DCHECK(draw_quad);
- quad_sink->Append(draw_quad.Pass());
-
if (iter->priority(ACTIVE_TREE).resolution != HIGH_RESOLUTION) {
append_quads_data->approximated_visible_content_area +=
visible_geometry_rect.width() * visible_geometry_rect.height();
seen_tilings.push_back(iter.CurrentTiling());
}
+ if (missing_tile_count) {
+ TRACE_EVENT_INSTANT2("cc",
+ "PictureLayerImpl::AppendQuads checkerboard",
+ TRACE_EVENT_SCOPE_THREAD,
+ "missing_tile_count",
+ missing_tile_count,
+ "on_demand_missing_tile_count",
+ on_demand_missing_tile_count);
+ }
+
// Aggressively remove any tilings that are not seen to save memory. Note
// that this is at the expense of doing cause more frequent re-painting. A
// better scheme would be to maintain a tighter visible_content_rect for the
CleanUpTilingsOnActiveLayer(seen_tilings);
}
-void PictureLayerImpl::DidUnregisterLayer() {
- layer_needs_to_register_itself_ = true;
-}
+void PictureLayerImpl::UpdateTiles(
+ const Occlusion& occlusion_in_content_space) {
+ TRACE_EVENT0("cc", "PictureLayerImpl::UpdateTiles");
+ DCHECK_EQ(1.f, contents_scale_x());
+ DCHECK_EQ(1.f, contents_scale_y());
-void PictureLayerImpl::UpdateTilePriorities() {
- DCHECK(!needs_post_commit_initialization_);
- CHECK(should_update_tile_priorities_);
+ DoPostCommitInitializationIfNeeded();
+
+ visible_rect_for_tile_priority_ = visible_content_rect();
+ viewport_rect_for_tile_priority_ =
+ layer_tree_impl()->ViewportRectForTilePriority();
+ screen_space_transform_for_tile_priority_ = screen_space_transform();
- if (layer_needs_to_register_itself_) {
- layer_tree_impl()->tile_manager()->RegisterPictureLayerImpl(this);
- layer_needs_to_register_itself_ = false;
+ if (!CanHaveTilings()) {
+ ideal_page_scale_ = 0.f;
+ ideal_device_scale_ = 0.f;
+ ideal_contents_scale_ = 0.f;
+ ideal_source_scale_ = 0.f;
+ SanityCheckTilingState();
+ return;
}
- if (layer_tree_impl()->device_viewport_valid_for_tile_management()) {
- visible_rect_for_tile_priority_ = visible_content_rect();
- viewport_size_for_tile_priority_ = layer_tree_impl()->DrawViewportSize();
- screen_space_transform_for_tile_priority_ = screen_space_transform();
+ UpdateIdealScales();
+
+ DCHECK(tilings_->num_tilings() > 0 || raster_contents_scale_ == 0.f)
+ << "A layer with no tilings shouldn't have valid raster scales";
+ if (!raster_contents_scale_ || ShouldAdjustRasterScale()) {
+ RecalculateRasterScales();
+ AddTilingsForRasterScale();
}
- if (!tilings_->num_tilings())
- return;
+ DCHECK(raster_page_scale_);
+ DCHECK(raster_device_scale_);
+ DCHECK(raster_source_scale_);
+ DCHECK(raster_contents_scale_);
+ DCHECK(low_res_raster_contents_scale_);
+
+ was_screen_space_transform_animating_ =
+ draw_properties().screen_space_transform_is_animating;
+
+ should_update_tile_priorities_ = true;
+
+ UpdateTilePriorities(occlusion_in_content_space);
+
+ if (layer_tree_impl()->IsPendingTree())
+ MarkVisibleResourcesAsRequired();
+}
+
+void PictureLayerImpl::UpdateTilePriorities(
+ const Occlusion& occlusion_in_content_space) {
+ DCHECK(!pile_->is_solid_color() || !tilings_->num_tilings());
+
+ TRACE_EVENT0("cc", "PictureLayerImpl::UpdateTilePriorities");
double current_frame_time_in_seconds =
- (layer_tree_impl()->CurrentFrameTimeTicks() -
+ (layer_tree_impl()->CurrentBeginFrameArgs().frame_time -
base::TimeTicks()).InSecondsF();
bool tiling_needs_update = false;
if (!tiling_needs_update)
return;
- UpdateLCDTextStatus(can_use_lcd_text());
+ gfx::Rect viewport_rect_in_layer_space =
+ GetViewportForTilePriorityInContentSpace();
+ WhichTree tree =
+ layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+ // Pass |occlusion_in_content_space| for |occlusion_in_layer_space| since
+ // they are the same space in picture lbayer, as contents scale is always 1.
+ tilings_->tiling_at(i)->UpdateTilePriorities(tree,
+ viewport_rect_in_layer_space,
+ ideal_contents_scale_,
+ current_frame_time_in_seconds,
+ occlusion_in_content_space);
+ }
+
+ // Tile priorities were modified.
+ layer_tree_impl()->DidModifyTilePriorities();
+}
- // Use visible_content_rect, unless it's empty. If it's empty, then
- // try to inverse project the viewport into layer space and use that.
+gfx::Rect PictureLayerImpl::GetViewportForTilePriorityInContentSpace() const {
+ // If visible_rect_for_tile_priority_ is empty or
+ // viewport_rect_for_tile_priority_ is set to be different from the device
+ // viewport, try to inverse project the viewport into layer space and use
+ // that. Otherwise just use visible_rect_for_tile_priority_
gfx::Rect visible_rect_in_content_space = visible_rect_for_tile_priority_;
- if (visible_rect_in_content_space.IsEmpty()) {
- gfx::Transform screen_to_layer(gfx::Transform::kSkipInitialization);
- if (screen_space_transform_for_tile_priority_.GetInverse(
- &screen_to_layer)) {
+
+ if (visible_rect_in_content_space.IsEmpty() ||
+ layer_tree_impl()->DeviceViewport() != viewport_rect_for_tile_priority_) {
+ gfx::Transform view_to_layer(gfx::Transform::kSkipInitialization);
+
+ if (screen_space_transform_for_tile_priority_.GetInverse(&view_to_layer)) {
+ // Transform from view space to content space.
visible_rect_in_content_space =
gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
- screen_to_layer, gfx::Rect(viewport_size_for_tile_priority_)));
- visible_rect_in_content_space.Intersect(gfx::Rect(content_bounds()));
+ view_to_layer, viewport_rect_for_tile_priority_));
}
}
+ return visible_rect_in_content_space;
+}
- WhichTree tree =
- layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
-
- tilings_->UpdateTilePriorities(tree,
- visible_rect_in_content_space,
- contents_scale_x(),
- current_frame_time_in_seconds);
-
- if (layer_tree_impl()->IsPendingTree())
- MarkVisibleResourcesAsRequired();
-
- // Tile priorities were modified.
- layer_tree_impl()->DidModifyTilePriorities();
+PictureLayerImpl* PictureLayerImpl::GetRecycledTwinLayer() {
+ // TODO(vmpstr): Maintain recycled twin as a member. crbug.com/407418
+ return static_cast<PictureLayerImpl*>(
+ layer_tree_impl()->FindRecycleTreeLayerById(id()));
}
-void PictureLayerImpl::NotifyTileInitialized(const Tile* tile) {
+void PictureLayerImpl::NotifyTileStateChanged(const Tile* tile) {
if (layer_tree_impl()->IsActiveTree()) {
gfx::RectF layer_damage_rect =
gfx::ScaleRect(tile->content_rect(), 1.f / tile->contents_scale());
layer_tree_impl()->set_needs_update_draw_properties();
}
-void PictureLayerImpl::CalculateContentsScale(
- float ideal_contents_scale,
- float device_scale_factor,
- float page_scale_factor,
- float maximum_animation_contents_scale,
- bool animating_transform_to_screen,
- float* contents_scale_x,
- float* contents_scale_y,
- gfx::Size* content_bounds) {
- DoPostCommitInitializationIfNeeded();
-
- // This function sets valid raster scales and manages tilings, so tile
- // priorities can now be updated.
- should_update_tile_priorities_ = true;
-
- if (!CanHaveTilings()) {
- ideal_page_scale_ = page_scale_factor;
- ideal_device_scale_ = device_scale_factor;
- ideal_contents_scale_ = ideal_contents_scale;
- ideal_source_scale_ =
- ideal_contents_scale_ / ideal_page_scale_ / ideal_device_scale_;
- *contents_scale_x = ideal_contents_scale_;
- *contents_scale_y = ideal_contents_scale_;
- *content_bounds = gfx::ToCeiledSize(gfx::ScaleSize(bounds(),
- ideal_contents_scale_,
- ideal_contents_scale_));
- return;
- }
-
- float min_contents_scale = MinimumContentsScale();
- DCHECK_GT(min_contents_scale, 0.f);
- float min_page_scale = layer_tree_impl()->min_page_scale_factor();
- DCHECK_GT(min_page_scale, 0.f);
- float min_device_scale = 1.f;
- float min_source_scale =
- min_contents_scale / min_page_scale / min_device_scale;
-
- float ideal_page_scale = page_scale_factor;
- float ideal_device_scale = device_scale_factor;
- float ideal_source_scale =
- ideal_contents_scale / ideal_page_scale / ideal_device_scale;
-
- ideal_contents_scale_ = std::max(ideal_contents_scale, min_contents_scale);
- ideal_page_scale_ = ideal_page_scale;
- ideal_device_scale_ = ideal_device_scale;
- ideal_source_scale_ = std::max(ideal_source_scale, min_source_scale);
-
- ManageTilings(animating_transform_to_screen,
- maximum_animation_contents_scale);
-
- // The content scale and bounds for a PictureLayerImpl is somewhat fictitious.
- // There are (usually) several tilings at different scales. However, the
- // content bounds is the (integer!) space in which quads are generated.
- // In order to guarantee that we can fill this integer space with any set of
- // tilings (and then map back to floating point texture coordinates), the
- // contents scale must be at least as large as the largest of the tilings.
- float max_contents_scale = min_contents_scale;
- for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
- const PictureLayerTiling* tiling = tilings_->tiling_at(i);
- max_contents_scale = std::max(max_contents_scale, tiling->contents_scale());
- }
-
- *contents_scale_x = max_contents_scale;
- *contents_scale_y = max_contents_scale;
- *content_bounds = gfx::ToCeiledSize(
- gfx::ScaleSize(bounds(), max_contents_scale, max_contents_scale));
-}
-
skia::RefPtr<SkPicture> PictureLayerImpl::GetPicture() {
return pile_->GetFlattenedPicture();
}
scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling* tiling,
const gfx::Rect& content_rect) {
+ DCHECK(!pile_->is_solid_color());
if (!pile_->CanRaster(tiling->contents_scale(), content_rect))
return scoped_refptr<Tile>();
int flags = 0;
- if (is_using_lcd_text_)
- flags |= Tile::USE_LCD_TEXT;
- if (use_gpu_rasterization())
- flags |= Tile::USE_GPU_RASTERIZATION;
+
+ // TODO(vmpstr): Revisit this. For now, enabling analysis means that we get as
+ // much savings on memory as we can. However, for some cases like ganesh or
+ // small layers, the amount of time we spend analyzing might not justify
+ // memory savings that we can get. Note that we don't handle solid color
+ // masks, so we shouldn't bother analyzing those.
+ // Bugs: crbug.com/397198, crbug.com/396908
+ if (!pile_->is_mask())
+ flags = Tile::USE_PICTURE_ANALYSIS;
+
return layer_tree_impl()->tile_manager()->CreateTile(
pile_.get(),
content_rect.size(),
content_rect,
- contents_opaque() ? content_rect : gfx::Rect(),
tiling->contents_scale(),
id(),
layer_tree_impl()->source_frame_number(),
flags);
}
-void PictureLayerImpl::UpdatePile(Tile* tile) {
- tile->set_picture_pile(pile_);
+PicturePileImpl* PictureLayerImpl::GetPile() {
+ return pile_.get();
}
const Region* PictureLayerImpl::GetInvalidation() {
const PictureLayerTiling* PictureLayerImpl::GetTwinTiling(
const PictureLayerTiling* tiling) const {
- if (!twin_layer_ ||
- twin_layer_->use_gpu_rasterization() != use_gpu_rasterization())
+ if (!twin_layer_)
+ return NULL;
+ return twin_layer_->tilings_->TilingAtScale(tiling->contents_scale());
+}
+
+PictureLayerTiling* PictureLayerImpl::GetRecycledTwinTiling(
+ const PictureLayerTiling* tiling) {
+ PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
+ if (!recycled_twin || !recycled_twin->tilings_)
return NULL;
- for (size_t i = 0; i < twin_layer_->tilings_->num_tilings(); ++i)
- if (twin_layer_->tilings_->tiling_at(i)->contents_scale() ==
- tiling->contents_scale())
- return twin_layer_->tilings_->tiling_at(i);
- return NULL;
+ return recycled_twin->tilings_->TilingAtScale(tiling->contents_scale());
}
size_t PictureLayerImpl::GetMaxTilesForInterestArea() const {
}
float PictureLayerImpl::GetSkewportTargetTimeInSeconds() const {
- float skewport_target_time_in_frames = use_gpu_rasterization()
- ? kGpuSkewportTargetTimeInFrames
- : kCpuSkewportTargetTimeInFrames;
+ float skewport_target_time_in_frames =
+ layer_tree_impl()->use_gpu_rasterization()
+ ? kGpuSkewportTargetTimeInFrames
+ : kCpuSkewportTargetTimeInFrames;
return skewport_target_time_in_frames *
layer_tree_impl()->begin_impl_frame_interval().InSecondsF() *
layer_tree_impl()->settings().skewport_target_time_multiplier;
gfx::Size PictureLayerImpl::CalculateTileSize(
const gfx::Size& content_bounds) const {
- if (is_mask_) {
- int max_size = layer_tree_impl()->MaxTextureSize();
- return gfx::Size(
- std::min(max_size, content_bounds.width()),
- std::min(max_size, content_bounds.height()));
- }
-
int max_texture_size =
layer_tree_impl()->resource_provider()->max_texture_size();
+ if (pile_->is_mask()) {
+ // Masks are not tiled, so if we can't cover the whole mask with one tile,
+ // don't make any tiles at all. Returning an empty size signals this.
+ if (content_bounds.width() > max_texture_size ||
+ content_bounds.height() > max_texture_size)
+ return gfx::Size();
+ return content_bounds;
+ }
+
gfx::Size default_tile_size = layer_tree_impl()->settings().default_tile_size;
- if (use_gpu_rasterization()) {
+ if (layer_tree_impl()->use_gpu_rasterization()) {
// TODO(ernstm) crbug.com/365877: We need a unified way to override the
// default-tile-size.
default_tile_size =
int height = std::min(
std::max(max_untiled_content_size.height(), default_tile_size.height()),
content_bounds.height());
- // Round width and height up to the closest multiple of 64, or 56 if
- // we should avoid power-of-two textures. This helps reduce the number
- // of different textures sizes to help recycling, and also keeps all
- // textures multiple-of-eight, which is preferred on some drivers (IMG).
- bool avoid_pow2 =
- layer_tree_impl()->GetRendererCapabilities().avoid_pow2_textures;
- int round_up_to = avoid_pow2 ? 56 : 64;
- width = RoundUp(width, round_up_to);
- height = RoundUp(height, round_up_to);
+ // Round up to the closest multiple of 64. This improves recycling and
+ // avoids odd texture sizes.
+ width = RoundUp(width, 64);
+ height = RoundUp(height, 64);
return gfx::Size(width, height);
}
}
void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) {
+ TRACE_EVENT0("cc", "SyncFromActiveLayer");
DCHECK(!other->needs_post_commit_initialization_);
DCHECK(other->tilings_);
- UpdateLCDTextStatus(other->is_using_lcd_text_);
-
if (!DrawsContent()) {
RemoveAllTilings();
return;
raster_contents_scale_ = other->raster_contents_scale_;
low_res_raster_contents_scale_ = other->low_res_raster_contents_scale_;
- // Add synthetic invalidations for any recordings that were dropped. As
- // tiles are updated to point to this new pile, this will force the dropping
- // of tiles that can no longer be rastered. This is not ideal, but is a
- // trade-off for memory (use the same pile as much as possible, by switching
- // during DidBecomeActive) and for time (don't bother checking every tile
- // during activation to see if the new pile can still raster it).
- for (int x = 0; x < pile_->num_tiles_x(); ++x) {
- for (int y = 0; y < pile_->num_tiles_y(); ++y) {
- bool previously_had = other->pile_->HasRecordingAt(x, y);
- bool now_has = pile_->HasRecordingAt(x, y);
- if (now_has || !previously_had)
- continue;
- gfx::Rect layer_rect = pile_->tile_bounds(x, y);
- invalidation_.Union(layer_rect);
- }
- }
-
- // Union in the other newly exposed regions as invalid.
- Region difference_region = Region(gfx::Rect(bounds()));
- difference_region.Subtract(gfx::Rect(other->bounds()));
- invalidation_.Union(difference_region);
-
+ bool synced_high_res_tiling = false;
if (CanHaveTilings()) {
- tilings_->SyncTilings(
+ synced_high_res_tiling = tilings_->SyncTilings(
*other->tilings_, bounds(), invalidation_, MinimumContentsScale());
} else {
RemoveAllTilings();
}
- SanityCheckTilingState();
+ // If our MinimumContentsScale has changed to prevent the twin's high res
+ // tiling from being synced, we should reset the raster scale and let it be
+ // recalculated (1) again. This can happen if our bounds shrink to the point
+ // where min contents scale grows.
+ // (1) - TODO(vmpstr) Instead of hoping that this will be recalculated, we
+ // should refactor this code a little bit and actually recalculate this.
+ // However, this is a larger undertaking, so this will work for now.
+ if (!synced_high_res_tiling)
+ ResetRasterScale();
+ else
+ SanityCheckTilingState();
}
void PictureLayerImpl::SyncTiling(
// we can create tiles for this tiling immediately.
if (!layer_tree_impl()->needs_update_draw_properties() &&
should_update_tile_priorities_) {
- UpdateTilePriorities();
+ // TODO(danakj): Add a DCHECK() that we are not using occlusion tracking
+ // when we stop using the pending tree in the browser compositor. If we want
+ // to support occlusion tracking here, we need to dirty the draw properties
+ // or save occlusion as a draw property.
+ UpdateTilePriorities(Occlusion());
}
}
-void PictureLayerImpl::SetIsMask(bool is_mask) {
- if (is_mask_ == is_mask)
- return;
- is_mask_ = is_mask;
- if (tilings_)
- tilings_->RemoveAllTiles();
-}
-
ResourceProvider::ResourceId PictureLayerImpl::ContentsResourceId() const {
gfx::Rect content_rect(content_bounds());
- float scale = contents_scale_x();
PictureLayerTilingSet::CoverageIterator iter(
- tilings_.get(), scale, content_rect, ideal_contents_scale_);
+ tilings_.get(), 1.f, content_rect, ideal_contents_scale_);
// Mask resource not ready yet.
if (!iter || !*iter)
return 0;
// Masks only supported if they fit on exactly one tile.
- if (iter.geometry_rect() != content_rect)
- return 0;
+ DCHECK(iter.geometry_rect() == content_rect)
+ << "iter rect " << iter.geometry_rect().ToString() << " content rect "
+ << content_rect.ToString();
const ManagedTileState::TileVersion& tile_version =
iter->GetTileVersionForDrawing();
void PictureLayerImpl::MarkVisibleResourcesAsRequired() const {
DCHECK(layer_tree_impl()->IsPendingTree());
- DCHECK(!layer_tree_impl()->needs_update_draw_properties());
DCHECK(ideal_contents_scale_);
DCHECK_GT(tilings_->num_tilings(), 0u);
// be ready to draw in order to activate without flashing content from a
// higher res on the active tree to a lower res on the pending tree.
- gfx::Rect rect(visible_content_rect());
+ // First, early out for layers with no visible content.
+ if (visible_content_rect().IsEmpty())
+ return;
+
+ // Only mark tiles inside the viewport for tile priority as required for
+ // activation. This viewport is normally the same as the draw viewport but
+ // can be independently overridden by embedders like Android WebView with
+ // SetExternalDrawConstraints.
+ gfx::Rect rect = GetViewportForTilePriorityInContentSpace();
+ rect.Intersect(visible_content_rect());
float min_acceptable_scale =
std::min(raster_contents_scale_, ideal_contents_scale_);
high_res = tiling;
continue;
}
- for (PictureLayerTiling::CoverageIterator iter(tiling,
- contents_scale_x(),
- rect);
- iter;
+ for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
++iter) {
if (!*iter || !iter->IsReadyToDraw())
continue;
const PictureLayerTiling* twin_high_res = NULL;
const PictureLayerTiling* twin_low_res = NULL;
- // As a simplification, only allow activating to skip twin tiles that the
- // active layer is also missing when both this layer and its twin have 2
- // tilings (high and low). This avoids having to iterate/track coverage of
- // non-ideal tilings during the last draw call on the active layer.
- if (high_res && low_res && tilings_->num_tilings() == 2 &&
- twin_layer_ && twin_layer_->tilings_->num_tilings() == 2) {
- twin_low_res = GetTwinTiling(low_res);
- if (twin_low_res)
- twin_high_res = GetTwinTiling(high_res);
- }
- // If this layer and its twin have different bounds or transforms, then don't
- // compare them and only allow activating to high res tiles, since tiles on
- // each layer will occupy different areas of the screen.
- if (!twin_high_res || !twin_low_res ||
- twin_layer_->layer_tree_impl()->RequiresHighResToDraw() ||
- bounds() != twin_layer_->bounds() ||
- draw_properties().screen_space_transform !=
- twin_layer_->draw_properties().screen_space_transform) {
- twin_high_res = NULL;
- twin_low_res = NULL;
+ if (twin_layer_) {
+ // As a simplification, only allow activating to skip twin tiles that the
+ // active layer is also missing when both this layer and its twin have
+ // "simple" sets of tilings: only 2 tilings (high and low) or only 1 high
+ // res tiling. This avoids having to iterate/track coverage of non-ideal
+ // tilings during the last draw call on the active layer.
+ if (tilings_->num_tilings() <= 2 &&
+ twin_layer_->tilings_->num_tilings() <= tilings_->num_tilings()) {
+ twin_low_res = low_res ? GetTwinTiling(low_res) : NULL;
+ twin_high_res = high_res ? GetTwinTiling(high_res) : NULL;
+ }
+
+ // If this layer and its twin have different transforms, then don't compare
+ // them and only allow activating to high res tiles, since tiles on each
+ // layer will be in different places on screen.
+ if (twin_layer_->layer_tree_impl()->RequiresHighResToDraw() ||
+ bounds() != twin_layer_->bounds() ||
+ draw_properties().screen_space_transform !=
+ twin_layer_->draw_properties().screen_space_transform) {
+ twin_high_res = NULL;
+ twin_low_res = NULL;
+ }
}
// As a second pass, mark as required any visible high res tiles not filled in
// by acceptable non-ideal tiles from the first pass.
if (MarkVisibleTilesAsRequired(
- high_res, twin_high_res, contents_scale_x(), rect, missing_region)) {
+ high_res, twin_high_res, rect, missing_region)) {
// As an optional third pass, if a high res tile was skipped because its
// twin was also missing, then fall back to mark low res tiles as required
// in case the active twin is substituting those for missing high res
- // content.
- MarkVisibleTilesAsRequired(
- low_res, twin_low_res, contents_scale_x(), rect, missing_region);
+ // content. Only suitable, when low res is enabled.
+ if (low_res) {
+ MarkVisibleTilesAsRequired(low_res, twin_low_res, rect, missing_region);
+ }
}
}
bool PictureLayerImpl::MarkVisibleTilesAsRequired(
PictureLayerTiling* tiling,
const PictureLayerTiling* optional_twin_tiling,
- float contents_scale,
const gfx::Rect& rect,
const Region& missing_region) const {
bool twin_had_missing_tile = false;
- for (PictureLayerTiling::CoverageIterator iter(tiling,
- contents_scale,
- rect);
- iter;
+ for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
++iter) {
Tile* tile = *iter;
// A null tile (i.e. missing recording) can just be skipped.
if (!tile)
continue;
+ // If the tile is occluded, don't mark it as required for activation.
+ if (tile->is_occluded(PENDING_TREE))
+ continue;
+
// If the missing region doesn't cover it, this tile is fully
// covered by acceptable tiles at other scales.
if (!missing_region.Intersects(iter.geometry_rect()))
if (optional_twin_tiling) {
Tile* twin_tile = optional_twin_tiling->TileAt(iter.i(), iter.j());
if (!twin_tile || twin_tile == tile) {
- twin_had_missing_tile = true;
+ // However if the shared tile is being used on the active tree, then
+ // there's no missing content in this place, and low res is not needed.
+ if (!twin_tile || !twin_tile->IsReadyToDraw())
+ twin_had_missing_tile = true;
continue;
}
}
DCHECK(pile_->HasRecordings());
- if (twin_layer_ &&
- twin_layer_->use_gpu_rasterization() == use_gpu_rasterization())
+ if (twin_layer_)
twin_layer_->SyncTiling(tiling);
return tiling;
}
void PictureLayerImpl::RemoveTiling(float contents_scale) {
+ if (!tilings_ || tilings_->num_tilings() == 0)
+ return;
+
for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
PictureLayerTiling* tiling = tilings_->tiling_at(i);
if (tiling->contents_scale() == contents_scale) {
} // namespace
-void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen,
- float maximum_animation_contents_scale) {
- DCHECK(ideal_contents_scale_);
- DCHECK(ideal_page_scale_);
- DCHECK(ideal_device_scale_);
- DCHECK(ideal_source_scale_);
- DCHECK(CanHaveTilings());
- DCHECK(!needs_post_commit_initialization_);
-
- bool change_target_tiling =
- raster_page_scale_ == 0.f ||
- raster_device_scale_ == 0.f ||
- raster_source_scale_ == 0.f ||
- raster_contents_scale_ == 0.f ||
- low_res_raster_contents_scale_ == 0.f ||
- ShouldAdjustRasterScale(animating_transform_to_screen);
-
- if (tilings_->num_tilings() == 0) {
- DCHECK(change_target_tiling)
- << "A layer with no tilings shouldn't have valid raster scales";
- }
-
- if (change_target_tiling) {
- RecalculateRasterScales(animating_transform_to_screen,
- maximum_animation_contents_scale);
- }
-
- was_animating_transform_to_screen_ = animating_transform_to_screen;
-
- if (!change_target_tiling)
- return;
-
+void PictureLayerImpl::AddTilingsForRasterScale() {
PictureLayerTiling* high_res = NULL;
PictureLayerTiling* low_res = NULL;
// prevents wastefully creating a paired low res tiling for every new high res
// tiling during a pinch or a CSS animation.
bool is_pinching = layer_tree_impl()->PinchGestureActive();
- if (ShouldHaveLowResTiling() && !is_pinching &&
- !animating_transform_to_screen &&
- !low_res && low_res != high_res)
+ if (layer_tree_impl()->create_low_res_tiling() && !is_pinching &&
+ !draw_properties().screen_space_transform_is_animating && !low_res &&
+ low_res != high_res)
low_res = AddTiling(low_res_raster_contents_scale_);
// Set low-res if we have one.
SanityCheckTilingState();
}
-bool PictureLayerImpl::ShouldAdjustRasterScale(
- bool animating_transform_to_screen) const {
- if (was_animating_transform_to_screen_ != animating_transform_to_screen)
+bool PictureLayerImpl::ShouldAdjustRasterScale() const {
+ if (was_screen_space_transform_animating_ !=
+ draw_properties().screen_space_transform_is_animating)
+ return true;
+
+ if (draw_properties().screen_space_transform_is_animating &&
+ raster_contents_scale_ != ideal_contents_scale_ &&
+ ShouldAdjustRasterScaleDuringScaleAnimations())
return true;
bool is_pinching = layer_tree_impl()->PinchGestureActive();
// When the source scale changes we want to match it, but not when animating
// or when we've fixed the scale in place.
- if (!animating_transform_to_screen && !raster_source_scale_is_fixed_ &&
+ if (!draw_properties().screen_space_transform_is_animating &&
+ !raster_source_scale_is_fixed_ &&
raster_source_scale_ != ideal_source_scale_)
return true;
return snapped_contents_scale;
}
-void PictureLayerImpl::RecalculateRasterScales(
- bool animating_transform_to_screen,
- float maximum_animation_contents_scale) {
+void PictureLayerImpl::RecalculateRasterScales() {
float old_raster_contents_scale = raster_contents_scale_;
float old_raster_page_scale = raster_page_scale_;
float old_raster_source_scale = raster_source_scale_;
// If we're not animating, or leaving an animation, and the
// ideal_source_scale_ changes, then things are unpredictable, and we fix
// the raster_source_scale_ in place.
- if (old_raster_source_scale && !animating_transform_to_screen &&
- !was_animating_transform_to_screen_ &&
+ if (old_raster_source_scale &&
+ !draw_properties().screen_space_transform_is_animating &&
+ !was_screen_space_transform_animating_ &&
old_raster_source_scale != ideal_source_scale_)
raster_source_scale_is_fixed_ = true;
// TODO(danakj): Adjust raster source scale closer to ideal source scale at
// a throttled rate. Possibly make use of invalidation_.IsEmpty() on pending
// tree. This will allow CSS scale changes to get re-rastered at an
- // appropriate rate.
+ // appropriate rate. (crbug.com/413636)
if (raster_source_scale_is_fixed_) {
raster_contents_scale_ /= raster_source_scale_;
raster_source_scale_ = 1.f;
raster_contents_scale_ =
std::max(raster_contents_scale_, MinimumContentsScale());
- // Since we're not re-rasterizing during animation, rasterize at the maximum
+ // If we're not re-rasterizing during animation, rasterize at the maximum
// scale that will occur during the animation, if the maximum scale is
- // known.
- if (animating_transform_to_screen) {
- if (maximum_animation_contents_scale > 0.f) {
+ // known. However, to avoid excessive memory use, don't rasterize at a scale
+ // at which this layer would become larger than the viewport.
+ if (draw_properties().screen_space_transform_is_animating &&
+ !ShouldAdjustRasterScaleDuringScaleAnimations()) {
+ bool can_raster_at_maximum_scale = false;
+ if (draw_properties().maximum_animation_contents_scale > 0.f) {
+ gfx::Size bounds_at_maximum_scale = gfx::ToCeiledSize(gfx::ScaleSize(
+ bounds(), draw_properties().maximum_animation_contents_scale));
+ if (bounds_at_maximum_scale.GetArea() <=
+ layer_tree_impl()->device_viewport_size().GetArea())
+ can_raster_at_maximum_scale = true;
+ }
+ if (can_raster_at_maximum_scale) {
raster_contents_scale_ =
- std::max(raster_contents_scale_, maximum_animation_contents_scale);
+ std::max(raster_contents_scale_,
+ draw_properties().maximum_animation_contents_scale);
} else {
raster_contents_scale_ =
std::max(raster_contents_scale_,
}
}
- // If this layer would only create one tile at this content scale,
+ // If this layer would create zero or one tiles at this content scale,
// don't create a low res tiling.
gfx::Size content_bounds =
gfx::ToCeiledSize(gfx::ScaleSize(bounds(), raster_contents_scale_));
gfx::Size tile_size = CalculateTileSize(content_bounds);
- if (tile_size.width() >= content_bounds.width() &&
- tile_size.height() >= content_bounds.height()) {
+ bool tile_covers_bounds = tile_size.width() >= content_bounds.width() &&
+ tile_size.height() >= content_bounds.height();
+ if (tile_size.IsEmpty() || tile_covers_bounds) {
low_res_raster_contents_scale_ = raster_contents_scale_;
return;
}
raster_contents_scale_, ideal_contents_scale_);
float max_acceptable_high_res_scale = std::max(
raster_contents_scale_, ideal_contents_scale_);
+ float twin_low_res_scale = 0.f;
PictureLayerImpl* twin = twin_layer_;
- if (twin) {
+ if (twin && twin->CanHaveTilings()) {
min_acceptable_high_res_scale = std::min(
min_acceptable_high_res_scale,
std::min(twin->raster_contents_scale_, twin->ideal_contents_scale_));
max_acceptable_high_res_scale = std::max(
max_acceptable_high_res_scale,
std::max(twin->raster_contents_scale_, twin->ideal_contents_scale_));
+
+ for (size_t i = 0; i < twin->tilings_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = twin->tilings_->tiling_at(i);
+ if (tiling->resolution() == LOW_RESOLUTION)
+ twin_low_res_scale = tiling->contents_scale();
+ }
}
std::vector<PictureLayerTiling*> to_remove;
continue;
// Keep low resolution tilings, if the layer should have them.
- if (tiling->resolution() == LOW_RESOLUTION && ShouldHaveLowResTiling())
- continue;
+ if (layer_tree_impl()->create_low_res_tiling()) {
+ if (tiling->resolution() == LOW_RESOLUTION ||
+ tiling->contents_scale() == twin_low_res_scale)
+ continue;
+ }
// Don't remove tilings that are being used (and thus would cause a flash.)
if (std::find(used_tilings.begin(), used_tilings.end(), tiling) !=
to_remove.push_back(tiling);
}
+ if (to_remove.empty())
+ return;
+
+ PictureLayerImpl* recycled_twin = GetRecycledTwinLayer();
+ // Remove tilings on this tree and the twin tree.
for (size_t i = 0; i < to_remove.size(); ++i) {
const PictureLayerTiling* twin_tiling = GetTwinTiling(to_remove[i]);
// Only remove tilings from the twin layer if they have
// NON_IDEAL_RESOLUTION.
if (twin_tiling && twin_tiling->resolution() == NON_IDEAL_RESOLUTION)
twin->RemoveTiling(to_remove[i]->contents_scale());
+ // Remove the tiling from the recycle tree. Note that we ignore resolution,
+ // since we don't need to maintain high/low res on the recycle tree.
+ if (recycled_twin)
+ recycled_twin->RemoveTiling(to_remove[i]->contents_scale());
// TODO(enne): temporary sanity CHECK for http://crbug.com/358350
CHECK_NE(HIGH_RESOLUTION, to_remove[i]->resolution());
tilings_->Remove(to_remove[i]);
}
- DCHECK_GT(tilings_->num_tilings(), 0u);
+ DCHECK_GT(tilings_->num_tilings(), 0u);
SanityCheckTilingState();
}
return std::max(1.f / min_dimension, setting_min);
}
-void PictureLayerImpl::UpdateLCDTextStatus(bool new_status) {
- // Once this layer is not using lcd text, don't switch back.
- if (!is_using_lcd_text_)
- return;
-
- if (is_using_lcd_text_ == new_status)
- return;
-
- is_using_lcd_text_ = new_status;
- tilings_->SetCanUseLCDText(is_using_lcd_text_);
-}
-
void PictureLayerImpl::ResetRasterScale() {
raster_page_scale_ = 0.f;
raster_device_scale_ = 0.f;
}
bool PictureLayerImpl::CanHaveTilings() const {
+ if (pile_->is_solid_color())
+ return false;
if (!DrawsContent())
return false;
if (!pile_->HasRecordings())
void PictureLayerImpl::SanityCheckTilingState() const {
#if DCHECK_IS_ON
+ // Recycle tree doesn't have any restrictions.
+ if (layer_tree_impl()->IsRecycleTree())
+ return;
+
if (!CanHaveTilings()) {
DCHECK_EQ(0u, tilings_->num_tilings());
return;
#endif
}
+bool PictureLayerImpl::ShouldAdjustRasterScaleDuringScaleAnimations() const {
+ if (!layer_tree_impl()->use_gpu_rasterization())
+ return false;
+
+ // Re-rastering text at different scales using GPU rasterization causes
+ // texture uploads for glyphs at each scale (see crbug.com/366225). To
+ // workaround this performance issue, we don't re-rasterize layers with
+ // text during scale animations.
+ // TODO(ajuma): Remove this workaround once text can be efficiently
+ // re-rastered at different scales (e.g. by using distance-field fonts).
+ if (pile_->has_text())
+ return false;
+
+ return true;
+}
+
+float PictureLayerImpl::MaximumTilingContentsScale() const {
+ float max_contents_scale = MinimumContentsScale();
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+ const PictureLayerTiling* tiling = tilings_->tiling_at(i);
+ max_contents_scale = std::max(max_contents_scale, tiling->contents_scale());
+ }
+ return max_contents_scale;
+}
+
+void PictureLayerImpl::UpdateIdealScales() {
+ DCHECK(CanHaveTilings());
+
+ float min_contents_scale = MinimumContentsScale();
+ DCHECK_GT(min_contents_scale, 0.f);
+ float min_page_scale = layer_tree_impl()->min_page_scale_factor();
+ DCHECK_GT(min_page_scale, 0.f);
+ float min_device_scale = 1.f;
+ float min_source_scale =
+ min_contents_scale / min_page_scale / min_device_scale;
+
+ float ideal_page_scale = draw_properties().page_scale_factor;
+ float ideal_device_scale = draw_properties().device_scale_factor;
+ float ideal_source_scale = draw_properties().ideal_contents_scale /
+ ideal_page_scale / ideal_device_scale;
+ ideal_contents_scale_ =
+ std::max(draw_properties().ideal_contents_scale, min_contents_scale);
+ ideal_page_scale_ = draw_properties().page_scale_factor;
+ ideal_device_scale_ = draw_properties().device_scale_factor;
+ ideal_source_scale_ = std::max(ideal_source_scale, min_source_scale);
+}
+
void PictureLayerImpl::GetDebugBorderProperties(
SkColor* color,
float* width) const {
*width = DebugColors::TiledContentLayerBorderWidth(layer_tree_impl());
}
-void PictureLayerImpl::AsValueInto(base::DictionaryValue* state) const {
+void PictureLayerImpl::GetAllTilesForTracing(
+ std::set<const Tile*>* tiles) const {
+ if (!tilings_)
+ return;
+
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i)
+ tilings_->tiling_at(i)->GetAllTilesForTracing(tiles);
+}
+
+void PictureLayerImpl::AsValueInto(base::debug::TracedValue* state) const {
const_cast<PictureLayerImpl*>(this)->DoPostCommitInitializationIfNeeded();
LayerImpl::AsValueInto(state);
state->SetDouble("ideal_contents_scale", ideal_contents_scale_);
- state->SetDouble("geometry_contents_scale", contents_scale_x());
- state->Set("tilings", tilings_->AsValue().release());
- state->Set("pictures", pile_->AsValue().release());
- state->Set("invalidation", invalidation_.AsValue().release());
+ state->SetDouble("geometry_contents_scale", MaximumTilingContentsScale());
+ state->BeginArray("tilings");
+ tilings_->AsValueInto(state);
+ state->EndArray();
- scoped_ptr<base::ListValue> coverage_tiles(new base::ListValue);
+ state->BeginArray("tile_priority_rect");
+ MathUtil::AddToTracedValue(GetViewportForTilePriorityInContentSpace(), state);
+ state->EndArray();
+
+ state->BeginArray("visible_rect");
+ MathUtil::AddToTracedValue(visible_content_rect(), state);
+ state->EndArray();
+
+ state->BeginArray("pictures");
+ pile_->AsValueInto(state);
+ state->EndArray();
+
+ state->BeginArray("invalidation");
+ invalidation_.AsValueInto(state);
+ state->EndArray();
+
+ state->BeginArray("coverage_tiles");
for (PictureLayerTilingSet::CoverageIterator iter(tilings_.get(),
- contents_scale_x(),
+ 1.f,
gfx::Rect(content_bounds()),
ideal_contents_scale_);
iter;
++iter) {
- scoped_ptr<base::DictionaryValue> tile_data(new base::DictionaryValue);
- tile_data->Set("geometry_rect",
- MathUtil::AsValue(iter.geometry_rect()).release());
+ state->BeginDictionary();
+
+ state->BeginArray("geometry_rect");
+ MathUtil::AddToTracedValue(iter.geometry_rect(), state);
+ state->EndArray();
+
if (*iter)
- tile_data->Set("tile", TracedValue::CreateIDRef(*iter).release());
+ TracedValue::SetIDRef(*iter, state, "tile");
- coverage_tiles->Append(tile_data.release());
+ state->EndDictionary();
}
- state->Set("coverage_tiles", coverage_tiles.release());
- state->SetBoolean("is_using_lcd_text", is_using_lcd_text_);
- state->SetBoolean("using_gpu_rasterization", use_gpu_rasterization());
+ state->EndArray();
}
size_t PictureLayerImpl::GPUMemoryUsageInBytes() const {
return !layer_tree_impl()->IsRecycleTree();
}
+bool PictureLayerImpl::HasValidTilePriorities() const {
+ return IsOnActiveOrPendingTree() && IsDrawnRenderSurfaceLayerListMember();
+}
+
+bool PictureLayerImpl::AllTilesRequiredForActivationAreReadyToDraw() const {
+ if (!layer_tree_impl()->IsPendingTree())
+ return true;
+
+ if (!HasValidTilePriorities())
+ return true;
+
+ if (!tilings_)
+ return true;
+
+ if (visible_content_rect().IsEmpty())
+ return true;
+
+ for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+ PictureLayerTiling* tiling = tilings_->tiling_at(i);
+ if (tiling->resolution() != HIGH_RESOLUTION &&
+ tiling->resolution() != LOW_RESOLUTION)
+ continue;
+
+ gfx::Rect rect(visible_content_rect());
+ for (PictureLayerTiling::CoverageIterator iter(tiling, 1.f, rect); iter;
+ ++iter) {
+ const Tile* tile = *iter;
+ // A null tile (i.e. missing recording) can just be skipped.
+ if (!tile)
+ continue;
+
+ if (tile->required_for_activation() && !tile->IsReadyToDraw())
+ return false;
+ }
+ }
+
+ return true;
+}
+
PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator()
- : layer_(NULL) {}
+ : layer_(NULL), current_stage_(arraysize(stages_)) {
+}
PictureLayerImpl::LayerRasterTileIterator::LayerRasterTileIterator(
PictureLayerImpl* layer,
bool prioritize_low_res)
: layer_(layer), current_stage_(0) {
DCHECK(layer_);
+
+ // Early out if the layer has no tilings.
if (!layer_->tilings_ || !layer_->tilings_->num_tilings()) {
current_stage_ = arraysize(stages_);
return;
}
- WhichTree tree =
- layer_->layer_tree_impl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE;
+ // Tiles without valid priority are treated as having lowest priority and
+ // never considered for raster.
+ if (!layer_->HasValidTilePriorities()) {
+ current_stage_ = arraysize(stages_);
+ return;
+ }
+
+ WhichTree tree = layer_->GetTree();
// Find high and low res tilings and initialize the iterators.
for (size_t i = 0; i < layer_->tilings_->num_tilings(); ++i) {
IteratorType index = stages_[current_stage_].iterator_type;
TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
if (!iterators_[index] || iterators_[index].get_type() != tile_type)
- ++(*this);
+ AdvanceToNextStage();
}
PictureLayerImpl::LayerRasterTileIterator::~LayerRasterTileIterator() {}
PictureLayerImpl::LayerRasterTileIterator::operator bool() const {
- return layer_ && static_cast<size_t>(current_stage_) < arraysize(stages_);
+ return current_stage_ < arraysize(stages_);
}
PictureLayerImpl::LayerRasterTileIterator&
TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
// First advance the iterator.
- if (iterators_[index])
- ++iterators_[index];
-
- if (iterators_[index] && iterators_[index].get_type() == tile_type)
- return *this;
+ DCHECK(iterators_[index]);
+ DCHECK(iterators_[index].get_type() == tile_type);
+ ++iterators_[index];
- // Next, advance the stage.
- int stage_count = arraysize(stages_);
- ++current_stage_;
- while (current_stage_ < stage_count) {
- index = stages_[current_stage_].iterator_type;
- tile_type = stages_[current_stage_].tile_type;
+ if (!iterators_[index] || iterators_[index].get_type() != tile_type)
+ AdvanceToNextStage();
- if (iterators_[index] && iterators_[index].get_type() == tile_type)
- break;
- ++current_stage_;
- }
return *this;
}
return *iterators_[index];
}
-PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator()
- : iterator_index_(0),
- iteration_stage_(TilePriority::EVENTUALLY),
- required_for_activation_(false),
- layer_(NULL) {}
-
-PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator(
- PictureLayerImpl* layer,
- TreePriority tree_priority)
- : iterator_index_(0),
- iteration_stage_(TilePriority::EVENTUALLY),
- required_for_activation_(false),
- layer_(layer) {
- if (!layer_->tilings_ || !layer_->tilings_->num_tilings())
- return;
-
- size_t high_res_tiling_index = layer_->tilings_->num_tilings();
- size_t low_res_tiling_index = layer_->tilings_->num_tilings();
- for (size_t i = 0; i < layer_->tilings_->num_tilings(); ++i) {
- PictureLayerTiling* tiling = layer_->tilings_->tiling_at(i);
- if (tiling->resolution() == HIGH_RESOLUTION)
- high_res_tiling_index = i;
- else if (tiling->resolution() == LOW_RESOLUTION)
- low_res_tiling_index = i;
- }
-
- iterators_.reserve(layer_->tilings_->num_tilings());
+const Tile* PictureLayerImpl::LayerRasterTileIterator::operator*() const {
+ DCHECK(*this);
- // Higher resolution non-ideal goes first.
- for (size_t i = 0; i < high_res_tiling_index; ++i) {
- iterators_.push_back(PictureLayerTiling::TilingEvictionTileIterator(
- layer_->tilings_->tiling_at(i), tree_priority));
- }
+ IteratorType index = stages_[current_stage_].iterator_type;
+ DCHECK(iterators_[index]);
+ DCHECK(iterators_[index].get_type() == stages_[current_stage_].tile_type);
- // Lower resolution non-ideal goes next.
- for (size_t i = layer_->tilings_->num_tilings() - 1;
- i > high_res_tiling_index;
- --i) {
- PictureLayerTiling* tiling = layer_->tilings_->tiling_at(i);
- if (tiling->resolution() == LOW_RESOLUTION)
- continue;
+ return *iterators_[index];
+}
- iterators_.push_back(
- PictureLayerTiling::TilingEvictionTileIterator(tiling, tree_priority));
- }
+void PictureLayerImpl::LayerRasterTileIterator::AdvanceToNextStage() {
+ DCHECK_LT(current_stage_, arraysize(stages_));
+ ++current_stage_;
+ while (current_stage_ < arraysize(stages_)) {
+ IteratorType index = stages_[current_stage_].iterator_type;
+ TilePriority::PriorityBin tile_type = stages_[current_stage_].tile_type;
- // Now, put the low res tiling if we have one.
- if (low_res_tiling_index < layer_->tilings_->num_tilings()) {
- iterators_.push_back(PictureLayerTiling::TilingEvictionTileIterator(
- layer_->tilings_->tiling_at(low_res_tiling_index), tree_priority));
+ if (iterators_[index] && iterators_[index].get_type() == tile_type)
+ break;
+ ++current_stage_;
}
+}
- // Finally, put the high res tiling if we have one.
- if (high_res_tiling_index < layer_->tilings_->num_tilings()) {
- iterators_.push_back(PictureLayerTiling::TilingEvictionTileIterator(
- layer_->tilings_->tiling_at(high_res_tiling_index), tree_priority));
- }
+PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator()
+ : layer_(NULL),
+ tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES),
+ current_category_(PictureLayerTiling::EVENTUALLY),
+ current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
+ current_tiling_(0u) {
+}
- DCHECK_GT(iterators_.size(), 0u);
+PictureLayerImpl::LayerEvictionTileIterator::LayerEvictionTileIterator(
+ PictureLayerImpl* layer,
+ TreePriority tree_priority)
+ : layer_(layer),
+ tree_priority_(tree_priority),
+ current_category_(PictureLayerTiling::EVENTUALLY),
+ current_tiling_range_type_(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES),
+ current_tiling_(CurrentTilingRange().start - 1u) {
+ // TODO(vmpstr): Once tile priorities are determined by the iterators, ensure
+ // that layers that don't have valid tile priorities have lowest priorities so
+ // they evict their tiles first (crbug.com/381704)
+ DCHECK(layer_->tilings_);
+ do {
+ if (!AdvanceToNextTiling())
+ break;
- if (!iterators_[iterator_index_] ||
- !IsCorrectType(&iterators_[iterator_index_])) {
- AdvanceToNextIterator();
- }
+ current_iterator_ = PictureLayerTiling::TilingEvictionTileIterator(
+ layer_->tilings_->tiling_at(CurrentTilingIndex()),
+ tree_priority,
+ current_category_);
+ } while (!current_iterator_);
}
-PictureLayerImpl::LayerEvictionTileIterator::~LayerEvictionTileIterator() {}
+PictureLayerImpl::LayerEvictionTileIterator::~LayerEvictionTileIterator() {
+}
Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() {
DCHECK(*this);
- return *iterators_[iterator_index_];
+ return *current_iterator_;
+}
+
+const Tile* PictureLayerImpl::LayerEvictionTileIterator::operator*() const {
+ DCHECK(*this);
+ return *current_iterator_;
}
PictureLayerImpl::LayerEvictionTileIterator&
PictureLayerImpl::LayerEvictionTileIterator::
operator++() {
DCHECK(*this);
- ++iterators_[iterator_index_];
- if (!iterators_[iterator_index_] ||
- !IsCorrectType(&iterators_[iterator_index_])) {
- AdvanceToNextIterator();
+ ++current_iterator_;
+ while (!current_iterator_) {
+ if (!AdvanceToNextTiling())
+ break;
+
+ current_iterator_ = PictureLayerTiling::TilingEvictionTileIterator(
+ layer_->tilings_->tiling_at(CurrentTilingIndex()),
+ tree_priority_,
+ current_category_);
}
return *this;
}
-void PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextIterator() {
- ++iterator_index_;
+PictureLayerImpl::LayerEvictionTileIterator::operator bool() const {
+ return !!current_iterator_;
+}
- while (true) {
- while (iterator_index_ < iterators_.size()) {
- if (iterators_[iterator_index_] &&
- IsCorrectType(&iterators_[iterator_index_])) {
- return;
- }
- ++iterator_index_;
- }
+bool PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextCategory() {
+ switch (current_category_) {
+ case PictureLayerTiling::EVENTUALLY:
+ current_category_ =
+ PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION;
+ return true;
+ case PictureLayerTiling::EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
+ current_category_ = PictureLayerTiling::SOON;
+ return true;
+ case PictureLayerTiling::SOON:
+ current_category_ = PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION;
+ return true;
+ case PictureLayerTiling::SOON_AND_REQUIRED_FOR_ACTIVATION:
+ current_category_ = PictureLayerTiling::NOW;
+ return true;
+ case PictureLayerTiling::NOW:
+ current_category_ = PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION;
+ return true;
+ case PictureLayerTiling::NOW_AND_REQUIRED_FOR_ACTIVATION:
+ return false;
+ }
+ NOTREACHED();
+ return false;
+}
- // If we're NOW and required_for_activation, then this was the last pass
- // through the iterators.
- if (iteration_stage_ == TilePriority::NOW && required_for_activation_)
- break;
+bool
+PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextTilingRangeType() {
+ switch (current_tiling_range_type_) {
+ case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
+ current_tiling_range_type_ = PictureLayerTilingSet::LOWER_THAN_LOW_RES;
+ return true;
+ case PictureLayerTilingSet::LOWER_THAN_LOW_RES:
+ current_tiling_range_type_ =
+ PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES;
+ return true;
+ case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
+ current_tiling_range_type_ = PictureLayerTilingSet::LOW_RES;
+ return true;
+ case PictureLayerTilingSet::LOW_RES:
+ current_tiling_range_type_ = PictureLayerTilingSet::HIGH_RES;
+ return true;
+ case PictureLayerTilingSet::HIGH_RES:
+ if (!AdvanceToNextCategory())
+ return false;
- if (!required_for_activation_) {
- required_for_activation_ = true;
- } else {
- required_for_activation_ = false;
- iteration_stage_ =
- static_cast<TilePriority::PriorityBin>(iteration_stage_ - 1);
- }
- iterator_index_ = 0;
+ current_tiling_range_type_ = PictureLayerTilingSet::HIGHER_THAN_HIGH_RES;
+ return true;
}
+ NOTREACHED();
+ return false;
}
-PictureLayerImpl::LayerEvictionTileIterator::operator bool() const {
- return iterator_index_ < iterators_.size();
+bool PictureLayerImpl::LayerEvictionTileIterator::AdvanceToNextTiling() {
+ DCHECK_NE(current_tiling_, CurrentTilingRange().end);
+ ++current_tiling_;
+ while (current_tiling_ == CurrentTilingRange().end) {
+ if (!AdvanceToNextTilingRangeType())
+ return false;
+
+ current_tiling_ = CurrentTilingRange().start;
+ }
+ return true;
+}
+
+PictureLayerTilingSet::TilingRange
+PictureLayerImpl::LayerEvictionTileIterator::CurrentTilingRange() const {
+ return layer_->tilings_->GetTilingRange(current_tiling_range_type_);
}
-bool PictureLayerImpl::LayerEvictionTileIterator::IsCorrectType(
- PictureLayerTiling::TilingEvictionTileIterator* it) const {
- return it->get_type() == iteration_stage_ &&
- (**it)->required_for_activation() == required_for_activation_;
+size_t PictureLayerImpl::LayerEvictionTileIterator::CurrentTilingIndex() const {
+ DCHECK_NE(current_tiling_, CurrentTilingRange().end);
+ switch (current_tiling_range_type_) {
+ case PictureLayerTilingSet::HIGHER_THAN_HIGH_RES:
+ case PictureLayerTilingSet::LOW_RES:
+ case PictureLayerTilingSet::HIGH_RES:
+ return current_tiling_;
+ // Tilings in the following ranges are accessed in reverse order.
+ case PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES:
+ case PictureLayerTilingSet::LOWER_THAN_LOW_RES: {
+ PictureLayerTilingSet::TilingRange tiling_range = CurrentTilingRange();
+ size_t current_tiling_range_offset = current_tiling_ - tiling_range.start;
+ return tiling_range.end - 1 - current_tiling_range_offset;
+ }
+ }
+ NOTREACHED();
+ return 0;
}
} // namespace cc