Enable right clicking on the applist doodle web contents and log the data.
[chromium-blink-merge.git] / cc / resources / tile_manager.cc
blob00ae3da6e92fed3b9a96a0d8e5b781df8541b4d8
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/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/trace_event/trace_event_argument.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 const base::Callback<void(bool was_canceled)>& reply)
139 : pixel_ref_(skia::SharePtr(pixel_ref)),
140 reply_(reply) {}
142 // Overridden from Task:
143 void RunOnWorkerThread() override {
144 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
146 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
147 pixel_ref_.get());
148 // This will cause the image referred to by pixel ref to be decoded.
149 pixel_ref_->lockPixels();
150 pixel_ref_->unlockPixels();
153 // Overridden from TileTask:
154 void ScheduleOnOriginThread(TileTaskClient* client) override {}
155 void CompleteOnOriginThread(TileTaskClient* client) override {}
156 void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
158 protected:
159 ~ImageDecodeTaskImpl() override {}
161 private:
162 skia::RefPtr<SkPixelRef> pixel_ref_;
163 const base::Callback<void(bool was_canceled)> reply_;
165 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
168 const char* TaskSetName(TaskSet task_set) {
169 switch (task_set) {
170 case TileManager::ALL:
171 return "ALL";
172 case TileManager::REQUIRED_FOR_ACTIVATION:
173 return "REQUIRED_FOR_ACTIVATION";
174 case TileManager::REQUIRED_FOR_DRAW:
175 return "REQUIRED_FOR_DRAW";
178 NOTREACHED();
179 return "Invalid TaskSet";
182 } // namespace
184 RasterTaskCompletionStats::RasterTaskCompletionStats()
185 : completed_count(0u), canceled_count(0u) {}
187 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
188 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
189 scoped_refptr<base::trace_event::TracedValue> state =
190 new base::trace_event::TracedValue();
191 state->SetInteger("completed_count", stats.completed_count);
192 state->SetInteger("canceled_count", stats.canceled_count);
193 return state;
196 // static
197 scoped_ptr<TileManager> TileManager::Create(
198 TileManagerClient* client,
199 base::SequencedTaskRunner* task_runner,
200 ResourcePool* resource_pool,
201 TileTaskRunner* tile_task_runner,
202 Rasterizer* rasterizer,
203 size_t scheduled_raster_task_limit) {
204 return make_scoped_ptr(new TileManager(client, task_runner, resource_pool,
205 tile_task_runner, rasterizer,
206 scheduled_raster_task_limit));
209 TileManager::TileManager(
210 TileManagerClient* client,
211 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
212 ResourcePool* resource_pool,
213 TileTaskRunner* tile_task_runner,
214 Rasterizer* rasterizer,
215 size_t scheduled_raster_task_limit)
216 : client_(client),
217 task_runner_(task_runner),
218 resource_pool_(resource_pool),
219 tile_task_runner_(tile_task_runner),
220 rasterizer_(rasterizer),
221 scheduled_raster_task_limit_(scheduled_raster_task_limit),
222 all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
223 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
224 did_oom_on_last_assign_(false),
225 ready_to_activate_notifier_(
226 task_runner_.get(),
227 base::Bind(&TileManager::NotifyReadyToActivate,
228 base::Unretained(this))),
229 ready_to_draw_notifier_(
230 task_runner_.get(),
231 base::Bind(&TileManager::NotifyReadyToDraw, base::Unretained(this))),
232 ready_to_activate_check_notifier_(
233 task_runner_.get(),
234 base::Bind(&TileManager::CheckIfReadyToActivate,
235 base::Unretained(this))),
236 ready_to_draw_check_notifier_(
237 task_runner_.get(),
238 base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))),
239 more_tiles_need_prepare_check_notifier_(
240 task_runner_.get(),
241 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
242 base::Unretained(this))),
243 did_notify_ready_to_activate_(false),
244 did_notify_ready_to_draw_(false) {
245 tile_task_runner_->SetClient(this);
248 TileManager::~TileManager() {
249 // Reset global state and manage. This should cause
250 // our memory usage to drop to zero.
251 global_state_ = GlobalStateThatImpactsTilePriority();
253 TileTaskQueue empty;
254 tile_task_runner_->ScheduleTasks(&empty);
255 orphan_raster_tasks_.clear();
257 // This should finish all pending tasks and release any uninitialized
258 // resources.
259 tile_task_runner_->Shutdown();
260 tile_task_runner_->CheckForCompletedTasks();
262 FreeResourcesForReleasedTiles();
263 CleanUpReleasedTiles();
266 void TileManager::Release(Tile* tile) {
267 released_tiles_.push_back(tile);
270 TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const {
271 TaskSetCollection tasks_that_should_be_forced_to_complete;
272 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY)
273 tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true;
274 return tasks_that_should_be_forced_to_complete;
277 void TileManager::FreeResourcesForReleasedTiles() {
278 for (std::vector<Tile*>::iterator it = released_tiles_.begin();
279 it != released_tiles_.end();
280 ++it) {
281 Tile* tile = *it;
282 FreeResourcesForTile(tile);
286 void TileManager::CleanUpReleasedTiles() {
287 std::vector<Tile*>::iterator it = released_tiles_.begin();
288 while (it != released_tiles_.end()) {
289 Tile* tile = *it;
291 if (tile->HasRasterTask()) {
292 ++it;
293 continue;
296 DCHECK(!tile->HasResource());
297 DCHECK(tiles_.find(tile->id()) != tiles_.end());
298 tiles_.erase(tile->id());
300 LayerCountMap::iterator layer_it =
301 used_layer_counts_.find(tile->layer_id());
302 DCHECK_GT(layer_it->second, 0);
303 if (--layer_it->second == 0) {
304 used_layer_counts_.erase(layer_it);
305 image_decode_tasks_.erase(tile->layer_id());
308 delete tile;
309 it = released_tiles_.erase(it);
313 void TileManager::DidFinishRunningTileTasks(TaskSet task_set) {
314 TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
315 TaskSetName(task_set));
317 switch (task_set) {
318 case ALL: {
319 bool memory_usage_above_limit =
320 resource_pool_->total_memory_usage_bytes() >
321 global_state_.soft_memory_limit_in_bytes;
323 if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
324 !memory_usage_above_limit)
325 return;
327 more_tiles_need_prepare_check_notifier_.Schedule();
328 return;
330 case REQUIRED_FOR_ACTIVATION:
331 ready_to_activate_check_notifier_.Schedule();
332 return;
333 case REQUIRED_FOR_DRAW:
334 ready_to_draw_check_notifier_.Schedule();
335 return;
338 NOTREACHED();
341 void TileManager::PrepareTiles(
342 const GlobalStateThatImpactsTilePriority& state) {
343 TRACE_EVENT0("cc", "TileManager::PrepareTiles");
345 global_state_ = state;
347 PrepareTilesMode prepare_tiles_mode = rasterizer_->GetPrepareTilesMode();
349 // TODO(hendrikw): Consider moving some of this code to the rasterizer.
350 if (prepare_tiles_mode != PrepareTilesMode::PREPARE_NONE) {
351 // We need to call CheckForCompletedTasks() once in-between each call
352 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
353 if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
354 tile_task_runner_->CheckForCompletedTasks();
355 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
358 FreeResourcesForReleasedTiles();
359 CleanUpReleasedTiles();
361 TileVector tiles_that_need_to_be_rasterized;
362 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
363 client_->BuildRasterQueue(global_state_.tree_priority,
364 RasterTilePriorityQueue::Type::ALL));
365 // Inform the client that will likely require a draw if the top tile is
366 // required for draw.
367 client_->SetIsLikelyToRequireADraw(
368 !raster_priority_queue->IsEmpty() &&
369 raster_priority_queue->Top()->required_for_draw());
370 AssignGpuMemoryToTiles(raster_priority_queue.get(),
371 scheduled_raster_task_limit_,
372 &tiles_that_need_to_be_rasterized);
374 // Schedule tile tasks.
375 ScheduleTasks(tiles_that_need_to_be_rasterized);
377 did_notify_ready_to_activate_ = false;
378 did_notify_ready_to_draw_ = false;
379 } else {
380 if (global_state_.hard_memory_limit_in_bytes == 0) {
381 resource_pool_->CheckBusyResources(false);
382 MemoryUsage memory_limit(0, 0);
383 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
384 resource_pool_->acquired_resource_count());
385 FreeTileResourcesUntilUsageIsWithinLimit(nullptr, memory_limit,
386 &memory_usage);
389 did_notify_ready_to_activate_ = false;
390 did_notify_ready_to_draw_ = false;
391 ready_to_activate_notifier_.Schedule();
392 ready_to_draw_notifier_.Schedule();
395 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
396 "state", BasicStateAsValue());
398 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
399 resource_pool_->total_memory_usage_bytes() -
400 resource_pool_->acquired_memory_usage_bytes());
403 void TileManager::SynchronouslyRasterizeTiles(
404 const GlobalStateThatImpactsTilePriority& state) {
405 TRACE_EVENT0("cc", "TileManager::SynchronouslyRasterizeTiles");
407 DCHECK(rasterizer_->GetPrepareTilesMode() !=
408 PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES);
410 global_state_ = state;
412 FreeResourcesForReleasedTiles();
413 CleanUpReleasedTiles();
415 scoped_ptr<RasterTilePriorityQueue> required_for_draw_queue(
416 client_->BuildRasterQueue(
417 global_state_.tree_priority,
418 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
419 TileVector tiles_that_need_to_be_rasterized;
420 AssignGpuMemoryToTiles(required_for_draw_queue.get(),
421 std::numeric_limits<size_t>::max(),
422 &tiles_that_need_to_be_rasterized);
424 // We must reduce the amount of unused resources before calling
425 // RunTasks to prevent usage from rising above limits.
426 resource_pool_->ReduceResourceUsage();
428 // Run and complete all raster task synchronously.
429 rasterizer_->RasterizeTiles(
430 tiles_that_need_to_be_rasterized, resource_pool_,
431 tile_task_runner_->GetResourceFormat(),
432 base::Bind(&TileManager::UpdateTileDrawInfo, base::Unretained(this)));
434 // Use on-demand raster for any required-for-draw tiles that have not been
435 // assigned memory after reaching a steady memory state.
436 // TODO(hendrikw): Figure out why this would improve jank on some tests - See
437 // crbug.com/449288
438 required_for_draw_queue = client_->BuildRasterQueue(
439 global_state_.tree_priority,
440 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
442 // Change to OOM mode for any tiles that have not been been assigned memory.
443 // This ensures that we draw even when OOM.
444 for (; !required_for_draw_queue->IsEmpty(); required_for_draw_queue->Pop()) {
445 Tile* tile = required_for_draw_queue->Top();
446 tile->draw_info().set_oom();
447 client_->NotifyTileStateChanged(tile);
450 TRACE_EVENT_INSTANT1("cc", "DidRasterize", TRACE_EVENT_SCOPE_THREAD, "state",
451 BasicStateAsValue());
453 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
454 resource_pool_->total_memory_usage_bytes() -
455 resource_pool_->acquired_memory_usage_bytes());
458 void TileManager::UpdateVisibleTiles(
459 const GlobalStateThatImpactsTilePriority& state) {
460 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
462 tile_task_runner_->CheckForCompletedTasks();
464 DCHECK(rasterizer_);
465 PrepareTilesMode prepare_tiles_mode = rasterizer_->GetPrepareTilesMode();
466 if (prepare_tiles_mode != PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES)
467 SynchronouslyRasterizeTiles(state);
469 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
471 TRACE_EVENT_INSTANT1(
472 "cc",
473 "DidUpdateVisibleTiles",
474 TRACE_EVENT_SCOPE_THREAD,
475 "stats",
476 RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
477 update_visible_tiles_stats_ = RasterTaskCompletionStats();
480 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
481 TileManager::BasicStateAsValue() const {
482 scoped_refptr<base::trace_event::TracedValue> value =
483 new base::trace_event::TracedValue();
484 BasicStateAsValueInto(value.get());
485 return value;
488 void TileManager::BasicStateAsValueInto(
489 base::trace_event::TracedValue* state) const {
490 state->SetInteger("tile_count", tiles_.size());
491 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
492 state->BeginDictionary("global_state");
493 global_state_.AsValueInto(state);
494 state->EndDictionary();
497 scoped_ptr<EvictionTilePriorityQueue>
498 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
499 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
500 const MemoryUsage& limit,
501 MemoryUsage* usage) {
502 while (usage->Exceeds(limit)) {
503 if (!eviction_priority_queue) {
504 eviction_priority_queue =
505 client_->BuildEvictionQueue(global_state_.tree_priority);
507 if (eviction_priority_queue->IsEmpty())
508 break;
510 Tile* tile = eviction_priority_queue->Top();
511 *usage -= MemoryUsage::FromTile(tile);
512 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
513 eviction_priority_queue->Pop();
515 return eviction_priority_queue;
518 scoped_ptr<EvictionTilePriorityQueue>
519 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
520 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
521 const MemoryUsage& limit,
522 const TilePriority& other_priority,
523 MemoryUsage* usage) {
524 while (usage->Exceeds(limit)) {
525 if (!eviction_priority_queue) {
526 eviction_priority_queue =
527 client_->BuildEvictionQueue(global_state_.tree_priority);
529 if (eviction_priority_queue->IsEmpty())
530 break;
532 Tile* tile = eviction_priority_queue->Top();
533 if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
534 break;
536 *usage -= MemoryUsage::FromTile(tile);
537 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
538 eviction_priority_queue->Pop();
540 return eviction_priority_queue;
543 bool TileManager::TilePriorityViolatesMemoryPolicy(
544 const TilePriority& priority) {
545 switch (global_state_.memory_limit_policy) {
546 case ALLOW_NOTHING:
547 return true;
548 case ALLOW_ABSOLUTE_MINIMUM:
549 return priority.priority_bin > TilePriority::NOW;
550 case ALLOW_PREPAINT_ONLY:
551 return priority.priority_bin > TilePriority::SOON;
552 case ALLOW_ANYTHING:
553 return priority.distance_to_visible ==
554 std::numeric_limits<float>::infinity();
556 NOTREACHED();
557 return true;
560 void TileManager::AssignGpuMemoryToTiles(
561 RasterTilePriorityQueue* raster_priority_queue,
562 size_t scheduled_raster_task_limit,
563 TileVector* tiles_that_need_to_be_rasterized) {
564 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
566 // Maintain the list of released resources that can potentially be re-used
567 // or deleted. If this operation becomes expensive too, only do this after
568 // some resource(s) was returned. Note that in that case, one also need to
569 // invalidate when releasing some resource from the pool.
570 resource_pool_->CheckBusyResources(false);
572 // Now give memory out to the tiles until we're out, and build
573 // the needs-to-be-rasterized queue.
574 unsigned schedule_priority = 1u;
575 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
576 bool had_enough_memory_to_schedule_tiles_needed_now = true;
578 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
579 global_state_.num_resources_limit);
580 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
581 global_state_.num_resources_limit);
582 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
583 resource_pool_->acquired_resource_count());
585 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
586 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
587 Tile* tile = raster_priority_queue->Top();
588 TilePriority priority = tile->combined_priority();
590 if (TilePriorityViolatesMemoryPolicy(priority)) {
591 TRACE_EVENT_INSTANT0(
592 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
593 TRACE_EVENT_SCOPE_THREAD);
594 break;
597 // We won't be able to schedule this tile, so break out early.
598 if (tiles_that_need_to_be_rasterized->size() >=
599 scheduled_raster_task_limit) {
600 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
601 break;
604 TileDrawInfo& draw_info = tile->draw_info();
605 tile->scheduled_priority_ = schedule_priority++;
607 DCHECK_IMPLIES(draw_info.mode() != TileDrawInfo::OOM_MODE,
608 !draw_info.IsReadyToDraw());
610 // If the tile already has a raster_task, then the memory used by it is
611 // already accounted for in memory_usage. Otherwise, we'll have to acquire
612 // more memory to create a raster task.
613 MemoryUsage memory_required_by_tile_to_be_scheduled;
614 if (!tile->raster_task_.get()) {
615 memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
616 tile->desired_texture_size(), tile_task_runner_->GetResourceFormat());
619 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
621 // This is the memory limit that will be used by this tile. Depending on
622 // the tile priority, it will be one of hard_memory_limit or
623 // soft_memory_limit.
624 MemoryUsage& tile_memory_limit =
625 tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
627 const MemoryUsage& scheduled_tile_memory_limit =
628 tile_memory_limit - memory_required_by_tile_to_be_scheduled;
629 eviction_priority_queue =
630 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
631 eviction_priority_queue.Pass(), scheduled_tile_memory_limit,
632 priority, &memory_usage);
633 bool memory_usage_is_within_limit =
634 !memory_usage.Exceeds(scheduled_tile_memory_limit);
636 // If we couldn't fit the tile into our current memory limit, then we're
637 // done.
638 if (!memory_usage_is_within_limit) {
639 if (tile_is_needed_now)
640 had_enough_memory_to_schedule_tiles_needed_now = false;
641 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
642 break;
645 memory_usage += memory_required_by_tile_to_be_scheduled;
646 tiles_that_need_to_be_rasterized->push_back(tile);
649 // Note that we should try and further reduce memory in case the above loop
650 // didn't reduce memory. This ensures that we always release as many resources
651 // as possible to stay within the memory limit.
652 eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
653 eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage);
655 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
656 !had_enough_memory_to_schedule_tiles_needed_now);
657 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
659 memory_stats_from_last_assign_.total_budget_in_bytes =
660 global_state_.hard_memory_limit_in_bytes;
661 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
662 memory_stats_from_last_assign_.had_enough_memory =
663 had_enough_memory_to_schedule_tiles_needed_now;
665 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
666 "all_tiles_that_need_to_be_rasterized_are_scheduled",
667 all_tiles_that_need_to_be_rasterized_are_scheduled_,
668 "had_enough_memory_to_schedule_tiles_needed_now",
669 had_enough_memory_to_schedule_tiles_needed_now);
672 void TileManager::FreeResourcesForTile(Tile* tile) {
673 TileDrawInfo& draw_info = tile->draw_info();
674 if (draw_info.resource_)
675 resource_pool_->ReleaseResource(draw_info.resource_.Pass());
678 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
679 Tile* tile) {
680 bool was_ready_to_draw = tile->IsReadyToDraw();
681 FreeResourcesForTile(tile);
682 if (was_ready_to_draw)
683 client_->NotifyTileStateChanged(tile);
686 void TileManager::ScheduleTasks(
687 const TileVector& tiles_that_need_to_be_rasterized) {
688 TRACE_EVENT1("cc",
689 "TileManager::ScheduleTasks",
690 "count",
691 tiles_that_need_to_be_rasterized.size());
693 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
695 raster_queue_.Reset();
697 // Build a new task queue containing all task currently needed. Tasks
698 // are added in order of priority, highest priority task first.
699 for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
700 it != tiles_that_need_to_be_rasterized.end();
701 ++it) {
702 Tile* tile = *it;
703 TileDrawInfo& draw_info = tile->draw_info();
705 DCHECK(draw_info.requires_resource());
706 DCHECK(!draw_info.resource_);
708 if (!tile->raster_task_.get())
709 tile->raster_task_ = CreateRasterTask(tile);
711 TaskSetCollection task_sets;
712 if (tile->required_for_activation())
713 task_sets.set(REQUIRED_FOR_ACTIVATION);
714 if (tile->required_for_draw())
715 task_sets.set(REQUIRED_FOR_DRAW);
716 task_sets.set(ALL);
717 raster_queue_.items.push_back(
718 TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
721 // We must reduce the amount of unused resoruces before calling
722 // ScheduleTasks to prevent usage from rising above limits.
723 resource_pool_->ReduceResourceUsage();
725 // Schedule running of |raster_queue_|. This replaces any previously
726 // scheduled tasks and effectively cancels all tasks not present
727 // in |raster_queue_|.
728 tile_task_runner_->ScheduleTasks(&raster_queue_);
730 // It's now safe to clean up orphan tasks as raster worker pool is not
731 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
732 // been called.
733 orphan_raster_tasks_.clear();
735 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
738 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
739 Tile* tile,
740 SkPixelRef* pixel_ref) {
741 return make_scoped_refptr(new ImageDecodeTaskImpl(
742 pixel_ref,
743 base::Bind(&TileManager::OnImageDecodeTaskCompleted,
744 base::Unretained(this),
745 tile->layer_id(),
746 base::Unretained(pixel_ref))));
749 scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
750 scoped_ptr<ScopedResource> resource =
751 resource_pool_->AcquireResource(tile->desired_texture_size(),
752 tile_task_runner_->GetResourceFormat());
753 const ScopedResource* const_resource = resource.get();
755 // Create and queue all image decode tasks that this tile depends on.
756 ImageDecodeTask::Vector decode_tasks;
757 PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
758 std::vector<SkPixelRef*> pixel_refs;
759 tile->raster_source()->GatherPixelRefs(
760 tile->content_rect(), tile->contents_scale(), &pixel_refs);
761 for (SkPixelRef* pixel_ref : pixel_refs) {
762 uint32_t id = pixel_ref->getGenerationID();
764 // Append existing image decode task if available.
765 PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
766 if (decode_task_it != existing_pixel_refs.end()) {
767 decode_tasks.push_back(decode_task_it->second);
768 continue;
771 // Create and append new image decode task for this pixel ref.
772 scoped_refptr<ImageDecodeTask> decode_task =
773 CreateImageDecodeTask(tile, pixel_ref);
774 decode_tasks.push_back(decode_task);
775 existing_pixel_refs[id] = decode_task;
778 return make_scoped_refptr(new RasterTaskImpl(
779 const_resource, tile->raster_source(), tile->content_rect(),
780 tile->contents_scale(), tile->combined_priority().resolution,
781 tile->layer_id(), static_cast<const void*>(tile),
782 tile->source_frame_number(), tile->use_picture_analysis(),
783 base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this),
784 tile->id(), base::Passed(&resource)),
785 &decode_tasks));
788 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
789 SkPixelRef* pixel_ref,
790 bool was_canceled) {
791 // If the task was canceled, we need to clean it up
792 // from |image_decode_tasks_|.
793 if (!was_canceled)
794 return;
796 LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
797 if (layer_it == image_decode_tasks_.end())
798 return;
800 PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
801 PixelRefTaskMap::iterator task_it =
802 pixel_ref_tasks.find(pixel_ref->getGenerationID());
804 if (task_it != pixel_ref_tasks.end())
805 pixel_ref_tasks.erase(task_it);
808 void TileManager::OnRasterTaskCompleted(
809 Tile::Id tile_id,
810 scoped_ptr<ScopedResource> resource,
811 const RasterSource::SolidColorAnalysis& analysis,
812 bool was_canceled) {
813 DCHECK(tiles_.find(tile_id) != tiles_.end());
815 Tile* tile = tiles_[tile_id];
816 DCHECK(tile->raster_task_.get());
817 orphan_raster_tasks_.push_back(tile->raster_task_);
818 tile->raster_task_ = nullptr;
820 if (was_canceled) {
821 ++update_visible_tiles_stats_.canceled_count;
822 resource_pool_->ReleaseResource(resource.Pass());
823 return;
826 UpdateTileDrawInfo(tile, resource.Pass(), analysis);
829 void TileManager::UpdateTileDrawInfo(
830 Tile* tile,
831 scoped_ptr<ScopedResource> resource,
832 const RasterSource::SolidColorAnalysis& analysis) {
833 TileDrawInfo& draw_info = tile->draw_info();
835 ++update_visible_tiles_stats_.completed_count;
837 if (analysis.is_solid_color) {
838 draw_info.set_solid_color(analysis.solid_color);
839 if (resource)
840 resource_pool_->ReleaseResource(resource.Pass());
841 } else {
842 DCHECK(resource);
843 draw_info.set_use_resource();
844 draw_info.resource_ = resource.Pass();
847 client_->NotifyTileStateChanged(tile);
850 scoped_refptr<Tile> TileManager::CreateTile(
851 RasterSource* raster_source,
852 const gfx::Size& desired_texture_size,
853 const gfx::Rect& content_rect,
854 float contents_scale,
855 int layer_id,
856 int source_frame_number,
857 int flags) {
858 scoped_refptr<Tile> tile = make_scoped_refptr(
859 new Tile(this, raster_source, desired_texture_size, content_rect,
860 contents_scale, layer_id, source_frame_number, flags));
861 DCHECK(tiles_.find(tile->id()) == tiles_.end());
863 tiles_[tile->id()] = tile.get();
864 used_layer_counts_[tile->layer_id()]++;
865 return tile;
868 void TileManager::SetTileTaskRunnerForTesting(
869 TileTaskRunner* tile_task_runner) {
870 tile_task_runner_ = tile_task_runner;
871 tile_task_runner_->SetClient(this);
874 bool TileManager::AreRequiredTilesReadyToDraw(
875 RasterTilePriorityQueue::Type type) const {
876 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
877 client_->BuildRasterQueue(global_state_.tree_priority, type));
878 // It is insufficient to check whether the raster queue we constructed is
879 // empty. The reason for this is that there are situations (rasterize on
880 // demand) when the tile both needs raster and it's ready to draw. Hence, we
881 // have to iterate the queue to check whether the required tiles are ready to
882 // draw.
883 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
884 if (!raster_priority_queue->Top()->IsReadyToDraw())
885 return false;
887 return true;
889 bool TileManager::IsReadyToActivate() const {
890 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
891 return AreRequiredTilesReadyToDraw(
892 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
895 bool TileManager::IsReadyToDraw() const {
896 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
897 return AreRequiredTilesReadyToDraw(
898 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
901 void TileManager::NotifyReadyToActivate() {
902 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
903 if (did_notify_ready_to_activate_)
904 return;
905 client_->NotifyReadyToActivate();
906 did_notify_ready_to_activate_ = true;
909 void TileManager::NotifyReadyToDraw() {
910 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
911 if (did_notify_ready_to_draw_)
912 return;
913 client_->NotifyReadyToDraw();
914 did_notify_ready_to_draw_ = true;
917 void TileManager::CheckIfReadyToActivate() {
918 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
920 tile_task_runner_->CheckForCompletedTasks();
921 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
923 if (did_notify_ready_to_activate_)
924 return;
925 if (!IsReadyToActivate())
926 return;
928 NotifyReadyToActivate();
931 void TileManager::CheckIfReadyToDraw() {
932 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
934 tile_task_runner_->CheckForCompletedTasks();
935 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
937 if (did_notify_ready_to_draw_)
938 return;
939 if (!IsReadyToDraw())
940 return;
942 NotifyReadyToDraw();
945 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
946 tile_task_runner_->CheckForCompletedTasks();
947 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
949 // When OOM, keep re-assigning memory until we reach a steady state
950 // where top-priority tiles are initialized.
951 TileVector tiles_that_need_to_be_rasterized;
952 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
953 client_->BuildRasterQueue(global_state_.tree_priority,
954 RasterTilePriorityQueue::Type::ALL));
955 AssignGpuMemoryToTiles(raster_priority_queue.get(),
956 scheduled_raster_task_limit_,
957 &tiles_that_need_to_be_rasterized);
959 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
960 // steady memory state. Keep scheduling tasks until we reach this state.
961 if (!tiles_that_need_to_be_rasterized.empty()) {
962 ScheduleTasks(tiles_that_need_to_be_rasterized);
963 return;
966 FreeResourcesForReleasedTiles();
968 resource_pool_->ReduceResourceUsage();
970 // We don't reserve memory for required-for-activation tiles during
971 // accelerated gestures, so we just postpone activation when we don't
972 // have these tiles, and activate after the accelerated gesture.
973 // Likewise if we don't allow any tiles (as is the case when we're
974 // invisible), if we have tiles that aren't ready, then we shouldn't
975 // activate as activation can cause checkerboards.
976 bool wait_for_all_required_tiles =
977 global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
978 global_state_.memory_limit_policy == ALLOW_NOTHING;
980 // Mark any required-for-activation tiles that have not been been assigned
981 // memory after reaching a steady memory state as OOM. This ensures that we
982 // activate even when OOM. Note that we can't reuse the queue we used for
983 // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
984 // evicted some tiles that would not be picked up by the old raster queue.
985 scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue(
986 client_->BuildRasterQueue(
987 global_state_.tree_priority,
988 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
990 // If we have tiles left to raster for activation, and we don't allow
991 // activating without them, then skip activation and return early.
992 if (!required_for_activation_queue->IsEmpty() && wait_for_all_required_tiles)
993 return;
995 // Mark required tiles as OOM so that we can activate without them.
996 for (; !required_for_activation_queue->IsEmpty();
997 required_for_activation_queue->Pop()) {
998 Tile* tile = required_for_activation_queue->Top();
999 tile->draw_info().set_oom();
1000 client_->NotifyTileStateChanged(tile);
1003 DCHECK(IsReadyToActivate());
1004 ready_to_activate_check_notifier_.Schedule();
1007 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
1010 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count)
1011 : memory_bytes_(memory_bytes), resource_count_(resource_count) {
1014 // static
1015 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
1016 const gfx::Size& size,
1017 ResourceFormat format) {
1018 return MemoryUsage(Resource::MemorySizeBytes(size, format), 1);
1021 // static
1022 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
1023 const TileDrawInfo& draw_info = tile->draw_info();
1024 if (draw_info.resource_) {
1025 return MemoryUsage::FromConfig(draw_info.resource_->size(),
1026 draw_info.resource_->format());
1028 return MemoryUsage();
1031 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
1032 const MemoryUsage& other) {
1033 memory_bytes_ += other.memory_bytes_;
1034 resource_count_ += other.resource_count_;
1035 return *this;
1038 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
1039 const MemoryUsage& other) {
1040 memory_bytes_ -= other.memory_bytes_;
1041 resource_count_ -= other.resource_count_;
1042 return *this;
1045 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
1046 const MemoryUsage& other) {
1047 MemoryUsage result = *this;
1048 result -= other;
1049 return result;
1052 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
1053 return memory_bytes_ > limit.memory_bytes_ ||
1054 resource_count_ > limit.resource_count_;
1057 } // namespace cc