Home | History | Annotate | Download | only in resources
      1 // Copyright 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "cc/resources/tile_manager.h"
      6 
      7 #include <algorithm>
      8 #include <limits>
      9 #include <string>
     10 
     11 #include "base/bind.h"
     12 #include "base/json/json_writer.h"
     13 #include "base/logging.h"
     14 #include "base/metrics/histogram.h"
     15 #include "cc/debug/traced_value.h"
     16 #include "cc/resources/image_raster_worker_pool.h"
     17 #include "cc/resources/pixel_buffer_raster_worker_pool.h"
     18 #include "cc/resources/tile.h"
     19 #include "third_party/skia/include/core/SkCanvas.h"
     20 #include "ui/gfx/rect_conversions.h"
     21 
     22 namespace cc {
     23 
     24 namespace {
     25 
     26 // Memory limit policy works by mapping some bin states to the NEVER bin.
     27 const ManagedTileBin kBinPolicyMap[NUM_TILE_MEMORY_LIMIT_POLICIES][NUM_BINS] = {
     28   {  // [ALLOW_NOTHING]
     29     NEVER_BIN,                  // [NOW_AND_READY_TO_DRAW_BIN]
     30     NEVER_BIN,                  // [NOW_BIN]
     31     NEVER_BIN,                  // [SOON_BIN]
     32     NEVER_BIN,                  // [EVENTUALLY_AND_ACTIVE_BIN]
     33     NEVER_BIN,                  // [EVENTUALLY_BIN]
     34     NEVER_BIN,                  // [AT_LAST_AND_ACTIVE_BIN]
     35     NEVER_BIN,                  // [AT_LAST_BIN]
     36     NEVER_BIN
     37   }, {  // [ALLOW_ABSOLUTE_MINIMUM]
     38     NOW_AND_READY_TO_DRAW_BIN,
     39     NOW_BIN,
     40     NEVER_BIN,                  // [SOON_BIN]
     41     NEVER_BIN,                  // [EVENTUALLY_AND_ACTIVE_BIN]
     42     NEVER_BIN,                  // [EVENTUALLY_BIN]
     43     NEVER_BIN,                  // [AT_LAST_AND_ACTIVE_BIN]
     44     NEVER_BIN,                  // [AT_LAST_BIN]
     45     NEVER_BIN
     46   }, {  // [ALLOW_PREPAINT_ONLY]
     47     NOW_AND_READY_TO_DRAW_BIN,
     48     NOW_BIN,
     49     SOON_BIN,
     50     NEVER_BIN,                  // [EVENTUALLY_AND_ACTIVE_BIN]
     51     NEVER_BIN,                  // [EVENTUALLY_BIN]
     52     NEVER_BIN,                  // [AT_LAST_AND_ACTIVE_BIN]
     53     NEVER_BIN,                  // [AT_LAST_BIN]
     54     NEVER_BIN
     55   }, {  // [ALLOW_ANYTHING]
     56     NOW_AND_READY_TO_DRAW_BIN,
     57     NOW_BIN,
     58     SOON_BIN,
     59     EVENTUALLY_AND_ACTIVE_BIN,
     60     EVENTUALLY_BIN,
     61     AT_LAST_AND_ACTIVE_BIN,
     62     AT_LAST_BIN,
     63     NEVER_BIN
     64   }
     65 };
     66 
     67 // Ready to draw works by mapping NOW_BIN to NOW_AND_READY_TO_DRAW_BIN.
     68 const ManagedTileBin kBinReadyToDrawMap[2][NUM_BINS] = {
     69   {  // Not ready
     70     NOW_AND_READY_TO_DRAW_BIN,
     71     NOW_BIN,
     72     SOON_BIN,
     73     EVENTUALLY_AND_ACTIVE_BIN,
     74     EVENTUALLY_BIN,
     75     AT_LAST_AND_ACTIVE_BIN,
     76     AT_LAST_BIN,
     77     NEVER_BIN
     78   }, {  // Ready
     79     NOW_AND_READY_TO_DRAW_BIN,
     80     NOW_AND_READY_TO_DRAW_BIN,  // [NOW_BIN]
     81     SOON_BIN,
     82     EVENTUALLY_AND_ACTIVE_BIN,
     83     EVENTUALLY_BIN,
     84     AT_LAST_AND_ACTIVE_BIN,
     85     AT_LAST_BIN,
     86     NEVER_BIN
     87   }
     88 };
     89 
     90 // Active works by mapping some bin stats to equivalent _ACTIVE_BIN state.
     91 const ManagedTileBin kBinIsActiveMap[2][NUM_BINS] = {
     92   {  // Inactive
     93     NOW_AND_READY_TO_DRAW_BIN,
     94     NOW_BIN,
     95     SOON_BIN,
     96     EVENTUALLY_AND_ACTIVE_BIN,
     97     EVENTUALLY_BIN,
     98     AT_LAST_AND_ACTIVE_BIN,
     99     AT_LAST_BIN,
    100     NEVER_BIN
    101   }, {  // Active
    102     NOW_AND_READY_TO_DRAW_BIN,
    103     NOW_BIN,
    104     SOON_BIN,
    105     EVENTUALLY_AND_ACTIVE_BIN,
    106     EVENTUALLY_AND_ACTIVE_BIN,  // [EVENTUALLY_BIN]
    107     AT_LAST_AND_ACTIVE_BIN,
    108     AT_LAST_AND_ACTIVE_BIN,     // [AT_LAST_BIN]
    109     NEVER_BIN
    110   }
    111 };
    112 
    113 // Determine bin based on three categories of tiles: things we need now,
    114 // things we need soon, and eventually.
    115 inline ManagedTileBin BinFromTilePriority(const TilePriority& prio) {
    116   // The amount of time/pixels for which we want to have prepainting coverage.
    117   // Note: All very arbitrary constants: metric-based tuning is welcome!
    118   const float kPrepaintingWindowTimeSeconds = 1.0f;
    119   const float kBackflingGuardDistancePixels = 314.0f;
    120   // Note: The max distances here assume that SOON_BIN will never help overcome
    121   // raster being too slow (only caching in advance will do that), so we just
    122   // need enough padding to handle some latency and per-tile variability.
    123   const float kMaxPrepaintingDistancePixelsHighRes = 2000.0f;
    124   const float kMaxPrepaintingDistancePixelsLowRes = 4000.0f;
    125 
    126   if (prio.distance_to_visible_in_pixels ==
    127       std::numeric_limits<float>::infinity())
    128     return NEVER_BIN;
    129 
    130   if (prio.time_to_visible_in_seconds == 0)
    131     return NOW_BIN;
    132 
    133   if (prio.resolution == NON_IDEAL_RESOLUTION)
    134     return EVENTUALLY_BIN;
    135 
    136   float max_prepainting_distance_pixels =
    137       (prio.resolution == HIGH_RESOLUTION)
    138           ? kMaxPrepaintingDistancePixelsHighRes
    139           : kMaxPrepaintingDistancePixelsLowRes;
    140 
    141   // Soon bin if we are within backfling-guard, or under both the time window
    142   // and the max distance window.
    143   if (prio.distance_to_visible_in_pixels < kBackflingGuardDistancePixels ||
    144       (prio.time_to_visible_in_seconds < kPrepaintingWindowTimeSeconds &&
    145        prio.distance_to_visible_in_pixels <= max_prepainting_distance_pixels))
    146     return SOON_BIN;
    147 
    148   return EVENTUALLY_BIN;
    149 }
    150 
    151 }  // namespace
    152 
    153 RasterTaskCompletionStats::RasterTaskCompletionStats()
    154     : completed_count(0u),
    155       canceled_count(0u) {
    156 }
    157 
    158 scoped_ptr<base::Value> RasterTaskCompletionStatsAsValue(
    159     const RasterTaskCompletionStats& stats) {
    160   scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
    161   state->SetInteger("completed_count", stats.completed_count);
    162   state->SetInteger("canceled_count", stats.canceled_count);
    163   return state.PassAs<base::Value>();
    164 }
    165 
    166 // static
    167 scoped_ptr<TileManager> TileManager::Create(
    168     TileManagerClient* client,
    169     ResourceProvider* resource_provider,
    170     size_t num_raster_threads,
    171     RenderingStatsInstrumentation* rendering_stats_instrumentation,
    172     bool use_map_image,
    173     size_t max_transfer_buffer_usage_bytes,
    174     size_t max_raster_usage_bytes,
    175     GLenum map_image_texture_target) {
    176   return make_scoped_ptr(
    177       new TileManager(client,
    178                       resource_provider,
    179                       use_map_image ?
    180                       ImageRasterWorkerPool::Create(
    181                           resource_provider,
    182                           num_raster_threads,
    183                           map_image_texture_target) :
    184                       PixelBufferRasterWorkerPool::Create(
    185                           resource_provider,
    186                           num_raster_threads,
    187                           max_transfer_buffer_usage_bytes),
    188                       num_raster_threads,
    189                       max_raster_usage_bytes,
    190                       rendering_stats_instrumentation));
    191 }
    192 
    193 TileManager::TileManager(
    194     TileManagerClient* client,
    195     ResourceProvider* resource_provider,
    196     scoped_ptr<RasterWorkerPool> raster_worker_pool,
    197     size_t num_raster_threads,
    198     size_t max_raster_usage_bytes,
    199     RenderingStatsInstrumentation* rendering_stats_instrumentation)
    200     : client_(client),
    201       resource_pool_(ResourcePool::Create(
    202                          resource_provider,
    203                          raster_worker_pool->GetResourceTarget(),
    204                          raster_worker_pool->GetResourceFormat())),
    205       raster_worker_pool_(raster_worker_pool.Pass()),
    206       prioritized_tiles_dirty_(false),
    207       all_tiles_that_need_to_be_rasterized_have_memory_(true),
    208       all_tiles_required_for_activation_have_memory_(true),
    209       memory_required_bytes_(0),
    210       memory_nice_to_have_bytes_(0),
    211       bytes_releasable_(0),
    212       resources_releasable_(0),
    213       max_raster_usage_bytes_(max_raster_usage_bytes),
    214       ever_exceeded_memory_budget_(false),
    215       rendering_stats_instrumentation_(rendering_stats_instrumentation),
    216       did_initialize_visible_tile_(false),
    217       did_check_for_completed_tasks_since_last_schedule_tasks_(true) {
    218   raster_worker_pool_->SetClient(this);
    219 }
    220 
    221 TileManager::~TileManager() {
    222   // Reset global state and manage. This should cause
    223   // our memory usage to drop to zero.
    224   global_state_ = GlobalStateThatImpactsTilePriority();
    225 
    226   CleanUpReleasedTiles();
    227   DCHECK_EQ(0u, tiles_.size());
    228 
    229   RasterWorkerPool::RasterTask::Queue empty;
    230   raster_worker_pool_->ScheduleTasks(&empty);
    231 
    232   // This should finish all pending tasks and release any uninitialized
    233   // resources.
    234   raster_worker_pool_->Shutdown();
    235   raster_worker_pool_->CheckForCompletedTasks();
    236 
    237   DCHECK_EQ(0u, bytes_releasable_);
    238   DCHECK_EQ(0u, resources_releasable_);
    239 }
    240 
    241 void TileManager::Release(Tile* tile) {
    242   prioritized_tiles_dirty_ = true;
    243   released_tiles_.push_back(tile);
    244 }
    245 
    246 void TileManager::DidChangeTilePriority(Tile* tile) {
    247   prioritized_tiles_dirty_ = true;
    248 }
    249 
    250 bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const {
    251   return global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY;
    252 }
    253 
    254 void TileManager::CleanUpReleasedTiles() {
    255   for (std::vector<Tile*>::iterator it = released_tiles_.begin();
    256        it != released_tiles_.end();
    257        ++it) {
    258     Tile* tile = *it;
    259 
    260     FreeResourcesForTile(tile);
    261 
    262     DCHECK(tiles_.find(tile->id()) != tiles_.end());
    263     tiles_.erase(tile->id());
    264 
    265     LayerCountMap::iterator layer_it =
    266         used_layer_counts_.find(tile->layer_id());
    267     DCHECK_GT(layer_it->second, 0);
    268     if (--layer_it->second == 0) {
    269       used_layer_counts_.erase(layer_it);
    270       image_decode_tasks_.erase(tile->layer_id());
    271     }
    272 
    273     delete tile;
    274   }
    275 
    276   released_tiles_.clear();
    277 }
    278 
    279 void TileManager::UpdatePrioritizedTileSetIfNeeded() {
    280   if (!prioritized_tiles_dirty_)
    281     return;
    282 
    283   CleanUpReleasedTiles();
    284 
    285   prioritized_tiles_.Clear();
    286   GetTilesWithAssignedBins(&prioritized_tiles_);
    287   prioritized_tiles_dirty_ = false;
    288 }
    289 
    290 void TileManager::DidFinishRunningTasks() {
    291   TRACE_EVENT0("cc", "TileManager::DidFinishRunningTasks");
    292 
    293   // When OOM, keep re-assigning memory until we reach a steady state
    294   // where top-priority tiles are initialized.
    295   if (all_tiles_that_need_to_be_rasterized_have_memory_)
    296     return;
    297 
    298   raster_worker_pool_->CheckForCompletedTasks();
    299   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
    300 
    301   TileVector tiles_that_need_to_be_rasterized;
    302   AssignGpuMemoryToTiles(&prioritized_tiles_,
    303                          &tiles_that_need_to_be_rasterized);
    304 
    305   // |tiles_that_need_to_be_rasterized| will be empty when we reach a
    306   // steady memory state. Keep scheduling tasks until we reach this state.
    307   if (!tiles_that_need_to_be_rasterized.empty()) {
    308     ScheduleTasks(tiles_that_need_to_be_rasterized);
    309     return;
    310   }
    311 
    312   // We don't reserve memory for required-for-activation tiles during
    313   // accelerated gestures, so we just postpone activation when we don't
    314   // have these tiles, and activate after the accelerated gesture.
    315   bool allow_rasterize_on_demand =
    316       global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY;
    317 
    318   // Use on-demand raster for any required-for-activation tiles that have not
    319   // been been assigned memory after reaching a steady memory state. This
    320   // ensures that we activate even when OOM.
    321   for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
    322     Tile* tile = it->second;
    323     ManagedTileState& mts = tile->managed_state();
    324     ManagedTileState::TileVersion& tile_version =
    325         mts.tile_versions[mts.raster_mode];
    326 
    327     if (tile->required_for_activation() && !tile_version.IsReadyToDraw()) {
    328       // If we can't raster on demand, give up early (and don't activate).
    329       if (!allow_rasterize_on_demand)
    330         return;
    331       tile_version.set_rasterize_on_demand();
    332     }
    333   }
    334 
    335   client_->NotifyReadyToActivate();
    336 }
    337 
    338 void TileManager::DidFinishRunningTasksRequiredForActivation() {
    339   // This is only a true indication that all tiles required for
    340   // activation are initialized when no tiles are OOM. We need to
    341   // wait for DidFinishRunningTasks() to be called, try to re-assign
    342   // memory and in worst case use on-demand raster when tiles
    343   // required for activation are OOM.
    344   if (!all_tiles_required_for_activation_have_memory_)
    345     return;
    346 
    347   client_->NotifyReadyToActivate();
    348 }
    349 
    350 void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet* tiles) {
    351   TRACE_EVENT0("cc", "TileManager::GetTilesWithAssignedBins");
    352 
    353   // Compute new stats to be return by GetMemoryStats().
    354   memory_required_bytes_ = 0;
    355   memory_nice_to_have_bytes_ = 0;
    356 
    357   const TileMemoryLimitPolicy memory_policy = global_state_.memory_limit_policy;
    358   const TreePriority tree_priority = global_state_.tree_priority;
    359 
    360   // For each tree, bin into different categories of tiles.
    361   for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
    362     Tile* tile = it->second;
    363     ManagedTileState& mts = tile->managed_state();
    364 
    365     const ManagedTileState::TileVersion& tile_version =
    366         tile->GetTileVersionForDrawing();
    367     bool tile_is_ready_to_draw = tile_version.IsReadyToDraw();
    368     bool tile_is_active =
    369         tile_is_ready_to_draw ||
    370         !mts.tile_versions[mts.raster_mode].raster_task_.is_null();
    371 
    372     // Get the active priority and bin.
    373     TilePriority active_priority = tile->priority(ACTIVE_TREE);
    374     ManagedTileBin active_bin = BinFromTilePriority(active_priority);
    375 
    376     // Get the pending priority and bin.
    377     TilePriority pending_priority = tile->priority(PENDING_TREE);
    378     ManagedTileBin pending_bin = BinFromTilePriority(pending_priority);
    379 
    380     bool pending_is_low_res =
    381         pending_priority.resolution == LOW_RESOLUTION;
    382     bool pending_is_non_ideal =
    383         pending_priority.resolution == NON_IDEAL_RESOLUTION;
    384     bool active_is_non_ideal =
    385         active_priority.resolution == NON_IDEAL_RESOLUTION;
    386 
    387     // Adjust pending bin state for low res tiles. This prevents
    388     // pending tree low-res tiles from being initialized before
    389     // high-res tiles.
    390     if (pending_is_low_res)
    391       pending_bin = std::max(pending_bin, EVENTUALLY_BIN);
    392 
    393     // Adjust bin state based on if ready to draw.
    394     active_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][active_bin];
    395     pending_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][pending_bin];
    396 
    397     // Adjust bin state based on if active.
    398     active_bin = kBinIsActiveMap[tile_is_active][active_bin];
    399     pending_bin = kBinIsActiveMap[tile_is_active][pending_bin];
    400 
    401     // We never want to paint new non-ideal tiles, as we always have
    402     // a high-res tile covering that content (paint that instead).
    403     if (!tile_is_ready_to_draw && active_is_non_ideal)
    404       active_bin = NEVER_BIN;
    405     if (!tile_is_ready_to_draw && pending_is_non_ideal)
    406       pending_bin = NEVER_BIN;
    407 
    408     // Compute combined bin.
    409     ManagedTileBin combined_bin = std::min(active_bin, pending_bin);
    410 
    411     ManagedTileBin tree_bin[NUM_TREES];
    412     tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin];
    413     tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin];
    414 
    415     // The bin that the tile would have if the GPU memory manager had
    416     // a maximally permissive policy, send to the GPU memory manager
    417     // to determine policy.
    418     ManagedTileBin gpu_memmgr_stats_bin = NEVER_BIN;
    419     TilePriority tile_priority;
    420 
    421     switch (tree_priority) {
    422       case SAME_PRIORITY_FOR_BOTH_TREES:
    423         mts.bin = kBinPolicyMap[memory_policy][combined_bin];
    424         gpu_memmgr_stats_bin = combined_bin;
    425         tile_priority = tile->combined_priority();
    426         break;
    427       case SMOOTHNESS_TAKES_PRIORITY:
    428         mts.bin = tree_bin[ACTIVE_TREE];
    429         gpu_memmgr_stats_bin = active_bin;
    430         tile_priority = active_priority;
    431         break;
    432       case NEW_CONTENT_TAKES_PRIORITY:
    433         mts.bin = tree_bin[PENDING_TREE];
    434         gpu_memmgr_stats_bin = pending_bin;
    435         tile_priority = pending_priority;
    436         break;
    437     }
    438 
    439     if (!tile_is_ready_to_draw || tile_version.requires_resource()) {
    440       if ((gpu_memmgr_stats_bin == NOW_BIN) ||
    441           (gpu_memmgr_stats_bin == NOW_AND_READY_TO_DRAW_BIN))
    442         memory_required_bytes_ += BytesConsumedIfAllocated(tile);
    443       if (gpu_memmgr_stats_bin != NEVER_BIN)
    444         memory_nice_to_have_bytes_ += BytesConsumedIfAllocated(tile);
    445     }
    446 
    447     // Bump up the priority if we determined it's NEVER_BIN on one tree,
    448     // but is still required on the other tree.
    449     bool is_in_never_bin_on_both_trees =
    450         tree_bin[ACTIVE_TREE] == NEVER_BIN &&
    451         tree_bin[PENDING_TREE] == NEVER_BIN;
    452 
    453     if (mts.bin == NEVER_BIN && !is_in_never_bin_on_both_trees)
    454       mts.bin = tile_is_active ? AT_LAST_AND_ACTIVE_BIN : AT_LAST_BIN;
    455 
    456     mts.resolution = tile_priority.resolution;
    457     mts.time_to_needed_in_seconds = tile_priority.time_to_visible_in_seconds;
    458     mts.distance_to_visible_in_pixels =
    459         tile_priority.distance_to_visible_in_pixels;
    460     mts.required_for_activation = tile_priority.required_for_activation;
    461 
    462     mts.visible_and_ready_to_draw =
    463         tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN;
    464 
    465     if (mts.bin == NEVER_BIN) {
    466       FreeResourcesForTile(tile);
    467       continue;
    468     }
    469 
    470     // Note that if the tile is visible_and_ready_to_draw, then we always want
    471     // the priority to be NOW_AND_READY_TO_DRAW_BIN, even if HIGH_PRIORITY_BIN
    472     // is something different. The reason for this is that if we're prioritizing
    473     // the pending tree, we still want visible tiles to take the highest
    474     // priority.
    475     ManagedTileBin priority_bin = mts.visible_and_ready_to_draw
    476                                   ? NOW_AND_READY_TO_DRAW_BIN
    477                                   : mts.bin;
    478 
    479     // Insert the tile into a priority set.
    480     tiles->InsertTile(tile, priority_bin);
    481   }
    482 }
    483 
    484 void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) {
    485   TRACE_EVENT0("cc", "TileManager::ManageTiles");
    486 
    487   // Update internal state.
    488   if (state != global_state_) {
    489     global_state_ = state;
    490     prioritized_tiles_dirty_ = true;
    491     resource_pool_->SetResourceUsageLimits(
    492         global_state_.memory_limit_in_bytes,
    493         global_state_.unused_memory_limit_in_bytes,
    494         global_state_.num_resources_limit);
    495   }
    496 
    497   // We need to call CheckForCompletedTasks() once in-between each call
    498   // to ScheduleTasks() to prevent canceled tasks from being scheduled.
    499   if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
    500     raster_worker_pool_->CheckForCompletedTasks();
    501     did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
    502   }
    503 
    504   UpdatePrioritizedTileSetIfNeeded();
    505 
    506   TileVector tiles_that_need_to_be_rasterized;
    507   AssignGpuMemoryToTiles(&prioritized_tiles_,
    508                          &tiles_that_need_to_be_rasterized);
    509 
    510   // Finally, schedule rasterizer tasks.
    511   ScheduleTasks(tiles_that_need_to_be_rasterized);
    512 
    513   TRACE_EVENT_INSTANT1(
    514       "cc", "DidManage", TRACE_EVENT_SCOPE_THREAD,
    515       "state", TracedValue::FromValue(BasicStateAsValue().release()));
    516 
    517   TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
    518                     resource_pool_->total_memory_usage_bytes() -
    519                     resource_pool_->acquired_memory_usage_bytes());
    520 }
    521 
    522 bool TileManager::UpdateVisibleTiles() {
    523   TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
    524 
    525   raster_worker_pool_->CheckForCompletedTasks();
    526   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
    527 
    528   TRACE_EVENT_INSTANT1(
    529       "cc", "DidUpdateVisibleTiles", TRACE_EVENT_SCOPE_THREAD,
    530       "stats", TracedValue::FromValue(
    531           RasterTaskCompletionStatsAsValue(
    532               update_visible_tiles_stats_).release()));
    533   update_visible_tiles_stats_ = RasterTaskCompletionStats();
    534 
    535   bool did_initialize_visible_tile = did_initialize_visible_tile_;
    536   did_initialize_visible_tile_ = false;
    537   return did_initialize_visible_tile;
    538 }
    539 
    540 void TileManager::GetMemoryStats(
    541     size_t* memory_required_bytes,
    542     size_t* memory_nice_to_have_bytes,
    543     size_t* memory_allocated_bytes,
    544     size_t* memory_used_bytes) const {
    545   *memory_required_bytes = memory_required_bytes_;
    546   *memory_nice_to_have_bytes = memory_nice_to_have_bytes_;
    547   *memory_allocated_bytes = resource_pool_->total_memory_usage_bytes();
    548   *memory_used_bytes = resource_pool_->acquired_memory_usage_bytes();
    549 }
    550 
    551 scoped_ptr<base::Value> TileManager::BasicStateAsValue() const {
    552   scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
    553   state->SetInteger("tile_count", tiles_.size());
    554   state->Set("global_state", global_state_.AsValue().release());
    555   state->Set("memory_requirements", GetMemoryRequirementsAsValue().release());
    556   return state.PassAs<base::Value>();
    557 }
    558 
    559 scoped_ptr<base::Value> TileManager::AllTilesAsValue() const {
    560   scoped_ptr<base::ListValue> state(new base::ListValue());
    561   for (TileMap::const_iterator it = tiles_.begin();
    562        it != tiles_.end();
    563        it++) {
    564     state->Append(it->second->AsValue().release());
    565   }
    566   return state.PassAs<base::Value>();
    567 }
    568 
    569 scoped_ptr<base::Value> TileManager::GetMemoryRequirementsAsValue() const {
    570   scoped_ptr<base::DictionaryValue> requirements(
    571       new base::DictionaryValue());
    572 
    573   size_t memory_required_bytes;
    574   size_t memory_nice_to_have_bytes;
    575   size_t memory_allocated_bytes;
    576   size_t memory_used_bytes;
    577   GetMemoryStats(&memory_required_bytes,
    578                  &memory_nice_to_have_bytes,
    579                  &memory_allocated_bytes,
    580                  &memory_used_bytes);
    581   requirements->SetInteger("memory_required_bytes", memory_required_bytes);
    582   requirements->SetInteger("memory_nice_to_have_bytes",
    583                            memory_nice_to_have_bytes);
    584   requirements->SetInteger("memory_allocated_bytes", memory_allocated_bytes);
    585   requirements->SetInteger("memory_used_bytes", memory_used_bytes);
    586   return requirements.PassAs<base::Value>();
    587 }
    588 
    589 RasterMode TileManager::DetermineRasterMode(const Tile* tile) const {
    590   DCHECK(tile);
    591   DCHECK(tile->picture_pile());
    592 
    593   const ManagedTileState& mts = tile->managed_state();
    594   RasterMode current_mode = mts.raster_mode;
    595 
    596   RasterMode raster_mode = HIGH_QUALITY_RASTER_MODE;
    597   if (tile->managed_state().resolution == LOW_RESOLUTION)
    598     raster_mode = LOW_QUALITY_RASTER_MODE;
    599   else if (tile->can_use_lcd_text())
    600     raster_mode = HIGH_QUALITY_RASTER_MODE;
    601   else if (mts.tile_versions[current_mode].has_text_ ||
    602            !mts.tile_versions[current_mode].IsReadyToDraw())
    603     raster_mode = HIGH_QUALITY_NO_LCD_RASTER_MODE;
    604 
    605   return std::min(raster_mode, current_mode);
    606 }
    607 
    608 void TileManager::AssignGpuMemoryToTiles(
    609     PrioritizedTileSet* tiles,
    610     TileVector* tiles_that_need_to_be_rasterized) {
    611   TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles");
    612 
    613   // Maintain the list of released resources that can potentially be re-used
    614   // or deleted.
    615   // If this operation becomes expensive too, only do this after some
    616   // resource(s) was returned. Note that in that case, one also need to
    617   // invalidate when releasing some resource from the pool.
    618   resource_pool_->CheckBusyResources();
    619 
    620   // Now give memory out to the tiles until we're out, and build
    621   // the needs-to-be-rasterized queue.
    622   all_tiles_that_need_to_be_rasterized_have_memory_ = true;
    623   all_tiles_required_for_activation_have_memory_ = true;
    624 
    625   // Cast to prevent overflow.
    626   int64 bytes_available =
    627       static_cast<int64>(bytes_releasable_) +
    628       static_cast<int64>(global_state_.memory_limit_in_bytes) -
    629       static_cast<int64>(resource_pool_->acquired_memory_usage_bytes());
    630   int resources_available =
    631       resources_releasable_ +
    632       global_state_.num_resources_limit -
    633       resource_pool_->acquired_resource_count();
    634 
    635   size_t bytes_allocatable =
    636       std::max(static_cast<int64>(0), bytes_available);
    637   size_t resources_allocatable = std::max(0, resources_available);
    638 
    639   size_t bytes_that_exceeded_memory_budget = 0;
    640   size_t bytes_left = bytes_allocatable;
    641   size_t resources_left = resources_allocatable;
    642   bool oomed = false;
    643 
    644   // Memory we assign to raster tasks now will be deducted from our memory
    645   // in future iterations if priorities change. By assigning at most half
    646   // the raster limit, we will always have another 50% left even if priorities
    647   // change completely (assuming we check for completed/cancelled rasters
    648   // between each call to this function).
    649   size_t max_raster_bytes = max_raster_usage_bytes_ / 2;
    650   size_t raster_bytes = 0;
    651 
    652   unsigned schedule_priority = 1u;
    653   for (PrioritizedTileSet::Iterator it(tiles, true);
    654        it;
    655        ++it) {
    656     Tile* tile = *it;
    657     ManagedTileState& mts = tile->managed_state();
    658 
    659     mts.scheduled_priority = schedule_priority++;
    660 
    661     mts.raster_mode = DetermineRasterMode(tile);
    662 
    663     ManagedTileState::TileVersion& tile_version =
    664         mts.tile_versions[mts.raster_mode];
    665 
    666     // If this tile doesn't need a resource, then nothing to do.
    667     if (!tile_version.requires_resource())
    668       continue;
    669 
    670     // If the tile is not needed, free it up.
    671     if (mts.bin == NEVER_BIN) {
    672       FreeResourcesForTile(tile);
    673       continue;
    674     }
    675 
    676     size_t bytes_if_allocated = BytesConsumedIfAllocated(tile);
    677     size_t raster_bytes_if_rastered = raster_bytes + bytes_if_allocated;
    678 
    679     size_t tile_bytes = 0;
    680     size_t tile_resources = 0;
    681 
    682     // It costs to maintain a resource.
    683     for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
    684       if (mts.tile_versions[mode].resource_) {
    685         tile_bytes += bytes_if_allocated;
    686         tile_resources++;
    687       }
    688     }
    689 
    690     // Allow lower priority tiles with initialized resources to keep
    691     // their memory by only assigning memory to new raster tasks if
    692     // they can be scheduled.
    693     if (raster_bytes_if_rastered <= max_raster_bytes) {
    694       // If we don't have the required version, and it's not in flight
    695       // then we'll have to pay to create a new task.
    696       if (!tile_version.resource_ && tile_version.raster_task_.is_null()) {
    697         tile_bytes += bytes_if_allocated;
    698         tile_resources++;
    699       }
    700     }
    701 
    702     // Tile is OOM.
    703     if (tile_bytes > bytes_left || tile_resources > resources_left) {
    704       FreeResourcesForTile(tile);
    705 
    706       // This tile was already on screen and now its resources have been
    707       // released. In order to prevent checkerboarding, set this tile as
    708       // rasterize on demand immediately.
    709       if (mts.visible_and_ready_to_draw)
    710         tile_version.set_rasterize_on_demand();
    711 
    712       oomed = true;
    713       bytes_that_exceeded_memory_budget += tile_bytes;
    714     } else {
    715       bytes_left -= tile_bytes;
    716       resources_left -= tile_resources;
    717 
    718       if (tile_version.resource_)
    719         continue;
    720     }
    721 
    722     DCHECK(!tile_version.resource_);
    723 
    724     // Tile shouldn't be rasterized if |tiles_that_need_to_be_rasterized|
    725     // has reached it's limit or we've failed to assign gpu memory to this
    726     // or any higher priority tile. Preventing tiles that fit into memory
    727     // budget to be rasterized when higher priority tile is oom is
    728     // important for two reasons:
    729     // 1. Tile size should not impact raster priority.
    730     // 2. Tiles with existing raster task could otherwise incorrectly
    731     //    be added as they are not affected by |bytes_allocatable|.
    732     if (oomed || raster_bytes_if_rastered > max_raster_bytes) {
    733       all_tiles_that_need_to_be_rasterized_have_memory_ = false;
    734       if (tile->required_for_activation())
    735         all_tiles_required_for_activation_have_memory_ = false;
    736       it.DisablePriorityOrdering();
    737       continue;
    738     }
    739 
    740     raster_bytes = raster_bytes_if_rastered;
    741     tiles_that_need_to_be_rasterized->push_back(tile);
    742   }
    743 
    744   ever_exceeded_memory_budget_ |= bytes_that_exceeded_memory_budget > 0;
    745   if (ever_exceeded_memory_budget_) {
    746       TRACE_COUNTER_ID2("cc", "over_memory_budget", this,
    747                         "budget", global_state_.memory_limit_in_bytes,
    748                         "over", bytes_that_exceeded_memory_budget);
    749   }
    750   memory_stats_from_last_assign_.total_budget_in_bytes =
    751       global_state_.memory_limit_in_bytes;
    752   memory_stats_from_last_assign_.bytes_allocated =
    753       bytes_allocatable - bytes_left;
    754   memory_stats_from_last_assign_.bytes_unreleasable =
    755       bytes_allocatable - bytes_releasable_;
    756   memory_stats_from_last_assign_.bytes_over =
    757       bytes_that_exceeded_memory_budget;
    758 }
    759 
    760 void TileManager::FreeResourceForTile(Tile* tile, RasterMode mode) {
    761   ManagedTileState& mts = tile->managed_state();
    762   if (mts.tile_versions[mode].resource_) {
    763     resource_pool_->ReleaseResource(
    764         mts.tile_versions[mode].resource_.Pass());
    765 
    766     DCHECK_GE(bytes_releasable_, BytesConsumedIfAllocated(tile));
    767     DCHECK_GE(resources_releasable_, 1u);
    768 
    769     bytes_releasable_ -= BytesConsumedIfAllocated(tile);
    770     --resources_releasable_;
    771   }
    772 }
    773 
    774 void TileManager::FreeResourcesForTile(Tile* tile) {
    775   for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
    776     FreeResourceForTile(tile, static_cast<RasterMode>(mode));
    777   }
    778 }
    779 
    780 void TileManager::FreeUnusedResourcesForTile(Tile* tile) {
    781   DCHECK(tile->IsReadyToDraw());
    782   ManagedTileState& mts = tile->managed_state();
    783   RasterMode used_mode = HIGH_QUALITY_NO_LCD_RASTER_MODE;
    784   for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
    785     if (mts.tile_versions[mode].IsReadyToDraw()) {
    786       used_mode = static_cast<RasterMode>(mode);
    787       break;
    788     }
    789   }
    790 
    791   for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
    792     if (mode != used_mode)
    793       FreeResourceForTile(tile, static_cast<RasterMode>(mode));
    794   }
    795 }
    796 
    797 void TileManager::ScheduleTasks(
    798     const TileVector& tiles_that_need_to_be_rasterized) {
    799   TRACE_EVENT1("cc", "TileManager::ScheduleTasks",
    800                "count", tiles_that_need_to_be_rasterized.size());
    801   RasterWorkerPool::RasterTask::Queue tasks;
    802 
    803   DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
    804 
    805   // Build a new task queue containing all task currently needed. Tasks
    806   // are added in order of priority, highest priority task first.
    807   for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
    808        it != tiles_that_need_to_be_rasterized.end();
    809        ++it) {
    810     Tile* tile = *it;
    811     ManagedTileState& mts = tile->managed_state();
    812     ManagedTileState::TileVersion& tile_version =
    813         mts.tile_versions[mts.raster_mode];
    814 
    815     DCHECK(tile_version.requires_resource());
    816     DCHECK(!tile_version.resource_);
    817 
    818     if (tile_version.raster_task_.is_null())
    819       tile_version.raster_task_ = CreateRasterTask(tile);
    820 
    821     tasks.Append(tile_version.raster_task_, tile->required_for_activation());
    822   }
    823 
    824   // We must reduce the amount of unused resoruces before calling
    825   // ScheduleTasks to prevent usage from rising above limits.
    826   resource_pool_->ReduceResourceUsage();
    827 
    828   // Schedule running of |tasks|. This replaces any previously
    829   // scheduled tasks and effectively cancels all tasks not present
    830   // in |tasks|.
    831   raster_worker_pool_->ScheduleTasks(&tasks);
    832 
    833   did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
    834 }
    835 
    836 RasterWorkerPool::Task TileManager::CreateImageDecodeTask(
    837     Tile* tile, skia::LazyPixelRef* pixel_ref) {
    838   return RasterWorkerPool::CreateImageDecodeTask(
    839       pixel_ref,
    840       tile->layer_id(),
    841       rendering_stats_instrumentation_,
    842       base::Bind(&TileManager::OnImageDecodeTaskCompleted,
    843                  base::Unretained(this),
    844                  tile->layer_id(),
    845                  base::Unretained(pixel_ref)));
    846 }
    847 
    848 RasterWorkerPool::RasterTask TileManager::CreateRasterTask(Tile* tile) {
    849   ManagedTileState& mts = tile->managed_state();
    850 
    851   scoped_ptr<ScopedResource> resource =
    852       resource_pool_->AcquireResource(tile->tile_size_.size());
    853   const ScopedResource* const_resource = resource.get();
    854 
    855   // Create and queue all image decode tasks that this tile depends on.
    856   RasterWorkerPool::Task::Set decode_tasks;
    857   PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
    858   for (PicturePileImpl::PixelRefIterator iter(tile->content_rect(),
    859                                               tile->contents_scale(),
    860                                               tile->picture_pile());
    861        iter; ++iter) {
    862     skia::LazyPixelRef* pixel_ref = *iter;
    863     uint32_t id = pixel_ref->getGenerationID();
    864 
    865     // Append existing image decode task if available.
    866     PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
    867     if (decode_task_it != existing_pixel_refs.end()) {
    868       decode_tasks.Insert(decode_task_it->second);
    869       continue;
    870     }
    871 
    872     // Create and append new image decode task for this pixel ref.
    873     RasterWorkerPool::Task decode_task = CreateImageDecodeTask(
    874         tile, pixel_ref);
    875     decode_tasks.Insert(decode_task);
    876     existing_pixel_refs[id] = decode_task;
    877   }
    878 
    879   return RasterWorkerPool::CreateRasterTask(
    880       const_resource,
    881       tile->picture_pile(),
    882       tile->content_rect(),
    883       tile->contents_scale(),
    884       mts.raster_mode,
    885       mts.resolution,
    886       tile->layer_id(),
    887       static_cast<const void *>(tile),
    888       tile->source_frame_number(),
    889       rendering_stats_instrumentation_,
    890       base::Bind(&TileManager::OnRasterTaskCompleted,
    891                  base::Unretained(this),
    892                  tile->id(),
    893                  base::Passed(&resource),
    894                  mts.raster_mode),
    895       &decode_tasks);
    896 }
    897 
    898 void TileManager::OnImageDecodeTaskCompleted(
    899     int layer_id,
    900     skia::LazyPixelRef* pixel_ref,
    901     bool was_canceled) {
    902   // If the task was canceled, we need to clean it up
    903   // from |image_decode_tasks_|.
    904   if (!was_canceled)
    905     return;
    906 
    907   LayerPixelRefTaskMap::iterator layer_it =
    908       image_decode_tasks_.find(layer_id);
    909 
    910   if (layer_it == image_decode_tasks_.end())
    911     return;
    912 
    913   PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
    914   PixelRefTaskMap::iterator task_it =
    915       pixel_ref_tasks.find(pixel_ref->getGenerationID());
    916 
    917   if (task_it != pixel_ref_tasks.end())
    918     pixel_ref_tasks.erase(task_it);
    919 }
    920 
    921 void TileManager::OnRasterTaskCompleted(
    922     Tile::Id tile_id,
    923     scoped_ptr<ScopedResource> resource,
    924     RasterMode raster_mode,
    925     const PicturePileImpl::Analysis& analysis,
    926     bool was_canceled) {
    927   TileMap::iterator it = tiles_.find(tile_id);
    928   if (it == tiles_.end()) {
    929     ++update_visible_tiles_stats_.canceled_count;
    930     resource_pool_->ReleaseResource(resource.Pass());
    931     return;
    932   }
    933 
    934   Tile* tile = it->second;
    935   ManagedTileState& mts = tile->managed_state();
    936   ManagedTileState::TileVersion& tile_version =
    937       mts.tile_versions[raster_mode];
    938   DCHECK(!tile_version.raster_task_.is_null());
    939   tile_version.raster_task_.Reset();
    940 
    941   if (was_canceled) {
    942     ++update_visible_tiles_stats_.canceled_count;
    943     resource_pool_->ReleaseResource(resource.Pass());
    944     return;
    945   }
    946 
    947   ++update_visible_tiles_stats_.completed_count;
    948 
    949   tile_version.set_has_text(analysis.has_text);
    950   if (analysis.is_solid_color) {
    951     tile_version.set_solid_color(analysis.solid_color);
    952     resource_pool_->ReleaseResource(resource.Pass());
    953   } else {
    954     tile_version.set_use_resource();
    955     tile_version.resource_ = resource.Pass();
    956 
    957     bytes_releasable_ += BytesConsumedIfAllocated(tile);
    958     ++resources_releasable_;
    959   }
    960 
    961   FreeUnusedResourcesForTile(tile);
    962   if (tile->priority(ACTIVE_TREE).distance_to_visible_in_pixels == 0)
    963     did_initialize_visible_tile_ = true;
    964 }
    965 
    966 scoped_refptr<Tile> TileManager::CreateTile(PicturePileImpl* picture_pile,
    967                                             gfx::Size tile_size,
    968                                             gfx::Rect content_rect,
    969                                             gfx::Rect opaque_rect,
    970                                             float contents_scale,
    971                                             int layer_id,
    972                                             int source_frame_number,
    973                                             int flags) {
    974   scoped_refptr<Tile> tile = make_scoped_refptr(new Tile(this,
    975                                                          picture_pile,
    976                                                          tile_size,
    977                                                          content_rect,
    978                                                          opaque_rect,
    979                                                          contents_scale,
    980                                                          layer_id,
    981                                                          source_frame_number,
    982                                                          flags));
    983   DCHECK(tiles_.find(tile->id()) == tiles_.end());
    984 
    985   tiles_[tile->id()] = tile;
    986   used_layer_counts_[tile->layer_id()]++;
    987   prioritized_tiles_dirty_ = true;
    988   return tile;
    989 }
    990 
    991 }  // namespace cc
    992