| Index: cc/resources/tile_manager.cc
|
| diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
|
| index 3eb7bc29714c803b2ab51bb2870dd587f6325ea7..54e5ed9243db97963d72d2881b90ee2f036ed5b8 100644
|
| --- a/cc/resources/tile_manager.cc
|
| +++ b/cc/resources/tile_manager.cc
|
| @@ -166,6 +166,7 @@ void TileManager::UnregisterTile(Tile* tile) {
|
| tiles_that_need_to_be_rasterized_.erase(raster_iter);
|
|
|
| tiles_that_need_to_be_initialized_for_activation_.erase(tile);
|
| + oom_tiles_that_need_to_be_initialized_for_activation_.erase(tile);
|
|
|
| DCHECK(std::find(tiles_.begin(), tiles_.end(), tile) != tiles_.end());
|
| FreeResourcesForTile(tile);
|
| @@ -176,6 +177,54 @@ bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const {
|
| return GlobalState().tree_priority != SMOOTHNESS_TAKES_PRIORITY;
|
| }
|
|
|
| +void TileManager::DidFinishedRunningTasks() {
|
| + // When OOM, keep re-assigning memory until we reach a steady state
|
| + // where top-priority tiles are initialized.
|
| + if (!memory_stats_from_last_assign_.bytes_over)
|
| + return;
|
| +
|
| + raster_worker_pool_->CheckForCompletedTasks();
|
| +
|
| + AssignGpuMemoryToTiles();
|
| +
|
| + if (!oom_tiles_that_need_to_be_initialized_for_activation_.empty())
|
| + ReassignGpuMemoryToOOMTilesRequiredForActivation();
|
| +
|
| + // |tiles_that_need_to_be_rasterized_| will be empty when we reach a
|
| + // steady memory state. Keep scheduling tasks until we reach this state.
|
| + if (!tiles_that_need_to_be_rasterized_.empty()) {
|
| + ScheduleTasks();
|
| + return;
|
| + }
|
| +
|
| + // Use on-demand raster for any tiles that have not been been assigned
|
| + // memory after reaching a steady memory state.
|
| + for (TileSet::iterator it =
|
| + oom_tiles_that_need_to_be_initialized_for_activation_.begin();
|
| + it != oom_tiles_that_need_to_be_initialized_for_activation_.end();
|
| + ++it) {
|
| + Tile* tile = *it;
|
| + ManagedTileState& mts = tile->managed_state();
|
| + mts.tile_versions[mts.raster_mode].set_rasterize_on_demand();
|
| + }
|
| + oom_tiles_that_need_to_be_initialized_for_activation_.clear();
|
| +
|
| + DCHECK_EQ(0u, tiles_that_need_to_be_initialized_for_activation_.size());
|
| + client_->NotifyReadyToActivate();
|
| +}
|
| +
|
| +void TileManager::DidFinishedRunningTasksRequiredForActivation() {
|
| + // This is only a true indication that all tiles required for
|
| + // activation are initialized when no tiles are OOM. We need to
|
| + // wait for DidFinishRunningTasks() to be called, try to re-assign
|
| + // memory and in worst case use on-demand raster when tiles
|
| + // required for activation are OOM.
|
| + if (!oom_tiles_that_need_to_be_initialized_for_activation_.empty())
|
| + return;
|
| +
|
| + client_->NotifyReadyToActivate();
|
| +}
|
| +
|
| class BinComparator {
|
| public:
|
| bool operator() (const Tile* a, const Tile* b) const {
|
| @@ -302,10 +351,6 @@ void TileManager::ManageTiles() {
|
| AssignGpuMemoryToTiles();
|
| CleanUpUnusedImageDecodeTasks();
|
|
|
| - // This could have changed after AssignGpuMemoryToTiles.
|
| - if (AreTilesRequiredForActivationReady())
|
| - client_->NotifyReadyToActivate();
|
| -
|
| TRACE_EVENT_INSTANT1(
|
| "cc", "DidManage", TRACE_EVENT_SCOPE_THREAD,
|
| "state", TracedValue::FromValue(BasicStateAsValue().release()));
|
| @@ -316,6 +361,11 @@ void TileManager::ManageTiles() {
|
|
|
| void TileManager::CheckForCompletedTileUploads() {
|
| raster_worker_pool_->CheckForCompletedTasks();
|
| +
|
| + if (did_initialize_visible_tile_) {
|
| + client_->DidInitializeVisibleTile();
|
| + did_initialize_visible_tile_ = false;
|
| + }
|
| }
|
|
|
| void TileManager::GetMemoryStats(
|
| @@ -413,6 +463,7 @@ void TileManager::AssignGpuMemoryToTiles() {
|
| // the needs-to-be-rasterized queue.
|
| tiles_that_need_to_be_rasterized_.clear();
|
| tiles_that_need_to_be_initialized_for_activation_.clear();
|
| + oom_tiles_that_need_to_be_initialized_for_activation_.clear();
|
|
|
| size_t bytes_releasable = 0;
|
| for (TileVector::const_iterator it = tiles_.begin();
|
| @@ -435,10 +486,9 @@ void TileManager::AssignGpuMemoryToTiles() {
|
| size_t bytes_allocatable =
|
| std::max(static_cast<int64>(0), bytes_available);
|
|
|
| - size_t bytes_that_exceeded_memory_budget_in_now_bin = 0;
|
| + size_t bytes_that_exceeded_memory_budget = 0;
|
| size_t bytes_left = bytes_allocatable;
|
| - size_t bytes_oom_in_now_bin_on_pending_tree = 0;
|
| - TileVector tiles_requiring_memory_but_oomed;
|
| + size_t bytes_oom_tiles_that_need_to_be_initialized_for_activation = 0;
|
| bool higher_priority_tile_oomed = false;
|
| for (TileVector::iterator it = tiles_.begin();
|
| it != tiles_.end();
|
| @@ -476,13 +526,22 @@ void TileManager::AssignGpuMemoryToTiles() {
|
|
|
| // Tile is OOM.
|
| if (tile_bytes > bytes_left) {
|
| - mts.tile_versions[mts.raster_mode].set_rasterize_on_demand();
|
| - if (mts.tree_bin[PENDING_TREE] == NOW_BIN) {
|
| - tiles_requiring_memory_but_oomed.push_back(tile);
|
| - bytes_oom_in_now_bin_on_pending_tree += tile_bytes;
|
| + if (tile->required_for_activation()) {
|
| + // Immediately mark tiles for on-demand raster once the amount
|
| + // of memory for oom tiles required for activation exceeds our
|
| + // memory limit.
|
| + if (bytes_oom_tiles_that_need_to_be_initialized_for_activation <
|
| + global_state_.memory_limit_in_bytes) {
|
| + oom_tiles_that_need_to_be_initialized_for_activation_.insert(tile);
|
| + bytes_oom_tiles_that_need_to_be_initialized_for_activation +=
|
| + tile_bytes;
|
| + } else {
|
| + tile_version.set_rasterize_on_demand();
|
| + }
|
| }
|
| FreeResourcesForTile(tile);
|
| higher_priority_tile_oomed = true;
|
| + bytes_that_exceeded_memory_budget += tile_bytes;
|
| continue;
|
| }
|
|
|
| @@ -507,85 +566,94 @@ void TileManager::AssignGpuMemoryToTiles() {
|
| }
|
| }
|
|
|
| + ever_exceeded_memory_budget_ |= bytes_that_exceeded_memory_budget > 0;
|
| + if (ever_exceeded_memory_budget_) {
|
| + TRACE_COUNTER_ID2("cc", "over_memory_budget", this,
|
| + "budget", global_state_.memory_limit_in_bytes,
|
| + "over", bytes_that_exceeded_memory_budget);
|
| + }
|
| + memory_stats_from_last_assign_.total_budget_in_bytes =
|
| + global_state_.memory_limit_in_bytes;
|
| + memory_stats_from_last_assign_.bytes_allocated =
|
| + bytes_allocatable - bytes_left;
|
| + memory_stats_from_last_assign_.bytes_unreleasable =
|
| + bytes_allocatable - bytes_releasable;
|
| + memory_stats_from_last_assign_.bytes_over =
|
| + bytes_that_exceeded_memory_budget;
|
| +}
|
| +
|
| +void TileManager::ReassignGpuMemoryToOOMTilesRequiredForActivation() {
|
| + TRACE_EVENT0(
|
| + "cc", "TileManager::ReassignGpuMemoryToOOMTilesRequiredForActivation");
|
| +
|
| + size_t bytes_oom_for_required_tiles = 0;
|
| + TileVector tiles_requiring_memory_but_oomed;
|
| + for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
|
| + Tile* tile = *it;
|
| + if (oom_tiles_that_need_to_be_initialized_for_activation_.find(tile) ==
|
| + oom_tiles_that_need_to_be_initialized_for_activation_.end())
|
| + continue;
|
| +
|
| + tiles_requiring_memory_but_oomed.push_back(tile);
|
| + bytes_oom_for_required_tiles += tile->bytes_consumed_if_allocated();
|
| + }
|
| +
|
| + if (tiles_requiring_memory_but_oomed.empty())
|
| + return;
|
| +
|
| // In OOM situation, we iterate tiles_, remove the memory for active tree
|
| - // and not the now bin. And give them to bytes_oom_in_now_bin_on_pending_tree
|
| - if (!tiles_requiring_memory_but_oomed.empty()) {
|
| - size_t bytes_freed = 0;
|
| - for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
|
| - Tile* tile = *it;
|
| - ManagedTileState& mts = tile->managed_state();
|
| + // and not the now bin. And give them to bytes_oom_for_required_tiles
|
| + size_t bytes_freed = 0;
|
| + for (TileVector::reverse_iterator it = tiles_.rbegin();
|
| + it != tiles_.rend(); ++it) {
|
| + Tile* tile = *it;
|
| + ManagedTileState& mts = tile->managed_state();
|
| + if (mts.tree_bin[PENDING_TREE] == NEVER_BIN &&
|
| + mts.tree_bin[ACTIVE_TREE] != NOW_BIN) {
|
| ManagedTileState::TileVersion& tile_version =
|
| mts.tile_versions[mts.raster_mode];
|
| - if (mts.tree_bin[PENDING_TREE] == NEVER_BIN &&
|
| - mts.tree_bin[ACTIVE_TREE] != NOW_BIN) {
|
| - size_t bytes_that_can_be_freed = 0;
|
| -
|
| - // If the tile is in the to-rasterize list, but it has no task,
|
| - // then it means that we have assigned memory for it.
|
| - TileVector::iterator raster_it =
|
| - std::find(tiles_that_need_to_be_rasterized_.begin(),
|
| - tiles_that_need_to_be_rasterized_.end(),
|
| - tile);
|
| - if (raster_it != tiles_that_need_to_be_rasterized_.end() &&
|
| - tile_version.raster_task_.is_null()) {
|
| - bytes_that_can_be_freed += tile->bytes_consumed_if_allocated();
|
| - }
|
|
|
| - // Also consider all of the completed resources for freeing.
|
| - for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
|
| - ManagedTileState::TileVersion& tile_version =
|
| - mts.tile_versions[mode];
|
| - if (tile_version.resource_) {
|
| - DCHECK(!tile->required_for_activation());
|
| - bytes_that_can_be_freed += tile->bytes_consumed_if_allocated();
|
| - }
|
| - }
|
| + // If the tile is in the to-rasterize list, but it has no task,
|
| + // then it means that we have assigned memory for it.
|
| + TileVector::iterator raster_it =
|
| + std::find(tiles_that_need_to_be_rasterized_.begin(),
|
| + tiles_that_need_to_be_rasterized_.end(),
|
| + tile);
|
| + if (raster_it != tiles_that_need_to_be_rasterized_.end() &&
|
| + tile_version.raster_task_.is_null()) {
|
| + bytes_freed += tile->bytes_consumed_if_allocated();
|
| + tiles_that_need_to_be_rasterized_.erase(raster_it);
|
| + }
|
|
|
| - // If we can free anything, then do so.
|
| - if (bytes_that_can_be_freed > 0) {
|
| - FreeResourcesForTile(tile);
|
| - bytes_freed += bytes_that_can_be_freed;
|
| - mts.tile_versions[mts.raster_mode].set_rasterize_on_demand();
|
| - if (raster_it != tiles_that_need_to_be_rasterized_.end())
|
| - tiles_that_need_to_be_rasterized_.erase(raster_it);
|
| + // Also consider all of the completed resources for freeing.
|
| + for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
|
| + if (mts.tile_versions[mode].resource_) {
|
| + DCHECK(!tile->required_for_activation());
|
| + FreeResourceForTile(tile, static_cast<RasterMode>(mode));
|
| + bytes_freed += tile->bytes_consumed_if_allocated();
|
| }
|
| }
|
| -
|
| - if (bytes_oom_in_now_bin_on_pending_tree <= bytes_freed)
|
| - break;
|
| }
|
|
|
| - for (TileVector::iterator it = tiles_requiring_memory_but_oomed.begin();
|
| - it != tiles_requiring_memory_but_oomed.end() && bytes_freed > 0;
|
| - ++it) {
|
| - Tile* tile = *it;
|
| - ManagedTileState& mts = tile->managed_state();
|
| - size_t bytes_needed = tile->bytes_consumed_if_allocated();
|
| - if (bytes_needed > bytes_freed)
|
| - continue;
|
| - mts.tile_versions[mts.raster_mode].set_use_resource();
|
| - bytes_freed -= bytes_needed;
|
| - tiles_that_need_to_be_rasterized_.push_back(tile);
|
| - if (tile->required_for_activation())
|
| - AddRequiredTileForActivation(tile);
|
| - }
|
| + if (bytes_oom_for_required_tiles <= bytes_freed)
|
| + break;
|
| }
|
|
|
| - ever_exceeded_memory_budget_ |=
|
| - bytes_that_exceeded_memory_budget_in_now_bin > 0;
|
| - if (ever_exceeded_memory_budget_) {
|
| - TRACE_COUNTER_ID2("cc", "over_memory_budget", this,
|
| - "budget", global_state_.memory_limit_in_bytes,
|
| - "over", bytes_that_exceeded_memory_budget_in_now_bin);
|
| + for (TileVector::iterator it = tiles_requiring_memory_but_oomed.begin();
|
| + it != tiles_requiring_memory_but_oomed.end() && bytes_freed > 0;
|
| + ++it) {
|
| + Tile* tile = *it;
|
| + ManagedTileState& mts = tile->managed_state();
|
| + size_t bytes_needed = tile->bytes_consumed_if_allocated();
|
| + if (bytes_needed > bytes_freed)
|
| + continue;
|
| + mts.tile_versions[mts.raster_mode].set_use_resource();
|
| + bytes_freed -= bytes_needed;
|
| + tiles_that_need_to_be_rasterized_.push_back(tile);
|
| + DCHECK(tile->required_for_activation());
|
| + AddRequiredTileForActivation(tile);
|
| + oom_tiles_that_need_to_be_initialized_for_activation_.erase(tile);
|
| }
|
| - memory_stats_from_last_assign_.total_budget_in_bytes =
|
| - global_state_.memory_limit_in_bytes;
|
| - memory_stats_from_last_assign_.bytes_allocated =
|
| - bytes_allocatable - bytes_left;
|
| - memory_stats_from_last_assign_.bytes_unreleasable =
|
| - bytes_allocatable - bytes_releasable;
|
| - memory_stats_from_last_assign_.bytes_over =
|
| - bytes_that_exceeded_memory_budget_in_now_bin;
|
| }
|
|
|
| void TileManager::CleanUpUnusedImageDecodeTasks() {
|
| @@ -636,7 +704,8 @@ void TileManager::FreeUnusedResourcesForTile(Tile* tile) {
|
| }
|
|
|
| void TileManager::ScheduleTasks() {
|
| - TRACE_EVENT0("cc", "TileManager::ScheduleTasks");
|
| + TRACE_EVENT1("cc", "TileManager::ScheduleTasks",
|
| + "count", tiles_that_need_to_be_rasterized_.size());
|
| RasterWorkerPool::RasterTask::Queue tasks;
|
|
|
| // Build a new task queue containing all task currently needed. Tasks
|
| @@ -666,8 +735,6 @@ void TileManager::ScheduleTasks() {
|
|
|
| RasterWorkerPool::Task TileManager::CreateImageDecodeTask(
|
| Tile* tile, skia::LazyPixelRef* pixel_ref) {
|
| - TRACE_EVENT0("cc", "TileManager::CreateImageDecodeTask");
|
| -
|
| return RasterWorkerPool::CreateImageDecodeTask(
|
| pixel_ref,
|
| tile->layer_id(),
|
| @@ -692,8 +759,6 @@ RasterTaskMetadata TileManager::GetRasterTaskMetadata(
|
| }
|
|
|
| RasterWorkerPool::RasterTask TileManager::CreateRasterTask(Tile* tile) {
|
| - TRACE_EVENT0("cc", "TileManager::CreateRasterTask");
|
| -
|
| ManagedTileState& mts = tile->managed_state();
|
|
|
| scoped_ptr<ResourcePool::Resource> resource =
|
| @@ -806,9 +871,6 @@ void TileManager::DidFinishTileInitialization(Tile* tile) {
|
| // if it was marked as being required after being dispatched for
|
| // rasterization but before AssignGPUMemory was called again.
|
| tiles_that_need_to_be_initialized_for_activation_.erase(tile);
|
| -
|
| - if (AreTilesRequiredForActivationReady())
|
| - client_->NotifyReadyToActivate();
|
| }
|
| }
|
|
|
|
|