• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
BinFromTilePriority(const TilePriority & prio)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 
RasterTaskCompletionStats()153 RasterTaskCompletionStats::RasterTaskCompletionStats()
154     : completed_count(0u),
155       canceled_count(0u) {
156 }
157 
RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats & stats)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
Create(TileManagerClient * client,ResourceProvider * resource_provider,size_t num_raster_threads,RenderingStatsInstrumentation * rendering_stats_instrumentation,bool use_map_image,size_t max_transfer_buffer_usage_bytes,size_t max_raster_usage_bytes,GLenum map_image_texture_target)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 
TileManager(TileManagerClient * client,ResourceProvider * resource_provider,scoped_ptr<RasterWorkerPool> raster_worker_pool,size_t num_raster_threads,size_t max_raster_usage_bytes,RenderingStatsInstrumentation * rendering_stats_instrumentation)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 
~TileManager()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 
Release(Tile * tile)241 void TileManager::Release(Tile* tile) {
242   prioritized_tiles_dirty_ = true;
243   released_tiles_.push_back(tile);
244 }
245 
DidChangeTilePriority(Tile * tile)246 void TileManager::DidChangeTilePriority(Tile* tile) {
247   prioritized_tiles_dirty_ = true;
248 }
249 
ShouldForceTasksRequiredForActivationToComplete() const250 bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const {
251   return global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY;
252 }
253 
CleanUpReleasedTiles()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 
UpdatePrioritizedTileSetIfNeeded()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 
DidFinishRunningTasks()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 
DidFinishRunningTasksRequiredForActivation()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 
GetTilesWithAssignedBins(PrioritizedTileSet * tiles)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 
ManageTiles(const GlobalStateThatImpactsTilePriority & state)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 
UpdateVisibleTiles()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 
GetMemoryStats(size_t * memory_required_bytes,size_t * memory_nice_to_have_bytes,size_t * memory_allocated_bytes,size_t * memory_used_bytes) const540 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 
BasicStateAsValue() const551 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 
AllTilesAsValue() const559 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 
GetMemoryRequirementsAsValue() const569 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 
DetermineRasterMode(const Tile * tile) const589 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 
AssignGpuMemoryToTiles(PrioritizedTileSet * tiles,TileVector * tiles_that_need_to_be_rasterized)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 
FreeResourceForTile(Tile * tile,RasterMode mode)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 
FreeResourcesForTile(Tile * tile)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 
FreeUnusedResourcesForTile(Tile * tile)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 
ScheduleTasks(const TileVector & tiles_that_need_to_be_rasterized)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 
CreateImageDecodeTask(Tile * tile,skia::LazyPixelRef * pixel_ref)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 
CreateRasterTask(Tile * tile)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 
OnImageDecodeTaskCompleted(int layer_id,skia::LazyPixelRef * pixel_ref,bool was_canceled)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 
OnRasterTaskCompleted(Tile::Id tile_id,scoped_ptr<ScopedResource> resource,RasterMode raster_mode,const PicturePileImpl::Analysis & analysis,bool was_canceled)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 
CreateTile(PicturePileImpl * picture_pile,gfx::Size tile_size,gfx::Rect content_rect,gfx::Rect opaque_rect,float contents_scale,int layer_id,int source_frame_number,int flags)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