root/cc/resources/tile_manager_unittest.cc

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ready_to_activate_
  2. Initialize
  3. SetTreePriority
  4. TearDown
  5. NotifyReadyToActivate
  6. CreateTilesWithSize
  7. CreateTiles
  8. tile_manager
  9. AssignedMemoryCount
  10. TilesWithLCDCount
  11. ready_to_activate
  12. UsingResourceLimit
  13. UsingMemoryLimit
  14. TEST_P
  15. TEST_P
  16. TEST_P
  17. TEST_P
  18. TEST_P
  19. TEST_P
  20. TEST_P
  21. TEST_P
  22. TEST_P
  23. TEST_P
  24. TEST_P
  25. TEST_P
  26. TEST_P
  27. TEST_P
  28. TEST_P
  29. TEST_P
  30. TEST_P
  31. TEST_P
  32. host_impl_
  33. SetTreePriority
  34. SetUp
  35. InitializeRenderer
  36. SetupDefaultTrees
  37. ActivateTree
  38. SetupDefaultTreesWithFixedTileSize
  39. SetupTrees
  40. SetupPendingTree
  41. CreateHighLowResAndSetAllTilesVisible
  42. NotifyReadyToActivate
  43. tile_manager
  44. TEST_F
  45. TEST_F

// Copyright 2013 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/resources/tile.h"
#include "cc/resources/tile_priority.h"
#include "cc/test/fake_impl_proxy.h"
#include "cc/test/fake_layer_tree_host_impl.h"
#include "cc/test/fake_output_surface.h"
#include "cc/test/fake_output_surface_client.h"
#include "cc/test/fake_picture_layer_impl.h"
#include "cc/test/fake_picture_pile_impl.h"
#include "cc/test/fake_tile_manager.h"
#include "cc/test/impl_side_painting_settings.h"
#include "cc/test/test_shared_bitmap_manager.h"
#include "cc/test/test_tile_priorities.h"
#include "cc/trees/layer_tree_impl.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace cc {
namespace {

class TileManagerTest : public testing::TestWithParam<bool>,
                        public TileManagerClient {
 public:
  typedef std::vector<scoped_refptr<Tile> > TileVector;

  TileManagerTest()
      : memory_limit_policy_(ALLOW_ANYTHING),
        max_tiles_(0),
        ready_to_activate_(false) {}

  void Initialize(int max_tiles,
                  TileMemoryLimitPolicy memory_limit_policy,
                  TreePriority tree_priority,
                  bool allow_on_demand_raster = true) {
    output_surface_ = FakeOutputSurface::Create3d();
    CHECK(output_surface_->BindToClient(&output_surface_client_));

    shared_bitmap_manager_.reset(new TestSharedBitmapManager());
    resource_provider_ = ResourceProvider::Create(
        output_surface_.get(), shared_bitmap_manager_.get(), 0, false, 1);
    tile_manager_ = make_scoped_ptr(new FakeTileManager(
        this, resource_provider_.get(), allow_on_demand_raster));

    memory_limit_policy_ = memory_limit_policy;
    max_tiles_ = max_tiles;
    picture_pile_ = FakePicturePileImpl::CreateInfiniteFilledPile();

    SetTreePriority(tree_priority);
  }

  void SetTreePriority(TreePriority tree_priority) {
    GlobalStateThatImpactsTilePriority state;
    gfx::Size tile_size = settings_.default_tile_size;

    if (UsingMemoryLimit()) {
      state.soft_memory_limit_in_bytes =
          max_tiles_ * 4 * tile_size.width() * tile_size.height();
      state.num_resources_limit = 100;
    } else {
      state.soft_memory_limit_in_bytes = 100 * 1000 * 1000;
      state.num_resources_limit = max_tiles_;
    }
    state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes * 2;
    state.unused_memory_limit_in_bytes = state.soft_memory_limit_in_bytes;
    state.memory_limit_policy = memory_limit_policy_;
    state.tree_priority = tree_priority;

    global_state_ = state;
    tile_manager_->SetGlobalStateForTesting(state);
  }

  virtual void TearDown() OVERRIDE {
    tile_manager_.reset(NULL);
    picture_pile_ = NULL;

    testing::Test::TearDown();
  }

  // TileManagerClient implementation.
  virtual void NotifyReadyToActivate() OVERRIDE { ready_to_activate_ = true; }

  TileVector CreateTilesWithSize(int count,
                                 TilePriority active_priority,
                                 TilePriority pending_priority,
                                 const gfx::Size& tile_size) {
    TileVector tiles;
    for (int i = 0; i < count; ++i) {
      scoped_refptr<Tile> tile = tile_manager_->CreateTile(picture_pile_.get(),
                                                           tile_size,
                                                           gfx::Rect(),
                                                           gfx::Rect(),
                                                           1.0,
                                                           0,
                                                           0,
                                                           Tile::USE_LCD_TEXT);
      tile->SetPriority(ACTIVE_TREE, active_priority);
      tile->SetPriority(PENDING_TREE, pending_priority);
      tiles.push_back(tile);
    }
    return tiles;
  }

  TileVector CreateTiles(int count,
                         TilePriority active_priority,
                         TilePriority pending_priority) {
    return CreateTilesWithSize(
        count, active_priority, pending_priority, settings_.default_tile_size);
  }

  FakeTileManager* tile_manager() { return tile_manager_.get(); }

  int AssignedMemoryCount(const TileVector& tiles) {
    int has_memory_count = 0;
    for (TileVector::const_iterator it = tiles.begin(); it != tiles.end();
         ++it) {
      if (tile_manager_->HasBeenAssignedMemory(*it))
        ++has_memory_count;
    }
    return has_memory_count;
  }

  int TilesWithLCDCount(const TileVector& tiles) {
    int has_lcd_count = 0;
    for (TileVector::const_iterator it = tiles.begin(); it != tiles.end();
         ++it) {
      if ((*it)->GetRasterModeForTesting() == HIGH_QUALITY_RASTER_MODE)
        ++has_lcd_count;
    }
    return has_lcd_count;
  }

  bool ready_to_activate() const { return ready_to_activate_; }

  // The parametrization specifies whether the max tile limit should
  // be applied to memory or resources.
  bool UsingResourceLimit() { return !GetParam(); }
  bool UsingMemoryLimit() { return GetParam(); }

 protected:
  GlobalStateThatImpactsTilePriority global_state_;

 private:
  LayerTreeSettings settings_;
  scoped_ptr<FakeTileManager> tile_manager_;
  scoped_refptr<FakePicturePileImpl> picture_pile_;
  FakeOutputSurfaceClient output_surface_client_;
  scoped_ptr<FakeOutputSurface> output_surface_;
  scoped_ptr<SharedBitmapManager> shared_bitmap_manager_;
  scoped_ptr<ResourceProvider> resource_provider_;
  TileMemoryLimitPolicy memory_limit_policy_;
  int max_tiles_;
  bool ready_to_activate_;
};

TEST_P(TileManagerTest, EnoughMemoryAllowAnything) {
  // A few tiles of each type of priority, with enough memory for all tiles.

  Initialize(10, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_now =
      CreateTiles(3, TilePriorityForNowBin(), TilePriority());
  TileVector pending_now =
      CreateTiles(3, TilePriority(), TilePriorityForNowBin());
  TileVector active_pending_soon =
      CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
  TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(3, AssignedMemoryCount(active_now));
  EXPECT_EQ(3, AssignedMemoryCount(pending_now));
  EXPECT_EQ(3, AssignedMemoryCount(active_pending_soon));
  EXPECT_EQ(0, AssignedMemoryCount(never_bin));
}

TEST_P(TileManagerTest, EnoughMemoryAllowPrepaintOnly) {
  // A few tiles of each type of priority, with enough memory for all tiles,
  // with the exception of never bin.

  Initialize(10, ALLOW_PREPAINT_ONLY, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_now =
      CreateTiles(3, TilePriorityForNowBin(), TilePriority());
  TileVector pending_now =
      CreateTiles(3, TilePriority(), TilePriorityForNowBin());
  TileVector active_pending_soon =
      CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
  TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(3, AssignedMemoryCount(active_now));
  EXPECT_EQ(3, AssignedMemoryCount(pending_now));
  EXPECT_EQ(3, AssignedMemoryCount(active_pending_soon));
  EXPECT_EQ(0, AssignedMemoryCount(never_bin));
}

TEST_P(TileManagerTest, EnoughMemoryAllowAbsoluteMinimum) {
  // A few tiles of each type of priority, with enough memory for all tiles,
  // with the exception of never and soon bins.

  Initialize(10, ALLOW_ABSOLUTE_MINIMUM, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_now =
      CreateTiles(3, TilePriorityForNowBin(), TilePriority());
  TileVector pending_now =
      CreateTiles(3, TilePriority(), TilePriorityForNowBin());
  TileVector active_pending_soon =
      CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
  TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(3, AssignedMemoryCount(active_now));
  EXPECT_EQ(3, AssignedMemoryCount(pending_now));
  EXPECT_EQ(0, AssignedMemoryCount(active_pending_soon));
  EXPECT_EQ(0, AssignedMemoryCount(never_bin));
}

TEST_P(TileManagerTest, EnoughMemoryAllowNothing) {
  // A few tiles of each type of priority, with enough memory for all tiles,
  // but allow nothing should not assign any memory.

  Initialize(10, ALLOW_NOTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_now =
      CreateTiles(3, TilePriorityForNowBin(), TilePriority());
  TileVector pending_now =
      CreateTiles(3, TilePriority(), TilePriorityForNowBin());
  TileVector active_pending_soon =
      CreateTiles(3, TilePriorityForSoonBin(), TilePriorityForSoonBin());
  TileVector never_bin = CreateTiles(1, TilePriority(), TilePriority());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(0, AssignedMemoryCount(active_now));
  EXPECT_EQ(0, AssignedMemoryCount(pending_now));
  EXPECT_EQ(0, AssignedMemoryCount(active_pending_soon));
  EXPECT_EQ(0, AssignedMemoryCount(never_bin));
}

TEST_P(TileManagerTest, PartialOOMMemoryToPending) {
  // 5 tiles on active tree eventually bin, 5 tiles on pending tree that are
  // required for activation, but only enough memory for 8 tiles. The result
  // is all pending tree tiles get memory, and 3 of the active tree tiles
  // get memory. None of these tiles is needed to avoid calimity (flickering or
  // raster-on-demand) so the soft memory limit is used.

  Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(5, TilePriorityForEventualBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(5, TilePriority(), TilePriorityRequiredForActivation());
  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(5, AssignedMemoryCount(active_tree_tiles));
  EXPECT_EQ(3, AssignedMemoryCount(pending_tree_tiles));

  SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(3, AssignedMemoryCount(active_tree_tiles));
  EXPECT_EQ(5, AssignedMemoryCount(pending_tree_tiles));
}

TEST_P(TileManagerTest, PartialOOMMemoryToActive) {
  // 5 tiles on active tree eventually bin, 5 tiles on pending tree now bin,
  // but only enough memory for 8 tiles. The result is all active tree tiles
  // get memory, and 3 of the pending tree tiles get memory.
  // The pending tiles are not needed to avoid calimity (flickering or
  // raster-on-demand) and the active tiles fit, so the soft limit is used.

  Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(5, TilePriorityForNowBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(5, TilePriority(), TilePriorityForNowBin());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(5, AssignedMemoryCount(active_tree_tiles));
  EXPECT_EQ(3, AssignedMemoryCount(pending_tree_tiles));
}

TEST_P(TileManagerTest, TotalOOMMemoryToPending) {
  // 10 tiles on active tree eventually bin, 10 tiles on pending tree that are
  // required for activation, but only enough tiles for 4 tiles. The result
  // is 4 pending tree tiles get memory, and none of the active tree tiles
  // get memory.

  Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(10, TilePriorityForEventualBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(10, TilePriority(), TilePriorityRequiredForActivation());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles));
  EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));

  SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
  tile_manager()->AssignMemoryToTiles(global_state_);

  if (UsingResourceLimit()) {
    EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
    EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles));
  } else {
    // Pending tiles are now required to avoid calimity (flickering or
    // raster-on-demand). Hard-limit is used and double the tiles fit.
    EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
    EXPECT_EQ(8, AssignedMemoryCount(pending_tree_tiles));
  }
}

TEST_P(TileManagerTest, TotalOOMActiveSoonMemoryToPending) {
  // 10 tiles on active tree soon bin, 10 tiles on pending tree that are
  // required for activation, but only enough tiles for 4 tiles. The result
  // is 4 pending tree tiles get memory, and none of the active tree tiles
  // get memory.

  Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(10, TilePriorityForSoonBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(10, TilePriority(), TilePriorityRequiredForActivation());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles));
  EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));

  SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
  tile_manager()->AssignMemoryToTiles(global_state_);

  if (UsingResourceLimit()) {
    EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
    EXPECT_EQ(4, AssignedMemoryCount(pending_tree_tiles));
  } else {
    // Pending tiles are now required to avoid calimity (flickering or
    // raster-on-demand). Hard-limit is used and double the tiles fit.
    EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
    EXPECT_EQ(8, AssignedMemoryCount(pending_tree_tiles));
  }
}

TEST_P(TileManagerTest, TotalOOMMemoryToActive) {
  // 10 tiles on active tree eventually bin, 10 tiles on pending tree now bin,
  // but only enough memory for 4 tiles. The result is 4 active tree tiles
  // get memory, and none of the pending tree tiles get memory.

  Initialize(4, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(10, TilePriorityForNowBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(10, TilePriority(), TilePriorityForNowBin());

  tile_manager()->AssignMemoryToTiles(global_state_);

  if (UsingResourceLimit()) {
    EXPECT_EQ(4, AssignedMemoryCount(active_tree_tiles));
    EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));
  } else {
    // Active tiles are required to avoid calimity (flickering or
    // raster-on-demand). Hard-limit is used and double the tiles fit.
    EXPECT_EQ(8, AssignedMemoryCount(active_tree_tiles));
    EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));
  }
}

TEST_P(TileManagerTest, TotalOOMMemoryToNewContent) {
  // 10 tiles on active tree now bin, 10 tiles on pending tree now bin,
  // but only enough memory for 8 tiles. Any tile missing would cause
  // a calamity (flickering or raster-on-demand). Depending on mode,
  // we should use varying amounts of the higher hard memory limit.
  if (UsingResourceLimit())
    return;

  Initialize(8, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(10, TilePriorityForNowBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(10, TilePriority(), TilePriorityForNowBin());

  // Active tiles are required to avoid calimity. The hard-limit is used and all
  // active-tiles fit. No pending tiles are needed to avoid calamity so only 10
  // tiles total are used.
  tile_manager()->AssignMemoryToTiles(global_state_);
  EXPECT_EQ(10, AssignedMemoryCount(active_tree_tiles));
  EXPECT_EQ(0, AssignedMemoryCount(pending_tree_tiles));

  // Even the hard-limit won't save us now. All tiles are required to avoid
  // a clamity but we only have 16. The tiles will be distribted randomly
  // given they are identical, in practice depending on their screen location.
  SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
  tile_manager()->AssignMemoryToTiles(global_state_);
  EXPECT_EQ(16,
            AssignedMemoryCount(active_tree_tiles) +
                AssignedMemoryCount(pending_tree_tiles));

  // The pending tree is now more important. Active tiles will take higher
  // priority if they are ready-to-draw in practice. Importantly though,
  // pending tiles also utilize the hard-limit.
  SetTreePriority(NEW_CONTENT_TAKES_PRIORITY);
  tile_manager()->AssignMemoryToTiles(global_state_);
  EXPECT_EQ(0, AssignedMemoryCount(active_tree_tiles));
  EXPECT_EQ(10, AssignedMemoryCount(pending_tree_tiles));
}

TEST_P(TileManagerTest, RasterAsLCD) {
  Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(5, TilePriorityForNowBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(5, TilePriority(), TilePriorityForNowBin());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
  EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));
}

TEST_P(TileManagerTest, RasterAsNoLCD) {
  Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(5, TilePriorityForNowBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(5, TilePriority(), TilePriorityForNowBin());

  for (TileVector::iterator it = active_tree_tiles.begin();
       it != active_tree_tiles.end();
       ++it) {
    (*it)->set_can_use_lcd_text(false);
  }
  for (TileVector::iterator it = pending_tree_tiles.begin();
       it != pending_tree_tiles.end();
       ++it) {
    (*it)->set_can_use_lcd_text(false);
  }

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles));
  EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles));
}

TEST_P(TileManagerTest, ReRasterAsNoLCD) {
  Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(5, TilePriorityForNowBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(5, TilePriority(), TilePriorityForNowBin());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
  EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));

  for (TileVector::iterator it = active_tree_tiles.begin();
       it != active_tree_tiles.end();
       ++it) {
    (*it)->set_can_use_lcd_text(false);
  }
  for (TileVector::iterator it = pending_tree_tiles.begin();
       it != pending_tree_tiles.end();
       ++it) {
    (*it)->set_can_use_lcd_text(false);
  }

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles));
  EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles));
}

TEST_P(TileManagerTest, NoTextDontReRasterAsNoLCD) {
  Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(5, TilePriorityForNowBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(5, TilePriority(), TilePriorityForNowBin());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
  EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));

  for (TileVector::iterator it = active_tree_tiles.begin();
       it != active_tree_tiles.end();
       ++it) {
    ManagedTileState::TileVersion& tile_version =
        (*it)->GetTileVersionForTesting(HIGH_QUALITY_RASTER_MODE);
    tile_version.SetSolidColorForTesting(SkColorSetARGB(0, 0, 0, 0));
    (*it)->set_can_use_lcd_text(false);
    EXPECT_TRUE((*it)->IsReadyToDraw());
  }
  for (TileVector::iterator it = pending_tree_tiles.begin();
       it != pending_tree_tiles.end();
       ++it) {
    ManagedTileState::TileVersion& tile_version =
        (*it)->GetTileVersionForTesting(HIGH_QUALITY_RASTER_MODE);
    tile_version.SetSolidColorForTesting(SkColorSetARGB(0, 0, 0, 0));
    (*it)->set_can_use_lcd_text(false);
    EXPECT_TRUE((*it)->IsReadyToDraw());
  }

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
  EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));
}

TEST_P(TileManagerTest, TextReRasterAsNoLCD) {
  Initialize(20, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);
  TileVector active_tree_tiles =
      CreateTiles(5, TilePriorityForNowBin(), TilePriority());
  TileVector pending_tree_tiles =
      CreateTiles(5, TilePriority(), TilePriorityForNowBin());

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(5, TilesWithLCDCount(active_tree_tiles));
  EXPECT_EQ(5, TilesWithLCDCount(pending_tree_tiles));

  for (TileVector::iterator it = active_tree_tiles.begin();
       it != active_tree_tiles.end();
       ++it) {
    ManagedTileState::TileVersion& tile_version =
        (*it)->GetTileVersionForTesting(HIGH_QUALITY_RASTER_MODE);
    tile_version.SetSolidColorForTesting(SkColorSetARGB(0, 0, 0, 0));
    tile_version.SetHasTextForTesting(true);
    (*it)->set_can_use_lcd_text(false);

    EXPECT_TRUE((*it)->IsReadyToDraw());
  }
  for (TileVector::iterator it = pending_tree_tiles.begin();
       it != pending_tree_tiles.end();
       ++it) {
    ManagedTileState::TileVersion& tile_version =
        (*it)->GetTileVersionForTesting(HIGH_QUALITY_RASTER_MODE);
    tile_version.SetSolidColorForTesting(SkColorSetARGB(0, 0, 0, 0));
    tile_version.SetHasTextForTesting(true);
    (*it)->set_can_use_lcd_text(false);

    EXPECT_TRUE((*it)->IsReadyToDraw());
  }

  tile_manager()->AssignMemoryToTiles(global_state_);

  EXPECT_EQ(0, TilesWithLCDCount(active_tree_tiles));
  EXPECT_EQ(0, TilesWithLCDCount(pending_tree_tiles));
}

TEST_P(TileManagerTest, RespectMemoryLimit) {
  if (UsingResourceLimit())
    return;

  Initialize(5, ALLOW_ANYTHING, SMOOTHNESS_TAKES_PRIORITY);

  // We use double the tiles since the hard-limit is double.
  TileVector large_tiles =
      CreateTiles(10, TilePriorityForNowBin(), TilePriority());

  size_t memory_required_bytes;
  size_t memory_nice_to_have_bytes;
  size_t memory_allocated_bytes;
  size_t memory_used_bytes;

  tile_manager()->AssignMemoryToTiles(global_state_);
  tile_manager()->GetMemoryStats(&memory_required_bytes,
                                 &memory_nice_to_have_bytes,
                                 &memory_allocated_bytes,
                                 &memory_used_bytes);
  // Allocated bytes should never be more than the memory limit.
  EXPECT_LE(memory_allocated_bytes, global_state_.hard_memory_limit_in_bytes);

  // Finish raster of large tiles.
  tile_manager()->UpdateVisibleTiles();

  // Remove all large tiles. This will leave the memory currently
  // used by these tiles as unused when AssignMemoryToTiles() is called.
  large_tiles.clear();

  // Create a new set of tiles using a different size. These tiles
  // can use the memory currently assigned to the large tiles but
  // they can't use the same resources as the size doesn't match.
  TileVector small_tiles = CreateTilesWithSize(
      10, TilePriorityForNowBin(), TilePriority(), gfx::Size(128, 128));

  tile_manager()->AssignMemoryToTiles(global_state_);
  tile_manager()->GetMemoryStats(&memory_required_bytes,
                                 &memory_nice_to_have_bytes,
                                 &memory_allocated_bytes,
                                 &memory_used_bytes);
  // Allocated bytes should never be more than the memory limit.
  EXPECT_LE(memory_allocated_bytes, global_state_.hard_memory_limit_in_bytes);
}

TEST_P(TileManagerTest, AllowRasterizeOnDemand) {
  // Not enough memory to initialize tiles required for activation.
  Initialize(0, ALLOW_ANYTHING, SAME_PRIORITY_FOR_BOTH_TREES);
  TileVector tiles =
      CreateTiles(2, TilePriority(), TilePriorityRequiredForActivation());

  tile_manager()->AssignMemoryToTiles(global_state_);

  // This should make required tiles ready to draw by marking them as
  // required tiles for on-demand raster.
  tile_manager()->DidFinishRunningTasksForTesting();

  EXPECT_TRUE(ready_to_activate());
  for (TileVector::iterator it = tiles.begin(); it != tiles.end(); ++it)
    EXPECT_TRUE((*it)->IsReadyToDraw());
}

TEST_P(TileManagerTest, PreventRasterizeOnDemand) {
  // Not enough memory to initialize tiles required for activation.
  Initialize(0, ALLOW_ANYTHING, SAME_PRIORITY_FOR_BOTH_TREES, false);
  TileVector tiles =
      CreateTiles(2, TilePriority(), TilePriorityRequiredForActivation());

  tile_manager()->AssignMemoryToTiles(global_state_);

  // This should make required tiles ready to draw by marking them as
  // required tiles for on-demand raster.
  tile_manager()->DidFinishRunningTasksForTesting();

  EXPECT_TRUE(ready_to_activate());
  for (TileVector::iterator it = tiles.begin(); it != tiles.end(); ++it)
    EXPECT_FALSE((*it)->IsReadyToDraw());
}

// If true, the max tile limit should be applied as bytes; if false,
// as num_resources_limit.
INSTANTIATE_TEST_CASE_P(TileManagerTests,
                        TileManagerTest,
                        ::testing::Values(true, false));

class TileManagerTileIteratorTest : public testing::Test,
                                    public TileManagerClient {
 public:
  TileManagerTileIteratorTest()
      : memory_limit_policy_(ALLOW_ANYTHING),
        max_tiles_(10000),
        ready_to_activate_(false),
        id_(7),
        proxy_(base::MessageLoopProxy::current()),
        host_impl_(ImplSidePaintingSettings(),
                   &proxy_,
                   &shared_bitmap_manager_) {}

  void SetTreePriority(TreePriority tree_priority) {
    GlobalStateThatImpactsTilePriority state;
    gfx::Size tile_size(256, 256);

    state.soft_memory_limit_in_bytes = 100 * 1000 * 1000;
    state.num_resources_limit = max_tiles_;
    state.hard_memory_limit_in_bytes = state.soft_memory_limit_in_bytes * 2;
    state.unused_memory_limit_in_bytes = state.soft_memory_limit_in_bytes;
    state.memory_limit_policy = memory_limit_policy_;
    state.tree_priority = tree_priority;

    global_state_ = state;
    host_impl_.tile_manager()->SetGlobalStateForTesting(state);
  }

  virtual void SetUp() OVERRIDE {
    InitializeRenderer();
    SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
  }

  virtual void InitializeRenderer() {
    host_impl_.InitializeRenderer(
        FakeOutputSurface::Create3d().PassAs<OutputSurface>());
  }

  void SetupDefaultTrees(const gfx::Size& layer_bounds) {
    gfx::Size tile_size(100, 100);

    scoped_refptr<FakePicturePileImpl> pending_pile =
        FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
    scoped_refptr<FakePicturePileImpl> active_pile =
        FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);

    SetupTrees(pending_pile, active_pile);
  }

  void ActivateTree() {
    host_impl_.ActivatePendingTree();
    CHECK(!host_impl_.pending_tree());
    pending_layer_ = NULL;
    active_layer_ = static_cast<FakePictureLayerImpl*>(
        host_impl_.active_tree()->LayerById(id_));
  }

  void SetupDefaultTreesWithFixedTileSize(const gfx::Size& layer_bounds,
                                          const gfx::Size& tile_size) {
    SetupDefaultTrees(layer_bounds);
    pending_layer_->set_fixed_tile_size(tile_size);
    active_layer_->set_fixed_tile_size(tile_size);
  }

  void SetupTrees(scoped_refptr<PicturePileImpl> pending_pile,
                  scoped_refptr<PicturePileImpl> active_pile) {
    SetupPendingTree(active_pile);
    ActivateTree();
    SetupPendingTree(pending_pile);
  }

  void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
    host_impl_.CreatePendingTree();
    LayerTreeImpl* pending_tree = host_impl_.pending_tree();
    // Clear recycled tree.
    pending_tree->DetachLayerTree();

    scoped_ptr<FakePictureLayerImpl> pending_layer =
        FakePictureLayerImpl::CreateWithPile(pending_tree, id_, pile);
    pending_layer->SetDrawsContent(true);
    pending_tree->SetRootLayer(pending_layer.PassAs<LayerImpl>());

    pending_layer_ = static_cast<FakePictureLayerImpl*>(
        host_impl_.pending_tree()->LayerById(id_));
    pending_layer_->DoPostCommitInitializationIfNeeded();
  }

  void CreateHighLowResAndSetAllTilesVisible() {
    // Active layer must get updated first so pending layer can share from it.
    active_layer_->CreateDefaultTilingsAndTiles();
    active_layer_->SetAllTilesVisible();
    pending_layer_->CreateDefaultTilingsAndTiles();
    pending_layer_->SetAllTilesVisible();
  }

  // TileManagerClient implementation.
  virtual void NotifyReadyToActivate() OVERRIDE { ready_to_activate_ = true; }

  TileManager* tile_manager() { return host_impl_.tile_manager(); }

 protected:
  GlobalStateThatImpactsTilePriority global_state_;

  TestSharedBitmapManager shared_bitmap_manager_;
  TileMemoryLimitPolicy memory_limit_policy_;
  int max_tiles_;
  bool ready_to_activate_;
  int id_;
  FakeImplProxy proxy_;
  FakeLayerTreeHostImpl host_impl_;
  FakePictureLayerImpl* pending_layer_;
  FakePictureLayerImpl* active_layer_;
};

TEST_F(TileManagerTileIteratorTest, PairedPictureLayers) {
  FakeImplProxy proxy;
  TestSharedBitmapManager shared_bitmap_manager;
  FakeLayerTreeHostImpl host_impl(&proxy, &shared_bitmap_manager);
  host_impl.CreatePendingTree();
  host_impl.ActivatePendingTree();
  host_impl.CreatePendingTree();

  LayerTreeImpl* active_tree = host_impl.active_tree();
  LayerTreeImpl* pending_tree = host_impl.pending_tree();
  EXPECT_NE(active_tree, pending_tree);

  scoped_ptr<FakePictureLayerImpl> active_layer =
      FakePictureLayerImpl::Create(active_tree, 10);
  scoped_ptr<FakePictureLayerImpl> pending_layer =
      FakePictureLayerImpl::Create(pending_tree, 10);

  TileManager* tile_manager = TileManagerTileIteratorTest::tile_manager();
  EXPECT_TRUE(tile_manager);

  tile_manager->RegisterPictureLayerImpl(active_layer.get());
  tile_manager->RegisterPictureLayerImpl(pending_layer.get());

  std::vector<TileManager::PairedPictureLayer> paired_layers;
  tile_manager->GetPairedPictureLayers(&paired_layers);

  EXPECT_EQ(2u, paired_layers.size());
  if (paired_layers[0].active_layer) {
    EXPECT_EQ(active_layer.get(), paired_layers[0].active_layer);
    EXPECT_EQ(NULL, paired_layers[0].pending_layer);
  } else {
    EXPECT_EQ(pending_layer.get(), paired_layers[0].pending_layer);
    EXPECT_EQ(NULL, paired_layers[0].active_layer);
  }

  if (paired_layers[1].active_layer) {
    EXPECT_EQ(active_layer.get(), paired_layers[1].active_layer);
    EXPECT_EQ(NULL, paired_layers[1].pending_layer);
  } else {
    EXPECT_EQ(pending_layer.get(), paired_layers[1].pending_layer);
    EXPECT_EQ(NULL, paired_layers[1].active_layer);
  }

  active_layer->set_twin_layer(pending_layer.get());
  pending_layer->set_twin_layer(active_layer.get());

  tile_manager->GetPairedPictureLayers(&paired_layers);
  EXPECT_EQ(1u, paired_layers.size());

  EXPECT_EQ(active_layer.get(), paired_layers[0].active_layer);
  EXPECT_EQ(pending_layer.get(), paired_layers[0].pending_layer);

  tile_manager->UnregisterPictureLayerImpl(active_layer.get());
  tile_manager->UnregisterPictureLayerImpl(pending_layer.get());
}

TEST_F(TileManagerTileIteratorTest, RasterTileIterator) {
  SetupDefaultTrees(gfx::Size(1000, 1000));
  TileManager* tile_manager = TileManagerTileIteratorTest::tile_manager();
  EXPECT_TRUE(tile_manager);

  active_layer_->CreateDefaultTilingsAndTiles();
  pending_layer_->CreateDefaultTilingsAndTiles();

  std::vector<TileManager::PairedPictureLayer> paired_layers;
  tile_manager->GetPairedPictureLayers(&paired_layers);
  EXPECT_EQ(1u, paired_layers.size());

  TileManager::RasterTileIterator it(tile_manager,
                                     SAME_PRIORITY_FOR_BOTH_TREES);
  EXPECT_TRUE(it);
  std::set<Tile*> all_tiles;
  size_t tile_count = 0;

  for (; it; ++it) {
    ++tile_count;
    EXPECT_TRUE(*it);
    all_tiles.insert(*it);
  }

  EXPECT_EQ(tile_count, all_tiles.size());
  EXPECT_EQ(17u, tile_count);

  // Sanity check, all tiles should be visible.
  std::set<Tile*> smoothness_tiles;
  for (TileManager::RasterTileIterator it(tile_manager,
                                          SMOOTHNESS_TAKES_PRIORITY);
       it;
       ++it) {
    Tile* tile = *it;
    EXPECT_TRUE(tile);
    EXPECT_EQ(TilePriority::NOW, tile->priority(ACTIVE_TREE).priority_bin);
    EXPECT_EQ(TilePriority::NOW, tile->priority(PENDING_TREE).priority_bin);
    smoothness_tiles.insert(tile);
  }
  EXPECT_EQ(all_tiles, smoothness_tiles);

  Region invalidation(gfx::Rect(0, 0, 500, 500));

  // Invalidate the pending tree.
  pending_layer_->set_invalidation(invalidation);
  pending_layer_->HighResTiling()->Invalidate(invalidation);
  pending_layer_->LowResTiling()->Invalidate(invalidation);

  active_layer_->ResetAllTilesPriorities();
  pending_layer_->ResetAllTilesPriorities();

  // Renew all of the tile priorities.
  gfx::Rect viewport(50, 50, 100, 100);
  pending_layer_->HighResTiling()->UpdateTilePriorities(
      PENDING_TREE, viewport, 1.0f, 1.0);
  pending_layer_->LowResTiling()->UpdateTilePriorities(
      PENDING_TREE, viewport, 1.0f, 1.0);
  active_layer_->HighResTiling()->UpdateTilePriorities(
      ACTIVE_TREE, viewport, 1.0f, 1.0);
  active_layer_->LowResTiling()->UpdateTilePriorities(
      ACTIVE_TREE, viewport, 1.0f, 1.0);

  // Populate all tiles directly from the tilings.
  all_tiles.clear();
  std::vector<Tile*> pending_high_res_tiles =
      pending_layer_->HighResTiling()->AllTilesForTesting();
  for (size_t i = 0; i < pending_high_res_tiles.size(); ++i)
    all_tiles.insert(pending_high_res_tiles[i]);

  std::vector<Tile*> pending_low_res_tiles =
      pending_layer_->LowResTiling()->AllTilesForTesting();
  for (size_t i = 0; i < pending_low_res_tiles.size(); ++i)
    all_tiles.insert(pending_low_res_tiles[i]);

  std::vector<Tile*> active_high_res_tiles =
      active_layer_->HighResTiling()->AllTilesForTesting();
  for (size_t i = 0; i < active_high_res_tiles.size(); ++i)
    all_tiles.insert(active_high_res_tiles[i]);

  std::vector<Tile*> active_low_res_tiles =
      active_layer_->LowResTiling()->AllTilesForTesting();
  for (size_t i = 0; i < active_low_res_tiles.size(); ++i)
    all_tiles.insert(active_low_res_tiles[i]);

  Tile* last_tile = NULL;
  smoothness_tiles.clear();
  tile_count = 0;
  size_t increasing_distance_tiles = 0u;
  // Here we expect to get increasing ACTIVE_TREE priority_bin.
  for (TileManager::RasterTileIterator it(tile_manager,
                                          SMOOTHNESS_TAKES_PRIORITY);
       it;
       ++it) {
    Tile* tile = *it;
    EXPECT_TRUE(tile);

    if (!last_tile)
      last_tile = tile;

    EXPECT_LE(last_tile->priority(ACTIVE_TREE).priority_bin,
              tile->priority(ACTIVE_TREE).priority_bin);
    if (last_tile->priority(ACTIVE_TREE).priority_bin ==
        tile->priority(ACTIVE_TREE).priority_bin) {
      increasing_distance_tiles +=
          last_tile->priority(ACTIVE_TREE).distance_to_visible <=
          tile->priority(ACTIVE_TREE).distance_to_visible;
    }

    if (tile->priority(ACTIVE_TREE).priority_bin == TilePriority::NOW &&
        last_tile->priority(ACTIVE_TREE).resolution !=
            tile->priority(ACTIVE_TREE).resolution) {
      // Low resolution should come first.
      EXPECT_EQ(LOW_RESOLUTION, last_tile->priority(ACTIVE_TREE).resolution);
    }

    last_tile = tile;
    ++tile_count;
    smoothness_tiles.insert(tile);
  }

  EXPECT_EQ(tile_count, smoothness_tiles.size());
  EXPECT_EQ(all_tiles, smoothness_tiles);
  // Since we don't guarantee increasing distance due to spiral iterator, we
  // should check that we're _mostly_ right.
  EXPECT_GT(increasing_distance_tiles, 3 * tile_count / 4);

  std::set<Tile*> new_content_tiles;
  last_tile = NULL;
  increasing_distance_tiles = 0u;
  // Here we expect to get increasing PENDING_TREE priority_bin.
  for (TileManager::RasterTileIterator it(tile_manager,
                                          NEW_CONTENT_TAKES_PRIORITY);
       it;
       ++it) {
    Tile* tile = *it;
    EXPECT_TRUE(tile);

    if (!last_tile)
      last_tile = tile;

    EXPECT_LE(last_tile->priority(PENDING_TREE).priority_bin,
              tile->priority(PENDING_TREE).priority_bin);
    if (last_tile->priority(PENDING_TREE).priority_bin ==
        tile->priority(PENDING_TREE).priority_bin) {
      increasing_distance_tiles +=
          last_tile->priority(PENDING_TREE).distance_to_visible <=
          tile->priority(PENDING_TREE).distance_to_visible;
    }

    if (tile->priority(PENDING_TREE).priority_bin == TilePriority::NOW &&
        last_tile->priority(PENDING_TREE).resolution !=
            tile->priority(PENDING_TREE).resolution) {
      // High resolution should come first.
      EXPECT_EQ(HIGH_RESOLUTION, last_tile->priority(PENDING_TREE).resolution);
    }

    last_tile = tile;
    new_content_tiles.insert(tile);
  }

  EXPECT_EQ(tile_count, new_content_tiles.size());
  EXPECT_EQ(all_tiles, new_content_tiles);
  // Since we don't guarantee increasing distance due to spiral iterator, we
  // should check that we're _mostly_ right.
  EXPECT_GT(increasing_distance_tiles, 3 * tile_count / 4);
}

}  // namespace
}  // namespace cc

/* [<][>][^][v][top][bottom][index][help] */