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:
@ -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
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;
|
||||
|
63
cc/tile_priority_unittest.cc
Normal file
63
cc/tile_priority_unittest.cc
Normal file
@ -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
|
Reference in New Issue
Block a user