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/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"
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
{
41 const Resource
* resource
,
42 RasterSource
* raster_source
,
43 const gfx::Rect
& content_rect
,
45 TileResolution tile_resolution
,
48 int source_frame_number
,
50 const base::Callback
<void(const RasterSource::SolidColorAnalysis
&, bool)>&
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
),
60 source_frame_number_(source_frame_number
),
61 analyze_picture_(analyze_picture
),
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
)
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());
94 ~RasterTaskImpl() override
{ DCHECK(!raster_buffer_
); }
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_
,
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_
,
126 RasterSource::SolidColorAnalysis analysis_
;
127 scoped_refptr
<RasterSource
> raster_source_
;
128 gfx::Rect content_rect_
;
129 float contents_scale_
;
130 TileResolution tile_resolution_
;
132 const void* tile_id_
;
133 int source_frame_number_
;
134 bool analyze_picture_
;
135 const base::Callback
<void(const RasterSource::SolidColorAnalysis
&, bool)>
137 scoped_ptr
<RasterBuffer
> raster_buffer_
;
139 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl
);
142 class ImageDecodeTaskImpl
: public ImageDecodeTask
{
144 ImageDecodeTaskImpl(SkPixelRef
* pixel_ref
,
145 const base::Callback
<void(bool was_canceled
)>& reply
)
146 : pixel_ref_(skia::SharePtr(pixel_ref
)),
149 // Overridden from Task:
150 void RunOnWorkerThread() override
{
151 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
153 devtools_instrumentation::ScopedImageDecodeTask
image_decode_task(
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.
164 // Overridden from TileTask:
165 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{}
166 void CompleteOnOriginThread(TileTaskClient
* client
) override
{}
167 void RunReplyOnOriginThread() override
{ reply_
.Run(!HasFinishedRunning()); }
170 ~ImageDecodeTaskImpl() override
{}
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
) {
181 case TileManager::ALL
:
183 case TileManager::REQUIRED_FOR_ACTIVATION
:
184 return "REQUIRED_FOR_ACTIVATION";
185 case TileManager::REQUIRED_FOR_DRAW
:
186 return "REQUIRED_FOR_DRAW";
190 return "Invalid TaskSet";
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
);
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
,
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
)
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_(
235 base::Bind(&TileManager::CheckIfReadyToActivate
,
236 base::Unretained(this))),
237 ready_to_draw_check_notifier_(
239 base::Bind(&TileManager::CheckIfReadyToDraw
, base::Unretained(this))),
240 more_tiles_need_prepare_check_notifier_(
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();
255 tile_task_runner_
->ScheduleTasks(&empty
);
256 orphan_raster_tasks_
.clear();
258 // This should finish all pending tasks and release any uninitialized
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();
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
);
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());
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
));
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
)
326 more_tiles_need_prepare_check_notifier_
.Schedule();
329 case REQUIRED_FOR_ACTIVATION
:
330 ready_to_activate_check_notifier_
.Schedule();
332 case REQUIRED_FOR_DRAW
:
333 ready_to_draw_check_notifier_
.Schedule();
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(
394 "DidUpdateVisibleTiles",
395 TRACE_EVENT_SCOPE_THREAD
,
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());
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())
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())
453 Tile
* tile
= eviction_priority_queue
->Top();
454 if (!other_priority
.IsHigherPriorityThan(tile
->combined_priority()))
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
) {
469 case ALLOW_ABSOLUTE_MINIMUM
:
470 return priority
.priority_bin
> TilePriority::NOW
;
471 case ALLOW_PREPAINT_ONLY
:
472 return priority
.priority_bin
> TilePriority::SOON
;
474 return priority
.distance_to_visible
==
475 std::numeric_limits
<float>::infinity();
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
);
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;
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
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;
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(
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
) {
610 "TileManager::ScheduleTasks",
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();
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
);
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
654 orphan_raster_tasks_
.clear();
656 did_check_for_completed_tasks_since_last_schedule_tasks_
= false;
659 scoped_refptr
<ImageDecodeTask
> TileManager::CreateImageDecodeTask(
661 SkPixelRef
* pixel_ref
) {
662 return make_scoped_refptr(new ImageDecodeTaskImpl(
664 base::Bind(&TileManager::OnImageDecodeTaskCompleted
,
665 base::Unretained(this),
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
);
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
)),
709 void TileManager::OnImageDecodeTaskCompleted(int layer_id
,
710 SkPixelRef
* pixel_ref
,
712 // If the task was canceled, we need to clean it up
713 // from |image_decode_tasks_|.
717 LayerPixelRefTaskMap::iterator layer_it
= image_decode_tasks_
.find(layer_id
);
718 if (layer_it
== image_decode_tasks_
.end())
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(
731 scoped_ptr
<ScopedResource
> resource
,
732 const RasterSource::SolidColorAnalysis
& analysis
,
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;
742 ++update_visible_tiles_stats_
.canceled_count
;
743 resource_pool_
->ReleaseResource(resource
.Pass());
747 UpdateTileDrawInfo(tile
, resource
.Pass(), analysis
);
750 void TileManager::UpdateTileDrawInfo(
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
);
761 resource_pool_
->ReleaseResource(resource
.Pass());
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
,
777 int source_frame_number
,
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()]++;
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
804 for (; !raster_priority_queue
->IsEmpty(); raster_priority_queue
->Pop()) {
805 if (!raster_priority_queue
->Top()->IsReadyToDraw())
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_
)
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_
)
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_
)
846 if (!IsReadyToActivate())
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_
)
860 if (!IsReadyToDraw())
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
);
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
)
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
) {
942 TileManager::MemoryUsage
TileManager::MemoryUsage::FromConfig(
943 const gfx::Size
& size
,
944 ResourceFormat format
) {
945 return MemoryUsage(Resource::MemorySizeBytes(size
, format
), 1);
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_
;
965 TileManager::MemoryUsage
& TileManager::MemoryUsage::operator-=(
966 const MemoryUsage
& other
) {
967 memory_bytes_
-= other
.memory_bytes_
;
968 resource_count_
-= other
.resource_count_
;
972 TileManager::MemoryUsage
TileManager::MemoryUsage::operator-(
973 const MemoryUsage
& other
) {
974 MemoryUsage result
= *this;
979 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage
& limit
) const {
980 return memory_bytes_
> limit
.memory_bytes_
||
981 resource_count_
> limit
.resource_count_
;