Index: cc/resources/tile_manager.cc |
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc |
index 5a0338c4706ab7802143e4bb66290c09d821dee1..b505342a4c765cf0cad64e0be3b1b67e6533c58d 100644 |
--- a/cc/resources/tile_manager.cc |
+++ b/cc/resources/tile_manager.cc |
@@ -170,6 +170,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); |
@@ -180,6 +181,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 { |
@@ -306,10 +355,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())); |
@@ -320,6 +365,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( |
@@ -417,6 +467,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(); |
@@ -439,10 +490,8 @@ 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; |
bool higher_priority_tile_oomed = false; |
for (TileVector::iterator it = tiles_.begin(); |
it != tiles_.end(); |
@@ -480,13 +529,11 @@ 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()) |
+ oom_tiles_that_need_to_be_initialized_for_activation_.insert(tile); |
FreeResourcesForTile(tile); |
higher_priority_tile_oomed = true; |
+ bytes_that_exceeded_memory_budget += tile_bytes; |
continue; |
} |
@@ -511,85 +558,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() { |
@@ -640,7 +696,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 |
@@ -670,8 +727,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(), |
@@ -696,8 +751,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 = |
@@ -811,9 +864,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(); |
} |
} |