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
22namespace cc {
23
24namespace {
25
26// Memory limit policy works by mapping some bin states to the NEVER bin.
27const 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.
68const 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.
91const 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.
115inline 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
153RasterTaskCompletionStats::RasterTaskCompletionStats()
154    : completed_count(0u),
155      canceled_count(0u) {
156}
157
158scoped_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
167scoped_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
193TileManager::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
221TileManager::~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
241void TileManager::Release(Tile* tile) {
242  prioritized_tiles_dirty_ = true;
243  released_tiles_.push_back(tile);
244}
245
246void TileManager::DidChangeTilePriority(Tile* tile) {
247  prioritized_tiles_dirty_ = true;
248}
249
250bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const {
251  return global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY;
252}
253
254void 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
279void 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
290void 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
338void 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
350void 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
484void 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
522bool 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
540void 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
551scoped_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
559scoped_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
569scoped_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
589RasterMode 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
608void 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
760void 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
774void TileManager::FreeResourcesForTile(Tile* tile) {
775  for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
776    FreeResourceForTile(tile, static_cast<RasterMode>(mode));
777  }
778}
779
780void 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
797void 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
836RasterWorkerPool::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
848RasterWorkerPool::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
898void 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
921void 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
966scoped_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