blob: 6069d0028e0db53360f07e3e24b6aa6a242666f1 [file] [log] [blame]
// 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/tiles/picture_layer_tiling_set.h"
#include <map>
#include <vector>
#include "cc/resources/resource_provider.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_picture_layer_tiling_client.h"
#include "cc/test/fake_raster_source.h"
#include "cc/test/fake_resource_provider.h"
#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/trees/layer_tree_settings.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/size_conversions.h"
namespace cc {
namespace {
class TestablePictureLayerTilingSet : public PictureLayerTilingSet {
public:
TestablePictureLayerTilingSet(
WhichTree tree,
PictureLayerTilingClient* client,
int tiling_interest_area_padding,
float skewport_target_time_in_seconds,
int skewport_extrapolation_limit_in_screen_pixels,
float max_preraster_distance)
: PictureLayerTilingSet(tree,
client,
tiling_interest_area_padding,
skewport_target_time_in_seconds,
skewport_extrapolation_limit_in_screen_pixels,
max_preraster_distance) {}
using PictureLayerTilingSet::ComputeSkewport;
using PictureLayerTilingSet::ComputeSoonBorderRect;
using PictureLayerTilingSet::TilingsNeedUpdate;
};
std::unique_ptr<TestablePictureLayerTilingSet> CreateTilingSetWithSettings(
PictureLayerTilingClient* client,
const LayerTreeSettings& settings) {
return base::MakeUnique<TestablePictureLayerTilingSet>(
ACTIVE_TREE, client, settings.tiling_interest_area_padding,
settings.skewport_target_time_in_seconds,
settings.skewport_extrapolation_limit_in_screen_pixels,
settings.max_preraster_distance_in_screen_pixels);
}
std::unique_ptr<TestablePictureLayerTilingSet> CreateTilingSet(
PictureLayerTilingClient* client) {
return CreateTilingSetWithSettings(client, LayerTreeSettings());
}
TEST(PictureLayerTilingSetTest, NoResources) {
FakePictureLayerTilingClient client;
gfx::Size layer_bounds(1000, 800);
std::unique_ptr<TestablePictureLayerTilingSet> set = CreateTilingSet(&client);
client.SetTileSize(gfx::Size(256, 256));
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateEmpty(layer_bounds);
set->AddTiling(1.0, raster_source);
set->AddTiling(1.5, raster_source);
set->AddTiling(2.0, raster_source);
float contents_scale = 2.0;
gfx::Size content_bounds(
gfx::ScaleToCeiledSize(layer_bounds, contents_scale));
gfx::Rect content_rect(content_bounds);
Region remaining(content_rect);
PictureLayerTilingSet::CoverageIterator iter(set.get(), contents_scale,
content_rect, contents_scale);
for (; iter; ++iter) {
gfx::Rect geometry_rect = iter.geometry_rect();
EXPECT_TRUE(content_rect.Contains(geometry_rect));
ASSERT_TRUE(remaining.Contains(geometry_rect));
remaining.Subtract(geometry_rect);
// No tiles have resources, so no iter represents a real tile.
EXPECT_FALSE(*iter);
}
EXPECT_TRUE(remaining.IsEmpty());
}
TEST(PictureLayerTilingSetTest, TilingRange) {
FakePictureLayerTilingClient client;
gfx::Size layer_bounds(10, 10);
PictureLayerTilingSet::TilingRange higher_than_high_res_range(0, 0);
PictureLayerTilingSet::TilingRange high_res_range(0, 0);
PictureLayerTilingSet::TilingRange between_high_and_low_res_range(0, 0);
PictureLayerTilingSet::TilingRange low_res_range(0, 0);
PictureLayerTilingSet::TilingRange lower_than_low_res_range(0, 0);
PictureLayerTiling* high_res_tiling;
PictureLayerTiling* low_res_tiling;
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(layer_bounds);
std::unique_ptr<TestablePictureLayerTilingSet> set = CreateTilingSet(&client);
set->AddTiling(2.0, raster_source);
high_res_tiling = set->AddTiling(1.0, raster_source);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
set->AddTiling(0.5, raster_source);
low_res_tiling = set->AddTiling(0.25, raster_source);
low_res_tiling->set_resolution(LOW_RESOLUTION);
set->AddTiling(0.125, raster_source);
higher_than_high_res_range =
set->GetTilingRange(PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
EXPECT_EQ(0u, higher_than_high_res_range.start);
EXPECT_EQ(1u, higher_than_high_res_range.end);
high_res_range = set->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
EXPECT_EQ(1u, high_res_range.start);
EXPECT_EQ(2u, high_res_range.end);
between_high_and_low_res_range =
set->GetTilingRange(PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
EXPECT_EQ(2u, between_high_and_low_res_range.start);
EXPECT_EQ(3u, between_high_and_low_res_range.end);
low_res_range = set->GetTilingRange(PictureLayerTilingSet::LOW_RES);
EXPECT_EQ(3u, low_res_range.start);
EXPECT_EQ(4u, low_res_range.end);
lower_than_low_res_range =
set->GetTilingRange(PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(4u, lower_than_low_res_range.start);
EXPECT_EQ(5u, lower_than_low_res_range.end);
std::unique_ptr<TestablePictureLayerTilingSet> set_without_low_res =
CreateTilingSet(&client);
set_without_low_res->AddTiling(2.0, raster_source);
high_res_tiling = set_without_low_res->AddTiling(1.0, raster_source);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
set_without_low_res->AddTiling(0.5, raster_source);
set_without_low_res->AddTiling(0.25, raster_source);
higher_than_high_res_range = set_without_low_res->GetTilingRange(
PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
EXPECT_EQ(0u, higher_than_high_res_range.start);
EXPECT_EQ(1u, higher_than_high_res_range.end);
high_res_range =
set_without_low_res->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
EXPECT_EQ(1u, high_res_range.start);
EXPECT_EQ(2u, high_res_range.end);
between_high_and_low_res_range = set_without_low_res->GetTilingRange(
PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
EXPECT_EQ(2u, between_high_and_low_res_range.start);
EXPECT_EQ(4u, between_high_and_low_res_range.end);
low_res_range =
set_without_low_res->GetTilingRange(PictureLayerTilingSet::LOW_RES);
EXPECT_EQ(0u, low_res_range.end - low_res_range.start);
lower_than_low_res_range = set_without_low_res->GetTilingRange(
PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
std::unique_ptr<TestablePictureLayerTilingSet>
set_with_only_high_and_low_res = CreateTilingSet(&client);
high_res_tiling =
set_with_only_high_and_low_res->AddTiling(1.0, raster_source);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
low_res_tiling =
set_with_only_high_and_low_res->AddTiling(0.5, raster_source);
low_res_tiling->set_resolution(LOW_RESOLUTION);
higher_than_high_res_range = set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
EXPECT_EQ(0u,
higher_than_high_res_range.end - higher_than_high_res_range.start);
high_res_range = set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::HIGH_RES);
EXPECT_EQ(0u, high_res_range.start);
EXPECT_EQ(1u, high_res_range.end);
between_high_and_low_res_range =
set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
EXPECT_EQ(0u, between_high_and_low_res_range.end -
between_high_and_low_res_range.start);
low_res_range = set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::LOW_RES);
EXPECT_EQ(1u, low_res_range.start);
EXPECT_EQ(2u, low_res_range.end);
lower_than_low_res_range = set_with_only_high_and_low_res->GetTilingRange(
PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
std::unique_ptr<TestablePictureLayerTilingSet> set_with_only_high_res =
CreateTilingSet(&client);
high_res_tiling = set_with_only_high_res->AddTiling(1.0, raster_source);
high_res_tiling->set_resolution(HIGH_RESOLUTION);
higher_than_high_res_range = set_with_only_high_res->GetTilingRange(
PictureLayerTilingSet::HIGHER_THAN_HIGH_RES);
EXPECT_EQ(0u,
higher_than_high_res_range.end - higher_than_high_res_range.start);
high_res_range =
set_with_only_high_res->GetTilingRange(PictureLayerTilingSet::HIGH_RES);
EXPECT_EQ(0u, high_res_range.start);
EXPECT_EQ(1u, high_res_range.end);
between_high_and_low_res_range = set_with_only_high_res->GetTilingRange(
PictureLayerTilingSet::BETWEEN_HIGH_AND_LOW_RES);
EXPECT_EQ(0u, between_high_and_low_res_range.end -
between_high_and_low_res_range.start);
low_res_range =
set_with_only_high_res->GetTilingRange(PictureLayerTilingSet::LOW_RES);
EXPECT_EQ(0u, low_res_range.end - low_res_range.start);
lower_than_low_res_range = set_with_only_high_res->GetTilingRange(
PictureLayerTilingSet::LOWER_THAN_LOW_RES);
EXPECT_EQ(0u, lower_than_low_res_range.end - lower_than_low_res_range.start);
}
class PictureLayerTilingSetTestWithResources : public testing::Test {
public:
void RunTest(int num_tilings,
float min_scale,
float scale_increment,
float ideal_contents_scale,
float expected_scale) {
scoped_refptr<TestContextProvider> context_provider =
TestContextProvider::Create();
ASSERT_TRUE(context_provider->BindToCurrentThread());
auto shared_bitmap_manager = base::MakeUnique<TestSharedBitmapManager>();
std::unique_ptr<ResourceProvider> resource_provider =
FakeResourceProvider::Create(context_provider.get(),
shared_bitmap_manager.get());
FakePictureLayerTilingClient client(resource_provider.get());
client.SetTileSize(gfx::Size(256, 256));
gfx::Size layer_bounds(1000, 800);
std::unique_ptr<TestablePictureLayerTilingSet> set =
CreateTilingSet(&client);
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(layer_bounds);
float scale = min_scale;
for (int i = 0; i < num_tilings; ++i, scale += scale_increment) {
PictureLayerTiling* tiling = set->AddTiling(scale, raster_source);
tiling->set_resolution(HIGH_RESOLUTION);
tiling->CreateAllTilesForTesting();
std::vector<Tile*> tiles = tiling->AllTilesForTesting();
client.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
}
float max_contents_scale = scale;
gfx::Size content_bounds(
gfx::ScaleToCeiledSize(layer_bounds, max_contents_scale));
gfx::Rect content_rect(content_bounds);
Region remaining(content_rect);
PictureLayerTilingSet::CoverageIterator iter(
set.get(), max_contents_scale, content_rect, ideal_contents_scale);
for (; iter; ++iter) {
gfx::Rect geometry_rect = iter.geometry_rect();
EXPECT_TRUE(content_rect.Contains(geometry_rect));
ASSERT_TRUE(remaining.Contains(geometry_rect));
remaining.Subtract(geometry_rect);
float scale = iter.CurrentTiling()->contents_scale();
EXPECT_EQ(expected_scale, scale);
if (num_tilings)
EXPECT_TRUE(*iter);
else
EXPECT_FALSE(*iter);
}
EXPECT_TRUE(remaining.IsEmpty());
}
};
TEST_F(PictureLayerTilingSetTestWithResources, NoTilings) {
RunTest(0, 0.f, 0.f, 2.f, 0.f);
}
TEST_F(PictureLayerTilingSetTestWithResources, OneTiling_Smaller) {
RunTest(1, 1.f, 0.f, 2.f, 1.f);
}
TEST_F(PictureLayerTilingSetTestWithResources, OneTiling_Larger) {
RunTest(1, 3.f, 0.f, 2.f, 3.f);
}
TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_Smaller) {
RunTest(2, 1.f, 1.f, 3.f, 2.f);
}
TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_SmallerEqual) {
RunTest(2, 1.f, 1.f, 2.f, 2.f);
}
TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_LargerEqual) {
RunTest(2, 1.f, 1.f, 1.f, 1.f);
}
TEST_F(PictureLayerTilingSetTestWithResources, TwoTilings_Larger) {
RunTest(2, 2.f, 8.f, 1.f, 2.f);
}
TEST_F(PictureLayerTilingSetTestWithResources, ManyTilings_Equal) {
RunTest(10, 1.f, 1.f, 5.f, 5.f);
}
TEST_F(PictureLayerTilingSetTestWithResources, ManyTilings_NotEqual) {
RunTest(10, 1.f, 1.f, 4.5f, 5.f);
}
TEST(PictureLayerTilingSetTest, TileSizeChange) {
FakePictureLayerTilingClient pending_client;
FakePictureLayerTilingClient active_client;
std::unique_ptr<PictureLayerTilingSet> pending_set =
PictureLayerTilingSet::Create(PENDING_TREE, &pending_client, 1000, 1.f,
1000, 1000.f);
std::unique_ptr<PictureLayerTilingSet> active_set =
PictureLayerTilingSet::Create(ACTIVE_TREE, &active_client, 1000, 1.f,
1000, 1000.f);
gfx::Size layer_bounds(100, 100);
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(layer_bounds);
gfx::Size tile_size1(10, 10);
gfx::Size tile_size2(30, 30);
gfx::Size tile_size3(20, 20);
pending_client.SetTileSize(tile_size1);
pending_set->AddTiling(1.f, raster_source);
// New tilings get the correct tile size.
EXPECT_EQ(tile_size1, pending_set->tiling_at(0)->tile_size());
// Set some expected things for the tiling set to function.
pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION);
active_client.set_twin_tiling_set(pending_set.get());
// Set a priority rect so we get tiles.
pending_set->UpdateTilePriorities(gfx::Rect(layer_bounds), 1.f, 1.0,
Occlusion(), false);
EXPECT_EQ(tile_size1, pending_set->tiling_at(0)->tile_size());
// The tiles should get the correct size.
std::vector<Tile*> pending_tiles =
pending_set->tiling_at(0)->AllTilesForTesting();
EXPECT_GT(pending_tiles.size(), 0u);
for (auto* tile : pending_tiles)
EXPECT_EQ(tile_size1, tile->content_rect().size());
// Update to a new source frame with a new tile size.
// Note that setting a new raster source can typically only happen after
// activation, since we can't set the raster source twice on the pending tree
// without activating. For test, just remove and add a new tiling instead.
pending_set->RemoveAllTilings();
pending_set->AddTiling(1.f, raster_source);
pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION);
pending_client.SetTileSize(tile_size2);
pending_set->UpdateTilingsToCurrentRasterSourceForCommit(raster_source.get(),
Region(), 1.f, 1.f);
// The tiling should get the correct tile size.
EXPECT_EQ(tile_size2, pending_set->tiling_at(0)->tile_size());
// Set a priority rect so we get tiles.
pending_set->UpdateTilePriorities(gfx::Rect(layer_bounds), 1.f, 2.0,
Occlusion(), false);
EXPECT_EQ(tile_size2, pending_set->tiling_at(0)->tile_size());
// Tiles should have the new correct size.
pending_tiles = pending_set->tiling_at(0)->AllTilesForTesting();
EXPECT_GT(pending_tiles.size(), 0u);
for (auto* tile : pending_tiles)
EXPECT_EQ(tile_size2, tile->content_rect().size());
// Clone from the pending to the active tree.
active_client.SetTileSize(tile_size2);
active_set->UpdateTilingsToCurrentRasterSourceForActivation(
raster_source.get(), pending_set.get(), Region(), 1.f, 1.f);
// The active tiling should get the right tile size.
EXPECT_EQ(tile_size2, active_set->tiling_at(0)->tile_size());
// Cloned tiles should have the right size.
std::vector<Tile*> active_tiles =
active_set->tiling_at(0)->AllTilesForTesting();
EXPECT_GT(active_tiles.size(), 0u);
for (auto* tile : active_tiles)
EXPECT_EQ(tile_size2, tile->content_rect().size());
// A new source frame with a new tile size.
pending_client.SetTileSize(tile_size3);
pending_set->UpdateTilingsToCurrentRasterSourceForCommit(raster_source.get(),
Region(), 1.f, 1.f);
// The tiling gets the new size correctly.
EXPECT_EQ(tile_size3, pending_set->tiling_at(0)->tile_size());
// Set a priority rect so we get tiles.
pending_set->UpdateTilePriorities(gfx::Rect(layer_bounds), 1.f, 3.0,
Occlusion(), false);
EXPECT_EQ(tile_size3, pending_set->tiling_at(0)->tile_size());
// Tiles are resized for the new size.
pending_tiles = pending_set->tiling_at(0)->AllTilesForTesting();
EXPECT_GT(pending_tiles.size(), 0u);
for (auto* tile : pending_tiles)
EXPECT_EQ(tile_size3, tile->content_rect().size());
// Now we activate with a different tile size for the active tiling.
active_client.SetTileSize(tile_size3);
active_set->UpdateTilingsToCurrentRasterSourceForActivation(
raster_source.get(), pending_set.get(), Region(), 1.f, 1.f);
// The active tiling changes its tile size.
EXPECT_EQ(tile_size3, active_set->tiling_at(0)->tile_size());
// And its tiles are resized.
active_tiles = active_set->tiling_at(0)->AllTilesForTesting();
EXPECT_GT(active_tiles.size(), 0u);
for (auto* tile : active_tiles)
EXPECT_EQ(tile_size3, tile->content_rect().size());
}
TEST(PictureLayerTilingSetTest, MaxContentScale) {
FakePictureLayerTilingClient pending_client;
FakePictureLayerTilingClient active_client;
std::unique_ptr<PictureLayerTilingSet> pending_set =
PictureLayerTilingSet::Create(PENDING_TREE, &pending_client, 1000, 1.f,
1000, 1000.f);
std::unique_ptr<PictureLayerTilingSet> active_set =
PictureLayerTilingSet::Create(ACTIVE_TREE, &active_client, 1000, 1.f,
1000, 1000.f);
gfx::Size layer_bounds(100, 105);
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateEmpty(layer_bounds);
// Tilings can be added of any scale, the tiling client can controls this.
pending_set->AddTiling(1.f, raster_source);
pending_set->AddTiling(2.f, raster_source);
pending_set->AddTiling(3.f, raster_source);
// Set some expected things for the tiling set to function.
pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION);
active_client.set_twin_tiling_set(pending_set.get());
// Update to a new source frame with a max content scale that is larger than
// everything.
float max_content_scale = 3.f;
pending_set->UpdateTilingsToCurrentRasterSourceForCommit(
raster_source.get(), Region(), 1.f, max_content_scale);
// All the tilings are there still.
EXPECT_EQ(3u, pending_set->num_tilings());
// Clone from the pending to the active tree with the same max content size.
active_set->UpdateTilingsToCurrentRasterSourceForActivation(
raster_source.get(), pending_set.get(), Region(), 1.f, max_content_scale);
// All the tilings are on the active tree.
EXPECT_EQ(3u, active_set->num_tilings());
// Update to a new source frame with a max content scale that will drop one
// tiling.
max_content_scale = 2.9f;
pending_set->UpdateTilingsToCurrentRasterSourceForCommit(
raster_source.get(), Region(), 1.f, max_content_scale);
// All the tilings are there still.
EXPECT_EQ(2u, pending_set->num_tilings());
pending_set->tiling_at(0)->set_resolution(HIGH_RESOLUTION);
// Clone from the pending to the active tree with the same max content size.
active_set->UpdateTilingsToCurrentRasterSourceForActivation(
raster_source.get(), pending_set.get(), Region(), 1.f, max_content_scale);
// All the tilings are on the active tree.
EXPECT_EQ(2u, active_set->num_tilings());
}
TEST(PictureLayerTilingSetTest, SkewportLimits) {
FakePictureLayerTilingClient client;
gfx::Rect viewport(0, 0, 100, 100);
gfx::Size layer_bounds(200, 200);
client.SetTileSize(gfx::Size(100, 100));
LayerTreeSettings settings;
settings.skewport_extrapolation_limit_in_screen_pixels = 75;
settings.tiling_interest_area_padding = 1000000;
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(layer_bounds);
std::unique_ptr<TestablePictureLayerTilingSet> tiling_set =
CreateTilingSetWithSettings(&client, settings);
EXPECT_FALSE(tiling_set->TilingsNeedUpdate(viewport, 1.0));
tiling_set->AddTiling(1.f, raster_source);
EXPECT_TRUE(tiling_set->TilingsNeedUpdate(viewport, 1.0));
tiling_set->UpdateTilePriorities(viewport, 1.f, 1.0, Occlusion(), true);
// Move viewport down 50 pixels in 0.5 seconds.
gfx::Rect down_skewport =
tiling_set->ComputeSkewport(gfx::Rect(0, 50, 100, 100), 1.5, 1.f);
EXPECT_EQ(0, down_skewport.x());
EXPECT_EQ(50, down_skewport.y());
EXPECT_EQ(100, down_skewport.width());
EXPECT_EQ(175, down_skewport.height());
EXPECT_TRUE(down_skewport.Contains(gfx::Rect(0, 50, 100, 100)));
// Move viewport down 50 and right 10 pixels.
gfx::Rect down_right_skewport =
tiling_set->ComputeSkewport(gfx::Rect(10, 50, 100, 100), 1.5, 1.f);
EXPECT_EQ(10, down_right_skewport.x());
EXPECT_EQ(50, down_right_skewport.y());
EXPECT_EQ(120, down_right_skewport.width());
EXPECT_EQ(175, down_right_skewport.height());
EXPECT_TRUE(down_right_skewport.Contains(gfx::Rect(10, 50, 100, 100)));
// Move viewport left.
gfx::Rect left_skewport =
tiling_set->ComputeSkewport(gfx::Rect(-50, 0, 100, 100), 1.5, 1.f);
EXPECT_EQ(-125, left_skewport.x());
EXPECT_EQ(0, left_skewport.y());
EXPECT_EQ(175, left_skewport.width());
EXPECT_EQ(100, left_skewport.height());
EXPECT_TRUE(left_skewport.Contains(gfx::Rect(-50, 0, 100, 100)));
// Expand viewport.
gfx::Rect expand_skewport =
tiling_set->ComputeSkewport(gfx::Rect(-50, -50, 200, 200), 1.5, 1.f);
// x and y moved by -75 (-50 - 75 = -125).
// right side and bottom side moved by 75 [(350 - 125) - (200 - 50) = 75].
EXPECT_EQ(-125, expand_skewport.x());
EXPECT_EQ(-125, expand_skewport.y());
EXPECT_EQ(350, expand_skewport.width());
EXPECT_EQ(350, expand_skewport.height());
EXPECT_TRUE(expand_skewport.Contains(gfx::Rect(-50, -50, 200, 200)));
// Expand the viewport past the limit in all directions.
gfx::Rect big_expand_skewport =
tiling_set->ComputeSkewport(gfx::Rect(-500, -500, 1500, 1500), 1.5, 1.f);
EXPECT_EQ(-575, big_expand_skewport.x());
EXPECT_EQ(-575, big_expand_skewport.y());
EXPECT_EQ(1650, big_expand_skewport.width());
EXPECT_EQ(1650, big_expand_skewport.height());
EXPECT_TRUE(big_expand_skewport.Contains(gfx::Rect(-500, -500, 1500, 1500)));
// Shrink the skewport in all directions.
gfx::Rect shrink_viewport =
tiling_set->ComputeSkewport(gfx::Rect(0, 0, 100, 100), 1.5, 1.f);
EXPECT_EQ(0, shrink_viewport.x());
EXPECT_EQ(0, shrink_viewport.y());
EXPECT_EQ(100, shrink_viewport.width());
EXPECT_EQ(100, shrink_viewport.height());
// Move the skewport really far in one direction.
gfx::Rect move_skewport_far =
tiling_set->ComputeSkewport(gfx::Rect(0, 5000, 100, 100), 1.5, 1.f);
EXPECT_EQ(0, move_skewport_far.x());
EXPECT_EQ(5000, move_skewport_far.y());
EXPECT_EQ(100, move_skewport_far.width());
EXPECT_EQ(175, move_skewport_far.height());
EXPECT_TRUE(move_skewport_far.Contains(gfx::Rect(0, 5000, 100, 100)));
}
TEST(PictureLayerTilingSetTest, ComputeSkewportExtremeCases) {
FakePictureLayerTilingClient client;
gfx::Size layer_bounds(200, 200);
client.SetTileSize(gfx::Size(100, 100));
LayerTreeSettings settings;
settings.tiling_interest_area_padding = 1000000000;
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(layer_bounds);
std::unique_ptr<TestablePictureLayerTilingSet> tiling_set =
CreateTilingSetWithSettings(&client, settings);
tiling_set->AddTiling(1.f, raster_source);
gfx::Rect viewport1(-1918, 255860, 4010, 2356);
gfx::Rect viewport2(-7088, -91738, 14212, 8350);
gfx::Rect viewport3(-12730024, -158883296, 24607540, 14454512);
double time = 1.0;
tiling_set->UpdateTilePriorities(viewport1, 1.f, time, Occlusion(), true);
time += 0.016;
EXPECT_TRUE(
tiling_set->ComputeSkewport(viewport2, time, 1.f).Contains(viewport2));
tiling_set->UpdateTilePriorities(viewport2, 1.f, time, Occlusion(), true);
time += 0.016;
EXPECT_TRUE(
tiling_set->ComputeSkewport(viewport3, time, 1.f).Contains(viewport3));
// Use a tiling with a large scale, so the viewport times the scale no longer
// fits into integers, and the viewport is not anywhere close to the tiling.
PictureLayerTiling* tiling = tiling_set->AddTiling(1000.f, raster_source);
EXPECT_TRUE(tiling_set->TilingsNeedUpdate(viewport3, time));
tiling_set->UpdateTilePriorities(viewport3, 1.f, time, Occlusion(), true);
EXPECT_TRUE(tiling->GetCurrentVisibleRectForTesting().IsEmpty());
}
TEST(PictureLayerTilingSetTest, ComputeSkewport) {
FakePictureLayerTilingClient client;
gfx::Rect viewport(0, 0, 100, 100);
gfx::Size layer_bounds(200, 200);
client.SetTileSize(gfx::Size(100, 100));
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(layer_bounds);
std::unique_ptr<TestablePictureLayerTilingSet> tiling_set =
CreateTilingSet(&client);
tiling_set->AddTiling(1.f, raster_source);
tiling_set->UpdateTilePriorities(viewport, 1.f, 1.0, Occlusion(), true);
// Move viewport down 50 pixels in 0.5 seconds.
gfx::Rect down_skewport =
tiling_set->ComputeSkewport(gfx::Rect(0, 50, 100, 100), 1.5, 1.f);
EXPECT_EQ(0, down_skewport.x());
EXPECT_EQ(50, down_skewport.y());
EXPECT_EQ(100, down_skewport.width());
EXPECT_EQ(200, down_skewport.height());
// Shrink viewport.
gfx::Rect shrink_skewport =
tiling_set->ComputeSkewport(gfx::Rect(25, 25, 50, 50), 1.5, 1.f);
EXPECT_EQ(25, shrink_skewport.x());
EXPECT_EQ(25, shrink_skewport.y());
EXPECT_EQ(50, shrink_skewport.width());
EXPECT_EQ(50, shrink_skewport.height());
// Move viewport down 50 and right 10 pixels.
gfx::Rect down_right_skewport =
tiling_set->ComputeSkewport(gfx::Rect(10, 50, 100, 100), 1.5, 1.f);
EXPECT_EQ(10, down_right_skewport.x());
EXPECT_EQ(50, down_right_skewport.y());
EXPECT_EQ(120, down_right_skewport.width());
EXPECT_EQ(200, down_right_skewport.height());
// Move viewport left.
gfx::Rect left_skewport =
tiling_set->ComputeSkewport(gfx::Rect(-20, 0, 100, 100), 1.5, 1.f);
EXPECT_EQ(-60, left_skewport.x());
EXPECT_EQ(0, left_skewport.y());
EXPECT_EQ(140, left_skewport.width());
EXPECT_EQ(100, left_skewport.height());
// Expand viewport in 0.2 seconds.
gfx::Rect expanded_skewport =
tiling_set->ComputeSkewport(gfx::Rect(-5, -5, 110, 110), 1.2, 1.f);
EXPECT_EQ(-30, expanded_skewport.x());
EXPECT_EQ(-30, expanded_skewport.y());
EXPECT_EQ(160, expanded_skewport.width());
EXPECT_EQ(160, expanded_skewport.height());
}
TEST(PictureLayerTilingSetTest, SkewportThroughUpdateTilePriorities) {
FakePictureLayerTilingClient client;
gfx::Rect viewport(0, 0, 100, 100);
gfx::Size layer_bounds(200, 200);
client.SetTileSize(gfx::Size(100, 100));
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(layer_bounds);
std::unique_ptr<TestablePictureLayerTilingSet> tiling_set =
CreateTilingSet(&client);
tiling_set->AddTiling(1.f, raster_source);
tiling_set->UpdateTilePriorities(viewport, 1.f, 1.0, Occlusion(), true);
// Move viewport down 50 pixels in 0.5 seconds.
gfx::Rect viewport_50 = gfx::Rect(0, 50, 100, 100);
gfx::Rect skewport_50 = tiling_set->ComputeSkewport(viewport_50, 1.5, 1.f);
EXPECT_EQ(gfx::Rect(0, 50, 100, 200), skewport_50);
tiling_set->UpdateTilePriorities(viewport_50, 1.f, 1.5, Occlusion(), true);
gfx::Rect viewport_100 = gfx::Rect(0, 100, 100, 100);
gfx::Rect skewport_100 = tiling_set->ComputeSkewport(viewport_100, 2.0, 1.f);
EXPECT_EQ(gfx::Rect(0, 100, 100, 200), skewport_100);
tiling_set->UpdateTilePriorities(viewport_100, 1.f, 2.0, Occlusion(), true);
// Advance time, but not the viewport.
gfx::Rect result = tiling_set->ComputeSkewport(viewport_100, 2.5, 1.f);
// Since the history did advance, we should still get a skewport but a smaller
// one.
EXPECT_EQ(gfx::Rect(0, 100, 100, 150), result);
tiling_set->UpdateTilePriorities(viewport_100, 1.f, 2.5, Occlusion(), true);
// Advance time again.
result = tiling_set->ComputeSkewport(viewport_100, 3.0, 1.f);
EXPECT_EQ(viewport_100, result);
tiling_set->UpdateTilePriorities(viewport_100, 1.f, 3.0, Occlusion(), true);
// Ensure we have a skewport.
gfx::Rect viewport_150 = gfx::Rect(0, 150, 100, 100);
gfx::Rect skewport_150 = tiling_set->ComputeSkewport(viewport_150, 3.5, 1.f);
EXPECT_EQ(gfx::Rect(0, 150, 100, 150), skewport_150);
tiling_set->UpdateTilePriorities(viewport_150, 1.f, 3.5, Occlusion(), true);
// Advance the viewport, but not the time.
gfx::Rect viewport_200 = gfx::Rect(0, 200, 100, 100);
gfx::Rect skewport_200 = tiling_set->ComputeSkewport(viewport_200, 3.5, 1.f);
EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
// Ensure that continued calls with the same value, produce the same skewport.
tiling_set->UpdateTilePriorities(viewport_150, 1.f, 3.5, Occlusion(), true);
EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
tiling_set->UpdateTilePriorities(viewport_150, 1.f, 3.5, Occlusion(), true);
EXPECT_EQ(gfx::Rect(0, 200, 100, 300), skewport_200);
tiling_set->UpdateTilePriorities(viewport_200, 1.f, 3.5, Occlusion(), true);
// This should never happen, but advance the viewport yet again keeping the
// time the same.
gfx::Rect viewport_250 = gfx::Rect(0, 250, 100, 100);
gfx::Rect skewport_250 = tiling_set->ComputeSkewport(viewport_250, 3.5, 1.f);
EXPECT_EQ(viewport_250, skewport_250);
tiling_set->UpdateTilePriorities(viewport_250, 1.f, 3.5, Occlusion(), true);
}
TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
FakePictureLayerTilingClient client;
gfx::Rect viewport(0, 0, 100, 100);
gfx::Size layer_bounds(1500, 1500);
client.SetTileSize(gfx::Size(10, 10));
LayerTreeSettings settings;
// Tiling at 0.25 scale: this should create 47x47 tiles of size 10x10.
// The reason is that each tile has a one pixel border, so tile at (1, 2)
// for instance begins at (8, 16) pixels. So tile at (46, 46) will begin at
// (368, 368) and extend to the end of 1500 * 0.25 = 375 edge of the
// tiling.
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(layer_bounds);
std::unique_ptr<TestablePictureLayerTilingSet> tiling_set =
CreateTilingSet(&client);
auto* tiling = tiling_set->AddTiling(0.25f, raster_source);
tiling->set_resolution(HIGH_RESOLUTION);
gfx::Rect viewport_in_content_space =
gfx::ScaleToEnclosedRect(viewport, 0.25f);
tiling_set->UpdateTilePriorities(viewport, 1.f, 1.0, Occlusion(), true);
auto prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
// Compute the soon border.
gfx::Rect soon_border_rect_in_content_space =
tiling_set->ComputeSoonBorderRect(viewport, 1.f);
soon_border_rect_in_content_space =
gfx::ScaleToEnclosedRect(soon_border_rect_in_content_space, 0.25f);
// Sanity checks.
for (int i = 0; i < 47; ++i) {
for (int j = 0; j < 47; ++j) {
EXPECT_TRUE(tiling->TileAt(i, j)) << "i: " << i << " j: " << j;
}
}
for (int i = 0; i < 47; ++i) {
EXPECT_FALSE(tiling->TileAt(i, 47)) << "i: " << i;
EXPECT_FALSE(tiling->TileAt(47, i)) << "i: " << i;
}
// No movement in the viewport implies that tiles will either be NOW
// or EVENTUALLY, with the exception of tiles that are between 0 and 312
// pixels away from the viewport, which will be in the SOON bin.
bool have_now = false;
bool have_eventually = false;
bool have_soon = false;
for (int i = 0; i < 47; ++i) {
for (int j = 0; j < 47; ++j) {
Tile* tile = tiling->TileAt(i, j);
PrioritizedTile prioritized_tile = prioritized_tiles[tile];
TilePriority priority = prioritized_tile.priority();
gfx::Rect tile_rect = tiling->TilingDataForTesting().TileBounds(i, j);
if (viewport_in_content_space.Intersects(tile_rect)) {
EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
have_now = true;
} else if (soon_border_rect_in_content_space.Intersects(tile_rect)) {
EXPECT_EQ(TilePriority::SOON, priority.priority_bin);
have_soon = true;
} else {
EXPECT_EQ(TilePriority::EVENTUALLY, priority.priority_bin);
EXPECT_GT(priority.distance_to_visible, 0.f);
have_eventually = true;
}
}
}
EXPECT_TRUE(have_now);
EXPECT_TRUE(have_soon);
EXPECT_TRUE(have_eventually);
// Spot check some distances.
// Tile at 5, 1 should begin at 41x9 in content space (without borders),
// so the distance to a viewport that ends at 25x25 in content space
// should be 17 (41 - 25 + 1). In layer space, then that should be
// 17 / 0.25 = 68 pixels.
// We can verify that the content rect (with borders) is one pixel off
// 41,9 8x8 on all sides.
EXPECT_EQ(tiling->TileAt(5, 1)->content_rect().ToString(), "40,8 10x10");
TilePriority priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(40.f, priority.distance_to_visible);
// Move the viewport down 40 pixels.
viewport = gfx::Rect(0, 40, 100, 100);
viewport_in_content_space = gfx::ScaleToEnclosedRect(viewport, 0.25f);
gfx::Rect skewport_in_content_space =
tiling_set->ComputeSkewport(viewport, 2.0, 1.f);
skewport_in_content_space =
gfx::ScaleToEnclosedRect(skewport_in_content_space, 0.25f);
// Compute the soon border.
soon_border_rect_in_content_space =
tiling_set->ComputeSoonBorderRect(viewport, 1.f);
soon_border_rect_in_content_space =
gfx::ScaleToEnclosedRect(soon_border_rect_in_content_space, 0.25f);
EXPECT_EQ(0, skewport_in_content_space.x());
EXPECT_EQ(10, skewport_in_content_space.y());
EXPECT_EQ(25, skewport_in_content_space.width());
EXPECT_EQ(35, skewport_in_content_space.height());
EXPECT_TRUE(tiling_set->TilingsNeedUpdate(viewport, 2.0));
tiling_set->UpdateTilePriorities(viewport, 1.f, 2.0, Occlusion(), true);
prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
have_now = false;
have_eventually = false;
have_soon = false;
// Viewport moved, so we expect to find some NOW tiles, some SOON tiles and
// some EVENTUALLY tiles.
for (int i = 0; i < 47; ++i) {
for (int j = 0; j < 47; ++j) {
Tile* tile = tiling->TileAt(i, j);
TilePriority priority = prioritized_tiles[tile].priority();
gfx::Rect tile_rect = tiling->TilingDataForTesting().TileBounds(i, j);
if (viewport_in_content_space.Intersects(tile_rect)) {
EXPECT_EQ(TilePriority::NOW, priority.priority_bin) << "i: " << i
<< " j: " << j;
EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible) << "i: " << i
<< " j: " << j;
have_now = true;
} else if (skewport_in_content_space.Intersects(tile_rect) ||
soon_border_rect_in_content_space.Intersects(tile_rect)) {
EXPECT_EQ(TilePriority::SOON, priority.priority_bin) << "i: " << i
<< " j: " << j;
EXPECT_GT(priority.distance_to_visible, 0.f) << "i: " << i
<< " j: " << j;
have_soon = true;
} else {
EXPECT_EQ(TilePriority::EVENTUALLY, priority.priority_bin)
<< "i: " << i << " j: " << j;
EXPECT_GT(priority.distance_to_visible, 0.f) << "i: " << i
<< " j: " << j;
have_eventually = true;
}
}
}
EXPECT_TRUE(have_now);
EXPECT_TRUE(have_soon);
EXPECT_TRUE(have_eventually);
priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(68.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(28.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(4.f, priority.distance_to_visible);
// Change the underlying layer scale.
tiling_set->UpdateTilePriorities(viewport, 2.0f, 3.0, Occlusion(), true);
prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(136.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(56.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(8.f, priority.distance_to_visible);
// Test additional scales.
tiling = tiling_set->AddTiling(0.2f, raster_source);
tiling->set_resolution(HIGH_RESOLUTION);
tiling_set->UpdateTilePriorities(viewport, 1.0f, 4.0, Occlusion(), true);
prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(110.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(70.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(60.f, priority.distance_to_visible);
tiling_set->UpdateTilePriorities(viewport, 0.5f, 5.0, Occlusion(), true);
prioritized_tiles = tiling->UpdateAndGetAllPrioritizedTilesForTesting();
priority = prioritized_tiles[tiling->TileAt(5, 1)].priority();
EXPECT_FLOAT_EQ(55.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(2, 5)].priority();
EXPECT_FLOAT_EQ(35.f, priority.distance_to_visible);
priority = prioritized_tiles[tiling->TileAt(3, 4)].priority();
EXPECT_FLOAT_EQ(30.f, priority.distance_to_visible);
}
TEST(PictureLayerTilingTest, InvalidateAfterComputeTilePriorityRects) {
FakePictureLayerTilingClient pending_client;
pending_client.SetTileSize(gfx::Size(100, 100));
scoped_refptr<FakeRasterSource> raster_source =
FakeRasterSource::CreateFilled(gfx::Size(100, 100));
std::unique_ptr<TestablePictureLayerTilingSet> tiling_set =
CreateTilingSet(&pending_client);
auto* pending_tiling = tiling_set->AddTiling(1.f, raster_source);
pending_tiling->set_resolution(HIGH_RESOLUTION);
// Ensure that we can compute tile priority rects, invalidate, and compute the
// rects again. It is important that the second compute tile priority rects
// return true, indicating that things have changed (since invalidation has
// changed things). This causes PrepareTiles to be properly scheduled. If the
// second ComputeTilePriorityRects returns false, then we assume that
// PrepareTiles isn't needed and we signal that we're ready to draw
// immediately, which can cause visual glitches.
//
// This can happen we if we process an impl frame deadline before processing a
// commit. That is, when we draw we ComputeTilePriorityRects. If we process
// the commit afterwards, it would use the same timestamp and sometimes would
// use the same viewport to compute tile priority rects again.
double time = 1.;
gfx::Rect viewport(0, 0, 100, 100);
EXPECT_TRUE(
tiling_set->UpdateTilePriorities(viewport, 1.f, time, Occlusion(), true));
EXPECT_FALSE(
tiling_set->UpdateTilePriorities(viewport, 1.f, time, Occlusion(), true));
// This will invalidate tilings.
tiling_set->UpdateRasterSourceDueToLCDChange(raster_source, Region());
EXPECT_TRUE(
tiling_set->UpdateTilePriorities(viewport, 1.f, time, Occlusion(), true));
}
} // namespace
} // namespace cc