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"
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/tile.h"
22 #include "cc/resources/tile_task_runner.h"
23 #include "ui/gfx/geometry/rect_conversions.h"
28 // Flag to indicate whether we should try and detect that
29 // a tile is of solid color.
30 const bool kUseColorEstimator
= true;
32 class RasterTaskImpl
: public RasterTask
{
35 const Resource
* resource
,
36 RasterSource
* raster_source
,
37 const gfx::Rect
& content_rect
,
39 TileResolution tile_resolution
,
42 int source_frame_number
,
44 const base::Callback
<void(const RasterSource::SolidColorAnalysis
&, bool)>&
46 ImageDecodeTask::Vector
* dependencies
)
47 : RasterTask(resource
, dependencies
),
48 raster_source_(raster_source
),
49 content_rect_(content_rect
),
50 contents_scale_(contents_scale
),
51 tile_resolution_(tile_resolution
),
54 source_frame_number_(source_frame_number
),
55 analyze_picture_(analyze_picture
),
58 // Overridden from Task:
59 void RunOnWorkerThread() override
{
60 TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
62 DCHECK(raster_source_
.get());
63 DCHECK(raster_buffer_
);
65 if (analyze_picture_
) {
66 Analyze(raster_source_
.get());
67 if (analysis_
.is_solid_color
)
71 Raster(raster_source_
.get());
74 // Overridden from TileTask:
75 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{
76 DCHECK(!raster_buffer_
);
77 raster_buffer_
= client
->AcquireBufferForRaster(resource());
79 void CompleteOnOriginThread(TileTaskClient
* client
) override
{
80 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
82 void RunReplyOnOriginThread() override
{
83 DCHECK(!raster_buffer_
);
84 reply_
.Run(analysis_
, !HasFinishedRunning());
88 ~RasterTaskImpl() override
{ DCHECK(!raster_buffer_
); }
91 void Analyze(const RasterSource
* raster_source
) {
92 frame_viewer_instrumentation::ScopedAnalyzeTask
analyze_task(
93 tile_id_
, tile_resolution_
, source_frame_number_
, layer_id_
);
95 DCHECK(raster_source
);
97 raster_source
->PerformSolidColorAnalysis(content_rect_
, contents_scale_
,
100 // Record the solid color prediction.
101 UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
102 analysis_
.is_solid_color
);
104 // Clear the flag if we're not using the estimator.
105 analysis_
.is_solid_color
&= kUseColorEstimator
;
108 void Raster(const RasterSource
* raster_source
) {
109 frame_viewer_instrumentation::ScopedRasterTask
raster_task(
110 tile_id_
, tile_resolution_
, source_frame_number_
, layer_id_
);
112 DCHECK(raster_source
);
114 raster_buffer_
->Playback(raster_source_
.get(), content_rect_
,
118 RasterSource::SolidColorAnalysis analysis_
;
119 scoped_refptr
<RasterSource
> raster_source_
;
120 gfx::Rect content_rect_
;
121 float contents_scale_
;
122 TileResolution tile_resolution_
;
124 const void* tile_id_
;
125 int source_frame_number_
;
126 bool analyze_picture_
;
127 const base::Callback
<void(const RasterSource::SolidColorAnalysis
&, bool)>
129 scoped_ptr
<RasterBuffer
> raster_buffer_
;
131 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl
);
134 class ImageDecodeTaskImpl
: public ImageDecodeTask
{
136 ImageDecodeTaskImpl(SkPixelRef
* pixel_ref
,
137 const base::Callback
<void(bool was_canceled
)>& reply
)
138 : pixel_ref_(skia::SharePtr(pixel_ref
)),
141 // Overridden from Task:
142 void RunOnWorkerThread() override
{
143 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
145 devtools_instrumentation::ScopedImageDecodeTask
image_decode_task(
147 // This will cause the image referred to by pixel ref to be decoded.
148 pixel_ref_
->lockPixels();
149 pixel_ref_
->unlockPixels();
151 // Release the reference after decoding image to ensure that it is not
152 // kept alive unless needed.
156 // Overridden from TileTask:
157 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{}
158 void CompleteOnOriginThread(TileTaskClient
* client
) override
{}
159 void RunReplyOnOriginThread() override
{ reply_
.Run(!HasFinishedRunning()); }
162 ~ImageDecodeTaskImpl() override
{}
165 skia::RefPtr
<SkPixelRef
> pixel_ref_
;
166 const base::Callback
<void(bool was_canceled
)> reply_
;
168 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl
);
171 const char* TaskSetName(TaskSet task_set
) {
173 case TileManager::ALL
:
175 case TileManager::REQUIRED_FOR_ACTIVATION
:
176 return "REQUIRED_FOR_ACTIVATION";
177 case TileManager::REQUIRED_FOR_DRAW
:
178 return "REQUIRED_FOR_DRAW";
182 return "Invalid TaskSet";
187 RasterTaskCompletionStats::RasterTaskCompletionStats()
188 : completed_count(0u), canceled_count(0u) {}
190 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
191 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats
& stats
) {
192 scoped_refptr
<base::trace_event::TracedValue
> state
=
193 new base::trace_event::TracedValue();
194 state
->SetInteger("completed_count", stats
.completed_count
);
195 state
->SetInteger("canceled_count", stats
.canceled_count
);
200 scoped_ptr
<TileManager
> TileManager::Create(
201 TileManagerClient
* client
,
202 base::SequencedTaskRunner
* task_runner
,
203 ResourcePool
* resource_pool
,
204 TileTaskRunner
* tile_task_runner
,
205 size_t scheduled_raster_task_limit
) {
206 return make_scoped_ptr(new TileManager(client
, task_runner
, resource_pool
,
208 scheduled_raster_task_limit
));
211 TileManager::TileManager(
212 TileManagerClient
* client
,
213 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
,
214 ResourcePool
* resource_pool
,
215 TileTaskRunner
* tile_task_runner
,
216 size_t scheduled_raster_task_limit
)
218 task_runner_(task_runner
),
219 resource_pool_(resource_pool
),
220 tile_task_runner_(tile_task_runner
),
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_check_notifier_(
227 base::Bind(&TileManager::CheckIfReadyToActivate
,
228 base::Unretained(this))),
229 ready_to_draw_check_notifier_(
231 base::Bind(&TileManager::CheckIfReadyToDraw
, base::Unretained(this))),
232 more_tiles_need_prepare_check_notifier_(
234 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared
,
235 base::Unretained(this))),
236 did_notify_ready_to_activate_(false),
237 did_notify_ready_to_draw_(false) {
238 tile_task_runner_
->SetClient(this);
241 TileManager::~TileManager() {
242 // Reset global state and manage. This should cause
243 // our memory usage to drop to zero.
244 global_state_
= GlobalStateThatImpactsTilePriority();
247 tile_task_runner_
->ScheduleTasks(&empty
);
248 orphan_raster_tasks_
.clear();
250 // This should finish all pending tasks and release any uninitialized
252 tile_task_runner_
->Shutdown();
253 tile_task_runner_
->CheckForCompletedTasks();
255 FreeResourcesForReleasedTiles();
256 CleanUpReleasedTiles();
259 void TileManager::Release(Tile
* tile
) {
260 released_tiles_
.push_back(tile
);
263 TaskSetCollection
TileManager::TasksThatShouldBeForcedToComplete() const {
264 TaskSetCollection tasks_that_should_be_forced_to_complete
;
265 if (global_state_
.tree_priority
!= SMOOTHNESS_TAKES_PRIORITY
)
266 tasks_that_should_be_forced_to_complete
[REQUIRED_FOR_ACTIVATION
] = true;
267 return tasks_that_should_be_forced_to_complete
;
270 void TileManager::FreeResourcesForReleasedTiles() {
271 for (std::vector
<Tile
*>::iterator it
= released_tiles_
.begin();
272 it
!= released_tiles_
.end();
275 FreeResourcesForTile(tile
);
279 void TileManager::CleanUpReleasedTiles() {
280 std::vector
<Tile
*>::iterator it
= released_tiles_
.begin();
281 while (it
!= released_tiles_
.end()) {
284 if (tile
->HasRasterTask()) {
289 DCHECK(!tile
->HasResource());
290 DCHECK(tiles_
.find(tile
->id()) != tiles_
.end());
291 tiles_
.erase(tile
->id());
293 LayerCountMap::iterator layer_it
=
294 used_layer_counts_
.find(tile
->layer_id());
295 DCHECK_GT(layer_it
->second
, 0);
296 if (--layer_it
->second
== 0) {
297 used_layer_counts_
.erase(layer_it
);
298 image_decode_tasks_
.erase(tile
->layer_id());
302 it
= released_tiles_
.erase(it
);
306 void TileManager::DidFinishRunningTileTasks(TaskSet task_set
) {
307 TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
308 TaskSetName(task_set
));
312 bool memory_usage_above_limit
=
313 resource_pool_
->total_memory_usage_bytes() >
314 global_state_
.soft_memory_limit_in_bytes
;
316 if (all_tiles_that_need_to_be_rasterized_are_scheduled_
&&
317 !memory_usage_above_limit
)
320 more_tiles_need_prepare_check_notifier_
.Schedule();
323 case REQUIRED_FOR_ACTIVATION
:
324 ready_to_activate_check_notifier_
.Schedule();
326 case REQUIRED_FOR_DRAW
:
327 ready_to_draw_check_notifier_
.Schedule();
334 void TileManager::PrepareTiles(
335 const GlobalStateThatImpactsTilePriority
& state
) {
336 TRACE_EVENT0("cc", "TileManager::PrepareTiles");
338 global_state_
= state
;
340 // We need to call CheckForCompletedTasks() once in-between each call
341 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
342 if (!did_check_for_completed_tasks_since_last_schedule_tasks_
) {
343 tile_task_runner_
->CheckForCompletedTasks();
344 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
347 FreeResourcesForReleasedTiles();
348 CleanUpReleasedTiles();
350 TileVector tiles_that_need_to_be_rasterized
;
351 scoped_ptr
<RasterTilePriorityQueue
> raster_priority_queue(
352 client_
->BuildRasterQueue(global_state_
.tree_priority
,
353 RasterTilePriorityQueue::Type::ALL
));
354 AssignGpuMemoryToTiles(raster_priority_queue
.get(),
355 scheduled_raster_task_limit_
,
356 &tiles_that_need_to_be_rasterized
);
358 // Inform the client that will likely require a draw if the highest priority
359 // tile that will be rasterized is required for draw.
360 client_
->SetIsLikelyToRequireADraw(
361 !tiles_that_need_to_be_rasterized
.empty() &&
362 (*tiles_that_need_to_be_rasterized
.begin())->required_for_draw());
364 // Schedule tile tasks.
365 ScheduleTasks(tiles_that_need_to_be_rasterized
);
367 did_notify_ready_to_activate_
= false;
368 did_notify_ready_to_draw_
= false;
370 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD
,
371 "state", BasicStateAsValue());
373 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
374 resource_pool_
->total_memory_usage_bytes() -
375 resource_pool_
->acquired_memory_usage_bytes());
378 void TileManager::UpdateVisibleTiles(
379 const GlobalStateThatImpactsTilePriority
& state
) {
380 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
382 tile_task_runner_
->CheckForCompletedTasks();
384 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
386 TRACE_EVENT_INSTANT1(
388 "DidUpdateVisibleTiles",
389 TRACE_EVENT_SCOPE_THREAD
,
391 RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_
));
392 update_visible_tiles_stats_
= RasterTaskCompletionStats();
395 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
396 TileManager::BasicStateAsValue() const {
397 scoped_refptr
<base::trace_event::TracedValue
> value
=
398 new base::trace_event::TracedValue();
399 BasicStateAsValueInto(value
.get());
403 void TileManager::BasicStateAsValueInto(
404 base::trace_event::TracedValue
* state
) const {
405 state
->SetInteger("tile_count", tiles_
.size());
406 state
->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_
);
407 state
->BeginDictionary("global_state");
408 global_state_
.AsValueInto(state
);
409 state
->EndDictionary();
412 scoped_ptr
<EvictionTilePriorityQueue
>
413 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
414 scoped_ptr
<EvictionTilePriorityQueue
> eviction_priority_queue
,
415 const MemoryUsage
& limit
,
416 MemoryUsage
* usage
) {
417 while (usage
->Exceeds(limit
)) {
418 if (!eviction_priority_queue
) {
419 eviction_priority_queue
=
420 client_
->BuildEvictionQueue(global_state_
.tree_priority
);
422 if (eviction_priority_queue
->IsEmpty())
425 Tile
* tile
= eviction_priority_queue
->Top();
426 *usage
-= MemoryUsage::FromTile(tile
);
427 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile
);
428 eviction_priority_queue
->Pop();
430 return eviction_priority_queue
;
433 scoped_ptr
<EvictionTilePriorityQueue
>
434 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
435 scoped_ptr
<EvictionTilePriorityQueue
> eviction_priority_queue
,
436 const MemoryUsage
& limit
,
437 const TilePriority
& other_priority
,
438 MemoryUsage
* usage
) {
439 while (usage
->Exceeds(limit
)) {
440 if (!eviction_priority_queue
) {
441 eviction_priority_queue
=
442 client_
->BuildEvictionQueue(global_state_
.tree_priority
);
444 if (eviction_priority_queue
->IsEmpty())
447 Tile
* tile
= eviction_priority_queue
->Top();
448 if (!other_priority
.IsHigherPriorityThan(tile
->combined_priority()))
451 *usage
-= MemoryUsage::FromTile(tile
);
452 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile
);
453 eviction_priority_queue
->Pop();
455 return eviction_priority_queue
;
458 bool TileManager::TilePriorityViolatesMemoryPolicy(
459 const TilePriority
& priority
) {
460 switch (global_state_
.memory_limit_policy
) {
463 case ALLOW_ABSOLUTE_MINIMUM
:
464 return priority
.priority_bin
> TilePriority::NOW
;
465 case ALLOW_PREPAINT_ONLY
:
466 return priority
.priority_bin
> TilePriority::SOON
;
468 return priority
.distance_to_visible
==
469 std::numeric_limits
<float>::infinity();
475 void TileManager::AssignGpuMemoryToTiles(
476 RasterTilePriorityQueue
* raster_priority_queue
,
477 size_t scheduled_raster_task_limit
,
478 TileVector
* tiles_that_need_to_be_rasterized
) {
479 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
481 // Maintain the list of released resources that can potentially be re-used
482 // or deleted. If this operation becomes expensive too, only do this after
483 // some resource(s) was returned. Note that in that case, one also need to
484 // invalidate when releasing some resource from the pool.
485 resource_pool_
->CheckBusyResources(false);
487 // Now give memory out to the tiles until we're out, and build
488 // the needs-to-be-rasterized queue.
489 unsigned schedule_priority
= 1u;
490 all_tiles_that_need_to_be_rasterized_are_scheduled_
= true;
491 bool had_enough_memory_to_schedule_tiles_needed_now
= true;
493 MemoryUsage
hard_memory_limit(global_state_
.hard_memory_limit_in_bytes
,
494 global_state_
.num_resources_limit
);
495 MemoryUsage
soft_memory_limit(global_state_
.soft_memory_limit_in_bytes
,
496 global_state_
.num_resources_limit
);
497 MemoryUsage
memory_usage(resource_pool_
->acquired_memory_usage_bytes(),
498 resource_pool_
->acquired_resource_count());
500 scoped_ptr
<EvictionTilePriorityQueue
> eviction_priority_queue
;
501 for (; !raster_priority_queue
->IsEmpty(); raster_priority_queue
->Pop()) {
502 Tile
* tile
= raster_priority_queue
->Top();
503 TilePriority priority
= tile
->combined_priority();
505 if (TilePriorityViolatesMemoryPolicy(priority
)) {
506 TRACE_EVENT_INSTANT0(
507 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
508 TRACE_EVENT_SCOPE_THREAD
);
512 // We won't be able to schedule this tile, so break out early.
513 if (tiles_that_need_to_be_rasterized
->size() >=
514 scheduled_raster_task_limit
) {
515 all_tiles_that_need_to_be_rasterized_are_scheduled_
= false;
519 TileDrawInfo
& draw_info
= tile
->draw_info();
520 tile
->scheduled_priority_
= schedule_priority
++;
522 DCHECK_IMPLIES(draw_info
.mode() != TileDrawInfo::OOM_MODE
,
523 !draw_info
.IsReadyToDraw());
525 // If the tile already has a raster_task, then the memory used by it is
526 // already accounted for in memory_usage. Otherwise, we'll have to acquire
527 // more memory to create a raster task.
528 MemoryUsage memory_required_by_tile_to_be_scheduled
;
529 if (!tile
->raster_task_
.get()) {
530 memory_required_by_tile_to_be_scheduled
= MemoryUsage::FromConfig(
531 tile
->desired_texture_size(), tile_task_runner_
->GetResourceFormat());
534 bool tile_is_needed_now
= priority
.priority_bin
== TilePriority::NOW
;
536 // This is the memory limit that will be used by this tile. Depending on
537 // the tile priority, it will be one of hard_memory_limit or
538 // soft_memory_limit.
539 MemoryUsage
& tile_memory_limit
=
540 tile_is_needed_now
? hard_memory_limit
: soft_memory_limit
;
542 const MemoryUsage
& scheduled_tile_memory_limit
=
543 tile_memory_limit
- memory_required_by_tile_to_be_scheduled
;
544 eviction_priority_queue
=
545 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
546 eviction_priority_queue
.Pass(), scheduled_tile_memory_limit
,
547 priority
, &memory_usage
);
548 bool memory_usage_is_within_limit
=
549 !memory_usage
.Exceeds(scheduled_tile_memory_limit
);
551 // If we couldn't fit the tile into our current memory limit, then we're
553 if (!memory_usage_is_within_limit
) {
554 if (tile_is_needed_now
)
555 had_enough_memory_to_schedule_tiles_needed_now
= false;
556 all_tiles_that_need_to_be_rasterized_are_scheduled_
= false;
560 memory_usage
+= memory_required_by_tile_to_be_scheduled
;
561 tiles_that_need_to_be_rasterized
->push_back(tile
);
564 // Note that we should try and further reduce memory in case the above loop
565 // didn't reduce memory. This ensures that we always release as many resources
566 // as possible to stay within the memory limit.
567 eviction_priority_queue
= FreeTileResourcesUntilUsageIsWithinLimit(
568 eviction_priority_queue
.Pass(), hard_memory_limit
, &memory_usage
);
570 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
571 !had_enough_memory_to_schedule_tiles_needed_now
);
572 did_oom_on_last_assign_
= !had_enough_memory_to_schedule_tiles_needed_now
;
574 memory_stats_from_last_assign_
.total_budget_in_bytes
=
575 global_state_
.hard_memory_limit_in_bytes
;
576 memory_stats_from_last_assign_
.total_bytes_used
= memory_usage
.memory_bytes();
577 memory_stats_from_last_assign_
.had_enough_memory
=
578 had_enough_memory_to_schedule_tiles_needed_now
;
580 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
581 "all_tiles_that_need_to_be_rasterized_are_scheduled",
582 all_tiles_that_need_to_be_rasterized_are_scheduled_
,
583 "had_enough_memory_to_schedule_tiles_needed_now",
584 had_enough_memory_to_schedule_tiles_needed_now
);
587 void TileManager::FreeResourcesForTile(Tile
* tile
) {
588 TileDrawInfo
& draw_info
= tile
->draw_info();
589 if (draw_info
.resource_
)
590 resource_pool_
->ReleaseResource(draw_info
.resource_
.Pass());
593 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
595 bool was_ready_to_draw
= tile
->IsReadyToDraw();
596 FreeResourcesForTile(tile
);
597 if (was_ready_to_draw
)
598 client_
->NotifyTileStateChanged(tile
);
601 void TileManager::ScheduleTasks(
602 const TileVector
& tiles_that_need_to_be_rasterized
) {
604 "TileManager::ScheduleTasks",
606 tiles_that_need_to_be_rasterized
.size());
608 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_
);
610 raster_queue_
.Reset();
612 // Build a new task queue containing all task currently needed. Tasks
613 // are added in order of priority, highest priority task first.
614 for (TileVector::const_iterator it
= tiles_that_need_to_be_rasterized
.begin();
615 it
!= tiles_that_need_to_be_rasterized
.end();
618 TileDrawInfo
& draw_info
= tile
->draw_info();
620 DCHECK(draw_info
.requires_resource());
621 DCHECK(!draw_info
.resource_
);
623 if (!tile
->raster_task_
.get())
624 tile
->raster_task_
= CreateRasterTask(tile
);
626 TaskSetCollection task_sets
;
627 if (tile
->required_for_activation())
628 task_sets
.set(REQUIRED_FOR_ACTIVATION
);
629 if (tile
->required_for_draw())
630 task_sets
.set(REQUIRED_FOR_DRAW
);
632 raster_queue_
.items
.push_back(
633 TileTaskQueue::Item(tile
->raster_task_
.get(), task_sets
));
636 // We must reduce the amount of unused resoruces before calling
637 // ScheduleTasks to prevent usage from rising above limits.
638 resource_pool_
->ReduceResourceUsage();
640 // Schedule running of |raster_queue_|. This replaces any previously
641 // scheduled tasks and effectively cancels all tasks not present
642 // in |raster_queue_|.
643 tile_task_runner_
->ScheduleTasks(&raster_queue_
);
645 // It's now safe to clean up orphan tasks as raster worker pool is not
646 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
648 orphan_raster_tasks_
.clear();
650 did_check_for_completed_tasks_since_last_schedule_tasks_
= false;
653 scoped_refptr
<ImageDecodeTask
> TileManager::CreateImageDecodeTask(
655 SkPixelRef
* pixel_ref
) {
656 return make_scoped_refptr(new ImageDecodeTaskImpl(
658 base::Bind(&TileManager::OnImageDecodeTaskCompleted
,
659 base::Unretained(this),
661 base::Unretained(pixel_ref
))));
664 scoped_refptr
<RasterTask
> TileManager::CreateRasterTask(Tile
* tile
) {
665 scoped_ptr
<ScopedResource
> resource
=
666 resource_pool_
->AcquireResource(tile
->desired_texture_size(),
667 tile_task_runner_
->GetResourceFormat());
668 const ScopedResource
* const_resource
= resource
.get();
670 // Create and queue all image decode tasks that this tile depends on.
671 ImageDecodeTask::Vector decode_tasks
;
672 PixelRefTaskMap
& existing_pixel_refs
= image_decode_tasks_
[tile
->layer_id()];
673 std::vector
<SkPixelRef
*> pixel_refs
;
674 tile
->raster_source()->GatherPixelRefs(
675 tile
->content_rect(), tile
->contents_scale(), &pixel_refs
);
676 for (SkPixelRef
* pixel_ref
: pixel_refs
) {
677 uint32_t id
= pixel_ref
->getGenerationID();
679 // Append existing image decode task if available.
680 PixelRefTaskMap::iterator decode_task_it
= existing_pixel_refs
.find(id
);
681 if (decode_task_it
!= existing_pixel_refs
.end()) {
682 decode_tasks
.push_back(decode_task_it
->second
);
686 // Create and append new image decode task for this pixel ref.
687 scoped_refptr
<ImageDecodeTask
> decode_task
=
688 CreateImageDecodeTask(tile
, pixel_ref
);
689 decode_tasks
.push_back(decode_task
);
690 existing_pixel_refs
[id
] = decode_task
;
693 return make_scoped_refptr(new RasterTaskImpl(
694 const_resource
, tile
->raster_source(), tile
->content_rect(),
695 tile
->contents_scale(), tile
->combined_priority().resolution
,
696 tile
->layer_id(), static_cast<const void*>(tile
),
697 tile
->source_frame_number(), tile
->use_picture_analysis(),
698 base::Bind(&TileManager::OnRasterTaskCompleted
, base::Unretained(this),
699 tile
->id(), base::Passed(&resource
)),
703 void TileManager::OnImageDecodeTaskCompleted(int layer_id
,
704 SkPixelRef
* pixel_ref
,
706 // If the task was canceled, we need to clean it up
707 // from |image_decode_tasks_|.
711 LayerPixelRefTaskMap::iterator layer_it
= image_decode_tasks_
.find(layer_id
);
712 if (layer_it
== image_decode_tasks_
.end())
715 PixelRefTaskMap
& pixel_ref_tasks
= layer_it
->second
;
716 PixelRefTaskMap::iterator task_it
=
717 pixel_ref_tasks
.find(pixel_ref
->getGenerationID());
719 if (task_it
!= pixel_ref_tasks
.end())
720 pixel_ref_tasks
.erase(task_it
);
723 void TileManager::OnRasterTaskCompleted(
725 scoped_ptr
<ScopedResource
> resource
,
726 const RasterSource::SolidColorAnalysis
& analysis
,
728 DCHECK(tiles_
.find(tile_id
) != tiles_
.end());
730 Tile
* tile
= tiles_
[tile_id
];
731 DCHECK(tile
->raster_task_
.get());
732 orphan_raster_tasks_
.push_back(tile
->raster_task_
);
733 tile
->raster_task_
= nullptr;
736 ++update_visible_tiles_stats_
.canceled_count
;
737 resource_pool_
->ReleaseResource(resource
.Pass());
741 UpdateTileDrawInfo(tile
, resource
.Pass(), analysis
);
744 void TileManager::UpdateTileDrawInfo(
746 scoped_ptr
<ScopedResource
> resource
,
747 const RasterSource::SolidColorAnalysis
& analysis
) {
748 TileDrawInfo
& draw_info
= tile
->draw_info();
750 ++update_visible_tiles_stats_
.completed_count
;
752 if (analysis
.is_solid_color
) {
753 draw_info
.set_solid_color(analysis
.solid_color
);
755 resource_pool_
->ReleaseResource(resource
.Pass());
758 draw_info
.set_use_resource();
759 draw_info
.resource_
= resource
.Pass();
762 client_
->NotifyTileStateChanged(tile
);
765 scoped_refptr
<Tile
> TileManager::CreateTile(
766 RasterSource
* raster_source
,
767 const gfx::Size
& desired_texture_size
,
768 const gfx::Rect
& content_rect
,
769 float contents_scale
,
771 int source_frame_number
,
773 scoped_refptr
<Tile
> tile
= make_scoped_refptr(
774 new Tile(this, raster_source
, desired_texture_size
, content_rect
,
775 contents_scale
, layer_id
, source_frame_number
, flags
));
776 DCHECK(tiles_
.find(tile
->id()) == tiles_
.end());
778 tiles_
[tile
->id()] = tile
.get();
779 used_layer_counts_
[tile
->layer_id()]++;
783 void TileManager::SetTileTaskRunnerForTesting(
784 TileTaskRunner
* tile_task_runner
) {
785 tile_task_runner_
= tile_task_runner
;
786 tile_task_runner_
->SetClient(this);
789 bool TileManager::AreRequiredTilesReadyToDraw(
790 RasterTilePriorityQueue::Type type
) const {
791 scoped_ptr
<RasterTilePriorityQueue
> raster_priority_queue(
792 client_
->BuildRasterQueue(global_state_
.tree_priority
, type
));
793 // It is insufficient to check whether the raster queue we constructed is
794 // empty. The reason for this is that there are situations (rasterize on
795 // demand) when the tile both needs raster and it's ready to draw. Hence, we
796 // have to iterate the queue to check whether the required tiles are ready to
798 for (; !raster_priority_queue
->IsEmpty(); raster_priority_queue
->Pop()) {
799 if (!raster_priority_queue
->Top()->IsReadyToDraw())
804 bool TileManager::IsReadyToActivate() const {
805 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
806 return AreRequiredTilesReadyToDraw(
807 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION
);
810 bool TileManager::IsReadyToDraw() const {
811 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
812 return AreRequiredTilesReadyToDraw(
813 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW
);
816 void TileManager::NotifyReadyToActivate() {
817 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
818 if (did_notify_ready_to_activate_
)
820 client_
->NotifyReadyToActivate();
821 did_notify_ready_to_activate_
= true;
824 void TileManager::NotifyReadyToDraw() {
825 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
826 if (did_notify_ready_to_draw_
)
828 client_
->NotifyReadyToDraw();
829 did_notify_ready_to_draw_
= true;
832 void TileManager::CheckIfReadyToActivate() {
833 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
835 tile_task_runner_
->CheckForCompletedTasks();
836 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
838 if (did_notify_ready_to_activate_
)
840 if (!IsReadyToActivate())
843 NotifyReadyToActivate();
846 void TileManager::CheckIfReadyToDraw() {
847 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
849 tile_task_runner_
->CheckForCompletedTasks();
850 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
852 if (did_notify_ready_to_draw_
)
854 if (!IsReadyToDraw())
860 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
861 tile_task_runner_
->CheckForCompletedTasks();
862 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
864 // When OOM, keep re-assigning memory until we reach a steady state
865 // where top-priority tiles are initialized.
866 TileVector tiles_that_need_to_be_rasterized
;
867 scoped_ptr
<RasterTilePriorityQueue
> raster_priority_queue(
868 client_
->BuildRasterQueue(global_state_
.tree_priority
,
869 RasterTilePriorityQueue::Type::ALL
));
870 AssignGpuMemoryToTiles(raster_priority_queue
.get(),
871 scheduled_raster_task_limit_
,
872 &tiles_that_need_to_be_rasterized
);
874 // Inform the client that will likely require a draw if the highest priority
875 // tile that will be rasterized is required for draw.
876 client_
->SetIsLikelyToRequireADraw(
877 !tiles_that_need_to_be_rasterized
.empty() &&
878 (*tiles_that_need_to_be_rasterized
.begin())->required_for_draw());
880 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
881 // steady memory state. Keep scheduling tasks until we reach this state.
882 if (!tiles_that_need_to_be_rasterized
.empty()) {
883 ScheduleTasks(tiles_that_need_to_be_rasterized
);
887 FreeResourcesForReleasedTiles();
889 resource_pool_
->ReduceResourceUsage();
891 // We don't reserve memory for required-for-activation tiles during
892 // accelerated gestures, so we just postpone activation when we don't
893 // have these tiles, and activate after the accelerated gesture.
894 // Likewise if we don't allow any tiles (as is the case when we're
895 // invisible), if we have tiles that aren't ready, then we shouldn't
896 // activate as activation can cause checkerboards.
897 bool wait_for_all_required_tiles
=
898 global_state_
.tree_priority
== SMOOTHNESS_TAKES_PRIORITY
||
899 global_state_
.memory_limit_policy
== ALLOW_NOTHING
;
901 // Mark any required-for-activation tiles that have not been been assigned
902 // memory after reaching a steady memory state as OOM. This ensures that we
903 // activate even when OOM. Note that we can't reuse the queue we used for
904 // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
905 // evicted some tiles that would not be picked up by the old raster queue.
906 scoped_ptr
<RasterTilePriorityQueue
> required_for_activation_queue(
907 client_
->BuildRasterQueue(
908 global_state_
.tree_priority
,
909 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION
));
911 // If we have tiles left to raster for activation, and we don't allow
912 // activating without them, then skip activation and return early.
913 if (!required_for_activation_queue
->IsEmpty() && wait_for_all_required_tiles
)
916 // Mark required tiles as OOM so that we can activate without them.
917 for (; !required_for_activation_queue
->IsEmpty();
918 required_for_activation_queue
->Pop()) {
919 Tile
* tile
= required_for_activation_queue
->Top();
920 tile
->draw_info().set_oom();
921 client_
->NotifyTileStateChanged(tile
);
924 DCHECK(IsReadyToActivate());
925 ready_to_activate_check_notifier_
.Schedule();
928 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
931 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes
, int resource_count
)
932 : memory_bytes_(memory_bytes
), resource_count_(resource_count
) {
936 TileManager::MemoryUsage
TileManager::MemoryUsage::FromConfig(
937 const gfx::Size
& size
,
938 ResourceFormat format
) {
939 return MemoryUsage(Resource::MemorySizeBytes(size
, format
), 1);
943 TileManager::MemoryUsage
TileManager::MemoryUsage::FromTile(const Tile
* tile
) {
944 const TileDrawInfo
& draw_info
= tile
->draw_info();
945 if (draw_info
.resource_
) {
946 return MemoryUsage::FromConfig(draw_info
.resource_
->size(),
947 draw_info
.resource_
->format());
949 return MemoryUsage();
952 TileManager::MemoryUsage
& TileManager::MemoryUsage::operator+=(
953 const MemoryUsage
& other
) {
954 memory_bytes_
+= other
.memory_bytes_
;
955 resource_count_
+= other
.resource_count_
;
959 TileManager::MemoryUsage
& TileManager::MemoryUsage::operator-=(
960 const MemoryUsage
& other
) {
961 memory_bytes_
-= other
.memory_bytes_
;
962 resource_count_
-= other
.resource_count_
;
966 TileManager::MemoryUsage
TileManager::MemoryUsage::operator-(
967 const MemoryUsage
& other
) {
968 MemoryUsage result
= *this;
973 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage
& limit
) const {
974 return memory_bytes_
> limit
.memory_bytes_
||
975 resource_count_
> limit
.resource_count_
;