ChromeVox should only intercept 'tab' key if nothing has focus.
[chromium-blink-merge.git] / cc / resources / tile_manager.cc
blob0280e57969c914f1b96613c65cd4aec8f15c748f
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"
7 #include <algorithm>
8 #include <limits>
9 #include <string>
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 "cc/resources/tile_task_runner.h"
24 #include "ui/gfx/geometry/rect_conversions.h"
26 namespace cc {
27 namespace {
29 // Flag to indicate whether we should try and detect that
30 // a tile is of solid color.
31 const bool kUseColorEstimator = true;
33 class RasterTaskImpl : public RasterTask {
34 public:
35 RasterTaskImpl(
36 const Resource* resource,
37 RasterSource* raster_source,
38 const gfx::Rect& content_rect,
39 float contents_scale,
40 TileResolution tile_resolution,
41 int layer_id,
42 const void* tile_id,
43 int source_frame_number,
44 bool analyze_picture,
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 reply_(reply) {}
59 // Overridden from Task:
60 void RunOnWorkerThread() override {
61 TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
63 DCHECK(raster_source_.get());
64 DCHECK(raster_buffer_);
66 if (analyze_picture_) {
67 Analyze(raster_source_.get());
68 if (analysis_.is_solid_color)
69 return;
72 Raster(raster_source_.get());
75 // Overridden from TileTask:
76 void ScheduleOnOriginThread(TileTaskClient* client) override {
77 DCHECK(!raster_buffer_);
78 raster_buffer_ = client->AcquireBufferForRaster(resource());
80 void CompleteOnOriginThread(TileTaskClient* client) override {
81 client->ReleaseBufferForRaster(raster_buffer_.Pass());
83 void RunReplyOnOriginThread() override {
84 DCHECK(!raster_buffer_);
85 reply_.Run(analysis_, !HasFinishedRunning());
88 protected:
89 ~RasterTaskImpl() override { DCHECK(!raster_buffer_); }
91 private:
92 void Analyze(const RasterSource* raster_source) {
93 frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task(
94 tile_id_, tile_resolution_, source_frame_number_, layer_id_);
96 DCHECK(raster_source);
98 raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_,
99 &analysis_);
101 // Record the solid color prediction.
102 UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
103 analysis_.is_solid_color);
105 // Clear the flag if we're not using the estimator.
106 analysis_.is_solid_color &= kUseColorEstimator;
109 void Raster(const RasterSource* raster_source) {
110 frame_viewer_instrumentation::ScopedRasterTask raster_task(
111 tile_id_, tile_resolution_, source_frame_number_, layer_id_);
113 DCHECK(raster_source);
115 raster_buffer_->Playback(raster_source_.get(), content_rect_,
116 contents_scale_);
119 RasterSource::SolidColorAnalysis analysis_;
120 scoped_refptr<RasterSource> raster_source_;
121 gfx::Rect content_rect_;
122 float contents_scale_;
123 TileResolution tile_resolution_;
124 int layer_id_;
125 const void* tile_id_;
126 int source_frame_number_;
127 bool analyze_picture_;
128 const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>
129 reply_;
130 scoped_ptr<RasterBuffer> raster_buffer_;
132 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl);
135 class ImageDecodeTaskImpl : public ImageDecodeTask {
136 public:
137 ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
138 int layer_id,
139 const base::Callback<void(bool was_canceled)>& reply)
140 : pixel_ref_(skia::SharePtr(pixel_ref)),
141 layer_id_(layer_id),
142 reply_(reply) {}
144 // Overridden from Task:
145 void RunOnWorkerThread() override {
146 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
148 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
149 pixel_ref_.get());
150 // This will cause the image referred to by pixel ref to be decoded.
151 pixel_ref_->lockPixels();
152 pixel_ref_->unlockPixels();
155 // Overridden from TileTask:
156 void ScheduleOnOriginThread(TileTaskClient* client) override {}
157 void CompleteOnOriginThread(TileTaskClient* client) override {}
158 void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
160 protected:
161 ~ImageDecodeTaskImpl() override {}
163 private:
164 skia::RefPtr<SkPixelRef> pixel_ref_;
165 int layer_id_;
166 const base::Callback<void(bool was_canceled)> reply_;
168 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
171 const char* TaskSetName(TaskSet task_set) {
172 switch (task_set) {
173 case TileManager::ALL:
174 return "ALL";
175 case TileManager::REQUIRED_FOR_ACTIVATION:
176 return "REQUIRED_FOR_ACTIVATION";
177 case TileManager::REQUIRED_FOR_DRAW:
178 return "REQUIRED_FOR_DRAW";
181 NOTREACHED();
182 return "Invalid TaskSet";
185 } // namespace
187 RasterTaskCompletionStats::RasterTaskCompletionStats()
188 : completed_count(0u), canceled_count(0u) {}
190 scoped_refptr<base::debug::ConvertableToTraceFormat>
191 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
192 scoped_refptr<base::debug::TracedValue> state =
193 new base::debug::TracedValue();
194 state->SetInteger("completed_count", stats.completed_count);
195 state->SetInteger("canceled_count", stats.canceled_count);
196 return state;
199 // static
200 scoped_ptr<TileManager> TileManager::Create(
201 TileManagerClient* client,
202 base::SequencedTaskRunner* task_runner,
203 ResourcePool* resource_pool,
204 TileTaskRunner* tile_task_runner,
205 Rasterizer* rasterizer,
206 size_t scheduled_raster_task_limit) {
207 return make_scoped_ptr(new TileManager(client, task_runner, resource_pool,
208 tile_task_runner, rasterizer,
209 scheduled_raster_task_limit));
212 TileManager::TileManager(
213 TileManagerClient* client,
214 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
215 ResourcePool* resource_pool,
216 TileTaskRunner* tile_task_runner,
217 Rasterizer* rasterizer,
218 size_t scheduled_raster_task_limit)
219 : client_(client),
220 task_runner_(task_runner),
221 resource_pool_(resource_pool),
222 tile_task_runner_(tile_task_runner),
223 rasterizer_(rasterizer),
224 scheduled_raster_task_limit_(scheduled_raster_task_limit),
225 all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
226 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
227 did_oom_on_last_assign_(false),
228 ready_to_activate_notifier_(
229 task_runner_.get(),
230 base::Bind(&TileManager::NotifyReadyToActivate,
231 base::Unretained(this))),
232 ready_to_draw_notifier_(
233 task_runner_.get(),
234 base::Bind(&TileManager::NotifyReadyToDraw, base::Unretained(this))),
235 ready_to_activate_check_notifier_(
236 task_runner_.get(),
237 base::Bind(&TileManager::CheckIfReadyToActivate,
238 base::Unretained(this))),
239 ready_to_draw_check_notifier_(
240 task_runner_.get(),
241 base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))),
242 more_tiles_need_prepare_check_notifier_(
243 task_runner_.get(),
244 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
245 base::Unretained(this))),
246 eviction_priority_queue_is_up_to_date_(false),
247 did_notify_ready_to_activate_(false),
248 did_notify_ready_to_draw_(false) {
249 tile_task_runner_->SetClient(this);
252 TileManager::~TileManager() {
253 // Reset global state and manage. This should cause
254 // our memory usage to drop to zero.
255 global_state_ = GlobalStateThatImpactsTilePriority();
257 TileTaskQueue empty;
258 tile_task_runner_->ScheduleTasks(&empty);
259 orphan_raster_tasks_.clear();
261 // This should finish all pending tasks and release any uninitialized
262 // resources.
263 tile_task_runner_->Shutdown();
264 tile_task_runner_->CheckForCompletedTasks();
266 FreeResourcesForReleasedTiles();
267 CleanUpReleasedTiles();
270 void TileManager::Release(Tile* tile) {
271 released_tiles_.push_back(tile);
274 TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const {
275 TaskSetCollection tasks_that_should_be_forced_to_complete;
276 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY)
277 tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true;
278 return tasks_that_should_be_forced_to_complete;
281 void TileManager::FreeResourcesForReleasedTiles() {
282 for (std::vector<Tile*>::iterator it = released_tiles_.begin();
283 it != released_tiles_.end();
284 ++it) {
285 Tile* tile = *it;
286 FreeResourcesForTile(tile);
290 void TileManager::CleanUpReleasedTiles() {
291 std::vector<Tile*>::iterator it = released_tiles_.begin();
292 while (it != released_tiles_.end()) {
293 Tile* tile = *it;
295 if (tile->HasRasterTask()) {
296 ++it;
297 continue;
300 DCHECK(!tile->HasResource());
301 DCHECK(tiles_.find(tile->id()) != tiles_.end());
302 tiles_.erase(tile->id());
304 LayerCountMap::iterator layer_it =
305 used_layer_counts_.find(tile->layer_id());
306 DCHECK_GT(layer_it->second, 0);
307 if (--layer_it->second == 0) {
308 used_layer_counts_.erase(layer_it);
309 image_decode_tasks_.erase(tile->layer_id());
312 delete tile;
313 it = released_tiles_.erase(it);
317 void TileManager::DidFinishRunningTileTasks(TaskSet task_set) {
318 TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
319 TaskSetName(task_set));
321 switch (task_set) {
322 case ALL: {
323 bool memory_usage_above_limit =
324 resource_pool_->total_memory_usage_bytes() >
325 global_state_.soft_memory_limit_in_bytes;
327 if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
328 !memory_usage_above_limit)
329 return;
331 more_tiles_need_prepare_check_notifier_.Schedule();
332 return;
334 case REQUIRED_FOR_ACTIVATION:
335 ready_to_activate_check_notifier_.Schedule();
336 return;
337 case REQUIRED_FOR_DRAW:
338 ready_to_draw_check_notifier_.Schedule();
339 return;
342 NOTREACHED();
345 void TileManager::PrepareTiles(
346 const GlobalStateThatImpactsTilePriority& state) {
347 TRACE_EVENT0("cc", "TileManager::PrepareTiles");
349 global_state_ = state;
351 PrepareTilesMode prepare_tiles_mode = rasterizer_->GetPrepareTilesMode();
353 // TODO(hendrikw): Consider moving some of this code to the rasterizer.
354 if (prepare_tiles_mode != PrepareTilesMode::PREPARE_NONE) {
355 // We need to call CheckForCompletedTasks() once in-between each call
356 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
357 if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
358 tile_task_runner_->CheckForCompletedTasks();
359 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
362 FreeResourcesForReleasedTiles();
363 CleanUpReleasedTiles();
365 TileVector tiles_that_need_to_be_rasterized;
366 AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized,
367 scheduled_raster_task_limit_, false);
369 // Schedule tile tasks.
370 ScheduleTasks(tiles_that_need_to_be_rasterized);
372 did_notify_ready_to_activate_ = false;
373 did_notify_ready_to_draw_ = false;
374 } else {
375 if (global_state_.hard_memory_limit_in_bytes == 0) {
376 TileVector tiles_that_need_to_be_rasterized;
377 AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized,
378 scheduled_raster_task_limit_, false);
379 DCHECK(tiles_that_need_to_be_rasterized.empty());
382 did_notify_ready_to_activate_ = false;
383 did_notify_ready_to_draw_ = false;
384 ready_to_activate_notifier_.Schedule();
385 ready_to_draw_notifier_.Schedule();
388 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
389 "state", BasicStateAsValue());
391 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
392 resource_pool_->total_memory_usage_bytes() -
393 resource_pool_->acquired_memory_usage_bytes());
396 void TileManager::SynchronouslyRasterizeTiles(
397 const GlobalStateThatImpactsTilePriority& state) {
398 TRACE_EVENT0("cc", "TileManager::SynchronouslyRasterizeTiles");
400 DCHECK(rasterizer_->GetPrepareTilesMode() !=
401 PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES);
403 global_state_ = state;
405 FreeResourcesForReleasedTiles();
406 CleanUpReleasedTiles();
408 TileVector tiles_that_need_to_be_rasterized;
409 AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized,
410 std::numeric_limits<size_t>::max(), true);
412 // We must reduce the amount of unused resources before calling
413 // RunTasks to prevent usage from rising above limits.
414 resource_pool_->ReduceResourceUsage();
416 // Run and complete all raster task synchronously.
417 rasterizer_->RasterizeTiles(
418 tiles_that_need_to_be_rasterized, resource_pool_,
419 base::Bind(&TileManager::UpdateTileDrawInfo, base::Unretained(this)));
421 // Use on-demand raster for any required-for-draw tiles that have not been
422 // assigned memory after reaching a steady memory state.
423 // TODO(hendrikw): Figure out why this would improve jank on some tests - See
424 // crbug.com/449288
425 client_->BuildRasterQueue(&raster_priority_queue_,
426 global_state_.tree_priority,
427 RasterTilePriorityQueue::Type::ALL);
429 // Use on-demand raster for any tiles that have not been been assigned
430 // memory. This ensures that we draw even when OOM.
431 while (!raster_priority_queue_.IsEmpty()) {
432 Tile* tile = raster_priority_queue_.Top();
433 TileDrawInfo& draw_info = tile->draw_info();
435 if (tile->required_for_draw() && !draw_info.IsReadyToDraw()) {
436 draw_info.set_rasterize_on_demand();
437 client_->NotifyTileStateChanged(tile);
439 raster_priority_queue_.Pop();
441 raster_priority_queue_.Reset();
443 TRACE_EVENT_INSTANT1("cc", "DidRasterize", TRACE_EVENT_SCOPE_THREAD, "state",
444 BasicStateAsValue());
446 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
447 resource_pool_->total_memory_usage_bytes() -
448 resource_pool_->acquired_memory_usage_bytes());
451 void TileManager::UpdateVisibleTiles(
452 const GlobalStateThatImpactsTilePriority& state) {
453 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
455 tile_task_runner_->CheckForCompletedTasks();
457 DCHECK(rasterizer_);
458 PrepareTilesMode prepare_tiles_mode = rasterizer_->GetPrepareTilesMode();
459 if (prepare_tiles_mode != PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES)
460 SynchronouslyRasterizeTiles(state);
462 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
464 TRACE_EVENT_INSTANT1(
465 "cc",
466 "DidUpdateVisibleTiles",
467 TRACE_EVENT_SCOPE_THREAD,
468 "stats",
469 RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
470 update_visible_tiles_stats_ = RasterTaskCompletionStats();
473 scoped_refptr<base::debug::ConvertableToTraceFormat>
474 TileManager::BasicStateAsValue() const {
475 scoped_refptr<base::debug::TracedValue> value =
476 new base::debug::TracedValue();
477 BasicStateAsValueInto(value.get());
478 return value;
481 void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const {
482 state->SetInteger("tile_count", tiles_.size());
483 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
484 state->BeginDictionary("global_state");
485 global_state_.AsValueInto(state);
486 state->EndDictionary();
489 void TileManager::RebuildEvictionQueueIfNeeded() {
490 TRACE_EVENT1("cc",
491 "TileManager::RebuildEvictionQueueIfNeeded",
492 "eviction_priority_queue_is_up_to_date",
493 eviction_priority_queue_is_up_to_date_);
494 if (eviction_priority_queue_is_up_to_date_)
495 return;
497 eviction_priority_queue_.Reset();
498 client_->BuildEvictionQueue(&eviction_priority_queue_,
499 global_state_.tree_priority);
500 eviction_priority_queue_is_up_to_date_ = true;
503 bool TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
504 const MemoryUsage& limit,
505 MemoryUsage* usage) {
506 while (usage->Exceeds(limit)) {
507 RebuildEvictionQueueIfNeeded();
508 if (eviction_priority_queue_.IsEmpty())
509 return false;
511 Tile* tile = eviction_priority_queue_.Top();
512 *usage -= MemoryUsage::FromTile(tile);
513 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
514 eviction_priority_queue_.Pop();
516 return true;
519 bool TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
520 const MemoryUsage& limit,
521 const TilePriority& other_priority,
522 MemoryUsage* usage) {
523 while (usage->Exceeds(limit)) {
524 RebuildEvictionQueueIfNeeded();
525 if (eviction_priority_queue_.IsEmpty())
526 return false;
528 Tile* tile = eviction_priority_queue_.Top();
529 if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
530 return false;
532 *usage -= MemoryUsage::FromTile(tile);
533 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
534 eviction_priority_queue_.Pop();
536 return true;
539 bool TileManager::TilePriorityViolatesMemoryPolicy(
540 const TilePriority& priority) {
541 switch (global_state_.memory_limit_policy) {
542 case ALLOW_NOTHING:
543 return true;
544 case ALLOW_ABSOLUTE_MINIMUM:
545 return priority.priority_bin > TilePriority::NOW;
546 case ALLOW_PREPAINT_ONLY:
547 return priority.priority_bin > TilePriority::SOON;
548 case ALLOW_ANYTHING:
549 return priority.distance_to_visible ==
550 std::numeric_limits<float>::infinity();
552 NOTREACHED();
553 return true;
556 void TileManager::AssignGpuMemoryToTiles(
557 TileVector* tiles_that_need_to_be_rasterized,
558 size_t scheduled_raster_task_limit,
559 bool required_for_draw_only) {
560 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
562 // Maintain the list of released resources that can potentially be re-used
563 // or deleted.
564 // If this operation becomes expensive too, only do this after some
565 // resource(s) was returned. Note that in that case, one also need to
566 // invalidate when releasing some resource from the pool.
567 resource_pool_->CheckBusyResources(false);
569 // Now give memory out to the tiles until we're out, and build
570 // the needs-to-be-rasterized queue.
571 unsigned schedule_priority = 1u;
572 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
573 bool had_enough_memory_to_schedule_tiles_needed_now = true;
575 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
576 global_state_.num_resources_limit);
577 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
578 global_state_.num_resources_limit);
579 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
580 resource_pool_->acquired_resource_count());
582 eviction_priority_queue_is_up_to_date_ = false;
583 // TODO(vmpstr): Take this as a parameter and have SynchronousRaster build a
584 // REQUIRED_FOR_DRAW queue.
585 client_->BuildRasterQueue(&raster_priority_queue_,
586 global_state_.tree_priority,
587 RasterTilePriorityQueue::Type::ALL);
589 while (!raster_priority_queue_.IsEmpty()) {
590 Tile* tile = raster_priority_queue_.Top();
592 // TODO(vmpstr): Remove this when the iterator returns the correct tiles
593 // to draw for GPU rasterization.
594 if (required_for_draw_only) {
595 if (!tile->required_for_draw()) {
596 raster_priority_queue_.Pop();
597 continue;
600 TilePriority priority = tile->combined_priority();
602 if (TilePriorityViolatesMemoryPolicy(priority)) {
603 TRACE_EVENT_INSTANT0(
604 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
605 TRACE_EVENT_SCOPE_THREAD);
606 break;
609 // We won't be able to schedule this tile, so break out early.
610 if (tiles_that_need_to_be_rasterized->size() >=
611 scheduled_raster_task_limit) {
612 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
613 break;
616 TileDrawInfo& draw_info = tile->draw_info();
617 tile->scheduled_priority_ = schedule_priority++;
619 DCHECK(draw_info.mode() == TileDrawInfo::PICTURE_PILE_MODE ||
620 !draw_info.IsReadyToDraw());
622 // If the tile already has a raster_task, then the memory used by it is
623 // already accounted for in memory_usage. Otherwise, we'll have to acquire
624 // more memory to create a raster task.
625 MemoryUsage memory_required_by_tile_to_be_scheduled;
626 if (!tile->raster_task_.get()) {
627 memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
628 tile->desired_texture_size(), resource_pool_->resource_format());
631 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
633 // This is the memory limit that will be used by this tile. Depending on
634 // the tile priority, it will be one of hard_memory_limit or
635 // soft_memory_limit.
636 MemoryUsage& tile_memory_limit =
637 tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
639 bool memory_usage_is_within_limit =
640 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
641 tile_memory_limit - memory_required_by_tile_to_be_scheduled,
642 priority, &memory_usage);
644 // If we couldn't fit the tile into our current memory limit, then we're
645 // done.
646 if (!memory_usage_is_within_limit) {
647 if (tile_is_needed_now)
648 had_enough_memory_to_schedule_tiles_needed_now = false;
649 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
650 break;
653 memory_usage += memory_required_by_tile_to_be_scheduled;
654 tiles_that_need_to_be_rasterized->push_back(tile);
655 raster_priority_queue_.Pop();
658 // Note that we should try and further reduce memory in case the above loop
659 // didn't reduce memory. This ensures that we always release as many resources
660 // as possible to stay within the memory limit.
661 FreeTileResourcesUntilUsageIsWithinLimit(hard_memory_limit, &memory_usage);
663 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
664 !had_enough_memory_to_schedule_tiles_needed_now);
665 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
667 memory_stats_from_last_assign_.total_budget_in_bytes =
668 global_state_.hard_memory_limit_in_bytes;
669 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
670 memory_stats_from_last_assign_.had_enough_memory =
671 had_enough_memory_to_schedule_tiles_needed_now;
673 raster_priority_queue_.Reset();
675 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
676 "all_tiles_that_need_to_be_rasterized_are_scheduled",
677 all_tiles_that_need_to_be_rasterized_are_scheduled_,
678 "had_enough_memory_to_schedule_tiles_needed_now",
679 had_enough_memory_to_schedule_tiles_needed_now);
682 void TileManager::FreeResourcesForTile(Tile* tile) {
683 TileDrawInfo& draw_info = tile->draw_info();
684 if (draw_info.resource_)
685 resource_pool_->ReleaseResource(draw_info.resource_.Pass());
688 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
689 Tile* tile) {
690 bool was_ready_to_draw = tile->IsReadyToDraw();
691 FreeResourcesForTile(tile);
692 if (was_ready_to_draw)
693 client_->NotifyTileStateChanged(tile);
696 void TileManager::ScheduleTasks(
697 const TileVector& tiles_that_need_to_be_rasterized) {
698 TRACE_EVENT1("cc",
699 "TileManager::ScheduleTasks",
700 "count",
701 tiles_that_need_to_be_rasterized.size());
703 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
705 raster_queue_.Reset();
707 // Build a new task queue containing all task currently needed. Tasks
708 // are added in order of priority, highest priority task first.
709 for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
710 it != tiles_that_need_to_be_rasterized.end();
711 ++it) {
712 Tile* tile = *it;
713 TileDrawInfo& draw_info = tile->draw_info();
715 DCHECK(draw_info.requires_resource());
716 DCHECK(!draw_info.resource_);
718 if (!tile->raster_task_.get())
719 tile->raster_task_ = CreateRasterTask(tile);
721 TaskSetCollection task_sets;
722 if (tile->required_for_activation())
723 task_sets.set(REQUIRED_FOR_ACTIVATION);
724 if (tile->required_for_draw())
725 task_sets.set(REQUIRED_FOR_DRAW);
726 task_sets.set(ALL);
727 raster_queue_.items.push_back(
728 TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
731 // We must reduce the amount of unused resoruces before calling
732 // ScheduleTasks to prevent usage from rising above limits.
733 resource_pool_->ReduceResourceUsage();
735 // Schedule running of |raster_queue_|. This replaces any previously
736 // scheduled tasks and effectively cancels all tasks not present
737 // in |raster_queue_|.
738 tile_task_runner_->ScheduleTasks(&raster_queue_);
740 // It's now safe to clean up orphan tasks as raster worker pool is not
741 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
742 // been called.
743 orphan_raster_tasks_.clear();
745 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
748 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
749 Tile* tile,
750 SkPixelRef* pixel_ref) {
751 return make_scoped_refptr(new ImageDecodeTaskImpl(
752 pixel_ref,
753 tile->layer_id(),
754 base::Bind(&TileManager::OnImageDecodeTaskCompleted,
755 base::Unretained(this),
756 tile->layer_id(),
757 base::Unretained(pixel_ref))));
760 scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
761 scoped_ptr<ScopedResource> resource =
762 resource_pool_->AcquireResource(tile->desired_texture_size());
763 const ScopedResource* const_resource = resource.get();
765 // Create and queue all image decode tasks that this tile depends on.
766 ImageDecodeTask::Vector decode_tasks;
767 PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
768 std::vector<SkPixelRef*> pixel_refs;
769 tile->raster_source()->GatherPixelRefs(
770 tile->content_rect(), tile->contents_scale(), &pixel_refs);
771 for (SkPixelRef* pixel_ref : pixel_refs) {
772 uint32_t id = pixel_ref->getGenerationID();
774 // Append existing image decode task if available.
775 PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
776 if (decode_task_it != existing_pixel_refs.end()) {
777 decode_tasks.push_back(decode_task_it->second);
778 continue;
781 // Create and append new image decode task for this pixel ref.
782 scoped_refptr<ImageDecodeTask> decode_task =
783 CreateImageDecodeTask(tile, pixel_ref);
784 decode_tasks.push_back(decode_task);
785 existing_pixel_refs[id] = decode_task;
788 return make_scoped_refptr(new RasterTaskImpl(
789 const_resource, tile->raster_source(), tile->content_rect(),
790 tile->contents_scale(), tile->combined_priority().resolution,
791 tile->layer_id(), static_cast<const void*>(tile),
792 tile->source_frame_number(), tile->use_picture_analysis(),
793 base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this),
794 tile->id(), base::Passed(&resource)),
795 &decode_tasks));
798 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
799 SkPixelRef* pixel_ref,
800 bool was_canceled) {
801 // If the task was canceled, we need to clean it up
802 // from |image_decode_tasks_|.
803 if (!was_canceled)
804 return;
806 LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
807 if (layer_it == image_decode_tasks_.end())
808 return;
810 PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
811 PixelRefTaskMap::iterator task_it =
812 pixel_ref_tasks.find(pixel_ref->getGenerationID());
814 if (task_it != pixel_ref_tasks.end())
815 pixel_ref_tasks.erase(task_it);
818 void TileManager::OnRasterTaskCompleted(
819 Tile::Id tile_id,
820 scoped_ptr<ScopedResource> resource,
821 const RasterSource::SolidColorAnalysis& analysis,
822 bool was_canceled) {
823 DCHECK(tiles_.find(tile_id) != tiles_.end());
825 Tile* tile = tiles_[tile_id];
826 DCHECK(tile->raster_task_.get());
827 orphan_raster_tasks_.push_back(tile->raster_task_);
828 tile->raster_task_ = nullptr;
830 if (was_canceled) {
831 ++update_visible_tiles_stats_.canceled_count;
832 resource_pool_->ReleaseResource(resource.Pass());
833 return;
836 UpdateTileDrawInfo(tile, resource.Pass(), analysis);
839 void TileManager::UpdateTileDrawInfo(
840 Tile* tile,
841 scoped_ptr<ScopedResource> resource,
842 const RasterSource::SolidColorAnalysis& analysis) {
843 TileDrawInfo& draw_info = tile->draw_info();
845 ++update_visible_tiles_stats_.completed_count;
847 if (analysis.is_solid_color) {
848 draw_info.set_solid_color(analysis.solid_color);
849 resource_pool_->ReleaseResource(resource.Pass());
850 } else {
851 draw_info.set_use_resource();
852 draw_info.resource_ = resource.Pass();
855 client_->NotifyTileStateChanged(tile);
858 scoped_refptr<Tile> TileManager::CreateTile(
859 RasterSource* raster_source,
860 const gfx::Size& desired_texture_size,
861 const gfx::Rect& content_rect,
862 float contents_scale,
863 int layer_id,
864 int source_frame_number,
865 int flags) {
866 scoped_refptr<Tile> tile = make_scoped_refptr(
867 new Tile(this, raster_source, desired_texture_size, content_rect,
868 contents_scale, layer_id, source_frame_number, flags));
869 DCHECK(tiles_.find(tile->id()) == tiles_.end());
871 tiles_[tile->id()] = tile.get();
872 used_layer_counts_[tile->layer_id()]++;
873 return tile;
876 void TileManager::SetTileTaskRunnerForTesting(
877 TileTaskRunner* tile_task_runner) {
878 tile_task_runner_ = tile_task_runner;
879 tile_task_runner_->SetClient(this);
882 bool TileManager::IsReadyToActivate() const {
883 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
884 const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
886 // TODO(vmpstr): Replace this with building a REQUIRED_TO_ACTIVATE raster
887 // queue and checking if it's empty.
888 for (const auto& layer : layers) {
889 if (!layer->AllTilesRequiredForActivationAreReadyToDraw())
890 return false;
893 return true;
896 bool TileManager::IsReadyToDraw() const {
897 const std::vector<PictureLayerImpl*>& layers = client_->GetPictureLayers();
899 // TODO(vmpstr): Replace this with building a REQUIRED_TO_DRAW raster queue
900 // and checking if it's empty.
901 for (const auto& layer : layers) {
902 if (!layer->AllTilesRequiredForDrawAreReadyToDraw())
903 return false;
906 return true;
909 void TileManager::NotifyReadyToActivate() {
910 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
911 if (did_notify_ready_to_activate_)
912 return;
913 client_->NotifyReadyToActivate();
914 did_notify_ready_to_activate_ = true;
917 void TileManager::NotifyReadyToDraw() {
918 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
919 if (did_notify_ready_to_draw_)
920 return;
921 client_->NotifyReadyToDraw();
922 did_notify_ready_to_draw_ = true;
925 void TileManager::CheckIfReadyToActivate() {
926 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
928 tile_task_runner_->CheckForCompletedTasks();
929 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
931 if (did_notify_ready_to_activate_)
932 return;
933 if (!IsReadyToActivate())
934 return;
936 NotifyReadyToActivate();
939 void TileManager::CheckIfReadyToDraw() {
940 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
942 tile_task_runner_->CheckForCompletedTasks();
943 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
945 if (did_notify_ready_to_draw_)
946 return;
947 if (!IsReadyToDraw())
948 return;
950 NotifyReadyToDraw();
953 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
954 tile_task_runner_->CheckForCompletedTasks();
955 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
957 // When OOM, keep re-assigning memory until we reach a steady state
958 // where top-priority tiles are initialized.
959 TileVector tiles_that_need_to_be_rasterized;
960 AssignGpuMemoryToTiles(&tiles_that_need_to_be_rasterized,
961 scheduled_raster_task_limit_, false);
963 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
964 // steady memory state. Keep scheduling tasks until we reach this state.
965 if (!tiles_that_need_to_be_rasterized.empty()) {
966 ScheduleTasks(tiles_that_need_to_be_rasterized);
967 return;
970 FreeResourcesForReleasedTiles();
972 resource_pool_->ReduceResourceUsage();
974 // We don't reserve memory for required-for-activation tiles during
975 // accelerated gestures, so we just postpone activation when we don't
976 // have these tiles, and activate after the accelerated gesture.
977 // Likewise if we don't allow any tiles (as is the case when we're
978 // invisible), if we have tiles that aren't ready, then we shouldn't
979 // activate as activation can cause checkerboards.
980 bool allow_rasterize_on_demand =
981 global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
982 global_state_.memory_limit_policy != ALLOW_NOTHING;
984 // Use on-demand raster for any required-for-activation tiles that have
985 // not been been assigned memory after reaching a steady memory state. This
986 // ensures that we activate even when OOM. Note that we have to rebuilt the
987 // queue in case the last AssignGpuMemoryToTiles evicted some tiles that
988 // would otherwise not be picked up by the old raster queue.
989 // TODO(vmpstr): Make this use REQUIRED_FOR_ACTIVAITON queue.
990 client_->BuildRasterQueue(&raster_priority_queue_,
991 global_state_.tree_priority,
992 RasterTilePriorityQueue::Type::ALL);
993 bool ready_to_activate = true;
994 while (!raster_priority_queue_.IsEmpty()) {
995 Tile* tile = raster_priority_queue_.Top();
996 TileDrawInfo& draw_info = tile->draw_info();
998 if (tile->required_for_activation() && !draw_info.IsReadyToDraw()) {
999 // If we can't raster on demand, give up early (and don't activate).
1000 if (!allow_rasterize_on_demand) {
1001 ready_to_activate = false;
1002 break;
1005 draw_info.set_rasterize_on_demand();
1006 client_->NotifyTileStateChanged(tile);
1008 raster_priority_queue_.Pop();
1011 if (ready_to_activate) {
1012 DCHECK(IsReadyToActivate());
1013 ready_to_activate_check_notifier_.Schedule();
1015 raster_priority_queue_.Reset();
1018 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
1021 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count)
1022 : memory_bytes_(memory_bytes), resource_count_(resource_count) {
1025 // static
1026 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
1027 const gfx::Size& size,
1028 ResourceFormat format) {
1029 return MemoryUsage(Resource::MemorySizeBytes(size, format), 1);
1032 // static
1033 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
1034 const TileDrawInfo& draw_info = tile->draw_info();
1035 if (draw_info.resource_) {
1036 return MemoryUsage::FromConfig(draw_info.resource_->size(),
1037 draw_info.resource_->format());
1039 return MemoryUsage();
1042 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
1043 const MemoryUsage& other) {
1044 memory_bytes_ += other.memory_bytes_;
1045 resource_count_ += other.resource_count_;
1046 return *this;
1049 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
1050 const MemoryUsage& other) {
1051 memory_bytes_ -= other.memory_bytes_;
1052 resource_count_ -= other.resource_count_;
1053 return *this;
1056 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
1057 const MemoryUsage& other) {
1058 MemoryUsage result = *this;
1059 result -= other;
1060 return result;
1063 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
1064 return memory_bytes_ > limit.memory_bytes_ ||
1065 resource_count_ > limit.resource_count_;
1068 } // namespace cc