0

implement the logic to set tile priorities based on current matrix

BUG=163060


Review URL: https://chromiumcodereview.appspot.com/11414238

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@170908 0039d316-1c4b-4281-b951-d872f2087c98
This commit is contained in:
qinmin@chromium.org
2012-12-04 08:52:58 +00:00
parent a9f2a621cd
commit 4cbadc88bb
11 changed files with 296 additions and 2 deletions

@ -242,6 +242,7 @@
'tile_draw_quad.h',
'tile_manager.cc',
'tile_manager.h',
'tile_priority.cc',
'tile_priority.h',
'tiled_layer.cc',
'tiled_layer.h',

@ -52,6 +52,7 @@
'texture_copier_unittest.cc',
'texture_layer_unittest.cc',
'texture_uploader_unittest.cc',
'tile_priority_unittest.cc',
'tiled_layer_impl_unittest.cc',
'tiled_layer_unittest.cc',
'tree_synchronizer_unittest.cc',

@ -4,6 +4,7 @@
#include "cc/picture_layer_impl.h"
#include "base/time.h"
#include "cc/append_quads_data.h"
#include "cc/checkerboard_draw_quad.h"
#include "cc/debug_border_draw_quad.h"
@ -19,7 +20,8 @@ namespace cc {
PictureLayerImpl::PictureLayerImpl(int id) :
LayerImpl(id),
tilings_(this),
pile_(PicturePileImpl::Create()) {
pile_(PicturePileImpl::Create()),
last_update_time_(0) {
}
PictureLayerImpl::~PictureLayerImpl() {
@ -132,6 +134,30 @@ void PictureLayerImpl::didUpdateTransforms() {
tilings_.AddTiling(contentsScaleX(), tile_size);
// TODO(enne): handle invalidations, create new tiles
}
gfx::Transform current_screen_space_transform = screenSpaceTransform();
double current_time =
(base::TimeTicks::Now() - base::TimeTicks()).InSecondsF();
double time_delta = 0;
if (last_update_time_ != 0 && last_bounds_ == bounds() &&
last_content_bounds_ == contentBounds() &&
last_content_scale_x_ == contentsScaleX() &&
last_content_scale_y_ == contentsScaleY()) {
time_delta = current_time - last_update_time_;
}
tilings_.UpdateTilePriorities(layerTreeHostImpl()->deviceViewportSize(),
contentsScaleX(),
contentsScaleY(),
last_screen_space_transform_,
current_screen_space_transform,
time_delta);
last_screen_space_transform_ = current_screen_space_transform;
last_update_time_ = current_time;
last_bounds_ = bounds();
last_content_bounds_ = contentBounds();
last_content_scale_x_ = contentsScaleX();
last_content_scale_y_ = contentsScaleY();
}
scoped_refptr<Tile> PictureLayerImpl::CreateTile(PictureLayerTiling*,

@ -44,6 +44,13 @@ protected:
PictureLayerTilingSet tilings_;
scoped_refptr<PicturePileImpl> pile_;
gfx::Transform last_screen_space_transform_;
double last_update_time_;
gfx::Size last_bounds_;
gfx::Size last_content_bounds_;
float last_content_scale_x_;
float last_content_scale_y_;
friend class PictureLayer;
DISALLOW_COPY_AND_ASSIGN(PictureLayerImpl);
};

@ -3,6 +3,8 @@
// found in the LICENSE file.
#include "cc/picture_layer_tiling.h"
#include "cc/math_util.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/size_conversions.h"
@ -266,4 +268,52 @@ gfx::Size PictureLayerTiling::Iterator::texture_size() const {
return tiling_->tiling_data_.max_texture_size();
}
void PictureLayerTiling::UpdateTilePriorities(
const gfx::Size& device_viewport,
float layer_content_scale_x,
float layer_content_scale_y,
const gfx::Transform& last_screen_transform,
const gfx::Transform& current_screen_transform,
double time_delta) {
gfx::Rect content_rect = ContentRect();
if (content_rect.IsEmpty())
return;
gfx::Rect view_rect(gfx::Point(), device_viewport);
int right = tiling_data_.TileXIndexFromSrcCoord(content_rect.width() - 1);
int bottom = tiling_data_.TileYIndexFromSrcCoord(content_rect.height() - 1);
for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
TileMapKey key = it->first;
TilePriority priority;
if (key.first > right || key.second > bottom) {
priority.distance_to_visible_in_pixels = std::numeric_limits<int>::max();
priority.time_to_visible_in_seconds =
TilePriority::kMaxTimeToVisibleInSeconds;
// TODO(qinmin): pass the correct tree to this function.
it->second->set_priority(ACTIVE_TREE, priority);
continue;
}
gfx::Rect tile_bound = tiling_data_.TileBounds(key.first, key.second);
gfx::RectF layer_content_rect = gfx::ScaleRect(
tile_bound,
layer_content_scale_x / contents_scale_,
layer_content_scale_y / contents_scale_);
gfx::RectF screen_rect = MathUtil::mapClippedRect(
current_screen_transform, layer_content_rect);
gfx::RectF previous_rect = MathUtil::mapClippedRect(
last_screen_transform, layer_content_rect);
priority.resolution = HIGH_RESOLUTION;
priority.time_to_visible_in_seconds =
TilePriority::TimeForBoundsToIntersect(
previous_rect, screen_rect, time_delta, view_rect);
priority.distance_to_visible_in_pixels =
TilePriority::manhattanDistance(screen_rect, view_rect);
// TODO(qinmin): pass the correct tree to this function.
it->second->set_priority(ACTIVE_TREE, priority);
}
}
} // namespace cc

@ -86,6 +86,13 @@ class CC_EXPORT PictureLayerTiling {
void Reset() { return tiles_.clear(); }
void UpdateTilePriorities(const gfx::Size& device_viewport,
float layer_content_scale_x,
float layer_content_scale_y,
const gfx::Transform& last_screen_transform,
const gfx::Transform& current_screen_transform,
double time_delta);
protected:
typedef std::pair<int, int> TileMapKey;
typedef base::hash_map<TileMapKey, scoped_refptr<Tile> > TileMap;

@ -157,4 +157,18 @@ PictureLayerTilingSet::Iterator::operator bool() const {
region_iter_.has_rect();
}
void PictureLayerTilingSet::UpdateTilePriorities(
const gfx::Size& device_viewport,
float layer_content_scale_x,
float layer_content_scale_y,
const gfx::Transform& last_screen_transform,
const gfx::Transform& current_screen_transform,
double time_delta) {
for (size_t i = 0; i < tilings_.size(); ++i) {
tilings_[i]->UpdateTilePriorities(
device_viewport, layer_content_scale_x, layer_content_scale_y,
last_screen_transform, current_screen_transform, time_delta);
}
}
} // namespace cc

@ -28,6 +28,13 @@ class CC_EXPORT PictureLayerTilingSet {
void AddTiling(float contents_scale, gfx::Size tile_size);
size_t num_tilings() const { return tilings_.size(); }
void UpdateTilePriorities(const gfx::Size& device_viewport,
float layer_content_scale_x,
float layer_content_scale_y,
const gfx::Transform& last_screen_transform,
const gfx::Transform& current_screen_transform,
double time_delta);
// For a given rect, iterates through tiles that can fill it. If no
// set of tiles with resources can fill the rect, then it will iterate
// through null tiles with valid geometry_rect() until the rect is full.

104
cc/tile_priority.cc Normal file

@ -0,0 +1,104 @@
// Copyright 2012 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/tile_priority.h"
namespace {
// TODO(qinmin): modify ui/range/Range.h to support template so that we
// don't need to define this.
struct Range {
Range(double start, double end) : start_(start), end_(end) {}
Range Intersects(const Range& other);
bool IsEmpty();
double start_;
double end_;
};
Range Range::Intersects(const Range& other) {
start_ = std::max(start_, other.start_);
end_ = std::min(end_, other.end_);
return Range(start_, end_);
}
bool Range::IsEmpty() {
return start_ >= end_;
}
// Calculate a time range that |value| will be larger than |threshold|
// given the velocity of its change.
Range TimeRangeValueLargerThanThreshold(
int value, int threshold, double velocity) {
double minimum_time = 0;
double maximum_time = cc::TilePriority::kMaxTimeToVisibleInSeconds;
if (velocity > 0) {
if (value < threshold)
minimum_time = std::min(cc::TilePriority::kMaxTimeToVisibleInSeconds,
(threshold - value) / velocity);
} else if (velocity <= 0) {
if (value < threshold)
minimum_time = cc::TilePriority::kMaxTimeToVisibleInSeconds;
else if (velocity != 0)
maximum_time = std::min(maximum_time, (threshold - value) / velocity);
}
return Range(minimum_time, maximum_time);
}
} // namespace
namespace cc {
const double TilePriority::kMaxTimeToVisibleInSeconds = 1000;
int TilePriority::manhattanDistance(const gfx::RectF& a, const gfx::RectF& b) {
gfx::RectF c = gfx::UnionRects(a, b);
// Rects touching the edge of the screen should not be considered visible.
// So we add 1 pixel here to avoid that situation.
int x = static_cast<int>(
std::max(0.0f, c.width() - a.width() - b.width() + 1));
int y = static_cast<int>(
std::max(0.0f, c.height() - a.height() - b.height() + 1));
return (x + y);
}
double TilePriority::TimeForBoundsToIntersect(gfx::RectF previous_bounds,
gfx::RectF current_bounds,
double time_delta,
gfx::RectF target_bounds) {
if (current_bounds.Intersects(target_bounds))
return 0;
if (previous_bounds.Intersects(target_bounds) || time_delta == 0)
return kMaxTimeToVisibleInSeconds;
// As we are trying to solve the case of both scaling and scrolling, using
// a single coordinate with velocity is not enough. The logic here is to
// calculate the velocity for each edge. Then we calculate the time range that
// each edge will stay on the same side of the target bounds. If there is an
// overlap between these time ranges, the bounds must have intersect with
// each other during that period of time.
double velocity =
(current_bounds.right() - previous_bounds.right()) / time_delta;
Range range = TimeRangeValueLargerThanThreshold(
current_bounds.right(), target_bounds.x(), velocity);
velocity = (current_bounds.x() - previous_bounds.x()) / time_delta;
range = range.Intersects(TimeRangeValueLargerThanThreshold(
-current_bounds.x(), -target_bounds.right(), -velocity));
velocity = (current_bounds.y() - previous_bounds.y()) / time_delta;
range = range.Intersects(TimeRangeValueLargerThanThreshold(
-current_bounds.y(), -target_bounds.bottom(), -velocity));
velocity = (current_bounds.bottom() - previous_bounds.bottom()) / time_delta;
range = range.Intersects(TimeRangeValueLargerThanThreshold(
current_bounds.bottom(), target_bounds.y(), velocity));
return range.IsEmpty() ? kMaxTimeToVisibleInSeconds : range.start_;
}
} // namespace cc

@ -5,6 +5,8 @@
#ifndef CC_TILE_PRIORITY_H_
#define CC_TILE_PRIORITY_H_
#include <limits>
#include "base/memory/ref_counted.h"
#include "cc/picture_pile.h"
#include "ui/gfx/rect.h"
@ -25,7 +27,7 @@ enum TileResolution {
NON_IDEAL_RESOLUTION = 2
};
struct TilePriority {
struct CC_EXPORT TilePriority {
TilePriority()
: resolution(NON_IDEAL_RESOLUTION),
time_to_visible_in_seconds(std::numeric_limits<float>::max()),
@ -58,6 +60,18 @@ struct TilePriority {
time_to_ideal_resolution_in_seconds);
}
static const double kMaxTimeToVisibleInSeconds;
static int manhattanDistance(const gfx::RectF& a, const gfx::RectF& b);
// Calculate the time for the |current_bounds| to intersect with the
// |target_bounds| given its previous location and time delta.
// This function should work for both scaling and scrolling case.
static double TimeForBoundsToIntersect(gfx::RectF previous_bounds,
gfx::RectF current_bounds,
double time_delta,
gfx::RectF target_bounds);
TileResolution resolution;
float time_to_visible_in_seconds;
float time_to_ideal_resolution_in_seconds;

@ -0,0 +1,63 @@
// Copyright 2012 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/tile_priority.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
TEST(TilePriorityTest, TimeForBoundsToIntersectWithScroll) {
gfx::Rect target(0, 0, 800, 600);
gfx::Rect current(100, 100, 100, 100);
EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-200, 0, 100, 100), current, 1, target));
EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-100, 0, 100, 100), current, 1, target));
EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(400, 400, 100, 100), current, 1, target));
current = gfx::Rect(-300, -300, 100, 100);
EXPECT_EQ(1000, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(0, 0, 100, 100), current, 1, target));
EXPECT_EQ(1000, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-200, -200, 100, 100), current, 1, target));
EXPECT_EQ(2, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-400, -400, 100, 100), current, 1, target));
}
TEST(TilePriorityTest, TimeForBoundsToIntersectWithScale) {
gfx::Rect target(0, 0, 800, 600);
gfx::Rect current(100, 100, 100, 100);
EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-200, 0, 200, 200), current, 1, target));
EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-100, 0, 50, 50), current, 1, target));
EXPECT_EQ(0, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(400, 400, 400, 400), current, 1, target));
current = gfx::Rect(-300, -300, 100, 100);
EXPECT_EQ(1000, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-400, -400, 300, 300), current, 1, target));
EXPECT_EQ(8, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-275, -275, 50, 50), current, 1, target));
EXPECT_EQ(1, TilePriority::TimeForBoundsToIntersect(
gfx::Rect(-450, -450, 50, 50), current, 1, target));
}
TEST(TilePriorityTest, ManhattanDistanceBetweenRects) {
EXPECT_EQ(0, TilePriority::manhattanDistance(
gfx::RectF(0, 0, 400, 400), gfx::RectF(0, 0, 100, 100)));
EXPECT_EQ(2, TilePriority::manhattanDistance(
gfx::Rect(0, 0, 400, 400), gfx::Rect(-100, -100, 100, 100)));
EXPECT_EQ(1, TilePriority::manhattanDistance(
gfx::Rect(0, 0, 400, 400), gfx::Rect(0, -100, 100, 100)));
EXPECT_EQ(202, TilePriority::manhattanDistance(
gfx::Rect(0, 0, 100, 100), gfx::Rect(200, 200, 100, 100)));
}
} // namespace cc