Send a crash report when a hung process is detected.
[chromium-blink-merge.git] / cc / resources / tile_manager.cc
blobb98b7a6e6399d528701a1440b6debc9c422f2f00
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/base/histograms.h"
17 #include "cc/debug/devtools_instrumentation.h"
18 #include "cc/debug/frame_viewer_instrumentation.h"
19 #include "cc/debug/traced_value.h"
20 #include "cc/layers/picture_layer_impl.h"
21 #include "cc/resources/raster_buffer.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 DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER(
34 ScopedRasterTaskTimer,
35 "Compositing.RasterTask.RasterUs",
36 "Compositing.RasterTask.RasterPixelsPerMs");
38 class RasterTaskImpl : public RasterTask {
39 public:
40 RasterTaskImpl(
41 const Resource* resource,
42 RasterSource* raster_source,
43 const gfx::Rect& content_rect,
44 float contents_scale,
45 TileResolution tile_resolution,
46 int layer_id,
47 const void* tile_id,
48 int source_frame_number,
49 bool analyze_picture,
50 const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>&
51 reply,
52 ImageDecodeTask::Vector* dependencies)
53 : RasterTask(resource, dependencies),
54 raster_source_(raster_source),
55 content_rect_(content_rect),
56 contents_scale_(contents_scale),
57 tile_resolution_(tile_resolution),
58 layer_id_(layer_id),
59 tile_id_(tile_id),
60 source_frame_number_(source_frame_number),
61 analyze_picture_(analyze_picture),
62 reply_(reply) {}
64 // Overridden from Task:
65 void RunOnWorkerThread() override {
66 TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
68 DCHECK(raster_source_.get());
69 DCHECK(raster_buffer_);
71 if (analyze_picture_) {
72 Analyze(raster_source_.get());
73 if (analysis_.is_solid_color)
74 return;
77 Raster(raster_source_.get());
80 // Overridden from TileTask:
81 void ScheduleOnOriginThread(TileTaskClient* client) override {
82 DCHECK(!raster_buffer_);
83 raster_buffer_ = client->AcquireBufferForRaster(resource());
85 void CompleteOnOriginThread(TileTaskClient* client) override {
86 client->ReleaseBufferForRaster(raster_buffer_.Pass());
88 void RunReplyOnOriginThread() override {
89 DCHECK(!raster_buffer_);
90 reply_.Run(analysis_, !HasFinishedRunning());
93 protected:
94 ~RasterTaskImpl() override { DCHECK(!raster_buffer_); }
96 private:
97 void Analyze(const RasterSource* raster_source) {
98 frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task(
99 tile_id_, tile_resolution_, source_frame_number_, layer_id_);
101 DCHECK(raster_source);
103 raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_,
104 &analysis_);
106 // Record the solid color prediction.
107 UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
108 analysis_.is_solid_color);
110 // Clear the flag if we're not using the estimator.
111 analysis_.is_solid_color &= kUseColorEstimator;
114 void Raster(const RasterSource* raster_source) {
115 frame_viewer_instrumentation::ScopedRasterTask raster_task(
116 tile_id_, tile_resolution_, source_frame_number_, layer_id_);
117 ScopedRasterTaskTimer timer;
118 timer.SetArea(content_rect_.size().GetArea());
120 DCHECK(raster_source);
122 raster_buffer_->Playback(raster_source_.get(), content_rect_,
123 contents_scale_);
126 RasterSource::SolidColorAnalysis analysis_;
127 scoped_refptr<RasterSource> raster_source_;
128 gfx::Rect content_rect_;
129 float contents_scale_;
130 TileResolution tile_resolution_;
131 int layer_id_;
132 const void* tile_id_;
133 int source_frame_number_;
134 bool analyze_picture_;
135 const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>
136 reply_;
137 scoped_ptr<RasterBuffer> raster_buffer_;
139 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl);
142 class ImageDecodeTaskImpl : public ImageDecodeTask {
143 public:
144 ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
145 const base::Callback<void(bool was_canceled)>& reply)
146 : pixel_ref_(skia::SharePtr(pixel_ref)),
147 reply_(reply) {}
149 // Overridden from Task:
150 void RunOnWorkerThread() override {
151 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
153 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
154 pixel_ref_.get());
155 // This will cause the image referred to by pixel ref to be decoded.
156 pixel_ref_->lockPixels();
157 pixel_ref_->unlockPixels();
159 // Release the reference after decoding image to ensure that it is not
160 // kept alive unless needed.
161 pixel_ref_.clear();
164 // Overridden from TileTask:
165 void ScheduleOnOriginThread(TileTaskClient* client) override {}
166 void CompleteOnOriginThread(TileTaskClient* client) override {}
167 void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
169 protected:
170 ~ImageDecodeTaskImpl() override {}
172 private:
173 skia::RefPtr<SkPixelRef> pixel_ref_;
174 const base::Callback<void(bool was_canceled)> reply_;
176 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
179 const char* TaskSetName(TaskSet task_set) {
180 switch (task_set) {
181 case TileManager::ALL:
182 return "ALL";
183 case TileManager::REQUIRED_FOR_ACTIVATION:
184 return "REQUIRED_FOR_ACTIVATION";
185 case TileManager::REQUIRED_FOR_DRAW:
186 return "REQUIRED_FOR_DRAW";
189 NOTREACHED();
190 return "Invalid TaskSet";
193 } // namespace
195 RasterTaskCompletionStats::RasterTaskCompletionStats()
196 : completed_count(0u), canceled_count(0u) {}
198 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
199 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
200 scoped_refptr<base::trace_event::TracedValue> state =
201 new base::trace_event::TracedValue();
202 state->SetInteger("completed_count", stats.completed_count);
203 state->SetInteger("canceled_count", stats.canceled_count);
204 return state;
207 // static
208 scoped_ptr<TileManager> TileManager::Create(
209 TileManagerClient* client,
210 base::SequencedTaskRunner* task_runner,
211 ResourcePool* resource_pool,
212 TileTaskRunner* tile_task_runner,
213 size_t scheduled_raster_task_limit) {
214 return make_scoped_ptr(new TileManager(client, task_runner, resource_pool,
215 tile_task_runner,
216 scheduled_raster_task_limit));
219 TileManager::TileManager(
220 TileManagerClient* client,
221 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
222 ResourcePool* resource_pool,
223 TileTaskRunner* tile_task_runner,
224 size_t scheduled_raster_task_limit)
225 : client_(client),
226 task_runner_(task_runner),
227 resource_pool_(resource_pool),
228 tile_task_runner_(tile_task_runner),
229 scheduled_raster_task_limit_(scheduled_raster_task_limit),
230 all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
231 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
232 did_oom_on_last_assign_(false),
233 ready_to_activate_check_notifier_(
234 task_runner_.get(),
235 base::Bind(&TileManager::CheckIfReadyToActivate,
236 base::Unretained(this))),
237 ready_to_draw_check_notifier_(
238 task_runner_.get(),
239 base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))),
240 more_tiles_need_prepare_check_notifier_(
241 task_runner_.get(),
242 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
243 base::Unretained(this))),
244 did_notify_ready_to_activate_(false),
245 did_notify_ready_to_draw_(false) {
246 tile_task_runner_->SetClient(this);
249 TileManager::~TileManager() {
250 // Reset global state and manage. This should cause
251 // our memory usage to drop to zero.
252 global_state_ = GlobalStateThatImpactsTilePriority();
254 TileTaskQueue empty;
255 tile_task_runner_->ScheduleTasks(&empty);
256 orphan_raster_tasks_.clear();
258 // This should finish all pending tasks and release any uninitialized
259 // resources.
260 tile_task_runner_->Shutdown();
261 tile_task_runner_->CheckForCompletedTasks();
263 FreeResourcesForReleasedTiles();
264 CleanUpReleasedTiles();
267 void TileManager::Release(Tile* tile) {
268 released_tiles_.push_back(tile);
271 TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const {
272 TaskSetCollection tasks_that_should_be_forced_to_complete;
273 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY)
274 tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true;
275 return tasks_that_should_be_forced_to_complete;
278 void TileManager::FreeResourcesForReleasedTiles() {
279 for (std::vector<Tile*>::iterator it = released_tiles_.begin();
280 it != released_tiles_.end();
281 ++it) {
282 Tile* tile = *it;
283 FreeResourcesForTile(tile);
287 void TileManager::CleanUpReleasedTiles() {
288 std::vector<Tile*> tiles_to_retain;
289 for (auto* tile : released_tiles_) {
290 if (tile->HasRasterTask()) {
291 tiles_to_retain.push_back(tile);
292 continue;
295 DCHECK(!tile->HasResource());
296 DCHECK(tiles_.find(tile->id()) != tiles_.end());
297 tiles_.erase(tile->id());
299 LayerCountMap::iterator layer_it =
300 used_layer_counts_.find(tile->layer_id());
301 DCHECK_GT(layer_it->second, 0);
302 if (--layer_it->second == 0) {
303 used_layer_counts_.erase(layer_it);
304 image_decode_tasks_.erase(tile->layer_id());
307 delete tile;
309 released_tiles_.swap(tiles_to_retain);
312 void TileManager::DidFinishRunningTileTasks(TaskSet task_set) {
313 TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
314 TaskSetName(task_set));
316 switch (task_set) {
317 case ALL: {
318 bool memory_usage_above_limit =
319 resource_pool_->total_memory_usage_bytes() >
320 global_state_.soft_memory_limit_in_bytes;
322 if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
323 !memory_usage_above_limit)
324 return;
326 more_tiles_need_prepare_check_notifier_.Schedule();
327 return;
329 case REQUIRED_FOR_ACTIVATION:
330 ready_to_activate_check_notifier_.Schedule();
331 return;
332 case REQUIRED_FOR_DRAW:
333 ready_to_draw_check_notifier_.Schedule();
334 return;
337 NOTREACHED();
340 void TileManager::PrepareTiles(
341 const GlobalStateThatImpactsTilePriority& state) {
342 TRACE_EVENT0("cc", "TileManager::PrepareTiles");
344 global_state_ = state;
346 // We need to call CheckForCompletedTasks() once in-between each call
347 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
348 if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
349 tile_task_runner_->CheckForCompletedTasks();
350 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
353 FreeResourcesForReleasedTiles();
354 CleanUpReleasedTiles();
356 TileVector tiles_that_need_to_be_rasterized;
357 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
358 client_->BuildRasterQueue(global_state_.tree_priority,
359 RasterTilePriorityQueue::Type::ALL));
360 AssignGpuMemoryToTiles(raster_priority_queue.get(),
361 scheduled_raster_task_limit_,
362 &tiles_that_need_to_be_rasterized);
364 // Inform the client that will likely require a draw if the highest priority
365 // tile that will be rasterized is required for draw.
366 client_->SetIsLikelyToRequireADraw(
367 !tiles_that_need_to_be_rasterized.empty() &&
368 (*tiles_that_need_to_be_rasterized.begin())->required_for_draw());
370 // Schedule tile tasks.
371 ScheduleTasks(tiles_that_need_to_be_rasterized);
373 did_notify_ready_to_activate_ = false;
374 did_notify_ready_to_draw_ = false;
376 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
377 "state", BasicStateAsValue());
379 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
380 resource_pool_->total_memory_usage_bytes() -
381 resource_pool_->acquired_memory_usage_bytes());
384 void TileManager::UpdateVisibleTiles(
385 const GlobalStateThatImpactsTilePriority& state) {
386 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
388 tile_task_runner_->CheckForCompletedTasks();
390 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
392 TRACE_EVENT_INSTANT1(
393 "cc",
394 "DidUpdateVisibleTiles",
395 TRACE_EVENT_SCOPE_THREAD,
396 "stats",
397 RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
398 update_visible_tiles_stats_ = RasterTaskCompletionStats();
401 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
402 TileManager::BasicStateAsValue() const {
403 scoped_refptr<base::trace_event::TracedValue> value =
404 new base::trace_event::TracedValue();
405 BasicStateAsValueInto(value.get());
406 return value;
409 void TileManager::BasicStateAsValueInto(
410 base::trace_event::TracedValue* state) const {
411 state->SetInteger("tile_count", tiles_.size());
412 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
413 state->BeginDictionary("global_state");
414 global_state_.AsValueInto(state);
415 state->EndDictionary();
418 scoped_ptr<EvictionTilePriorityQueue>
419 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
420 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
421 const MemoryUsage& limit,
422 MemoryUsage* usage) {
423 while (usage->Exceeds(limit)) {
424 if (!eviction_priority_queue) {
425 eviction_priority_queue =
426 client_->BuildEvictionQueue(global_state_.tree_priority);
428 if (eviction_priority_queue->IsEmpty())
429 break;
431 Tile* tile = eviction_priority_queue->Top();
432 *usage -= MemoryUsage::FromTile(tile);
433 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
434 eviction_priority_queue->Pop();
436 return eviction_priority_queue;
439 scoped_ptr<EvictionTilePriorityQueue>
440 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
441 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
442 const MemoryUsage& limit,
443 const TilePriority& other_priority,
444 MemoryUsage* usage) {
445 while (usage->Exceeds(limit)) {
446 if (!eviction_priority_queue) {
447 eviction_priority_queue =
448 client_->BuildEvictionQueue(global_state_.tree_priority);
450 if (eviction_priority_queue->IsEmpty())
451 break;
453 Tile* tile = eviction_priority_queue->Top();
454 if (!other_priority.IsHigherPriorityThan(tile->combined_priority()))
455 break;
457 *usage -= MemoryUsage::FromTile(tile);
458 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
459 eviction_priority_queue->Pop();
461 return eviction_priority_queue;
464 bool TileManager::TilePriorityViolatesMemoryPolicy(
465 const TilePriority& priority) {
466 switch (global_state_.memory_limit_policy) {
467 case ALLOW_NOTHING:
468 return true;
469 case ALLOW_ABSOLUTE_MINIMUM:
470 return priority.priority_bin > TilePriority::NOW;
471 case ALLOW_PREPAINT_ONLY:
472 return priority.priority_bin > TilePriority::SOON;
473 case ALLOW_ANYTHING:
474 return priority.distance_to_visible ==
475 std::numeric_limits<float>::infinity();
477 NOTREACHED();
478 return true;
481 void TileManager::AssignGpuMemoryToTiles(
482 RasterTilePriorityQueue* raster_priority_queue,
483 size_t scheduled_raster_task_limit,
484 TileVector* tiles_that_need_to_be_rasterized) {
485 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
487 // Maintain the list of released resources that can potentially be re-used
488 // or deleted. If this operation becomes expensive too, only do this after
489 // some resource(s) was returned. Note that in that case, one also need to
490 // invalidate when releasing some resource from the pool.
491 resource_pool_->CheckBusyResources(false);
493 // Now give memory out to the tiles until we're out, and build
494 // the needs-to-be-rasterized queue.
495 unsigned schedule_priority = 1u;
496 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
497 bool had_enough_memory_to_schedule_tiles_needed_now = true;
499 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
500 global_state_.num_resources_limit);
501 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
502 global_state_.num_resources_limit);
503 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
504 resource_pool_->acquired_resource_count());
506 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
507 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
508 Tile* tile = raster_priority_queue->Top();
509 TilePriority priority = tile->combined_priority();
511 if (TilePriorityViolatesMemoryPolicy(priority)) {
512 TRACE_EVENT_INSTANT0(
513 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
514 TRACE_EVENT_SCOPE_THREAD);
515 break;
518 // We won't be able to schedule this tile, so break out early.
519 if (tiles_that_need_to_be_rasterized->size() >=
520 scheduled_raster_task_limit) {
521 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
522 break;
525 TileDrawInfo& draw_info = tile->draw_info();
526 tile->scheduled_priority_ = schedule_priority++;
528 DCHECK_IMPLIES(draw_info.mode() != TileDrawInfo::OOM_MODE,
529 !draw_info.IsReadyToDraw());
531 // If the tile already has a raster_task, then the memory used by it is
532 // already accounted for in memory_usage. Otherwise, we'll have to acquire
533 // more memory to create a raster task.
534 MemoryUsage memory_required_by_tile_to_be_scheduled;
535 if (!tile->raster_task_.get()) {
536 memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
537 tile->desired_texture_size(), tile_task_runner_->GetResourceFormat());
540 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
542 // This is the memory limit that will be used by this tile. Depending on
543 // the tile priority, it will be one of hard_memory_limit or
544 // soft_memory_limit.
545 MemoryUsage& tile_memory_limit =
546 tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
548 const MemoryUsage& scheduled_tile_memory_limit =
549 tile_memory_limit - memory_required_by_tile_to_be_scheduled;
550 eviction_priority_queue =
551 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
552 eviction_priority_queue.Pass(), scheduled_tile_memory_limit,
553 priority, &memory_usage);
554 bool memory_usage_is_within_limit =
555 !memory_usage.Exceeds(scheduled_tile_memory_limit);
557 // If we couldn't fit the tile into our current memory limit, then we're
558 // done.
559 if (!memory_usage_is_within_limit) {
560 if (tile_is_needed_now)
561 had_enough_memory_to_schedule_tiles_needed_now = false;
562 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
563 break;
566 memory_usage += memory_required_by_tile_to_be_scheduled;
567 tiles_that_need_to_be_rasterized->push_back(tile);
570 // Note that we should try and further reduce memory in case the above loop
571 // didn't reduce memory. This ensures that we always release as many resources
572 // as possible to stay within the memory limit.
573 eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
574 eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage);
576 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
577 !had_enough_memory_to_schedule_tiles_needed_now);
578 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
580 memory_stats_from_last_assign_.total_budget_in_bytes =
581 global_state_.hard_memory_limit_in_bytes;
582 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
583 memory_stats_from_last_assign_.had_enough_memory =
584 had_enough_memory_to_schedule_tiles_needed_now;
586 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
587 "all_tiles_that_need_to_be_rasterized_are_scheduled",
588 all_tiles_that_need_to_be_rasterized_are_scheduled_,
589 "had_enough_memory_to_schedule_tiles_needed_now",
590 had_enough_memory_to_schedule_tiles_needed_now);
593 void TileManager::FreeResourcesForTile(Tile* tile) {
594 TileDrawInfo& draw_info = tile->draw_info();
595 if (draw_info.resource_)
596 resource_pool_->ReleaseResource(draw_info.resource_.Pass());
599 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
600 Tile* tile) {
601 bool was_ready_to_draw = tile->IsReadyToDraw();
602 FreeResourcesForTile(tile);
603 if (was_ready_to_draw)
604 client_->NotifyTileStateChanged(tile);
607 void TileManager::ScheduleTasks(
608 const TileVector& tiles_that_need_to_be_rasterized) {
609 TRACE_EVENT1("cc",
610 "TileManager::ScheduleTasks",
611 "count",
612 tiles_that_need_to_be_rasterized.size());
614 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
616 raster_queue_.Reset();
618 // Build a new task queue containing all task currently needed. Tasks
619 // are added in order of priority, highest priority task first.
620 for (TileVector::const_iterator it = tiles_that_need_to_be_rasterized.begin();
621 it != tiles_that_need_to_be_rasterized.end();
622 ++it) {
623 Tile* tile = *it;
624 TileDrawInfo& draw_info = tile->draw_info();
626 DCHECK(draw_info.requires_resource());
627 DCHECK(!draw_info.resource_);
629 if (!tile->raster_task_.get())
630 tile->raster_task_ = CreateRasterTask(tile);
632 TaskSetCollection task_sets;
633 if (tile->required_for_activation())
634 task_sets.set(REQUIRED_FOR_ACTIVATION);
635 if (tile->required_for_draw())
636 task_sets.set(REQUIRED_FOR_DRAW);
637 task_sets.set(ALL);
638 raster_queue_.items.push_back(
639 TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
642 // We must reduce the amount of unused resoruces before calling
643 // ScheduleTasks to prevent usage from rising above limits.
644 resource_pool_->ReduceResourceUsage();
646 // Schedule running of |raster_queue_|. This replaces any previously
647 // scheduled tasks and effectively cancels all tasks not present
648 // in |raster_queue_|.
649 tile_task_runner_->ScheduleTasks(&raster_queue_);
651 // It's now safe to clean up orphan tasks as raster worker pool is not
652 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
653 // been called.
654 orphan_raster_tasks_.clear();
656 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
659 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
660 Tile* tile,
661 SkPixelRef* pixel_ref) {
662 return make_scoped_refptr(new ImageDecodeTaskImpl(
663 pixel_ref,
664 base::Bind(&TileManager::OnImageDecodeTaskCompleted,
665 base::Unretained(this),
666 tile->layer_id(),
667 base::Unretained(pixel_ref))));
670 scoped_refptr<RasterTask> TileManager::CreateRasterTask(Tile* tile) {
671 scoped_ptr<ScopedResource> resource =
672 resource_pool_->AcquireResource(tile->desired_texture_size(),
673 tile_task_runner_->GetResourceFormat());
674 const ScopedResource* const_resource = resource.get();
676 // Create and queue all image decode tasks that this tile depends on.
677 ImageDecodeTask::Vector decode_tasks;
678 PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
679 std::vector<SkPixelRef*> pixel_refs;
680 tile->raster_source()->GatherPixelRefs(
681 tile->content_rect(), tile->contents_scale(), &pixel_refs);
682 for (SkPixelRef* pixel_ref : pixel_refs) {
683 uint32_t id = pixel_ref->getGenerationID();
685 // Append existing image decode task if available.
686 PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
687 if (decode_task_it != existing_pixel_refs.end()) {
688 decode_tasks.push_back(decode_task_it->second);
689 continue;
692 // Create and append new image decode task for this pixel ref.
693 scoped_refptr<ImageDecodeTask> decode_task =
694 CreateImageDecodeTask(tile, pixel_ref);
695 decode_tasks.push_back(decode_task);
696 existing_pixel_refs[id] = decode_task;
699 return make_scoped_refptr(new RasterTaskImpl(
700 const_resource, tile->raster_source(), tile->content_rect(),
701 tile->contents_scale(), tile->combined_priority().resolution,
702 tile->layer_id(), static_cast<const void*>(tile),
703 tile->source_frame_number(), tile->use_picture_analysis(),
704 base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this),
705 tile->id(), base::Passed(&resource)),
706 &decode_tasks));
709 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
710 SkPixelRef* pixel_ref,
711 bool was_canceled) {
712 // If the task was canceled, we need to clean it up
713 // from |image_decode_tasks_|.
714 if (!was_canceled)
715 return;
717 LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
718 if (layer_it == image_decode_tasks_.end())
719 return;
721 PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
722 PixelRefTaskMap::iterator task_it =
723 pixel_ref_tasks.find(pixel_ref->getGenerationID());
725 if (task_it != pixel_ref_tasks.end())
726 pixel_ref_tasks.erase(task_it);
729 void TileManager::OnRasterTaskCompleted(
730 Tile::Id tile_id,
731 scoped_ptr<ScopedResource> resource,
732 const RasterSource::SolidColorAnalysis& analysis,
733 bool was_canceled) {
734 DCHECK(tiles_.find(tile_id) != tiles_.end());
736 Tile* tile = tiles_[tile_id];
737 DCHECK(tile->raster_task_.get());
738 orphan_raster_tasks_.push_back(tile->raster_task_);
739 tile->raster_task_ = nullptr;
741 if (was_canceled) {
742 ++update_visible_tiles_stats_.canceled_count;
743 resource_pool_->ReleaseResource(resource.Pass());
744 return;
747 UpdateTileDrawInfo(tile, resource.Pass(), analysis);
750 void TileManager::UpdateTileDrawInfo(
751 Tile* tile,
752 scoped_ptr<ScopedResource> resource,
753 const RasterSource::SolidColorAnalysis& analysis) {
754 TileDrawInfo& draw_info = tile->draw_info();
756 ++update_visible_tiles_stats_.completed_count;
758 if (analysis.is_solid_color) {
759 draw_info.set_solid_color(analysis.solid_color);
760 if (resource)
761 resource_pool_->ReleaseResource(resource.Pass());
762 } else {
763 DCHECK(resource);
764 draw_info.set_use_resource();
765 draw_info.resource_ = resource.Pass();
768 client_->NotifyTileStateChanged(tile);
771 scoped_refptr<Tile> TileManager::CreateTile(
772 RasterSource* raster_source,
773 const gfx::Size& desired_texture_size,
774 const gfx::Rect& content_rect,
775 float contents_scale,
776 int layer_id,
777 int source_frame_number,
778 int flags) {
779 scoped_refptr<Tile> tile = make_scoped_refptr(
780 new Tile(this, raster_source, desired_texture_size, content_rect,
781 contents_scale, layer_id, source_frame_number, flags));
782 DCHECK(tiles_.find(tile->id()) == tiles_.end());
784 tiles_[tile->id()] = tile.get();
785 used_layer_counts_[tile->layer_id()]++;
786 return tile;
789 void TileManager::SetTileTaskRunnerForTesting(
790 TileTaskRunner* tile_task_runner) {
791 tile_task_runner_ = tile_task_runner;
792 tile_task_runner_->SetClient(this);
795 bool TileManager::AreRequiredTilesReadyToDraw(
796 RasterTilePriorityQueue::Type type) const {
797 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
798 client_->BuildRasterQueue(global_state_.tree_priority, type));
799 // It is insufficient to check whether the raster queue we constructed is
800 // empty. The reason for this is that there are situations (rasterize on
801 // demand) when the tile both needs raster and it's ready to draw. Hence, we
802 // have to iterate the queue to check whether the required tiles are ready to
803 // draw.
804 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
805 if (!raster_priority_queue->Top()->IsReadyToDraw())
806 return false;
808 return true;
810 bool TileManager::IsReadyToActivate() const {
811 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
812 return AreRequiredTilesReadyToDraw(
813 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
816 bool TileManager::IsReadyToDraw() const {
817 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
818 return AreRequiredTilesReadyToDraw(
819 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
822 void TileManager::NotifyReadyToActivate() {
823 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
824 if (did_notify_ready_to_activate_)
825 return;
826 client_->NotifyReadyToActivate();
827 did_notify_ready_to_activate_ = true;
830 void TileManager::NotifyReadyToDraw() {
831 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
832 if (did_notify_ready_to_draw_)
833 return;
834 client_->NotifyReadyToDraw();
835 did_notify_ready_to_draw_ = true;
838 void TileManager::CheckIfReadyToActivate() {
839 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
841 tile_task_runner_->CheckForCompletedTasks();
842 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
844 if (did_notify_ready_to_activate_)
845 return;
846 if (!IsReadyToActivate())
847 return;
849 NotifyReadyToActivate();
852 void TileManager::CheckIfReadyToDraw() {
853 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
855 tile_task_runner_->CheckForCompletedTasks();
856 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
858 if (did_notify_ready_to_draw_)
859 return;
860 if (!IsReadyToDraw())
861 return;
863 NotifyReadyToDraw();
866 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
867 tile_task_runner_->CheckForCompletedTasks();
868 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
870 // When OOM, keep re-assigning memory until we reach a steady state
871 // where top-priority tiles are initialized.
872 TileVector tiles_that_need_to_be_rasterized;
873 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
874 client_->BuildRasterQueue(global_state_.tree_priority,
875 RasterTilePriorityQueue::Type::ALL));
876 AssignGpuMemoryToTiles(raster_priority_queue.get(),
877 scheduled_raster_task_limit_,
878 &tiles_that_need_to_be_rasterized);
880 // Inform the client that will likely require a draw if the highest priority
881 // tile that will be rasterized is required for draw.
882 client_->SetIsLikelyToRequireADraw(
883 !tiles_that_need_to_be_rasterized.empty() &&
884 (*tiles_that_need_to_be_rasterized.begin())->required_for_draw());
886 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
887 // steady memory state. Keep scheduling tasks until we reach this state.
888 if (!tiles_that_need_to_be_rasterized.empty()) {
889 ScheduleTasks(tiles_that_need_to_be_rasterized);
890 return;
893 FreeResourcesForReleasedTiles();
895 resource_pool_->ReduceResourceUsage();
897 // We don't reserve memory for required-for-activation tiles during
898 // accelerated gestures, so we just postpone activation when we don't
899 // have these tiles, and activate after the accelerated gesture.
900 // Likewise if we don't allow any tiles (as is the case when we're
901 // invisible), if we have tiles that aren't ready, then we shouldn't
902 // activate as activation can cause checkerboards.
903 bool wait_for_all_required_tiles =
904 global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
905 global_state_.memory_limit_policy == ALLOW_NOTHING;
907 // Mark any required-for-activation tiles that have not been been assigned
908 // memory after reaching a steady memory state as OOM. This ensures that we
909 // activate even when OOM. Note that we can't reuse the queue we used for
910 // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
911 // evicted some tiles that would not be picked up by the old raster queue.
912 scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue(
913 client_->BuildRasterQueue(
914 global_state_.tree_priority,
915 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
917 // If we have tiles left to raster for activation, and we don't allow
918 // activating without them, then skip activation and return early.
919 if (!required_for_activation_queue->IsEmpty() && wait_for_all_required_tiles)
920 return;
922 // Mark required tiles as OOM so that we can activate without them.
923 for (; !required_for_activation_queue->IsEmpty();
924 required_for_activation_queue->Pop()) {
925 Tile* tile = required_for_activation_queue->Top();
926 tile->draw_info().set_oom();
927 client_->NotifyTileStateChanged(tile);
930 DCHECK(IsReadyToActivate());
931 ready_to_activate_check_notifier_.Schedule();
934 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
937 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count)
938 : memory_bytes_(memory_bytes), resource_count_(resource_count) {
941 // static
942 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
943 const gfx::Size& size,
944 ResourceFormat format) {
945 return MemoryUsage(Resource::MemorySizeBytes(size, format), 1);
948 // static
949 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
950 const TileDrawInfo& draw_info = tile->draw_info();
951 if (draw_info.resource_) {
952 return MemoryUsage::FromConfig(draw_info.resource_->size(),
953 draw_info.resource_->format());
955 return MemoryUsage();
958 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
959 const MemoryUsage& other) {
960 memory_bytes_ += other.memory_bytes_;
961 resource_count_ += other.resource_count_;
962 return *this;
965 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
966 const MemoryUsage& other) {
967 memory_bytes_ -= other.memory_bytes_;
968 resource_count_ -= other.resource_count_;
969 return *this;
972 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
973 const MemoryUsage& other) {
974 MemoryUsage result = *this;
975 result -= other;
976 return result;
979 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
980 return memory_bytes_ > limit.memory_bytes_ ||
981 resource_count_ > limit.resource_count_;
984 } // namespace cc