Revert of Linux MSan: enable swarming/sharding for browser_tests. (patchset #1 id...
[chromium-blink-merge.git] / cc / resources / tile_manager.cc
blob2b247aa20856e22a2ba12b321ce0d3dd6f2e9d7c
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::debug::ConvertableToTraceFormat>
188 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
189 scoped_refptr<base::debug::TracedValue> state =
190 new base::debug::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 // Use on-demand raster for any tiles that have not been been assigned
443 // memory. 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_rasterize_on_demand();
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::debug::ConvertableToTraceFormat>
481 TileManager::BasicStateAsValue() const {
482 scoped_refptr<base::debug::TracedValue> value =
483 new base::debug::TracedValue();
484 BasicStateAsValueInto(value.get());
485 return value;
488 void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const {
489 state->SetInteger("tile_count", tiles_.size());
490 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
491 state->BeginDictionary("global_state");
492 global_state_.AsValueInto(state);
493 state->EndDictionary();
496 scoped_ptr<EvictionTilePriorityQueue>
497 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
498 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
499 const MemoryUsage& limit,
500 MemoryUsage* usage) {
501 while (usage->Exceeds(limit)) {
502 if (!eviction_priority_queue) {
503 eviction_priority_queue =
504 client_->BuildEvictionQueue(global_state_.tree_priority);
506 if (eviction_priority_queue->IsEmpty())
507 break;
509 Tile* tile = eviction_priority_queue->Top();
510 *usage -= MemoryUsage::FromTile(tile);
511 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
512 eviction_priority_queue->Pop();
514 return eviction_priority_queue;
517 scoped_ptr<EvictionTilePriorityQueue>
518 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
519 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
520 const MemoryUsage& limit,
521 const TilePriority& other_priority,
522 MemoryUsage* usage) {
523 while (usage->Exceeds(limit)) {
524 if (!eviction_priority_queue) {
525 eviction_priority_queue =
526 client_->BuildEvictionQueue(global_state_.tree_priority);
528 if (eviction_priority_queue->IsEmpty())
529 break;
531 Tile* tile = eviction_priority_queue->Top();
532 if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
533 break;
535 *usage -= MemoryUsage::FromTile(tile);
536 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
537 eviction_priority_queue->Pop();
539 return eviction_priority_queue;
542 bool TileManager::TilePriorityViolatesMemoryPolicy(
543 const TilePriority& priority) {
544 switch (global_state_.memory_limit_policy) {
545 case ALLOW_NOTHING:
546 return true;
547 case ALLOW_ABSOLUTE_MINIMUM:
548 return priority.priority_bin > TilePriority::NOW;
549 case ALLOW_PREPAINT_ONLY:
550 return priority.priority_bin > TilePriority::SOON;
551 case ALLOW_ANYTHING:
552 return priority.distance_to_visible ==
553 std::numeric_limits<float>::infinity();
555 NOTREACHED();
556 return true;
559 void TileManager::AssignGpuMemoryToTiles(
560 RasterTilePriorityQueue* raster_priority_queue,
561 size_t scheduled_raster_task_limit,
562 TileVector* tiles_that_need_to_be_rasterized) {
563 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
565 // Maintain the list of released resources that can potentially be re-used
566 // or deleted. If this operation becomes expensive too, only do this after
567 // some resource(s) was returned. Note that in that case, one also need to
568 // invalidate when releasing some resource from the pool.
569 resource_pool_->CheckBusyResources(false);
571 // Now give memory out to the tiles until we're out, and build
572 // the needs-to-be-rasterized queue.
573 unsigned schedule_priority = 1u;
574 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
575 bool had_enough_memory_to_schedule_tiles_needed_now = true;
577 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
578 global_state_.num_resources_limit);
579 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
580 global_state_.num_resources_limit);
581 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
582 resource_pool_->acquired_resource_count());
584 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
585 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
586 Tile* tile = raster_priority_queue->Top();
587 TilePriority priority = tile->combined_priority();
589 if (TilePriorityViolatesMemoryPolicy(priority)) {
590 TRACE_EVENT_INSTANT0(
591 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
592 TRACE_EVENT_SCOPE_THREAD);
593 break;
596 // We won't be able to schedule this tile, so break out early.
597 if (tiles_that_need_to_be_rasterized->size() >=
598 scheduled_raster_task_limit) {
599 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
600 break;
603 TileDrawInfo& draw_info = tile->draw_info();
604 tile->scheduled_priority_ = schedule_priority++;
606 DCHECK(draw_info.mode() == TileDrawInfo::PICTURE_PILE_MODE ||
607 !draw_info.IsReadyToDraw());
609 // If the tile already has a raster_task, then the memory used by it is
610 // already accounted for in memory_usage. Otherwise, we'll have to acquire
611 // more memory to create a raster task.
612 MemoryUsage memory_required_by_tile_to_be_scheduled;
613 if (!tile->raster_task_.get()) {
614 memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
615 tile->desired_texture_size(), tile_task_runner_->GetResourceFormat());
618 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
620 // This is the memory limit that will be used by this tile. Depending on
621 // the tile priority, it will be one of hard_memory_limit or
622 // soft_memory_limit.
623 MemoryUsage& tile_memory_limit =
624 tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
626 const MemoryUsage& scheduled_tile_memory_limit =
627 tile_memory_limit - memory_required_by_tile_to_be_scheduled;
628 eviction_priority_queue =
629 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
630 eviction_priority_queue.Pass(), scheduled_tile_memory_limit,
631 priority, &memory_usage);
632 bool memory_usage_is_within_limit =
633 !memory_usage.Exceeds(scheduled_tile_memory_limit);
635 // If we couldn't fit the tile into our current memory limit, then we're
636 // done.
637 if (!memory_usage_is_within_limit) {
638 if (tile_is_needed_now)
639 had_enough_memory_to_schedule_tiles_needed_now = false;
640 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
641 break;
644 memory_usage += memory_required_by_tile_to_be_scheduled;
645 tiles_that_need_to_be_rasterized->push_back(tile);
648 // Note that we should try and further reduce memory in case the above loop
649 // didn't reduce memory. This ensures that we always release as many resources
650 // as possible to stay within the memory limit.
651 eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
652 eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage);
654 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
655 !had_enough_memory_to_schedule_tiles_needed_now);
656 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
658 memory_stats_from_last_assign_.total_budget_in_bytes =
659 global_state_.hard_memory_limit_in_bytes;
660 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
661 memory_stats_from_last_assign_.had_enough_memory =
662 had_enough_memory_to_schedule_tiles_needed_now;
664 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
665 "all_tiles_that_need_to_be_rasterized_are_scheduled",
666 all_tiles_that_need_to_be_rasterized_are_scheduled_,
667 "had_enough_memory_to_schedule_tiles_needed_now",
668 had_enough_memory_to_schedule_tiles_needed_now);
671 void TileManager::FreeResourcesForTile(Tile* tile) {
672 TileDrawInfo& draw_info = tile->draw_info();
673 if (draw_info.resource_)
674 resource_pool_->ReleaseResource(draw_info.resource_.Pass());
677 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
678 Tile* tile) {
679 bool was_ready_to_draw = tile->IsReadyToDraw();
680 FreeResourcesForTile(tile);
681 if (was_ready_to_draw)
682 client_->NotifyTileStateChanged(tile);
685 void TileManager::ScheduleTasks(
686 const TileVector& tiles_that_need_to_be_rasterized) {
687 TRACE_EVENT1("cc",
688 "TileManager::ScheduleTasks",
689 "count",
690 tiles_that_need_to_be_rasterized.size());
692 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
694 raster_queue_.Reset();
696 // Build a new task queue containing all task currently needed. Tasks
697 // are added in order of priority, highest priority task first.
698 for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
699 it != tiles_that_need_to_be_rasterized.end();
700 ++it) {
701 Tile* tile = *it;
702 TileDrawInfo& draw_info = tile->draw_info();
704 DCHECK(draw_info.requires_resource());
705 DCHECK(!draw_info.resource_);
707 if (!tile->raster_task_.get())
708 tile->raster_task_ = CreateRasterTask(tile);
710 TaskSetCollection task_sets;
711 if (tile->required_for_activation())
712 task_sets.set(REQUIRED_FOR_ACTIVATION);
713 if (tile->required_for_draw())
714 task_sets.set(REQUIRED_FOR_DRAW);
715 task_sets.set(ALL);
716 raster_queue_.items.push_back(
717 TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
720 // We must reduce the amount of unused resoruces before calling
721 // ScheduleTasks to prevent usage from rising above limits.
722 resource_pool_->ReduceResourceUsage();
724 // Schedule running of |raster_queue_|. This replaces any previously
725 // scheduled tasks and effectively cancels all tasks not present
726 // in |raster_queue_|.
727 tile_task_runner_->ScheduleTasks(&raster_queue_);
729 // It's now safe to clean up orphan tasks as raster worker pool is not
730 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
731 // been called.
732 orphan_raster_tasks_.clear();
734 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
737 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
738 Tile* tile,
739 SkPixelRef* pixel_ref) {
740 return make_scoped_refptr(new ImageDecodeTaskImpl(
741 pixel_ref,
742 base::Bind(&TileManager::OnImageDecodeTaskCompleted,
743 base::Unretained(this),
744 tile->layer_id(),
745 base::Unretained(pixel_ref))));
748 scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
749 scoped_ptr<ScopedResource> resource =
750 resource_pool_->AcquireResource(tile->desired_texture_size(),
751 tile_task_runner_->GetResourceFormat());
752 const ScopedResource* const_resource = resource.get();
754 // Create and queue all image decode tasks that this tile depends on.
755 ImageDecodeTask::Vector decode_tasks;
756 PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
757 std::vector<SkPixelRef*> pixel_refs;
758 tile->raster_source()->GatherPixelRefs(
759 tile->content_rect(), tile->contents_scale(), &pixel_refs);
760 for (SkPixelRef* pixel_ref : pixel_refs) {
761 uint32_t id = pixel_ref->getGenerationID();
763 // Append existing image decode task if available.
764 PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
765 if (decode_task_it != existing_pixel_refs.end()) {
766 decode_tasks.push_back(decode_task_it->second);
767 continue;
770 // Create and append new image decode task for this pixel ref.
771 scoped_refptr<ImageDecodeTask> decode_task =
772 CreateImageDecodeTask(tile, pixel_ref);
773 decode_tasks.push_back(decode_task);
774 existing_pixel_refs[id] = decode_task;
777 return make_scoped_refptr(new RasterTaskImpl(
778 const_resource, tile->raster_source(), tile->content_rect(),
779 tile->contents_scale(), tile->combined_priority().resolution,
780 tile->layer_id(), static_cast<const void*>(tile),
781 tile->source_frame_number(), tile->use_picture_analysis(),
782 base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this),
783 tile->id(), base::Passed(&resource)),
784 &decode_tasks));
787 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
788 SkPixelRef* pixel_ref,
789 bool was_canceled) {
790 // If the task was canceled, we need to clean it up
791 // from |image_decode_tasks_|.
792 if (!was_canceled)
793 return;
795 LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
796 if (layer_it == image_decode_tasks_.end())
797 return;
799 PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
800 PixelRefTaskMap::iterator task_it =
801 pixel_ref_tasks.find(pixel_ref->getGenerationID());
803 if (task_it != pixel_ref_tasks.end())
804 pixel_ref_tasks.erase(task_it);
807 void TileManager::OnRasterTaskCompleted(
808 Tile::Id tile_id,
809 scoped_ptr<ScopedResource> resource,
810 const RasterSource::SolidColorAnalysis& analysis,
811 bool was_canceled) {
812 DCHECK(tiles_.find(tile_id) != tiles_.end());
814 Tile* tile = tiles_[tile_id];
815 DCHECK(tile->raster_task_.get());
816 orphan_raster_tasks_.push_back(tile->raster_task_);
817 tile->raster_task_ = nullptr;
819 if (was_canceled) {
820 ++update_visible_tiles_stats_.canceled_count;
821 resource_pool_->ReleaseResource(resource.Pass());
822 return;
825 UpdateTileDrawInfo(tile, resource.Pass(), analysis);
828 void TileManager::UpdateTileDrawInfo(
829 Tile* tile,
830 scoped_ptr<ScopedResource> resource,
831 const RasterSource::SolidColorAnalysis& analysis) {
832 TileDrawInfo& draw_info = tile->draw_info();
834 ++update_visible_tiles_stats_.completed_count;
836 if (analysis.is_solid_color) {
837 draw_info.set_solid_color(analysis.solid_color);
838 if (resource)
839 resource_pool_->ReleaseResource(resource.Pass());
840 } else {
841 DCHECK(resource);
842 draw_info.set_use_resource();
843 draw_info.resource_ = resource.Pass();
846 client_->NotifyTileStateChanged(tile);
849 scoped_refptr<Tile> TileManager::CreateTile(
850 RasterSource* raster_source,
851 const gfx::Size& desired_texture_size,
852 const gfx::Rect& content_rect,
853 float contents_scale,
854 int layer_id,
855 int source_frame_number,
856 int flags) {
857 scoped_refptr<Tile> tile = make_scoped_refptr(
858 new Tile(this, raster_source, desired_texture_size, content_rect,
859 contents_scale, layer_id, source_frame_number, flags));
860 DCHECK(tiles_.find(tile->id()) == tiles_.end());
862 tiles_[tile->id()] = tile.get();
863 used_layer_counts_[tile->layer_id()]++;
864 return tile;
867 void TileManager::SetTileTaskRunnerForTesting(
868 TileTaskRunner* tile_task_runner) {
869 tile_task_runner_ = tile_task_runner;
870 tile_task_runner_->SetClient(this);
873 bool TileManager::AreRequiredTilesReadyToDraw(
874 RasterTilePriorityQueue::Type type) const {
875 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
876 client_->BuildRasterQueue(global_state_.tree_priority, type));
877 // It is insufficient to check whether the raster queue we constructed is
878 // empty. The reason for this is that there are situations (rasterize on
879 // demand) when the tile both needs raster and it's ready to draw. Hence, we
880 // have to iterate the queue to check whether the required tiles are ready to
881 // draw.
882 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
883 if (!raster_priority_queue->Top()->IsReadyToDraw())
884 return false;
886 return true;
888 bool TileManager::IsReadyToActivate() const {
889 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
890 return AreRequiredTilesReadyToDraw(
891 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
894 bool TileManager::IsReadyToDraw() const {
895 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
896 return AreRequiredTilesReadyToDraw(
897 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
900 void TileManager::NotifyReadyToActivate() {
901 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
902 if (did_notify_ready_to_activate_)
903 return;
904 client_->NotifyReadyToActivate();
905 did_notify_ready_to_activate_ = true;
908 void TileManager::NotifyReadyToDraw() {
909 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
910 if (did_notify_ready_to_draw_)
911 return;
912 client_->NotifyReadyToDraw();
913 did_notify_ready_to_draw_ = true;
916 void TileManager::CheckIfReadyToActivate() {
917 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
919 tile_task_runner_->CheckForCompletedTasks();
920 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
922 if (did_notify_ready_to_activate_)
923 return;
924 if (!IsReadyToActivate())
925 return;
927 NotifyReadyToActivate();
930 void TileManager::CheckIfReadyToDraw() {
931 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
933 tile_task_runner_->CheckForCompletedTasks();
934 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
936 if (did_notify_ready_to_draw_)
937 return;
938 if (!IsReadyToDraw())
939 return;
941 NotifyReadyToDraw();
944 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
945 tile_task_runner_->CheckForCompletedTasks();
946 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
948 // When OOM, keep re-assigning memory until we reach a steady state
949 // where top-priority tiles are initialized.
950 TileVector tiles_that_need_to_be_rasterized;
951 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
952 client_->BuildRasterQueue(global_state_.tree_priority,
953 RasterTilePriorityQueue::Type::ALL));
954 AssignGpuMemoryToTiles(raster_priority_queue.get(),
955 scheduled_raster_task_limit_,
956 &tiles_that_need_to_be_rasterized);
958 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
959 // steady memory state. Keep scheduling tasks until we reach this state.
960 if (!tiles_that_need_to_be_rasterized.empty()) {
961 ScheduleTasks(tiles_that_need_to_be_rasterized);
962 return;
965 FreeResourcesForReleasedTiles();
967 resource_pool_->ReduceResourceUsage();
969 // We don't reserve memory for required-for-activation tiles during
970 // accelerated gestures, so we just postpone activation when we don't
971 // have these tiles, and activate after the accelerated gesture.
972 // Likewise if we don't allow any tiles (as is the case when we're
973 // invisible), if we have tiles that aren't ready, then we shouldn't
974 // activate as activation can cause checkerboards.
975 bool allow_rasterize_on_demand =
976 global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY &&
977 global_state_.memory_limit_policy != ALLOW_NOTHING;
979 // Use on-demand raster for any required-for-activation tiles that have
980 // not been been assigned memory after reaching a steady memory state. This
981 // ensures that we activate even when OOM. Note that we can't reuse the queue
982 // we used for AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call
983 // could have evicted some tiles that would not be picked up by the old raster
984 // 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 to mark as rasterize on demand, but we don't allow
991 // rasterize on demand, then skip activation and return early.
992 if (!required_for_activation_queue->IsEmpty() && !allow_rasterize_on_demand)
993 return;
995 // Mark required tiles as rasterize on demand.
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_rasterize_on_demand();
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