Supervised User SafeSites: normalize URLs when sending search query.
[chromium-blink-merge.git] / cc / tiles / tile_manager.cc
blob23d2eca12bc23f35ee754226ba18be01066341ca
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/tiles/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/numerics/safe_conversions.h"
16 #include "base/trace_event/trace_event_argument.h"
17 #include "cc/base/histograms.h"
18 #include "cc/debug/devtools_instrumentation.h"
19 #include "cc/debug/frame_viewer_instrumentation.h"
20 #include "cc/debug/traced_value.h"
21 #include "cc/layers/picture_layer_impl.h"
22 #include "cc/raster/raster_buffer.h"
23 #include "cc/raster/tile_task_runner.h"
24 #include "cc/tiles/tile.h"
25 #include "ui/gfx/geometry/rect_conversions.h"
27 namespace cc {
28 namespace {
30 // Flag to indicate whether we should try and detect that
31 // a tile is of solid color.
32 const bool kUseColorEstimator = true;
34 DEFINE_SCOPED_UMA_HISTOGRAM_AREA_TIMER(
35 ScopedRasterTaskTimer,
36 "Compositing.RasterTask.RasterUs",
37 "Compositing.RasterTask.RasterPixelsPerMs");
39 class RasterTaskImpl : public RasterTask {
40 public:
41 RasterTaskImpl(
42 const Resource* resource,
43 RasterSource* raster_source,
44 const gfx::Rect& content_rect,
45 const gfx::Rect& invalid_content_rect,
46 float contents_scale,
47 TileResolution tile_resolution,
48 int layer_id,
49 uint64_t source_prepare_tiles_id,
50 const void* tile,
51 uint64_t new_content_id,
52 uint64_t previous_content_id,
53 uint64_t resource_content_id,
54 int source_frame_number,
55 bool analyze_picture,
56 const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>&
57 reply,
58 ImageDecodeTask::Vector* dependencies)
59 : RasterTask(resource, dependencies),
60 raster_source_(raster_source),
61 content_rect_(content_rect),
62 invalid_content_rect_(invalid_content_rect),
63 contents_scale_(contents_scale),
64 tile_resolution_(tile_resolution),
65 layer_id_(layer_id),
66 source_prepare_tiles_id_(source_prepare_tiles_id),
67 tile_(tile),
68 new_content_id_(new_content_id),
69 previous_content_id_(previous_content_id),
70 resource_content_id_(resource_content_id),
71 source_frame_number_(source_frame_number),
72 analyze_picture_(analyze_picture),
73 reply_(reply) {}
75 // Overridden from Task:
76 void RunOnWorkerThread() override {
77 TRACE_EVENT1("cc", "RasterizerTaskImpl::RunOnWorkerThread",
78 "source_prepare_tiles_id", source_prepare_tiles_id_);
80 DCHECK(raster_source_.get());
81 DCHECK(raster_buffer_);
83 if (analyze_picture_) {
84 Analyze(raster_source_.get());
85 if (analysis_.is_solid_color)
86 return;
89 Raster(raster_source_.get());
92 // Overridden from TileTask:
93 void ScheduleOnOriginThread(TileTaskClient* client) override {
94 DCHECK(!raster_buffer_);
95 raster_buffer_ = client->AcquireBufferForRaster(
96 resource(), resource_content_id_, previous_content_id_);
98 void CompleteOnOriginThread(TileTaskClient* client) override {
99 client->ReleaseBufferForRaster(raster_buffer_.Pass());
101 void RunReplyOnOriginThread() override {
102 DCHECK(!raster_buffer_);
103 reply_.Run(analysis_, !HasFinishedRunning());
106 protected:
107 ~RasterTaskImpl() override { DCHECK(!raster_buffer_); }
109 private:
110 void Analyze(const RasterSource* raster_source) {
111 frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task(
112 tile_, tile_resolution_, source_frame_number_, layer_id_);
114 DCHECK(raster_source);
116 raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_,
117 &analysis_);
118 // Clear the flag if we're not using the estimator.
119 analysis_.is_solid_color &= kUseColorEstimator;
122 void Raster(const RasterSource* raster_source) {
123 frame_viewer_instrumentation::ScopedRasterTask raster_task(
124 tile_, tile_resolution_, source_frame_number_, layer_id_);
125 ScopedRasterTaskTimer timer;
126 timer.SetArea(content_rect_.size().GetArea());
128 DCHECK(raster_source);
130 raster_buffer_->Playback(raster_source_.get(), content_rect_,
131 invalid_content_rect_, new_content_id_,
132 contents_scale_);
135 RasterSource::SolidColorAnalysis analysis_;
136 scoped_refptr<RasterSource> raster_source_;
137 gfx::Rect content_rect_;
138 gfx::Rect invalid_content_rect_;
139 float contents_scale_;
140 TileResolution tile_resolution_;
141 int layer_id_;
142 uint64_t source_prepare_tiles_id_;
143 const void* tile_;
144 uint64_t new_content_id_;
145 uint64_t previous_content_id_;
146 uint64_t resource_content_id_;
147 int source_frame_number_;
148 bool analyze_picture_;
149 const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>
150 reply_;
151 scoped_ptr<RasterBuffer> raster_buffer_;
153 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl);
156 class ImageDecodeTaskImpl : public ImageDecodeTask {
157 public:
158 ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
159 uint64_t source_prepare_tiles_id,
160 const base::Callback<void(bool was_canceled)>& reply)
161 : pixel_ref_(skia::SharePtr(pixel_ref)),
162 source_prepare_tiles_id_(source_prepare_tiles_id),
163 reply_(reply) {}
165 // Overridden from Task:
166 void RunOnWorkerThread() override {
167 TRACE_EVENT1("cc", "ImageDecodeTaskImpl::RunOnWorkerThread",
168 "source_prepare_tiles_id", source_prepare_tiles_id_);
170 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
171 pixel_ref_.get());
172 // This will cause the image referred to by pixel ref to be decoded.
173 pixel_ref_->lockPixels();
174 pixel_ref_->unlockPixels();
176 // Release the reference after decoding image to ensure that it is not
177 // kept alive unless needed.
178 pixel_ref_.clear();
181 // Overridden from TileTask:
182 void ScheduleOnOriginThread(TileTaskClient* client) override {}
183 void CompleteOnOriginThread(TileTaskClient* client) override {}
184 void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
186 protected:
187 ~ImageDecodeTaskImpl() override {}
189 private:
190 skia::RefPtr<SkPixelRef> pixel_ref_;
191 uint64_t source_prepare_tiles_id_;
192 const base::Callback<void(bool was_canceled)> reply_;
194 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
197 const char* TaskSetName(TaskSet task_set) {
198 switch (task_set) {
199 case TileManager::ALL:
200 return "ALL";
201 case TileManager::REQUIRED_FOR_ACTIVATION:
202 return "REQUIRED_FOR_ACTIVATION";
203 case TileManager::REQUIRED_FOR_DRAW:
204 return "REQUIRED_FOR_DRAW";
207 NOTREACHED();
208 return "Invalid TaskSet";
211 } // namespace
213 RasterTaskCompletionStats::RasterTaskCompletionStats()
214 : completed_count(0u), canceled_count(0u) {}
216 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
217 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
218 scoped_refptr<base::trace_event::TracedValue> state =
219 new base::trace_event::TracedValue();
220 state->SetInteger("completed_count",
221 base::saturated_cast<int>(stats.completed_count));
222 state->SetInteger("canceled_count",
223 base::saturated_cast<int>(stats.canceled_count));
224 return state;
227 // static
228 scoped_ptr<TileManager> TileManager::Create(
229 TileManagerClient* client,
230 base::SequencedTaskRunner* task_runner,
231 size_t scheduled_raster_task_limit) {
232 return make_scoped_ptr(
233 new TileManager(client, task_runner, scheduled_raster_task_limit));
236 TileManager::TileManager(
237 TileManagerClient* client,
238 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
239 size_t scheduled_raster_task_limit)
240 : client_(client),
241 task_runner_(task_runner),
242 resource_pool_(nullptr),
243 tile_task_runner_(nullptr),
244 scheduled_raster_task_limit_(scheduled_raster_task_limit),
245 all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
246 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
247 did_oom_on_last_assign_(false),
248 more_tiles_need_prepare_check_notifier_(
249 task_runner_.get(),
250 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
251 base::Unretained(this))),
252 signals_check_notifier_(task_runner_.get(),
253 base::Bind(&TileManager::CheckAndIssueSignals,
254 base::Unretained(this))),
255 has_scheduled_tile_tasks_(false),
256 prepare_tiles_count_(0u) {
259 TileManager::~TileManager() {
260 FinishTasksAndCleanUp();
263 void TileManager::FinishTasksAndCleanUp() {
264 if (!tile_task_runner_)
265 return;
267 global_state_ = GlobalStateThatImpactsTilePriority();
269 TileTaskQueue empty;
270 tile_task_runner_->ScheduleTasks(&empty);
271 orphan_raster_tasks_.clear();
273 // This should finish all pending tasks and release any uninitialized
274 // resources.
275 tile_task_runner_->Shutdown();
276 tile_task_runner_->CheckForCompletedTasks();
278 FreeResourcesForReleasedTiles();
279 CleanUpReleasedTiles();
281 tile_task_runner_ = nullptr;
282 resource_pool_ = nullptr;
283 more_tiles_need_prepare_check_notifier_.Cancel();
284 signals_check_notifier_.Cancel();
287 void TileManager::SetResources(ResourcePool* resource_pool,
288 TileTaskRunner* tile_task_runner,
289 size_t scheduled_raster_task_limit) {
290 DCHECK(!tile_task_runner_);
291 DCHECK(tile_task_runner);
293 scheduled_raster_task_limit_ = scheduled_raster_task_limit;
294 resource_pool_ = resource_pool;
295 tile_task_runner_ = tile_task_runner;
296 tile_task_runner_->SetClient(this);
299 void TileManager::Release(Tile* tile) {
300 released_tiles_.push_back(tile);
303 TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const {
304 TaskSetCollection tasks_that_should_be_forced_to_complete;
305 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY)
306 tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true;
307 return tasks_that_should_be_forced_to_complete;
310 void TileManager::FreeResourcesForReleasedTiles() {
311 for (auto* tile : released_tiles_)
312 FreeResourcesForTile(tile);
315 void TileManager::CleanUpReleasedTiles() {
316 std::vector<Tile*> tiles_to_retain;
317 for (auto* tile : released_tiles_) {
318 if (tile->HasRasterTask()) {
319 tiles_to_retain.push_back(tile);
320 continue;
323 DCHECK(!tile->draw_info().has_resource());
324 DCHECK(tiles_.find(tile->id()) != tiles_.end());
325 tiles_.erase(tile->id());
327 LayerCountMap::iterator layer_it =
328 used_layer_counts_.find(tile->layer_id());
329 DCHECK_GT(layer_it->second, 0);
330 if (--layer_it->second == 0) {
331 used_layer_counts_.erase(layer_it);
332 image_decode_tasks_.erase(tile->layer_id());
335 delete tile;
337 released_tiles_.swap(tiles_to_retain);
340 void TileManager::DidFinishRunningTileTasks(TaskSet task_set) {
341 TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
342 TaskSetName(task_set));
343 DCHECK(resource_pool_);
344 DCHECK(tile_task_runner_);
346 switch (task_set) {
347 case ALL: {
348 has_scheduled_tile_tasks_ = false;
350 bool memory_usage_above_limit =
351 resource_pool_->total_memory_usage_bytes() >
352 global_state_.soft_memory_limit_in_bytes;
354 if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
355 !memory_usage_above_limit) {
356 // TODO(ericrk): We should find a better way to safely handle re-entrant
357 // notifications than always having to schedule a new task.
358 // http://crbug.com/498439
359 signals_.all_tile_tasks_completed = true;
360 signals_check_notifier_.Schedule();
361 return;
364 more_tiles_need_prepare_check_notifier_.Schedule();
365 return;
367 case REQUIRED_FOR_ACTIVATION:
368 signals_.ready_to_activate = true;
369 signals_check_notifier_.Schedule();
370 return;
372 case REQUIRED_FOR_DRAW:
373 signals_.ready_to_draw = true;
374 signals_check_notifier_.Schedule();
375 return;
378 NOTREACHED();
381 bool TileManager::PrepareTiles(
382 const GlobalStateThatImpactsTilePriority& state) {
383 ++prepare_tiles_count_;
385 TRACE_EVENT1("cc", "TileManager::PrepareTiles", "prepare_tiles_id",
386 prepare_tiles_count_);
388 if (!tile_task_runner_) {
389 TRACE_EVENT_INSTANT0("cc", "PrepareTiles aborted",
390 TRACE_EVENT_SCOPE_THREAD);
391 return false;
394 signals_.reset();
395 global_state_ = state;
397 // We need to call CheckForCompletedTasks() once in-between each call
398 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
399 if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
400 tile_task_runner_->CheckForCompletedTasks();
401 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
404 FreeResourcesForReleasedTiles();
405 CleanUpReleasedTiles();
407 PrioritizedTileVector tiles_that_need_to_be_rasterized;
408 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
409 client_->BuildRasterQueue(global_state_.tree_priority,
410 RasterTilePriorityQueue::Type::ALL));
411 AssignGpuMemoryToTiles(raster_priority_queue.get(),
412 scheduled_raster_task_limit_,
413 &tiles_that_need_to_be_rasterized);
415 // Inform the client that will likely require a draw if the highest priority
416 // tile that will be rasterized is required for draw.
417 client_->SetIsLikelyToRequireADraw(
418 !tiles_that_need_to_be_rasterized.empty() &&
419 tiles_that_need_to_be_rasterized.front().tile()->required_for_draw());
421 // Schedule tile tasks.
422 ScheduleTasks(tiles_that_need_to_be_rasterized);
424 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
425 "state", BasicStateAsValue());
427 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
428 resource_pool_->total_memory_usage_bytes() -
429 resource_pool_->acquired_memory_usage_bytes());
430 return true;
433 void TileManager::Flush() {
434 TRACE_EVENT0("cc", "TileManager::Flush");
436 if (!tile_task_runner_) {
437 TRACE_EVENT_INSTANT0("cc", "Flush aborted", TRACE_EVENT_SCOPE_THREAD);
438 return;
441 tile_task_runner_->CheckForCompletedTasks();
443 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
445 TRACE_EVENT_INSTANT1("cc", "DidFlush", TRACE_EVENT_SCOPE_THREAD, "stats",
446 RasterTaskCompletionStatsAsValue(flush_stats_));
447 flush_stats_ = RasterTaskCompletionStats();
450 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
451 TileManager::BasicStateAsValue() const {
452 scoped_refptr<base::trace_event::TracedValue> value =
453 new base::trace_event::TracedValue();
454 BasicStateAsValueInto(value.get());
455 return value;
458 void TileManager::BasicStateAsValueInto(
459 base::trace_event::TracedValue* state) const {
460 state->SetInteger("tile_count", base::saturated_cast<int>(tiles_.size()));
461 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
462 state->BeginDictionary("global_state");
463 global_state_.AsValueInto(state);
464 state->EndDictionary();
467 scoped_ptr<EvictionTilePriorityQueue>
468 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
469 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
470 const MemoryUsage& limit,
471 MemoryUsage* usage) {
472 while (usage->Exceeds(limit)) {
473 if (!eviction_priority_queue) {
474 eviction_priority_queue =
475 client_->BuildEvictionQueue(global_state_.tree_priority);
477 if (eviction_priority_queue->IsEmpty())
478 break;
480 Tile* tile = eviction_priority_queue->Top().tile();
481 *usage -= MemoryUsage::FromTile(tile);
482 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
483 eviction_priority_queue->Pop();
485 return eviction_priority_queue;
488 scoped_ptr<EvictionTilePriorityQueue>
489 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
490 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
491 const MemoryUsage& limit,
492 const TilePriority& other_priority,
493 MemoryUsage* usage) {
494 while (usage->Exceeds(limit)) {
495 if (!eviction_priority_queue) {
496 eviction_priority_queue =
497 client_->BuildEvictionQueue(global_state_.tree_priority);
499 if (eviction_priority_queue->IsEmpty())
500 break;
502 const PrioritizedTile& prioritized_tile = eviction_priority_queue->Top();
503 if (!other_priority.IsHigherPriorityThan(prioritized_tile.priority()))
504 break;
506 Tile* tile = prioritized_tile.tile();
507 *usage -= MemoryUsage::FromTile(tile);
508 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
509 eviction_priority_queue->Pop();
511 return eviction_priority_queue;
514 bool TileManager::TilePriorityViolatesMemoryPolicy(
515 const TilePriority& priority) {
516 switch (global_state_.memory_limit_policy) {
517 case ALLOW_NOTHING:
518 return true;
519 case ALLOW_ABSOLUTE_MINIMUM:
520 return priority.priority_bin > TilePriority::NOW;
521 case ALLOW_PREPAINT_ONLY:
522 return priority.priority_bin > TilePriority::SOON;
523 case ALLOW_ANYTHING:
524 return priority.distance_to_visible ==
525 std::numeric_limits<float>::infinity();
527 NOTREACHED();
528 return true;
531 void TileManager::AssignGpuMemoryToTiles(
532 RasterTilePriorityQueue* raster_priority_queue,
533 size_t scheduled_raster_task_limit,
534 PrioritizedTileVector* tiles_that_need_to_be_rasterized) {
535 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
537 DCHECK(resource_pool_);
538 DCHECK(tile_task_runner_);
540 // Maintain the list of released resources that can potentially be re-used
541 // or deleted. If this operation becomes expensive too, only do this after
542 // some resource(s) was returned. Note that in that case, one also need to
543 // invalidate when releasing some resource from the pool.
544 resource_pool_->CheckBusyResources(false);
546 // Now give memory out to the tiles until we're out, and build
547 // the needs-to-be-rasterized queue.
548 unsigned schedule_priority = 1u;
549 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
550 bool had_enough_memory_to_schedule_tiles_needed_now = true;
552 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
553 global_state_.num_resources_limit);
554 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
555 global_state_.num_resources_limit);
556 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
557 resource_pool_->acquired_resource_count());
559 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
560 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
561 const PrioritizedTile& prioritized_tile = raster_priority_queue->Top();
562 Tile* tile = prioritized_tile.tile();
563 TilePriority priority = prioritized_tile.priority();
565 if (TilePriorityViolatesMemoryPolicy(priority)) {
566 TRACE_EVENT_INSTANT0(
567 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
568 TRACE_EVENT_SCOPE_THREAD);
569 break;
572 // We won't be able to schedule this tile, so break out early.
573 if (tiles_that_need_to_be_rasterized->size() >=
574 scheduled_raster_task_limit) {
575 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
576 break;
579 tile->scheduled_priority_ = schedule_priority++;
581 DCHECK_IMPLIES(tile->draw_info().mode() != TileDrawInfo::OOM_MODE,
582 !tile->draw_info().IsReadyToDraw());
584 // If the tile already has a raster_task, then the memory used by it is
585 // already accounted for in memory_usage. Otherwise, we'll have to acquire
586 // more memory to create a raster task.
587 MemoryUsage memory_required_by_tile_to_be_scheduled;
588 if (!tile->raster_task_.get()) {
589 memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
590 tile->desired_texture_size(), tile_task_runner_->GetResourceFormat());
593 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
595 // This is the memory limit that will be used by this tile. Depending on
596 // the tile priority, it will be one of hard_memory_limit or
597 // soft_memory_limit.
598 MemoryUsage& tile_memory_limit =
599 tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
601 const MemoryUsage& scheduled_tile_memory_limit =
602 tile_memory_limit - memory_required_by_tile_to_be_scheduled;
603 eviction_priority_queue =
604 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
605 eviction_priority_queue.Pass(), scheduled_tile_memory_limit,
606 priority, &memory_usage);
607 bool memory_usage_is_within_limit =
608 !memory_usage.Exceeds(scheduled_tile_memory_limit);
610 // If we couldn't fit the tile into our current memory limit, then we're
611 // done.
612 if (!memory_usage_is_within_limit) {
613 if (tile_is_needed_now)
614 had_enough_memory_to_schedule_tiles_needed_now = false;
615 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
616 break;
619 memory_usage += memory_required_by_tile_to_be_scheduled;
620 tiles_that_need_to_be_rasterized->push_back(prioritized_tile);
623 // Note that we should try and further reduce memory in case the above loop
624 // didn't reduce memory. This ensures that we always release as many resources
625 // as possible to stay within the memory limit.
626 eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
627 eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage);
629 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
630 !had_enough_memory_to_schedule_tiles_needed_now);
631 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
633 memory_stats_from_last_assign_.total_budget_in_bytes =
634 global_state_.hard_memory_limit_in_bytes;
635 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
636 DCHECK_GE(memory_stats_from_last_assign_.total_bytes_used, 0);
637 memory_stats_from_last_assign_.had_enough_memory =
638 had_enough_memory_to_schedule_tiles_needed_now;
640 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
641 "all_tiles_that_need_to_be_rasterized_are_scheduled",
642 all_tiles_that_need_to_be_rasterized_are_scheduled_,
643 "had_enough_memory_to_schedule_tiles_needed_now",
644 had_enough_memory_to_schedule_tiles_needed_now);
647 void TileManager::FreeResourcesForTile(Tile* tile) {
648 TileDrawInfo& draw_info = tile->draw_info();
649 if (draw_info.resource_)
650 resource_pool_->ReleaseResource(draw_info.resource_.Pass(), tile->id());
653 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
654 Tile* tile) {
655 bool was_ready_to_draw = tile->draw_info().IsReadyToDraw();
656 FreeResourcesForTile(tile);
657 if (was_ready_to_draw)
658 client_->NotifyTileStateChanged(tile);
661 void TileManager::ScheduleTasks(
662 const PrioritizedTileVector& tiles_that_need_to_be_rasterized) {
663 TRACE_EVENT1("cc",
664 "TileManager::ScheduleTasks",
665 "count",
666 tiles_that_need_to_be_rasterized.size());
668 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
670 raster_queue_.Reset();
672 // Even when scheduling an empty set of tiles, the TTWP does some work, and
673 // will always trigger a DidFinishRunningTileTasks notification. Because of
674 // this we unconditionally set |has_scheduled_tile_tasks_| to true.
675 has_scheduled_tile_tasks_ = true;
677 // Build a new task queue containing all task currently needed. Tasks
678 // are added in order of priority, highest priority task first.
679 for (auto& prioritized_tile : tiles_that_need_to_be_rasterized) {
680 Tile* tile = prioritized_tile.tile();
682 DCHECK(tile->draw_info().requires_resource());
683 DCHECK(!tile->draw_info().resource_);
685 if (!tile->raster_task_.get())
686 tile->raster_task_ = CreateRasterTask(prioritized_tile);
688 TaskSetCollection task_sets;
689 if (tile->required_for_activation())
690 task_sets.set(REQUIRED_FOR_ACTIVATION);
691 if (tile->required_for_draw())
692 task_sets.set(REQUIRED_FOR_DRAW);
693 task_sets.set(ALL);
694 raster_queue_.items.push_back(
695 TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
698 // We must reduce the amount of unused resoruces before calling
699 // ScheduleTasks to prevent usage from rising above limits.
700 resource_pool_->ReduceResourceUsage();
702 // Schedule running of |raster_queue_|. This replaces any previously
703 // scheduled tasks and effectively cancels all tasks not present
704 // in |raster_queue_|.
705 tile_task_runner_->ScheduleTasks(&raster_queue_);
707 // It's now safe to clean up orphan tasks as raster worker pool is not
708 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
709 // been called.
710 orphan_raster_tasks_.clear();
712 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
715 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
716 Tile* tile,
717 SkPixelRef* pixel_ref) {
718 return make_scoped_refptr(new ImageDecodeTaskImpl(
719 pixel_ref, prepare_tiles_count_,
720 base::Bind(&TileManager::OnImageDecodeTaskCompleted,
721 base::Unretained(this), tile->layer_id(),
722 base::Unretained(pixel_ref))));
725 scoped_refptr<RasterTask> TileManager::CreateRasterTask(
726 const PrioritizedTile& prioritized_tile) {
727 Tile* tile = prioritized_tile.tile();
728 uint64_t resource_content_id = 0;
729 scoped_ptr<ScopedResource> resource;
730 if (tile->invalidated_id()) {
731 // TODO(danakj): For resources that are in use, we should still grab them
732 // and copy from them instead of rastering everything. crbug.com/492754
733 resource =
734 resource_pool_->TryAcquireResourceWithContentId(tile->invalidated_id());
736 if (resource) {
737 resource_content_id = tile->invalidated_id();
738 DCHECK_EQ(tile_task_runner_->GetResourceFormat(), resource->format());
739 DCHECK_EQ(tile->desired_texture_size().ToString(),
740 resource->size().ToString());
741 } else {
742 resource = resource_pool_->AcquireResource(
743 tile->desired_texture_size(), tile_task_runner_->GetResourceFormat());
745 const ScopedResource* const_resource = resource.get();
747 // Create and queue all image decode tasks that this tile depends on.
748 ImageDecodeTask::Vector decode_tasks;
749 PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
750 std::vector<SkPixelRef*> pixel_refs;
751 prioritized_tile.raster_source()->GatherPixelRefs(
752 tile->content_rect(), tile->contents_scale(), &pixel_refs);
753 for (SkPixelRef* pixel_ref : pixel_refs) {
754 uint32_t id = pixel_ref->getGenerationID();
756 // Append existing image decode task if available.
757 PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
758 if (decode_task_it != existing_pixel_refs.end()) {
759 decode_tasks.push_back(decode_task_it->second);
760 continue;
763 // Create and append new image decode task for this pixel ref.
764 scoped_refptr<ImageDecodeTask> decode_task =
765 CreateImageDecodeTask(tile, pixel_ref);
766 decode_tasks.push_back(decode_task);
767 existing_pixel_refs[id] = decode_task;
770 return make_scoped_refptr(new RasterTaskImpl(
771 const_resource, prioritized_tile.raster_source(), tile->content_rect(),
772 tile->invalidated_content_rect(), tile->contents_scale(),
773 prioritized_tile.priority().resolution, tile->layer_id(),
774 prepare_tiles_count_, static_cast<const void*>(tile), tile->id(),
775 tile->invalidated_id(), resource_content_id, tile->source_frame_number(),
776 tile->use_picture_analysis(),
777 base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this),
778 tile->id(), base::Passed(&resource)),
779 &decode_tasks));
782 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
783 SkPixelRef* pixel_ref,
784 bool was_canceled) {
785 // If the task was canceled, we need to clean it up
786 // from |image_decode_tasks_|.
787 if (!was_canceled)
788 return;
790 LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
791 if (layer_it == image_decode_tasks_.end())
792 return;
794 PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
795 PixelRefTaskMap::iterator task_it =
796 pixel_ref_tasks.find(pixel_ref->getGenerationID());
798 if (task_it != pixel_ref_tasks.end())
799 pixel_ref_tasks.erase(task_it);
802 void TileManager::OnRasterTaskCompleted(
803 Tile::Id tile_id,
804 scoped_ptr<ScopedResource> resource,
805 const RasterSource::SolidColorAnalysis& analysis,
806 bool was_canceled) {
807 DCHECK(tiles_.find(tile_id) != tiles_.end());
809 Tile* tile = tiles_[tile_id];
810 DCHECK(tile->raster_task_.get());
811 orphan_raster_tasks_.push_back(tile->raster_task_);
812 tile->raster_task_ = nullptr;
814 if (was_canceled) {
815 ++flush_stats_.canceled_count;
816 resource_pool_->ReleaseResource(resource.Pass(), tile->invalidated_id());
817 return;
820 UpdateTileDrawInfo(tile, resource.Pass(), analysis);
823 void TileManager::UpdateTileDrawInfo(
824 Tile* tile,
825 scoped_ptr<ScopedResource> resource,
826 const RasterSource::SolidColorAnalysis& analysis) {
827 TileDrawInfo& draw_info = tile->draw_info();
829 ++flush_stats_.completed_count;
831 if (analysis.is_solid_color) {
832 draw_info.set_solid_color(analysis.solid_color);
833 if (resource) {
834 // Pass the old tile id here because the tile is solid color so we did not
835 // raster anything into the tile resource.
836 resource_pool_->ReleaseResource(resource.Pass(), tile->invalidated_id());
838 } else {
839 DCHECK(resource);
840 draw_info.set_use_resource();
841 draw_info.resource_ = resource.Pass();
842 draw_info.contents_swizzled_ =
843 tile_task_runner_->GetResourceRequiresSwizzle();
845 DCHECK(draw_info.IsReadyToDraw());
846 draw_info.set_was_ever_ready_to_draw();
848 client_->NotifyTileStateChanged(tile);
851 ScopedTilePtr TileManager::CreateTile(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 // We need to have a tile task worker pool to do anything meaningful with
858 // tiles.
859 DCHECK(tile_task_runner_);
860 ScopedTilePtr tile(new Tile(this, desired_texture_size, content_rect,
861 contents_scale, layer_id, source_frame_number,
862 flags));
863 DCHECK(tiles_.find(tile->id()) == tiles_.end());
865 tiles_[tile->id()] = tile.get();
866 used_layer_counts_[tile->layer_id()]++;
867 return tile;
870 void TileManager::SetTileTaskRunnerForTesting(
871 TileTaskRunner* tile_task_runner) {
872 tile_task_runner_ = tile_task_runner;
873 tile_task_runner_->SetClient(this);
876 bool TileManager::AreRequiredTilesReadyToDraw(
877 RasterTilePriorityQueue::Type type) const {
878 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
879 client_->BuildRasterQueue(global_state_.tree_priority, type));
880 // It is insufficient to check whether the raster queue we constructed is
881 // empty. The reason for this is that there are situations (rasterize on
882 // demand) when the tile both needs raster and it's ready to draw. Hence, we
883 // have to iterate the queue to check whether the required tiles are ready to
884 // draw.
885 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
886 if (!raster_priority_queue->Top().tile()->draw_info().IsReadyToDraw())
887 return false;
890 #if DCHECK_IS_ON()
891 scoped_ptr<RasterTilePriorityQueue> all_queue(
892 client_->BuildRasterQueue(global_state_.tree_priority, type));
893 for (; !all_queue->IsEmpty(); all_queue->Pop()) {
894 Tile* tile = all_queue->Top().tile();
895 DCHECK_IMPLIES(tile->required_for_activation(),
896 tile->draw_info().IsReadyToDraw());
898 #endif
899 return true;
902 bool TileManager::IsReadyToActivate() const {
903 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
904 return AreRequiredTilesReadyToDraw(
905 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
908 bool TileManager::IsReadyToDraw() const {
909 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
910 return AreRequiredTilesReadyToDraw(
911 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
914 void TileManager::CheckAndIssueSignals() {
915 TRACE_EVENT0("cc", "TileManager::CheckAndIssueSignals");
916 tile_task_runner_->CheckForCompletedTasks();
917 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
919 // Ready to activate.
920 if (signals_.ready_to_activate && !signals_.did_notify_ready_to_activate) {
921 signals_.ready_to_activate = false;
922 if (IsReadyToActivate()) {
923 TRACE_EVENT0("cc",
924 "TileManager::CheckAndIssueSignals - ready to activate");
925 signals_.did_notify_ready_to_activate = true;
926 client_->NotifyReadyToActivate();
930 // Ready to draw.
931 if (signals_.ready_to_draw && !signals_.did_notify_ready_to_draw) {
932 signals_.ready_to_draw = false;
933 if (IsReadyToDraw()) {
934 TRACE_EVENT0("cc", "TileManager::CheckAndIssueSignals - ready to draw");
935 signals_.did_notify_ready_to_draw = true;
936 client_->NotifyReadyToDraw();
940 // All tile tasks completed.
941 if (signals_.all_tile_tasks_completed &&
942 !signals_.did_notify_all_tile_tasks_completed) {
943 signals_.all_tile_tasks_completed = false;
944 if (!has_scheduled_tile_tasks_) {
945 TRACE_EVENT0(
946 "cc", "TileManager::CheckAndIssueSignals - all tile tasks completed");
947 signals_.did_notify_all_tile_tasks_completed = true;
948 client_->NotifyAllTileTasksCompleted();
953 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
954 tile_task_runner_->CheckForCompletedTasks();
955 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
957 // When OOM, keep re-assigning memory until we reach a steady state
958 // where top-priority tiles are initialized.
959 PrioritizedTileVector tiles_that_need_to_be_rasterized;
960 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
961 client_->BuildRasterQueue(global_state_.tree_priority,
962 RasterTilePriorityQueue::Type::ALL));
963 AssignGpuMemoryToTiles(raster_priority_queue.get(),
964 scheduled_raster_task_limit_,
965 &tiles_that_need_to_be_rasterized);
967 // Inform the client that will likely require a draw if the highest priority
968 // tile that will be rasterized is required for draw.
969 client_->SetIsLikelyToRequireADraw(
970 !tiles_that_need_to_be_rasterized.empty() &&
971 tiles_that_need_to_be_rasterized.front().tile()->required_for_draw());
973 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
974 // steady memory state. Keep scheduling tasks until we reach this state.
975 if (!tiles_that_need_to_be_rasterized.empty()) {
976 ScheduleTasks(tiles_that_need_to_be_rasterized);
977 return;
980 FreeResourcesForReleasedTiles();
982 resource_pool_->ReduceResourceUsage();
984 signals_.all_tile_tasks_completed = true;
985 signals_check_notifier_.Schedule();
987 // We don't reserve memory for required-for-activation tiles during
988 // accelerated gestures, so we just postpone activation when we don't
989 // have these tiles, and activate after the accelerated gesture.
990 // Likewise if we don't allow any tiles (as is the case when we're
991 // invisible), if we have tiles that aren't ready, then we shouldn't
992 // activate as activation can cause checkerboards.
993 bool wait_for_all_required_tiles =
994 global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
995 global_state_.memory_limit_policy == ALLOW_NOTHING;
997 // Mark any required-for-activation tiles that have not been been assigned
998 // memory after reaching a steady memory state as OOM. This ensures that we
999 // activate even when OOM. Note that we can't reuse the queue we used for
1000 // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
1001 // evicted some tiles that would not be picked up by the old raster queue.
1002 scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue(
1003 client_->BuildRasterQueue(
1004 global_state_.tree_priority,
1005 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
1007 // If we have tiles left to raster for activation, and we don't allow
1008 // activating without them, then skip activation and return early.
1009 if (!required_for_activation_queue->IsEmpty() && wait_for_all_required_tiles)
1010 return;
1012 // Mark required tiles as OOM so that we can activate without them.
1013 for (; !required_for_activation_queue->IsEmpty();
1014 required_for_activation_queue->Pop()) {
1015 Tile* tile = required_for_activation_queue->Top().tile();
1016 tile->draw_info().set_oom();
1017 client_->NotifyTileStateChanged(tile);
1020 DCHECK(IsReadyToActivate());
1021 // TODO(ericrk): Investigate why we need to schedule this (not just call it
1022 // inline). http://crbug.com/498439
1023 signals_.ready_to_activate = true;
1024 signals_check_notifier_.Schedule();
1027 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
1030 TileManager::MemoryUsage::MemoryUsage(size_t memory_bytes,
1031 size_t resource_count)
1032 : memory_bytes_(static_cast<int64>(memory_bytes)),
1033 resource_count_(static_cast<int>(resource_count)) {
1034 // MemoryUsage is constructed using size_ts, since it deals with memory and
1035 // the inputs are typically size_t. However, during the course of usage (in
1036 // particular operator-=) can cause internal values to become negative. Thus,
1037 // member variables are signed.
1038 DCHECK_LE(memory_bytes,
1039 static_cast<size_t>(std::numeric_limits<int64>::max()));
1040 DCHECK_LE(resource_count,
1041 static_cast<size_t>(std::numeric_limits<int>::max()));
1044 // static
1045 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
1046 const gfx::Size& size,
1047 ResourceFormat format) {
1048 // We can use UncheckedMemorySizeBytes here since this is used with a tile
1049 // size which is determined by the compositor (it's at most max texture size).
1050 return MemoryUsage(Resource::UncheckedMemorySizeBytes(size, format), 1);
1053 // static
1054 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
1055 const TileDrawInfo& draw_info = tile->draw_info();
1056 if (draw_info.resource_) {
1057 return MemoryUsage::FromConfig(draw_info.resource_->size(),
1058 draw_info.resource_->format());
1060 return MemoryUsage();
1063 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
1064 const MemoryUsage& other) {
1065 memory_bytes_ += other.memory_bytes_;
1066 resource_count_ += other.resource_count_;
1067 return *this;
1070 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
1071 const MemoryUsage& other) {
1072 memory_bytes_ -= other.memory_bytes_;
1073 resource_count_ -= other.resource_count_;
1074 return *this;
1077 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
1078 const MemoryUsage& other) {
1079 MemoryUsage result = *this;
1080 result -= other;
1081 return result;
1084 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
1085 return memory_bytes_ > limit.memory_bytes_ ||
1086 resource_count_ > limit.resource_count_;
1089 TileManager::Signals::Signals() {
1090 reset();
1093 void TileManager::Signals::reset() {
1094 ready_to_activate = false;
1095 did_notify_ready_to_activate = false;
1096 ready_to_draw = false;
1097 did_notify_ready_to_draw = false;
1098 all_tile_tasks_completed = false;
1099 did_notify_all_tile_tasks_completed = false;
1102 } // namespace cc