[Enhanced Bookmark] Change "Bookmark Bar" to "Bookmark bar" on Android
[chromium-blink-merge.git] / cc / resources / tile_manager.cc
blob71f2e83017547d2aa9131b37c619bf8bee749041
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();
152 // Release the reference after decoding image to ensure that it is not
153 // kept alive unless needed.
154 pixel_ref_.clear();
157 // Overridden from TileTask:
158 void ScheduleOnOriginThread(TileTaskClient* client) override {}
159 void CompleteOnOriginThread(TileTaskClient* client) override {}
160 void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
162 protected:
163 ~ImageDecodeTaskImpl() override {}
165 private:
166 skia::RefPtr<SkPixelRef> pixel_ref_;
167 const base::Callback<void(bool was_canceled)> reply_;
169 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
172 const char* TaskSetName(TaskSet task_set) {
173 switch (task_set) {
174 case TileManager::ALL:
175 return "ALL";
176 case TileManager::REQUIRED_FOR_ACTIVATION:
177 return "REQUIRED_FOR_ACTIVATION";
178 case TileManager::REQUIRED_FOR_DRAW:
179 return "REQUIRED_FOR_DRAW";
182 NOTREACHED();
183 return "Invalid TaskSet";
186 } // namespace
188 RasterTaskCompletionStats::RasterTaskCompletionStats()
189 : completed_count(0u), canceled_count(0u) {}
191 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
192 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
193 scoped_refptr<base::trace_event::TracedValue> state =
194 new base::trace_event::TracedValue();
195 state->SetInteger("completed_count", stats.completed_count);
196 state->SetInteger("canceled_count", stats.canceled_count);
197 return state;
200 // static
201 scoped_ptr<TileManager> TileManager::Create(
202 TileManagerClient* client,
203 base::SequencedTaskRunner* task_runner,
204 ResourcePool* resource_pool,
205 TileTaskRunner* tile_task_runner,
206 Rasterizer* rasterizer,
207 size_t scheduled_raster_task_limit) {
208 return make_scoped_ptr(new TileManager(client, task_runner, resource_pool,
209 tile_task_runner, rasterizer,
210 scheduled_raster_task_limit));
213 TileManager::TileManager(
214 TileManagerClient* client,
215 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
216 ResourcePool* resource_pool,
217 TileTaskRunner* tile_task_runner,
218 Rasterizer* rasterizer,
219 size_t scheduled_raster_task_limit)
220 : client_(client),
221 task_runner_(task_runner),
222 resource_pool_(resource_pool),
223 tile_task_runner_(tile_task_runner),
224 rasterizer_(rasterizer),
225 scheduled_raster_task_limit_(scheduled_raster_task_limit),
226 all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
227 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
228 did_oom_on_last_assign_(false),
229 ready_to_activate_notifier_(
230 task_runner_.get(),
231 base::Bind(&TileManager::NotifyReadyToActivate,
232 base::Unretained(this))),
233 ready_to_draw_notifier_(
234 task_runner_.get(),
235 base::Bind(&TileManager::NotifyReadyToDraw, base::Unretained(this))),
236 ready_to_activate_check_notifier_(
237 task_runner_.get(),
238 base::Bind(&TileManager::CheckIfReadyToActivate,
239 base::Unretained(this))),
240 ready_to_draw_check_notifier_(
241 task_runner_.get(),
242 base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))),
243 more_tiles_need_prepare_check_notifier_(
244 task_runner_.get(),
245 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
246 base::Unretained(this))),
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 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
367 client_->BuildRasterQueue(global_state_.tree_priority,
368 RasterTilePriorityQueue::Type::ALL));
369 AssignGpuMemoryToTiles(raster_priority_queue.get(),
370 scheduled_raster_task_limit_,
371 &tiles_that_need_to_be_rasterized);
373 // Inform the client that will likely require a draw if the highest priority
374 // tile that will be rasterized is required for draw.
375 client_->SetIsLikelyToRequireADraw(
376 !tiles_that_need_to_be_rasterized.empty() &&
377 (*tiles_that_need_to_be_rasterized.begin())->required_for_draw());
379 // Schedule tile tasks.
380 ScheduleTasks(tiles_that_need_to_be_rasterized);
382 did_notify_ready_to_activate_ = false;
383 did_notify_ready_to_draw_ = false;
384 } else {
385 if (global_state_.hard_memory_limit_in_bytes == 0) {
386 resource_pool_->CheckBusyResources(false);
387 MemoryUsage memory_limit(0, 0);
388 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
389 resource_pool_->acquired_resource_count());
390 FreeTileResourcesUntilUsageIsWithinLimit(nullptr, memory_limit,
391 &memory_usage);
394 did_notify_ready_to_activate_ = false;
395 did_notify_ready_to_draw_ = false;
396 ready_to_activate_notifier_.Schedule();
397 ready_to_draw_notifier_.Schedule();
400 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
401 "state", BasicStateAsValue());
403 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
404 resource_pool_->total_memory_usage_bytes() -
405 resource_pool_->acquired_memory_usage_bytes());
408 void TileManager::SynchronouslyRasterizeTiles(
409 const GlobalStateThatImpactsTilePriority& state) {
410 TRACE_EVENT0("cc", "TileManager::SynchronouslyRasterizeTiles");
412 DCHECK(rasterizer_->GetPrepareTilesMode() !=
413 PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES);
415 global_state_ = state;
417 FreeResourcesForReleasedTiles();
418 CleanUpReleasedTiles();
420 scoped_ptr<RasterTilePriorityQueue> required_for_draw_queue(
421 client_->BuildRasterQueue(
422 global_state_.tree_priority,
423 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW));
424 TileVector tiles_that_need_to_be_rasterized;
425 AssignGpuMemoryToTiles(required_for_draw_queue.get(),
426 std::numeric_limits<size_t>::max(),
427 &tiles_that_need_to_be_rasterized);
429 // We must reduce the amount of unused resources before calling
430 // RunTasks to prevent usage from rising above limits.
431 resource_pool_->ReduceResourceUsage();
433 // Run and complete all raster task synchronously.
434 rasterizer_->RasterizeTiles(
435 tiles_that_need_to_be_rasterized, resource_pool_,
436 tile_task_runner_->GetResourceFormat(),
437 base::Bind(&TileManager::UpdateTileDrawInfo, base::Unretained(this)));
439 // Use on-demand raster for any required-for-draw tiles that have not been
440 // assigned memory after reaching a steady memory state.
441 // TODO(hendrikw): Figure out why this would improve jank on some tests - See
442 // crbug.com/449288
443 required_for_draw_queue = client_->BuildRasterQueue(
444 global_state_.tree_priority,
445 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
447 // Change to OOM mode for any tiles that have not been been assigned memory.
448 // This ensures that we draw even when OOM.
449 for (; !required_for_draw_queue->IsEmpty(); required_for_draw_queue->Pop()) {
450 Tile* tile = required_for_draw_queue->Top();
451 tile->draw_info().set_oom();
452 client_->NotifyTileStateChanged(tile);
455 TRACE_EVENT_INSTANT1("cc", "DidRasterize", TRACE_EVENT_SCOPE_THREAD, "state",
456 BasicStateAsValue());
458 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
459 resource_pool_->total_memory_usage_bytes() -
460 resource_pool_->acquired_memory_usage_bytes());
463 void TileManager::UpdateVisibleTiles(
464 const GlobalStateThatImpactsTilePriority& state) {
465 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
467 tile_task_runner_->CheckForCompletedTasks();
469 DCHECK(rasterizer_);
470 PrepareTilesMode prepare_tiles_mode = rasterizer_->GetPrepareTilesMode();
471 if (prepare_tiles_mode != PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES)
472 SynchronouslyRasterizeTiles(state);
474 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
476 TRACE_EVENT_INSTANT1(
477 "cc",
478 "DidUpdateVisibleTiles",
479 TRACE_EVENT_SCOPE_THREAD,
480 "stats",
481 RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
482 update_visible_tiles_stats_ = RasterTaskCompletionStats();
485 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
486 TileManager::BasicStateAsValue() const {
487 scoped_refptr<base::trace_event::TracedValue> value =
488 new base::trace_event::TracedValue();
489 BasicStateAsValueInto(value.get());
490 return value;
493 void TileManager::BasicStateAsValueInto(
494 base::trace_event::TracedValue* state) const {
495 state->SetInteger("tile_count", tiles_.size());
496 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
497 state->BeginDictionary("global_state");
498 global_state_.AsValueInto(state);
499 state->EndDictionary();
502 scoped_ptr<EvictionTilePriorityQueue>
503 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
504 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
505 const MemoryUsage& limit,
506 MemoryUsage* usage) {
507 while (usage->Exceeds(limit)) {
508 if (!eviction_priority_queue) {
509 eviction_priority_queue =
510 client_->BuildEvictionQueue(global_state_.tree_priority);
512 if (eviction_priority_queue->IsEmpty())
513 break;
515 Tile* tile = eviction_priority_queue->Top();
516 *usage -= MemoryUsage::FromTile(tile);
517 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
518 eviction_priority_queue->Pop();
520 return eviction_priority_queue;
523 scoped_ptr<EvictionTilePriorityQueue>
524 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
525 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
526 const MemoryUsage& limit,
527 const TilePriority& other_priority,
528 MemoryUsage* usage) {
529 while (usage->Exceeds(limit)) {
530 if (!eviction_priority_queue) {
531 eviction_priority_queue =
532 client_->BuildEvictionQueue(global_state_.tree_priority);
534 if (eviction_priority_queue->IsEmpty())
535 break;
537 Tile* tile = eviction_priority_queue->Top();
538 if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
539 break;
541 *usage -= MemoryUsage::FromTile(tile);
542 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
543 eviction_priority_queue->Pop();
545 return eviction_priority_queue;
548 bool TileManager::TilePriorityViolatesMemoryPolicy(
549 const TilePriority& priority) {
550 switch (global_state_.memory_limit_policy) {
551 case ALLOW_NOTHING:
552 return true;
553 case ALLOW_ABSOLUTE_MINIMUM:
554 return priority.priority_bin > TilePriority::NOW;
555 case ALLOW_PREPAINT_ONLY:
556 return priority.priority_bin > TilePriority::SOON;
557 case ALLOW_ANYTHING:
558 return priority.distance_to_visible ==
559 std::numeric_limits<float>::infinity();
561 NOTREACHED();
562 return true;
565 void TileManager::AssignGpuMemoryToTiles(
566 RasterTilePriorityQueue* raster_priority_queue,
567 size_t scheduled_raster_task_limit,
568 TileVector* tiles_that_need_to_be_rasterized) {
569 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
571 // Maintain the list of released resources that can potentially be re-used
572 // or deleted. If this operation becomes expensive too, only do this after
573 // some resource(s) was returned. Note that in that case, one also need to
574 // invalidate when releasing some resource from the pool.
575 resource_pool_->CheckBusyResources(false);
577 // Now give memory out to the tiles until we're out, and build
578 // the needs-to-be-rasterized queue.
579 unsigned schedule_priority = 1u;
580 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
581 bool had_enough_memory_to_schedule_tiles_needed_now = true;
583 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
584 global_state_.num_resources_limit);
585 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
586 global_state_.num_resources_limit);
587 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
588 resource_pool_->acquired_resource_count());
590 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
591 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
592 Tile* tile = raster_priority_queue->Top();
593 TilePriority priority = tile->combined_priority();
595 if (TilePriorityViolatesMemoryPolicy(priority)) {
596 TRACE_EVENT_INSTANT0(
597 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
598 TRACE_EVENT_SCOPE_THREAD);
599 break;
602 // We won't be able to schedule this tile, so break out early.
603 if (tiles_that_need_to_be_rasterized->size() >=
604 scheduled_raster_task_limit) {
605 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
606 break;
609 TileDrawInfo& draw_info = tile->draw_info();
610 tile->scheduled_priority_ = schedule_priority++;
612 DCHECK_IMPLIES(draw_info.mode() != TileDrawInfo::OOM_MODE,
613 !draw_info.IsReadyToDraw());
615 // If the tile already has a raster_task, then the memory used by it is
616 // already accounted for in memory_usage. Otherwise, we'll have to acquire
617 // more memory to create a raster task.
618 MemoryUsage memory_required_by_tile_to_be_scheduled;
619 if (!tile->raster_task_.get()) {
620 memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
621 tile->desired_texture_size(), tile_task_runner_->GetResourceFormat());
624 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
626 // This is the memory limit that will be used by this tile. Depending on
627 // the tile priority, it will be one of hard_memory_limit or
628 // soft_memory_limit.
629 MemoryUsage& tile_memory_limit =
630 tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
632 const MemoryUsage& scheduled_tile_memory_limit =
633 tile_memory_limit - memory_required_by_tile_to_be_scheduled;
634 eviction_priority_queue =
635 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
636 eviction_priority_queue.Pass(), scheduled_tile_memory_limit,
637 priority, &memory_usage);
638 bool memory_usage_is_within_limit =
639 !memory_usage.Exceeds(scheduled_tile_memory_limit);
641 // If we couldn't fit the tile into our current memory limit, then we're
642 // done.
643 if (!memory_usage_is_within_limit) {
644 if (tile_is_needed_now)
645 had_enough_memory_to_schedule_tiles_needed_now = false;
646 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
647 break;
650 memory_usage += memory_required_by_tile_to_be_scheduled;
651 tiles_that_need_to_be_rasterized->push_back(tile);
654 // Note that we should try and further reduce memory in case the above loop
655 // didn't reduce memory. This ensures that we always release as many resources
656 // as possible to stay within the memory limit.
657 eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
658 eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage);
660 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
661 !had_enough_memory_to_schedule_tiles_needed_now);
662 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
664 memory_stats_from_last_assign_.total_budget_in_bytes =
665 global_state_.hard_memory_limit_in_bytes;
666 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
667 memory_stats_from_last_assign_.had_enough_memory =
668 had_enough_memory_to_schedule_tiles_needed_now;
670 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
671 "all_tiles_that_need_to_be_rasterized_are_scheduled",
672 all_tiles_that_need_to_be_rasterized_are_scheduled_,
673 "had_enough_memory_to_schedule_tiles_needed_now",
674 had_enough_memory_to_schedule_tiles_needed_now);
677 void TileManager::FreeResourcesForTile(Tile* tile) {
678 TileDrawInfo& draw_info = tile->draw_info();
679 if (draw_info.resource_)
680 resource_pool_->ReleaseResource(draw_info.resource_.Pass());
683 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
684 Tile* tile) {
685 bool was_ready_to_draw = tile->IsReadyToDraw();
686 FreeResourcesForTile(tile);
687 if (was_ready_to_draw)
688 client_->NotifyTileStateChanged(tile);
691 void TileManager::ScheduleTasks(
692 const TileVector& tiles_that_need_to_be_rasterized) {
693 TRACE_EVENT1("cc",
694 "TileManager::ScheduleTasks",
695 "count",
696 tiles_that_need_to_be_rasterized.size());
698 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
700 raster_queue_.Reset();
702 // Build a new task queue containing all task currently needed. Tasks
703 // are added in order of priority, highest priority task first.
704 for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
705 it != tiles_that_need_to_be_rasterized.end();
706 ++it) {
707 Tile* tile = *it;
708 TileDrawInfo& draw_info = tile->draw_info();
710 DCHECK(draw_info.requires_resource());
711 DCHECK(!draw_info.resource_);
713 if (!tile->raster_task_.get())
714 tile->raster_task_ = CreateRasterTask(tile);
716 TaskSetCollection task_sets;
717 if (tile->required_for_activation())
718 task_sets.set(REQUIRED_FOR_ACTIVATION);
719 if (tile->required_for_draw())
720 task_sets.set(REQUIRED_FOR_DRAW);
721 task_sets.set(ALL);
722 raster_queue_.items.push_back(
723 TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
726 // We must reduce the amount of unused resoruces before calling
727 // ScheduleTasks to prevent usage from rising above limits.
728 resource_pool_->ReduceResourceUsage();
730 // Schedule running of |raster_queue_|. This replaces any previously
731 // scheduled tasks and effectively cancels all tasks not present
732 // in |raster_queue_|.
733 tile_task_runner_->ScheduleTasks(&raster_queue_);
735 // It's now safe to clean up orphan tasks as raster worker pool is not
736 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
737 // been called.
738 orphan_raster_tasks_.clear();
740 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
743 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
744 Tile* tile,
745 SkPixelRef* pixel_ref) {
746 return make_scoped_refptr(new ImageDecodeTaskImpl(
747 pixel_ref,
748 base::Bind(&TileManager::OnImageDecodeTaskCompleted,
749 base::Unretained(this),
750 tile->layer_id(),
751 base::Unretained(pixel_ref))));
754 scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
755 scoped_ptr<ScopedResource> resource =
756 resource_pool_->AcquireResource(tile->desired_texture_size(),
757 tile_task_runner_->GetResourceFormat());
758 const ScopedResource* const_resource = resource.get();
760 // Create and queue all image decode tasks that this tile depends on.
761 ImageDecodeTask::Vector decode_tasks;
762 PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
763 std::vector<SkPixelRef*> pixel_refs;
764 tile->raster_source()->GatherPixelRefs(
765 tile->content_rect(), tile->contents_scale(), &pixel_refs);
766 for (SkPixelRef* pixel_ref : pixel_refs) {
767 uint32_t id = pixel_ref->getGenerationID();
769 // Append existing image decode task if available.
770 PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
771 if (decode_task_it != existing_pixel_refs.end()) {
772 decode_tasks.push_back(decode_task_it->second);
773 continue;
776 // Create and append new image decode task for this pixel ref.
777 scoped_refptr<ImageDecodeTask> decode_task =
778 CreateImageDecodeTask(tile, pixel_ref);
779 decode_tasks.push_back(decode_task);
780 existing_pixel_refs[id] = decode_task;
783 return make_scoped_refptr(new RasterTaskImpl(
784 const_resource, tile->raster_source(), tile->content_rect(),
785 tile->contents_scale(), tile->combined_priority().resolution,
786 tile->layer_id(), static_cast<const void*>(tile),
787 tile->source_frame_number(), tile->use_picture_analysis(),
788 base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this),
789 tile->id(), base::Passed(&resource)),
790 &decode_tasks));
793 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
794 SkPixelRef* pixel_ref,
795 bool was_canceled) {
796 // If the task was canceled, we need to clean it up
797 // from |image_decode_tasks_|.
798 if (!was_canceled)
799 return;
801 LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
802 if (layer_it == image_decode_tasks_.end())
803 return;
805 PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
806 PixelRefTaskMap::iterator task_it =
807 pixel_ref_tasks.find(pixel_ref->getGenerationID());
809 if (task_it != pixel_ref_tasks.end())
810 pixel_ref_tasks.erase(task_it);
813 void TileManager::OnRasterTaskCompleted(
814 Tile::Id tile_id,
815 scoped_ptr<ScopedResource> resource,
816 const RasterSource::SolidColorAnalysis& analysis,
817 bool was_canceled) {
818 DCHECK(tiles_.find(tile_id) != tiles_.end());
820 Tile* tile = tiles_[tile_id];
821 DCHECK(tile->raster_task_.get());
822 orphan_raster_tasks_.push_back(tile->raster_task_);
823 tile->raster_task_ = nullptr;
825 if (was_canceled) {
826 ++update_visible_tiles_stats_.canceled_count;
827 resource_pool_->ReleaseResource(resource.Pass());
828 return;
831 UpdateTileDrawInfo(tile, resource.Pass(), analysis);
834 void TileManager::UpdateTileDrawInfo(
835 Tile* tile,
836 scoped_ptr<ScopedResource> resource,
837 const RasterSource::SolidColorAnalysis& analysis) {
838 TileDrawInfo& draw_info = tile->draw_info();
840 ++update_visible_tiles_stats_.completed_count;
842 if (analysis.is_solid_color) {
843 draw_info.set_solid_color(analysis.solid_color);
844 if (resource)
845 resource_pool_->ReleaseResource(resource.Pass());
846 } else {
847 DCHECK(resource);
848 draw_info.set_use_resource();
849 draw_info.resource_ = resource.Pass();
852 client_->NotifyTileStateChanged(tile);
855 scoped_refptr<Tile> TileManager::CreateTile(
856 RasterSource* raster_source,
857 const gfx::Size& desired_texture_size,
858 const gfx::Rect& content_rect,
859 float contents_scale,
860 int layer_id,
861 int source_frame_number,
862 int flags) {
863 scoped_refptr<Tile> tile = make_scoped_refptr(
864 new Tile(this, raster_source, desired_texture_size, content_rect,
865 contents_scale, layer_id, source_frame_number, flags));
866 DCHECK(tiles_.find(tile->id()) == tiles_.end());
868 tiles_[tile->id()] = tile.get();
869 used_layer_counts_[tile->layer_id()]++;
870 return tile;
873 void TileManager::SetTileTaskRunnerForTesting(
874 TileTaskRunner* tile_task_runner) {
875 tile_task_runner_ = tile_task_runner;
876 tile_task_runner_->SetClient(this);
879 bool TileManager::AreRequiredTilesReadyToDraw(
880 RasterTilePriorityQueue::Type type) const {
881 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
882 client_->BuildRasterQueue(global_state_.tree_priority, type));
883 // It is insufficient to check whether the raster queue we constructed is
884 // empty. The reason for this is that there are situations (rasterize on
885 // demand) when the tile both needs raster and it's ready to draw. Hence, we
886 // have to iterate the queue to check whether the required tiles are ready to
887 // draw.
888 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
889 if (!raster_priority_queue->Top()->IsReadyToDraw())
890 return false;
892 return true;
894 bool TileManager::IsReadyToActivate() const {
895 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
896 return AreRequiredTilesReadyToDraw(
897 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
900 bool TileManager::IsReadyToDraw() const {
901 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
902 return AreRequiredTilesReadyToDraw(
903 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
906 void TileManager::NotifyReadyToActivate() {
907 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
908 if (did_notify_ready_to_activate_)
909 return;
910 client_->NotifyReadyToActivate();
911 did_notify_ready_to_activate_ = true;
914 void TileManager::NotifyReadyToDraw() {
915 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
916 if (did_notify_ready_to_draw_)
917 return;
918 client_->NotifyReadyToDraw();
919 did_notify_ready_to_draw_ = true;
922 void TileManager::CheckIfReadyToActivate() {
923 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
925 tile_task_runner_->CheckForCompletedTasks();
926 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
928 if (did_notify_ready_to_activate_)
929 return;
930 if (!IsReadyToActivate())
931 return;
933 NotifyReadyToActivate();
936 void TileManager::CheckIfReadyToDraw() {
937 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
939 tile_task_runner_->CheckForCompletedTasks();
940 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
942 if (did_notify_ready_to_draw_)
943 return;
944 if (!IsReadyToDraw())
945 return;
947 NotifyReadyToDraw();
950 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
951 tile_task_runner_->CheckForCompletedTasks();
952 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
954 // When OOM, keep re-assigning memory until we reach a steady state
955 // where top-priority tiles are initialized.
956 TileVector tiles_that_need_to_be_rasterized;
957 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
958 client_->BuildRasterQueue(global_state_.tree_priority,
959 RasterTilePriorityQueue::Type::ALL));
960 AssignGpuMemoryToTiles(raster_priority_queue.get(),
961 scheduled_raster_task_limit_,
962 &tiles_that_need_to_be_rasterized);
964 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
965 // steady memory state. Keep scheduling tasks until we reach this state.
966 if (!tiles_that_need_to_be_rasterized.empty()) {
967 ScheduleTasks(tiles_that_need_to_be_rasterized);
968 return;
971 FreeResourcesForReleasedTiles();
973 resource_pool_->ReduceResourceUsage();
975 // We don't reserve memory for required-for-activation tiles during
976 // accelerated gestures, so we just postpone activation when we don't
977 // have these tiles, and activate after the accelerated gesture.
978 // Likewise if we don't allow any tiles (as is the case when we're
979 // invisible), if we have tiles that aren't ready, then we shouldn't
980 // activate as activation can cause checkerboards.
981 bool wait_for_all_required_tiles =
982 global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
983 global_state_.memory_limit_policy == ALLOW_NOTHING;
985 // Mark any required-for-activation tiles that have not been been assigned
986 // memory after reaching a steady memory state as OOM. This ensures that we
987 // activate even when OOM. Note that we can't reuse the queue we used for
988 // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
989 // evicted some tiles that would not be picked up by the old raster queue.
990 scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue(
991 client_->BuildRasterQueue(
992 global_state_.tree_priority,
993 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
995 // If we have tiles left to raster for activation, and we don't allow
996 // activating without them, then skip activation and return early.
997 if (!required_for_activation_queue->IsEmpty() && wait_for_all_required_tiles)
998 return;
1000 // Mark required tiles as OOM so that we can activate without them.
1001 for (; !required_for_activation_queue->IsEmpty();
1002 required_for_activation_queue->Pop()) {
1003 Tile* tile = required_for_activation_queue->Top();
1004 tile->draw_info().set_oom();
1005 client_->NotifyTileStateChanged(tile);
1008 DCHECK(IsReadyToActivate());
1009 ready_to_activate_check_notifier_.Schedule();
1012 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
1015 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count)
1016 : memory_bytes_(memory_bytes), resource_count_(resource_count) {
1019 // static
1020 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
1021 const gfx::Size& size,
1022 ResourceFormat format) {
1023 return MemoryUsage(Resource::MemorySizeBytes(size, format), 1);
1026 // static
1027 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
1028 const TileDrawInfo& draw_info = tile->draw_info();
1029 if (draw_info.resource_) {
1030 return MemoryUsage::FromConfig(draw_info.resource_->size(),
1031 draw_info.resource_->format());
1033 return MemoryUsage();
1036 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
1037 const MemoryUsage& other) {
1038 memory_bytes_ += other.memory_bytes_;
1039 resource_count_ += other.resource_count_;
1040 return *this;
1043 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
1044 const MemoryUsage& other) {
1045 memory_bytes_ -= other.memory_bytes_;
1046 resource_count_ -= other.resource_count_;
1047 return *this;
1050 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
1051 const MemoryUsage& other) {
1052 MemoryUsage result = *this;
1053 result -= other;
1054 return result;
1057 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
1058 return memory_bytes_ > limit.memory_bytes_ ||
1059 resource_count_ > limit.resource_count_;
1062 } // namespace cc