Upstream version 11.40.277.0
[platform/framework/web/crosswalk.git] / src / cc / resources / tile_manager.cc
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/debug/trace_event_argument.h"
13 #include "base/json/json_writer.h"
14 #include "base/logging.h"
15 #include "base/metrics/histogram.h"
16 #include "cc/debug/devtools_instrumentation.h"
17 #include "cc/debug/frame_viewer_instrumentation.h"
18 #include "cc/debug/traced_value.h"
19 #include "cc/layers/picture_layer_impl.h"
20 #include "cc/resources/raster_buffer.h"
21 #include "cc/resources/rasterizer.h"
22 #include "cc/resources/tile.h"
23 #include "ui/gfx/geometry/rect_conversions.h"
24
25 namespace cc {
26 namespace {
27
28 // Flag to indicate whether we should try and detect that
29 // a tile is of solid color.
30 const bool kUseColorEstimator = true;
31
32 class RasterTaskImpl : public RasterTask {
33  public:
34   RasterTaskImpl(
35       const Resource* resource,
36       RasterSource* raster_source,
37       const gfx::Rect& content_rect,
38       float contents_scale,
39       TileResolution tile_resolution,
40       int layer_id,
41       const void* tile_id,
42       int source_frame_number,
43       bool analyze_picture,
44       RenderingStatsInstrumentation* rendering_stats,
45       const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>&
46           reply,
47       ImageDecodeTask::Vector* dependencies)
48       : RasterTask(resource, dependencies),
49         raster_source_(raster_source),
50         content_rect_(content_rect),
51         contents_scale_(contents_scale),
52         tile_resolution_(tile_resolution),
53         layer_id_(layer_id),
54         tile_id_(tile_id),
55         source_frame_number_(source_frame_number),
56         analyze_picture_(analyze_picture),
57         rendering_stats_(rendering_stats),
58         reply_(reply) {}
59
60   // Overridden from Task:
61   void RunOnWorkerThread() override {
62     TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
63
64     DCHECK(raster_source_.get());
65     DCHECK(raster_buffer_);
66
67     if (analyze_picture_) {
68       Analyze(raster_source_.get());
69       if (analysis_.is_solid_color)
70         return;
71     }
72
73     Raster(raster_source_.get());
74   }
75
76   // Overridden from RasterizerTask:
77   void ScheduleOnOriginThread(RasterizerTaskClient* client) override {
78     DCHECK(!raster_buffer_);
79     raster_buffer_ = client->AcquireBufferForRaster(resource());
80   }
81   void CompleteOnOriginThread(RasterizerTaskClient* client) override {
82     client->ReleaseBufferForRaster(raster_buffer_.Pass());
83   }
84   void RunReplyOnOriginThread() override {
85     DCHECK(!raster_buffer_);
86     reply_.Run(analysis_, !HasFinishedRunning());
87   }
88
89  protected:
90   ~RasterTaskImpl() override { DCHECK(!raster_buffer_); }
91
92  private:
93   void Analyze(const RasterSource* raster_source) {
94     frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task(
95         tile_id_, tile_resolution_, source_frame_number_, layer_id_);
96
97     DCHECK(raster_source);
98
99     raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_,
100                                              &analysis_);
101
102     // Record the solid color prediction.
103     UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
104                           analysis_.is_solid_color);
105
106     // Clear the flag if we're not using the estimator.
107     analysis_.is_solid_color &= kUseColorEstimator;
108   }
109
110   void Raster(const RasterSource* raster_source) {
111     frame_viewer_instrumentation::ScopedRasterTask raster_task(
112         tile_id_, tile_resolution_, source_frame_number_, layer_id_);
113     devtools_instrumentation::ScopedLayerTask layer_task(
114         devtools_instrumentation::kRasterTask, layer_id_);
115
116     DCHECK(raster_source);
117
118     raster_buffer_->Playback(raster_source_.get(), content_rect_,
119                              contents_scale_);
120   }
121
122   RasterSource::SolidColorAnalysis analysis_;
123   scoped_refptr<RasterSource> raster_source_;
124   gfx::Rect content_rect_;
125   float contents_scale_;
126   TileResolution tile_resolution_;
127   int layer_id_;
128   const void* tile_id_;
129   int source_frame_number_;
130   bool analyze_picture_;
131   RenderingStatsInstrumentation* rendering_stats_;
132   const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>
133       reply_;
134   scoped_ptr<RasterBuffer> raster_buffer_;
135
136   DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl);
137 };
138
139 class ImageDecodeTaskImpl : public ImageDecodeTask {
140  public:
141   ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
142                       int layer_id,
143                       RenderingStatsInstrumentation* rendering_stats,
144                       const base::Callback<void(bool was_canceled)>& reply)
145       : pixel_ref_(skia::SharePtr(pixel_ref)),
146         layer_id_(layer_id),
147         rendering_stats_(rendering_stats),
148         reply_(reply) {}
149
150   // Overridden from Task:
151   void RunOnWorkerThread() override {
152     TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
153
154     devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
155         pixel_ref_.get());
156     // This will cause the image referred to by pixel ref to be decoded.
157     pixel_ref_->lockPixels();
158     pixel_ref_->unlockPixels();
159   }
160
161   // Overridden from RasterizerTask:
162   void ScheduleOnOriginThread(RasterizerTaskClient* client) override {}
163   void CompleteOnOriginThread(RasterizerTaskClient* client) override {}
164   void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
165
166  protected:
167   ~ImageDecodeTaskImpl() override {}
168
169  private:
170   skia::RefPtr<SkPixelRef> pixel_ref_;
171   int layer_id_;
172   RenderingStatsInstrumentation* rendering_stats_;
173   const base::Callback<void(bool was_canceled)> reply_;
174
175   DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
176 };
177
178 }  // namespace
179
180 RasterTaskCompletionStats::RasterTaskCompletionStats()
181     : completed_count(0u), canceled_count(0u) {}
182
183 scoped_refptr<base::debug::ConvertableToTraceFormat>
184 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
185   scoped_refptr<base::debug::TracedValue> state =
186       new base::debug::TracedValue();
187   state->SetInteger("completed_count", stats.completed_count);
188   state->SetInteger("canceled_count", stats.canceled_count);
189   return state;
190 }
191
192 // static
193 scoped_ptr<TileManager> TileManager::Create(
194     TileManagerClient* client,
195     base::SequencedTaskRunner* task_runner,
196     ResourcePool* resource_pool,
197     Rasterizer* rasterizer,
198     RenderingStatsInstrumentation* rendering_stats_instrumentation,
199     size_t scheduled_raster_task_limit) {
200   return make_scoped_ptr(new TileManager(client,
201                                          task_runner,
202                                          resource_pool,
203                                          rasterizer,
204                                          rendering_stats_instrumentation,
205                                          scheduled_raster_task_limit));
206 }
207
208 TileManager::TileManager(
209     TileManagerClient* client,
210     const scoped_refptr<base::SequencedTaskRunner>& task_runner,
211     ResourcePool* resource_pool,
212     Rasterizer* rasterizer,
213     RenderingStatsInstrumentation* rendering_stats_instrumentation,
214     size_t scheduled_raster_task_limit)
215     : client_(client),
216       task_runner_(task_runner),
217       resource_pool_(resource_pool),
218       rasterizer_(rasterizer),
219       scheduled_raster_task_limit_(scheduled_raster_task_limit),
220       all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
221       rendering_stats_instrumentation_(rendering_stats_instrumentation),
222       did_initialize_visible_tile_(false),
223       did_check_for_completed_tasks_since_last_schedule_tasks_(true),
224       did_oom_on_last_assign_(false),
225       ready_to_activate_check_notifier_(
226           task_runner_.get(),
227           base::Bind(&TileManager::CheckIfReadyToActivate,
228                      base::Unretained(this))) {
229   rasterizer_->SetClient(this);
230 }
231
232 TileManager::~TileManager() {
233   // Reset global state and manage. This should cause
234   // our memory usage to drop to zero.
235   global_state_ = GlobalStateThatImpactsTilePriority();
236
237   RasterTaskQueue empty;
238   rasterizer_->ScheduleTasks(&empty);
239   orphan_raster_tasks_.clear();
240
241   // This should finish all pending tasks and release any uninitialized
242   // resources.
243   rasterizer_->Shutdown();
244   rasterizer_->CheckForCompletedTasks();
245
246   FreeResourcesForReleasedTiles();
247   CleanUpReleasedTiles();
248 }
249
250 void TileManager::Release(Tile* tile) {
251   released_tiles_.push_back(tile);
252 }
253
254 TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const {
255   TaskSetCollection tasks_that_should_be_forced_to_complete;
256   if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY)
257     tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true;
258   return tasks_that_should_be_forced_to_complete;
259 }
260
261 void TileManager::FreeResourcesForReleasedTiles() {
262   for (std::vector<Tile*>::iterator it = released_tiles_.begin();
263        it != released_tiles_.end();
264        ++it) {
265     Tile* tile = *it;
266     FreeResourcesForTile(tile);
267   }
268 }
269
270 void TileManager::CleanUpReleasedTiles() {
271   std::vector<Tile*>::iterator it = released_tiles_.begin();
272   while (it != released_tiles_.end()) {
273     Tile* tile = *it;
274
275     if (tile->HasRasterTask()) {
276       ++it;
277       continue;
278     }
279
280     DCHECK(!tile->HasResources());
281     DCHECK(tiles_.find(tile->id()) != tiles_.end());
282     tiles_.erase(tile->id());
283
284     LayerCountMap::iterator layer_it =
285         used_layer_counts_.find(tile->layer_id());
286     DCHECK_GT(layer_it->second, 0);
287     if (--layer_it->second == 0) {
288       used_layer_counts_.erase(layer_it);
289       image_decode_tasks_.erase(tile->layer_id());
290     }
291
292     delete tile;
293     it = released_tiles_.erase(it);
294   }
295 }
296
297 void TileManager::DidFinishRunningTasks(TaskSet task_set) {
298   if (task_set == ALL) {
299     TRACE_EVENT1("cc", "TileManager::DidFinishRunningTasks", "task_set", "ALL");
300
301     bool memory_usage_above_limit = resource_pool_->total_memory_usage_bytes() >
302                                     global_state_.soft_memory_limit_in_bytes;
303
304     // When OOM, keep re-assigning memory until we reach a steady state
305     // where top-priority tiles are initialized.
306     if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
307         !memory_usage_above_limit)
308       return;
309
310     rasterizer_->CheckForCompletedTasks();
311     did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
312
313     TileVector tiles_that_need_to_be_rasterized;
314     AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
315
316     // |tiles_that_need_to_be_rasterized| will be empty when we reach a
317     // steady memory state. Keep scheduling tasks until we reach this state.
318     if (!tiles_that_need_to_be_rasterized.empty()) {
319       ScheduleTasks(tiles_that_need_to_be_rasterized);
320       return;
321     }
322
323     FreeResourcesForReleasedTiles();
324
325     resource_pool_->ReduceResourceUsage();
326
327     // We don't reserve memory for required-for-activation tiles during
328     // accelerated gestures, so we just postpone activation when we don't
329     // have these tiles, and activate after the accelerated gesture.
330     // Likewise if we don't allow any tiles (as is the case when we're
331     // invisible), if we have tiles that aren't ready, then we shouldn't
332     // activate as activation can cause checkerboards.
333     bool allow_rasterize_on_demand =
334         global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
335         global_state_.memory_limit_policy != ALLOW_NOTHING;
336
337     // Use on-demand raster for any required-for-activation tiles that have not
338     // been been assigned memory after reaching a steady memory state. This
339     // ensures that we activate even when OOM. Note that we have to rebuilt the
340     // queue in case the last AssignGpuMemoryToTiles evicted some tiles that
341     // would otherwise not be picked up by the old raster queue.
342     client_->BuildRasterQueue(&raster_priority_queue_,
343                               global_state_.tree_priority);
344     bool ready_to_activate = true;
345     while (!raster_priority_queue_.IsEmpty()) {
346       Tile* tile = raster_priority_queue_.Top();
347       ManagedTileState& mts = tile->managed_state();
348
349       if (tile->required_for_activation() && !mts.draw_info.IsReadyToDraw()) {
350         // If we can't raster on demand, give up early (and don't activate).
351         if (!allow_rasterize_on_demand) {
352           ready_to_activate = false;
353           break;
354         }
355
356         mts.draw_info.set_rasterize_on_demand();
357         client_->NotifyTileStateChanged(tile);
358       }
359       raster_priority_queue_.Pop();
360     }
361
362     if (ready_to_activate) {
363       DCHECK(IsReadyToActivate());
364       ready_to_activate_check_notifier_.Schedule();
365     }
366     raster_priority_queue_.Reset();
367     return;
368   }
369
370   if (task_set == REQUIRED_FOR_ACTIVATION) {
371     TRACE_EVENT1("cc",
372                  "TileManager::DidFinishRunningTasks",
373                  "task_set",
374                  "REQUIRED_FOR_ACTIVATION");
375     ready_to_activate_check_notifier_.Schedule();
376   }
377 }
378
379 void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) {
380   TRACE_EVENT0("cc", "TileManager::ManageTiles");
381
382   global_state_ = state;
383
384   // We need to call CheckForCompletedTasks() once in-between each call
385   // to ScheduleTasks() to prevent canceled tasks from being scheduled.
386   if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
387     rasterizer_->CheckForCompletedTasks();
388     did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
389   }
390
391   FreeResourcesForReleasedTiles();
392   CleanUpReleasedTiles();
393
394   TileVector tiles_that_need_to_be_rasterized;
395   AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
396
397   // Finally, schedule rasterizer tasks.
398   ScheduleTasks(tiles_that_need_to_be_rasterized);
399
400   TRACE_EVENT_INSTANT1("cc",
401                        "DidManage",
402                        TRACE_EVENT_SCOPE_THREAD,
403                        "state",
404                        BasicStateAsValue());
405
406   TRACE_COUNTER_ID1("cc",
407                     "unused_memory_bytes",
408                     this,
409                     resource_pool_->total_memory_usage_bytes() -
410                         resource_pool_->acquired_memory_usage_bytes());
411 }
412
413 bool TileManager::UpdateVisibleTiles() {
414   TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
415
416   rasterizer_->CheckForCompletedTasks();
417   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
418
419   TRACE_EVENT_INSTANT1(
420       "cc",
421       "DidUpdateVisibleTiles",
422       TRACE_EVENT_SCOPE_THREAD,
423       "stats",
424       RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
425   update_visible_tiles_stats_ = RasterTaskCompletionStats();
426
427   bool did_initialize_visible_tile = did_initialize_visible_tile_;
428   did_initialize_visible_tile_ = false;
429   return did_initialize_visible_tile;
430 }
431
432 scoped_refptr<base::debug::ConvertableToTraceFormat>
433 TileManager::BasicStateAsValue() const {
434   scoped_refptr<base::debug::TracedValue> value =
435       new base::debug::TracedValue();
436   BasicStateAsValueInto(value.get());
437   return value;
438 }
439
440 void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const {
441   state->SetInteger("tile_count", tiles_.size());
442   state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
443   state->BeginDictionary("global_state");
444   global_state_.AsValueInto(state);
445   state->EndDictionary();
446 }
447
448 void TileManager::RebuildEvictionQueueIfNeeded() {
449   TRACE_EVENT1("cc",
450                "TileManager::RebuildEvictionQueueIfNeeded",
451                "eviction_priority_queue_is_up_to_date",
452                eviction_priority_queue_is_up_to_date_);
453   if (eviction_priority_queue_is_up_to_date_)
454     return;
455
456   eviction_priority_queue_.Reset();
457   client_->BuildEvictionQueue(&eviction_priority_queue_,
458                               global_state_.tree_priority);
459   eviction_priority_queue_is_up_to_date_ = true;
460 }
461
462 bool TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
463     const MemoryUsage& limit,
464     MemoryUsage* usage) {
465   while (usage->Exceeds(limit)) {
466     RebuildEvictionQueueIfNeeded();
467     if (eviction_priority_queue_.IsEmpty())
468       return false;
469
470     Tile* tile = eviction_priority_queue_.Top();
471     *usage -= MemoryUsage::FromTile(tile);
472     FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
473     eviction_priority_queue_.Pop();
474   }
475   return true;
476 }
477
478 bool TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
479     const MemoryUsage& limit,
480     const TilePriority& other_priority,
481     MemoryUsage* usage) {
482   while (usage->Exceeds(limit)) {
483     RebuildEvictionQueueIfNeeded();
484     if (eviction_priority_queue_.IsEmpty())
485       return false;
486
487     Tile* tile = eviction_priority_queue_.Top();
488     if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
489       return false;
490
491     *usage -= MemoryUsage::FromTile(tile);
492     FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
493     eviction_priority_queue_.Pop();
494   }
495   return true;
496 }
497
498 bool TileManager::TilePriorityViolatesMemoryPolicy(
499     const TilePriority& priority) {
500   switch (global_state_.memory_limit_policy) {
501     case ALLOW_NOTHING:
502       return true;
503     case ALLOW_ABSOLUTE_MINIMUM:
504       return priority.priority_bin > TilePriority::NOW;
505     case ALLOW_PREPAINT_ONLY:
506       return priority.priority_bin > TilePriority::SOON;
507     case ALLOW_ANYTHING:
508       return priority.distance_to_visible ==
509              std::numeric_limits<float>::infinity();
510   }
511   NOTREACHED();
512   return true;
513 }
514
515 void TileManager::AssignGpuMemoryToTiles(
516     TileVector* tiles_that_need_to_be_rasterized) {
517   TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
518
519   // Maintain the list of released resources that can potentially be re-used
520   // or deleted.
521   // If this operation becomes expensive too, only do this after some
522   // resource(s) was returned. Note that in that case, one also need to
523   // invalidate when releasing some resource from the pool.
524   resource_pool_->CheckBusyResources(false);
525
526   // Now give memory out to the tiles until we're out, and build
527   // the needs-to-be-rasterized queue.
528   unsigned schedule_priority = 1u;
529   all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
530   bool had_enough_memory_to_schedule_tiles_needed_now = true;
531
532   MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
533                                 global_state_.num_resources_limit);
534   MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
535                                 global_state_.num_resources_limit);
536   MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
537                            resource_pool_->acquired_resource_count());
538
539   eviction_priority_queue_is_up_to_date_ = false;
540   client_->BuildRasterQueue(&raster_priority_queue_,
541                             global_state_.tree_priority);
542
543   while (!raster_priority_queue_.IsEmpty()) {
544     Tile* tile = raster_priority_queue_.Top();
545     TilePriority priority = tile->combined_priority();
546
547     if (TilePriorityViolatesMemoryPolicy(priority)) {
548       TRACE_EVENT_INSTANT0(
549           "cc",
550           "TileManager::AssignGpuMemory tile violates memory policy",
551           TRACE_EVENT_SCOPE_THREAD);
552       break;
553     }
554
555     // We won't be able to schedule this tile, so break out early.
556     if (tiles_that_need_to_be_rasterized->size() >=
557         scheduled_raster_task_limit_) {
558       all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
559       break;
560     }
561
562     ManagedTileState& mts = tile->managed_state();
563     mts.scheduled_priority = schedule_priority++;
564     mts.resolution = priority.resolution;
565
566     DCHECK(mts.draw_info.mode() ==
567                ManagedTileState::DrawInfo::PICTURE_PILE_MODE ||
568            !mts.draw_info.IsReadyToDraw());
569
570     // If the tile already has a raster_task, then the memory used by it is
571     // already accounted for in memory_usage. Otherwise, we'll have to acquire
572     // more memory to create a raster task.
573     MemoryUsage memory_required_by_tile_to_be_scheduled;
574     if (!mts.raster_task.get()) {
575       memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
576           tile->size(), resource_pool_->resource_format());
577     }
578
579     bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
580
581     // This is the memory limit that will be used by this tile. Depending on
582     // the tile priority, it will be one of hard_memory_limit or
583     // soft_memory_limit.
584     MemoryUsage& tile_memory_limit =
585         tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
586
587     bool memory_usage_is_within_limit =
588         FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
589             tile_memory_limit - memory_required_by_tile_to_be_scheduled,
590             priority,
591             &memory_usage);
592
593     // If we couldn't fit the tile into our current memory limit, then we're
594     // done.
595     if (!memory_usage_is_within_limit) {
596       if (tile_is_needed_now)
597         had_enough_memory_to_schedule_tiles_needed_now = false;
598       all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
599       break;
600     }
601
602     memory_usage += memory_required_by_tile_to_be_scheduled;
603     tiles_that_need_to_be_rasterized->push_back(tile);
604     raster_priority_queue_.Pop();
605   }
606
607   // Note that we should try and further reduce memory in case the above loop
608   // didn't reduce memory. This ensures that we always release as many resources
609   // as possible to stay within the memory limit.
610   FreeTileResourcesUntilUsageIsWithinLimit(hard_memory_limit, &memory_usage);
611
612   UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
613                         !had_enough_memory_to_schedule_tiles_needed_now);
614   did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
615
616   memory_stats_from_last_assign_.total_budget_in_bytes =
617       global_state_.hard_memory_limit_in_bytes;
618   memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
619   memory_stats_from_last_assign_.had_enough_memory =
620       had_enough_memory_to_schedule_tiles_needed_now;
621
622   raster_priority_queue_.Reset();
623
624   TRACE_EVENT_END2("cc",
625                    "TileManager::AssignGpuMemoryToTiles",
626                    "all_tiles_that_need_to_be_rasterized_are_scheduled",
627                    all_tiles_that_need_to_be_rasterized_are_scheduled_,
628                    "had_enough_memory_to_schedule_tiles_needed_now",
629                    had_enough_memory_to_schedule_tiles_needed_now);
630 }
631
632 void TileManager::FreeResourcesForTile(Tile* tile) {
633   ManagedTileState& mts = tile->managed_state();
634   if (mts.draw_info.resource_)
635     resource_pool_->ReleaseResource(mts.draw_info.resource_.Pass());
636 }
637
638 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
639     Tile* tile) {
640   bool was_ready_to_draw = tile->IsReadyToDraw();
641   FreeResourcesForTile(tile);
642   if (was_ready_to_draw)
643     client_->NotifyTileStateChanged(tile);
644 }
645
646 void TileManager::ScheduleTasks(
647     const TileVector& tiles_that_need_to_be_rasterized) {
648   TRACE_EVENT1("cc",
649                "TileManager::ScheduleTasks",
650                "count",
651                tiles_that_need_to_be_rasterized.size());
652
653   DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
654
655   raster_queue_.Reset();
656
657   // Build a new task queue containing all task currently needed. Tasks
658   // are added in order of priority, highest priority task first.
659   for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
660        it != tiles_that_need_to_be_rasterized.end();
661        ++it) {
662     Tile* tile = *it;
663     ManagedTileState& mts = tile->managed_state();
664
665     DCHECK(mts.draw_info.requires_resource());
666     DCHECK(!mts.draw_info.resource_);
667
668     if (!mts.raster_task.get())
669       mts.raster_task = CreateRasterTask(tile);
670
671     TaskSetCollection task_sets;
672     if (tile->required_for_activation())
673       task_sets.set(REQUIRED_FOR_ACTIVATION);
674     task_sets.set(ALL);
675     raster_queue_.items.push_back(
676         RasterTaskQueue::Item(mts.raster_task.get(), task_sets));
677   }
678
679   // We must reduce the amount of unused resoruces before calling
680   // ScheduleTasks to prevent usage from rising above limits.
681   resource_pool_->ReduceResourceUsage();
682
683   // Schedule running of |raster_queue_|. This replaces any previously
684   // scheduled tasks and effectively cancels all tasks not present
685   // in |raster_queue_|.
686   rasterizer_->ScheduleTasks(&raster_queue_);
687
688   // It's now safe to clean up orphan tasks as raster worker pool is not
689   // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
690   // been called.
691   orphan_raster_tasks_.clear();
692
693   did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
694 }
695
696 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
697     Tile* tile,
698     SkPixelRef* pixel_ref) {
699   return make_scoped_refptr(new ImageDecodeTaskImpl(
700       pixel_ref,
701       tile->layer_id(),
702       rendering_stats_instrumentation_,
703       base::Bind(&TileManager::OnImageDecodeTaskCompleted,
704                  base::Unretained(this),
705                  tile->layer_id(),
706                  base::Unretained(pixel_ref))));
707 }
708
709 scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
710   ManagedTileState& mts = tile->managed_state();
711
712   scoped_ptr<ScopedResource> resource =
713       resource_pool_->AcquireResource(tile->size());
714   const ScopedResource* const_resource = resource.get();
715
716   // Create and queue all image decode tasks that this tile depends on.
717   ImageDecodeTask::Vector decode_tasks;
718   PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
719   std::vector<SkPixelRef*> pixel_refs;
720   tile->raster_source()->GatherPixelRefs(
721       tile->content_rect(), tile->contents_scale(), &pixel_refs);
722   for (SkPixelRef* pixel_ref : pixel_refs) {
723     uint32_t id = pixel_ref->getGenerationID();
724
725     // Append existing image decode task if available.
726     PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
727     if (decode_task_it != existing_pixel_refs.end()) {
728       decode_tasks.push_back(decode_task_it->second);
729       continue;
730     }
731
732     // Create and append new image decode task for this pixel ref.
733     scoped_refptr<ImageDecodeTask> decode_task =
734         CreateImageDecodeTask(tile, pixel_ref);
735     decode_tasks.push_back(decode_task);
736     existing_pixel_refs[id] = decode_task;
737   }
738
739   return make_scoped_refptr(
740       new RasterTaskImpl(const_resource,
741                          tile->raster_source(),
742                          tile->content_rect(),
743                          tile->contents_scale(),
744                          mts.resolution,
745                          tile->layer_id(),
746                          static_cast<const void*>(tile),
747                          tile->source_frame_number(),
748                          tile->use_picture_analysis(),
749                          rendering_stats_instrumentation_,
750                          base::Bind(&TileManager::OnRasterTaskCompleted,
751                                     base::Unretained(this),
752                                     tile->id(),
753                                     base::Passed(&resource)),
754                          &decode_tasks));
755 }
756
757 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
758                                              SkPixelRef* pixel_ref,
759                                              bool was_canceled) {
760   // If the task was canceled, we need to clean it up
761   // from |image_decode_tasks_|.
762   if (!was_canceled)
763     return;
764
765   LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
766   if (layer_it == image_decode_tasks_.end())
767     return;
768
769   PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
770   PixelRefTaskMap::iterator task_it =
771       pixel_ref_tasks.find(pixel_ref->getGenerationID());
772
773   if (task_it != pixel_ref_tasks.end())
774     pixel_ref_tasks.erase(task_it);
775 }
776
777 void TileManager::OnRasterTaskCompleted(
778     Tile::Id tile_id,
779     scoped_ptr<ScopedResource> resource,
780     const RasterSource::SolidColorAnalysis& analysis,
781     bool was_canceled) {
782   DCHECK(tiles_.find(tile_id) != tiles_.end());
783
784   Tile* tile = tiles_[tile_id];
785   ManagedTileState& mts = tile->managed_state();
786   DCHECK(mts.raster_task.get());
787   orphan_raster_tasks_.push_back(mts.raster_task);
788   mts.raster_task = NULL;
789
790   if (was_canceled) {
791     ++update_visible_tiles_stats_.canceled_count;
792     resource_pool_->ReleaseResource(resource.Pass());
793     return;
794   }
795
796   ++update_visible_tiles_stats_.completed_count;
797
798   if (analysis.is_solid_color) {
799     mts.draw_info.set_solid_color(analysis.solid_color);
800     resource_pool_->ReleaseResource(resource.Pass());
801   } else {
802     mts.draw_info.set_use_resource();
803     mts.draw_info.resource_ = resource.Pass();
804   }
805
806   if (tile->priority(ACTIVE_TREE).distance_to_visible == 0.f)
807     did_initialize_visible_tile_ = true;
808
809   client_->NotifyTileStateChanged(tile);
810 }
811
812 scoped_refptr<Tile> TileManager::CreateTile(RasterSource* raster_source,
813                                             const gfx::Size& tile_size,
814                                             const gfx::Rect& content_rect,
815                                             float contents_scale,
816                                             int layer_id,
817                                             int source_frame_number,
818                                             int flags) {
819   scoped_refptr<Tile> tile = make_scoped_refptr(new Tile(this,
820                                                          raster_source,
821                                                          tile_size,
822                                                          content_rect,
823                                                          contents_scale,
824                                                          layer_id,
825                                                          source_frame_number,
826                                                          flags));
827   DCHECK(tiles_.find(tile->id()) == tiles_.end());
828
829   tiles_[tile->id()] = tile.get();
830   used_layer_counts_[tile->layer_id()]++;
831   return tile;
832 }
833
834 void TileManager::SetRasterizerForTesting(Rasterizer* rasterizer) {
835   rasterizer_ = rasterizer;
836   rasterizer_->SetClient(this);
837 }
838
839 bool TileManager::IsReadyToActivate() const {
840   TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
841   const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
842
843   for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin();
844        it != layers.end();
845        ++it) {
846     if (!(*it)->AllTilesRequiredForActivationAreReadyToDraw())
847       return false;
848   }
849
850   return true;
851 }
852
853 void TileManager::CheckIfReadyToActivate() {
854   TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
855
856   rasterizer_->CheckForCompletedTasks();
857   did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
858
859   if (IsReadyToActivate())
860     client_->NotifyReadyToActivate();
861 }
862
863 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
864 }
865
866 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count)
867     : memory_bytes_(memory_bytes), resource_count_(resource_count) {
868 }
869
870 // static
871 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
872     const gfx::Size& size,
873     ResourceFormat format) {
874   return MemoryUsage(Resource::MemorySizeBytes(size, format), 1);
875 }
876
877 // static
878 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
879   const ManagedTileState& mts = tile->managed_state();
880   if (mts.draw_info.resource_) {
881     return MemoryUsage::FromConfig(tile->size(),
882                                    mts.draw_info.resource_->format());
883   }
884   return MemoryUsage();
885 }
886
887 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
888     const MemoryUsage& other) {
889   memory_bytes_ += other.memory_bytes_;
890   resource_count_ += other.resource_count_;
891   return *this;
892 }
893
894 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
895     const MemoryUsage& other) {
896   memory_bytes_ -= other.memory_bytes_;
897   resource_count_ -= other.resource_count_;
898   return *this;
899 }
900
901 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
902     const MemoryUsage& other) {
903   MemoryUsage result = *this;
904   result -= other;
905   return result;
906 }
907
908 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
909   return memory_bytes_ > limit.memory_bytes_ ||
910          resource_count_ > limit.resource_count_;
911 }
912
913 }  // namespace cc