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.
5 #include "cc/resources/tile_manager.h"
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"
28 // Flag to indicate whether we should try and detect that
29 // a tile is of solid color.
30 const bool kUseColorEstimator = true;
32 class RasterTaskImpl : public RasterTask {
35 const Resource* resource,
36 RasterSource* raster_source,
37 const gfx::Rect& content_rect,
39 TileResolution tile_resolution,
42 int source_frame_number,
44 RenderingStatsInstrumentation* rendering_stats,
45 const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>&
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),
55 source_frame_number_(source_frame_number),
56 analyze_picture_(analyze_picture),
57 rendering_stats_(rendering_stats),
60 // Overridden from Task:
61 void RunOnWorkerThread() override {
62 TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
64 DCHECK(raster_source_.get());
65 DCHECK(raster_buffer_);
67 if (analyze_picture_) {
68 Analyze(raster_source_.get());
69 if (analysis_.is_solid_color)
73 Raster(raster_source_.get());
76 // Overridden from RasterizerTask:
77 void ScheduleOnOriginThread(RasterizerTaskClient* client) override {
78 DCHECK(!raster_buffer_);
79 raster_buffer_ = client->AcquireBufferForRaster(resource());
81 void CompleteOnOriginThread(RasterizerTaskClient* client) override {
82 client->ReleaseBufferForRaster(raster_buffer_.Pass());
84 void RunReplyOnOriginThread() override {
85 DCHECK(!raster_buffer_);
86 reply_.Run(analysis_, !HasFinishedRunning());
90 ~RasterTaskImpl() override { DCHECK(!raster_buffer_); }
93 void Analyze(const RasterSource* raster_source) {
94 frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task(
95 tile_id_, tile_resolution_, source_frame_number_, layer_id_);
97 DCHECK(raster_source);
99 raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_,
102 // Record the solid color prediction.
103 UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
104 analysis_.is_solid_color);
106 // Clear the flag if we're not using the estimator.
107 analysis_.is_solid_color &= kUseColorEstimator;
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_);
116 DCHECK(raster_source);
118 raster_buffer_->Playback(raster_source_.get(), content_rect_,
122 RasterSource::SolidColorAnalysis analysis_;
123 scoped_refptr<RasterSource> raster_source_;
124 gfx::Rect content_rect_;
125 float contents_scale_;
126 TileResolution tile_resolution_;
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)>
134 scoped_ptr<RasterBuffer> raster_buffer_;
136 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl);
139 class ImageDecodeTaskImpl : public ImageDecodeTask {
141 ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
143 RenderingStatsInstrumentation* rendering_stats,
144 const base::Callback<void(bool was_canceled)>& reply)
145 : pixel_ref_(skia::SharePtr(pixel_ref)),
147 rendering_stats_(rendering_stats),
150 // Overridden from Task:
151 void RunOnWorkerThread() override {
152 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
154 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
156 // This will cause the image referred to by pixel ref to be decoded.
157 pixel_ref_->lockPixels();
158 pixel_ref_->unlockPixels();
161 // Overridden from RasterizerTask:
162 void ScheduleOnOriginThread(RasterizerTaskClient* client) override {}
163 void CompleteOnOriginThread(RasterizerTaskClient* client) override {}
164 void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
167 ~ImageDecodeTaskImpl() override {}
170 skia::RefPtr<SkPixelRef> pixel_ref_;
172 RenderingStatsInstrumentation* rendering_stats_;
173 const base::Callback<void(bool was_canceled)> reply_;
175 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
180 RasterTaskCompletionStats::RasterTaskCompletionStats()
181 : completed_count(0u), canceled_count(0u) {}
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);
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,
204 rendering_stats_instrumentation,
205 scheduled_raster_task_limit));
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)
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_(
227 base::Bind(&TileManager::CheckIfReadyToActivate,
228 base::Unretained(this))) {
229 rasterizer_->SetClient(this);
232 TileManager::~TileManager() {
233 // Reset global state and manage. This should cause
234 // our memory usage to drop to zero.
235 global_state_ = GlobalStateThatImpactsTilePriority();
237 RasterTaskQueue empty;
238 rasterizer_->ScheduleTasks(&empty);
239 orphan_raster_tasks_.clear();
241 // This should finish all pending tasks and release any uninitialized
243 rasterizer_->Shutdown();
244 rasterizer_->CheckForCompletedTasks();
246 FreeResourcesForReleasedTiles();
247 CleanUpReleasedTiles();
250 void TileManager::Release(Tile* tile) {
251 released_tiles_.push_back(tile);
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;
261 void TileManager::FreeResourcesForReleasedTiles() {
262 for (std::vector<Tile*>::iterator it = released_tiles_.begin();
263 it != released_tiles_.end();
266 FreeResourcesForTile(tile);
270 void TileManager::CleanUpReleasedTiles() {
271 std::vector<Tile*>::iterator it = released_tiles_.begin();
272 while (it != released_tiles_.end()) {
275 if (tile->HasRasterTask()) {
280 DCHECK(!tile->HasResources());
281 DCHECK(tiles_.find(tile->id()) != tiles_.end());
282 tiles_.erase(tile->id());
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());
293 it = released_tiles_.erase(it);
297 void TileManager::DidFinishRunningTasks(TaskSet task_set) {
298 if (task_set == ALL) {
299 TRACE_EVENT1("cc", "TileManager::DidFinishRunningTasks", "task_set", "ALL");
301 bool memory_usage_above_limit = resource_pool_->total_memory_usage_bytes() >
302 global_state_.soft_memory_limit_in_bytes;
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)
310 rasterizer_->CheckForCompletedTasks();
311 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
313 TileVector tiles_that_need_to_be_rasterized;
314 AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
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);
323 FreeResourcesForReleasedTiles();
325 resource_pool_->ReduceResourceUsage();
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;
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();
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;
356 mts.draw_info.set_rasterize_on_demand();
357 client_->NotifyTileStateChanged(tile);
359 raster_priority_queue_.Pop();
362 if (ready_to_activate) {
363 DCHECK(IsReadyToActivate());
364 ready_to_activate_check_notifier_.Schedule();
366 raster_priority_queue_.Reset();
370 if (task_set == REQUIRED_FOR_ACTIVATION) {
372 "TileManager::DidFinishRunningTasks",
374 "REQUIRED_FOR_ACTIVATION");
375 ready_to_activate_check_notifier_.Schedule();
379 void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority& state) {
380 TRACE_EVENT0("cc", "TileManager::ManageTiles");
382 global_state_ = state;
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;
391 FreeResourcesForReleasedTiles();
392 CleanUpReleasedTiles();
394 TileVector tiles_that_need_to_be_rasterized;
395 AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized);
397 // Finally, schedule rasterizer tasks.
398 ScheduleTasks(tiles_that_need_to_be_rasterized);
400 TRACE_EVENT_INSTANT1("cc",
402 TRACE_EVENT_SCOPE_THREAD,
404 BasicStateAsValue());
406 TRACE_COUNTER_ID1("cc",
407 "unused_memory_bytes",
409 resource_pool_->total_memory_usage_bytes() -
410 resource_pool_->acquired_memory_usage_bytes());
413 bool TileManager::UpdateVisibleTiles() {
414 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
416 rasterizer_->CheckForCompletedTasks();
417 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
419 TRACE_EVENT_INSTANT1(
421 "DidUpdateVisibleTiles",
422 TRACE_EVENT_SCOPE_THREAD,
424 RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
425 update_visible_tiles_stats_ = RasterTaskCompletionStats();
427 bool did_initialize_visible_tile = did_initialize_visible_tile_;
428 did_initialize_visible_tile_ = false;
429 return did_initialize_visible_tile;
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());
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();
448 void TileManager::RebuildEvictionQueueIfNeeded() {
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_)
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;
462 bool TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
463 const MemoryUsage& limit,
464 MemoryUsage* usage) {
465 while (usage->Exceeds(limit)) {
466 RebuildEvictionQueueIfNeeded();
467 if (eviction_priority_queue_.IsEmpty())
470 Tile* tile = eviction_priority_queue_.Top();
471 *usage -= MemoryUsage::FromTile(tile);
472 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
473 eviction_priority_queue_.Pop();
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())
487 Tile* tile = eviction_priority_queue_.Top();
488 if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
491 *usage -= MemoryUsage::FromTile(tile);
492 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
493 eviction_priority_queue_.Pop();
498 bool TileManager::TilePriorityViolatesMemoryPolicy(
499 const TilePriority& priority) {
500 switch (global_state_.memory_limit_policy) {
503 case ALLOW_ABSOLUTE_MINIMUM:
504 return priority.priority_bin > TilePriority::NOW;
505 case ALLOW_PREPAINT_ONLY:
506 return priority.priority_bin > TilePriority::SOON;
508 return priority.distance_to_visible ==
509 std::numeric_limits<float>::infinity();
515 void TileManager::AssignGpuMemoryToTiles(
516 TileVector* tiles_that_need_to_be_rasterized) {
517 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
519 // Maintain the list of released resources that can potentially be re-used
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);
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;
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());
539 eviction_priority_queue_is_up_to_date_ = false;
540 client_->BuildRasterQueue(&raster_priority_queue_,
541 global_state_.tree_priority);
543 while (!raster_priority_queue_.IsEmpty()) {
544 Tile* tile = raster_priority_queue_.Top();
545 TilePriority priority = tile->combined_priority();
547 if (TilePriorityViolatesMemoryPolicy(priority)) {
548 TRACE_EVENT_INSTANT0(
550 "TileManager::AssignGpuMemory tile violates memory policy",
551 TRACE_EVENT_SCOPE_THREAD);
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;
562 ManagedTileState& mts = tile->managed_state();
563 mts.scheduled_priority = schedule_priority++;
564 mts.resolution = priority.resolution;
566 DCHECK(mts.draw_info.mode() ==
567 ManagedTileState::DrawInfo::PICTURE_PILE_MODE ||
568 !mts.draw_info.IsReadyToDraw());
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());
579 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
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;
587 bool memory_usage_is_within_limit =
588 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
589 tile_memory_limit - memory_required_by_tile_to_be_scheduled,
593 // If we couldn't fit the tile into our current memory limit, then we're
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;
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();
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);
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;
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;
622 raster_priority_queue_.Reset();
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);
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());
638 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
640 bool was_ready_to_draw = tile->IsReadyToDraw();
641 FreeResourcesForTile(tile);
642 if (was_ready_to_draw)
643 client_->NotifyTileStateChanged(tile);
646 void TileManager::ScheduleTasks(
647 const TileVector& tiles_that_need_to_be_rasterized) {
649 "TileManager::ScheduleTasks",
651 tiles_that_need_to_be_rasterized.size());
653 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
655 raster_queue_.Reset();
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();
663 ManagedTileState& mts = tile->managed_state();
665 DCHECK(mts.draw_info.requires_resource());
666 DCHECK(!mts.draw_info.resource_);
668 if (!mts.raster_task.get())
669 mts.raster_task = CreateRasterTask(tile);
671 TaskSetCollection task_sets;
672 if (tile->required_for_activation())
673 task_sets.set(REQUIRED_FOR_ACTIVATION);
675 raster_queue_.items.push_back(
676 RasterTaskQueue::Item(mts.raster_task.get(), task_sets));
679 // We must reduce the amount of unused resoruces before calling
680 // ScheduleTasks to prevent usage from rising above limits.
681 resource_pool_->ReduceResourceUsage();
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_);
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
691 orphan_raster_tasks_.clear();
693 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
696 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
698 SkPixelRef* pixel_ref) {
699 return make_scoped_refptr(new ImageDecodeTaskImpl(
702 rendering_stats_instrumentation_,
703 base::Bind(&TileManager::OnImageDecodeTaskCompleted,
704 base::Unretained(this),
706 base::Unretained(pixel_ref))));
709 scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
710 ManagedTileState& mts = tile->managed_state();
712 scoped_ptr<ScopedResource> resource =
713 resource_pool_->AcquireResource(tile->size());
714 const ScopedResource* const_resource = resource.get();
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();
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);
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;
739 return make_scoped_refptr(
740 new RasterTaskImpl(const_resource,
741 tile->raster_source(),
742 tile->content_rect(),
743 tile->contents_scale(),
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),
753 base::Passed(&resource)),
757 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
758 SkPixelRef* pixel_ref,
760 // If the task was canceled, we need to clean it up
761 // from |image_decode_tasks_|.
765 LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
766 if (layer_it == image_decode_tasks_.end())
769 PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
770 PixelRefTaskMap::iterator task_it =
771 pixel_ref_tasks.find(pixel_ref->getGenerationID());
773 if (task_it != pixel_ref_tasks.end())
774 pixel_ref_tasks.erase(task_it);
777 void TileManager::OnRasterTaskCompleted(
779 scoped_ptr<ScopedResource> resource,
780 const RasterSource::SolidColorAnalysis& analysis,
782 DCHECK(tiles_.find(tile_id) != tiles_.end());
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;
791 ++update_visible_tiles_stats_.canceled_count;
792 resource_pool_->ReleaseResource(resource.Pass());
796 ++update_visible_tiles_stats_.completed_count;
798 if (analysis.is_solid_color) {
799 mts.draw_info.set_solid_color(analysis.solid_color);
800 resource_pool_->ReleaseResource(resource.Pass());
802 mts.draw_info.set_use_resource();
803 mts.draw_info.resource_ = resource.Pass();
806 if (tile->priority(ACTIVE_TREE).distance_to_visible == 0.f)
807 did_initialize_visible_tile_ = true;
809 client_->NotifyTileStateChanged(tile);
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,
817 int source_frame_number,
819 scoped_refptr<Tile> tile = make_scoped_refptr(new Tile(this,
827 DCHECK(tiles_.find(tile->id()) == tiles_.end());
829 tiles_[tile->id()] = tile.get();
830 used_layer_counts_[tile->layer_id()]++;
834 void TileManager::SetRasterizerForTesting(Rasterizer* rasterizer) {
835 rasterizer_ = rasterizer;
836 rasterizer_->SetClient(this);
839 bool TileManager::IsReadyToActivate() const {
840 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
841 const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
843 for (std::vector<PictureLayerImpl*>::const_iterator it = layers.begin();
846 if (!(*it)->AllTilesRequiredForActivationAreReadyToDraw())
853 void TileManager::CheckIfReadyToActivate() {
854 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
856 rasterizer_->CheckForCompletedTasks();
857 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
859 if (IsReadyToActivate())
860 client_->NotifyReadyToActivate();
863 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
866 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count)
867 : memory_bytes_(memory_bytes), resource_count_(resource_count) {
871 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
872 const gfx::Size& size,
873 ResourceFormat format) {
874 return MemoryUsage(Resource::MemorySizeBytes(size, format), 1);
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());
884 return MemoryUsage();
887 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
888 const MemoryUsage& other) {
889 memory_bytes_ += other.memory_bytes_;
890 resource_count_ += other.resource_count_;
894 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
895 const MemoryUsage& other) {
896 memory_bytes_ -= other.memory_bytes_;
897 resource_count_ -= other.resource_count_;
901 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
902 const MemoryUsage& other) {
903 MemoryUsage result = *this;
908 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
909 return memory_bytes_ > limit.memory_bytes_ ||
910 resource_count_ > limit.resource_count_;