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/rasterizer.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 class RasterTaskImpl
: public RasterTask
{
36 const Resource
* resource
,
37 RasterSource
* raster_source
,
38 const gfx::Rect
& content_rect
,
40 TileResolution tile_resolution
,
43 int source_frame_number
,
45 const base::Callback
<void(const RasterSource::SolidColorAnalysis
&, bool)>&
47 ImageDecodeTask::Vector
* dependencies
)
48 : RasterTask(resource
, dependencies
),
49 raster_source_(raster_source
),
50 content_rect_(content_rect
),
51 contents_scale_(contents_scale
),
52 tile_resolution_(tile_resolution
),
55 source_frame_number_(source_frame_number
),
56 analyze_picture_(analyze_picture
),
59 // Overridden from Task:
60 void RunOnWorkerThread() override
{
61 TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
63 DCHECK(raster_source_
.get());
64 DCHECK(raster_buffer_
);
66 if (analyze_picture_
) {
67 Analyze(raster_source_
.get());
68 if (analysis_
.is_solid_color
)
72 Raster(raster_source_
.get());
75 // Overridden from TileTask:
76 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{
77 DCHECK(!raster_buffer_
);
78 raster_buffer_
= client
->AcquireBufferForRaster(resource());
80 void CompleteOnOriginThread(TileTaskClient
* client
) override
{
81 client
->ReleaseBufferForRaster(raster_buffer_
.Pass());
83 void RunReplyOnOriginThread() override
{
84 DCHECK(!raster_buffer_
);
85 reply_
.Run(analysis_
, !HasFinishedRunning());
89 ~RasterTaskImpl() override
{ DCHECK(!raster_buffer_
); }
92 void Analyze(const RasterSource
* raster_source
) {
93 frame_viewer_instrumentation::ScopedAnalyzeTask
analyze_task(
94 tile_id_
, tile_resolution_
, source_frame_number_
, layer_id_
);
96 DCHECK(raster_source
);
98 raster_source
->PerformSolidColorAnalysis(content_rect_
, contents_scale_
,
101 // Record the solid color prediction.
102 UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
103 analysis_
.is_solid_color
);
105 // Clear the flag if we're not using the estimator.
106 analysis_
.is_solid_color
&= kUseColorEstimator
;
109 void Raster(const RasterSource
* raster_source
) {
110 frame_viewer_instrumentation::ScopedRasterTask
raster_task(
111 tile_id_
, tile_resolution_
, source_frame_number_
, layer_id_
);
113 DCHECK(raster_source
);
115 raster_buffer_
->Playback(raster_source_
.get(), content_rect_
,
119 RasterSource::SolidColorAnalysis analysis_
;
120 scoped_refptr
<RasterSource
> raster_source_
;
121 gfx::Rect content_rect_
;
122 float contents_scale_
;
123 TileResolution tile_resolution_
;
125 const void* tile_id_
;
126 int source_frame_number_
;
127 bool analyze_picture_
;
128 const base::Callback
<void(const RasterSource::SolidColorAnalysis
&, bool)>
130 scoped_ptr
<RasterBuffer
> raster_buffer_
;
132 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl
);
135 class ImageDecodeTaskImpl
: public ImageDecodeTask
{
137 ImageDecodeTaskImpl(SkPixelRef
* pixel_ref
,
138 const base::Callback
<void(bool was_canceled
)>& reply
)
139 : pixel_ref_(skia::SharePtr(pixel_ref
)),
142 // Overridden from Task:
143 void RunOnWorkerThread() override
{
144 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
146 devtools_instrumentation::ScopedImageDecodeTask
image_decode_task(
148 // This will cause the image referred to by pixel ref to be decoded.
149 pixel_ref_
->lockPixels();
150 pixel_ref_
->unlockPixels();
152 // Release the reference after decoding image to ensure that it is not
153 // kept alive unless needed.
157 // Overridden from TileTask:
158 void ScheduleOnOriginThread(TileTaskClient
* client
) override
{}
159 void CompleteOnOriginThread(TileTaskClient
* client
) override
{}
160 void RunReplyOnOriginThread() override
{ reply_
.Run(!HasFinishedRunning()); }
163 ~ImageDecodeTaskImpl() override
{}
166 skia::RefPtr
<SkPixelRef
> pixel_ref_
;
167 const base::Callback
<void(bool was_canceled
)> reply_
;
169 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl
);
172 const char* TaskSetName(TaskSet task_set
) {
174 case TileManager::ALL
:
176 case TileManager::REQUIRED_FOR_ACTIVATION
:
177 return "REQUIRED_FOR_ACTIVATION";
178 case TileManager::REQUIRED_FOR_DRAW
:
179 return "REQUIRED_FOR_DRAW";
183 return "Invalid TaskSet";
188 RasterTaskCompletionStats::RasterTaskCompletionStats()
189 : completed_count(0u), canceled_count(0u) {}
191 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
192 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats
& stats
) {
193 scoped_refptr
<base::trace_event::TracedValue
> state
=
194 new base::trace_event::TracedValue();
195 state
->SetInteger("completed_count", stats
.completed_count
);
196 state
->SetInteger("canceled_count", stats
.canceled_count
);
201 scoped_ptr
<TileManager
> TileManager::Create(
202 TileManagerClient
* client
,
203 base::SequencedTaskRunner
* task_runner
,
204 ResourcePool
* resource_pool
,
205 TileTaskRunner
* tile_task_runner
,
206 Rasterizer
* rasterizer
,
207 size_t scheduled_raster_task_limit
) {
208 return make_scoped_ptr(new TileManager(client
, task_runner
, resource_pool
,
209 tile_task_runner
, rasterizer
,
210 scheduled_raster_task_limit
));
213 TileManager::TileManager(
214 TileManagerClient
* client
,
215 const scoped_refptr
<base::SequencedTaskRunner
>& task_runner
,
216 ResourcePool
* resource_pool
,
217 TileTaskRunner
* tile_task_runner
,
218 Rasterizer
* rasterizer
,
219 size_t scheduled_raster_task_limit
)
221 task_runner_(task_runner
),
222 resource_pool_(resource_pool
),
223 tile_task_runner_(tile_task_runner
),
224 rasterizer_(rasterizer
),
225 scheduled_raster_task_limit_(scheduled_raster_task_limit
),
226 all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
227 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
228 did_oom_on_last_assign_(false),
229 ready_to_activate_notifier_(
231 base::Bind(&TileManager::NotifyReadyToActivate
,
232 base::Unretained(this))),
233 ready_to_draw_notifier_(
235 base::Bind(&TileManager::NotifyReadyToDraw
, base::Unretained(this))),
236 ready_to_activate_check_notifier_(
238 base::Bind(&TileManager::CheckIfReadyToActivate
,
239 base::Unretained(this))),
240 ready_to_draw_check_notifier_(
242 base::Bind(&TileManager::CheckIfReadyToDraw
, base::Unretained(this))),
243 more_tiles_need_prepare_check_notifier_(
245 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared
,
246 base::Unretained(this))),
247 did_notify_ready_to_activate_(false),
248 did_notify_ready_to_draw_(false) {
249 tile_task_runner_
->SetClient(this);
252 TileManager::~TileManager() {
253 // Reset global state and manage. This should cause
254 // our memory usage to drop to zero.
255 global_state_
= GlobalStateThatImpactsTilePriority();
258 tile_task_runner_
->ScheduleTasks(&empty
);
259 orphan_raster_tasks_
.clear();
261 // This should finish all pending tasks and release any uninitialized
263 tile_task_runner_
->Shutdown();
264 tile_task_runner_
->CheckForCompletedTasks();
266 FreeResourcesForReleasedTiles();
267 CleanUpReleasedTiles();
270 void TileManager::Release(Tile
* tile
) {
271 released_tiles_
.push_back(tile
);
274 TaskSetCollection
TileManager::TasksThatShouldBeForcedToComplete() const {
275 TaskSetCollection tasks_that_should_be_forced_to_complete
;
276 if (global_state_
.tree_priority
!= SMOOTHNESS_TAKES_PRIORITY
)
277 tasks_that_should_be_forced_to_complete
[REQUIRED_FOR_ACTIVATION
] = true;
278 return tasks_that_should_be_forced_to_complete
;
281 void TileManager::FreeResourcesForReleasedTiles() {
282 for (std::vector
<Tile
*>::iterator it
= released_tiles_
.begin();
283 it
!= released_tiles_
.end();
286 FreeResourcesForTile(tile
);
290 void TileManager::CleanUpReleasedTiles() {
291 std::vector
<Tile
*>::iterator it
= released_tiles_
.begin();
292 while (it
!= released_tiles_
.end()) {
295 if (tile
->HasRasterTask()) {
300 DCHECK(!tile
->HasResource());
301 DCHECK(tiles_
.find(tile
->id()) != tiles_
.end());
302 tiles_
.erase(tile
->id());
304 LayerCountMap::iterator layer_it
=
305 used_layer_counts_
.find(tile
->layer_id());
306 DCHECK_GT(layer_it
->second
, 0);
307 if (--layer_it
->second
== 0) {
308 used_layer_counts_
.erase(layer_it
);
309 image_decode_tasks_
.erase(tile
->layer_id());
313 it
= released_tiles_
.erase(it
);
317 void TileManager::DidFinishRunningTileTasks(TaskSet task_set
) {
318 TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
319 TaskSetName(task_set
));
323 bool memory_usage_above_limit
=
324 resource_pool_
->total_memory_usage_bytes() >
325 global_state_
.soft_memory_limit_in_bytes
;
327 if (all_tiles_that_need_to_be_rasterized_are_scheduled_
&&
328 !memory_usage_above_limit
)
331 more_tiles_need_prepare_check_notifier_
.Schedule();
334 case REQUIRED_FOR_ACTIVATION
:
335 ready_to_activate_check_notifier_
.Schedule();
337 case REQUIRED_FOR_DRAW
:
338 ready_to_draw_check_notifier_
.Schedule();
345 void TileManager::PrepareTiles(
346 const GlobalStateThatImpactsTilePriority
& state
) {
347 TRACE_EVENT0("cc", "TileManager::PrepareTiles");
349 global_state_
= state
;
351 PrepareTilesMode prepare_tiles_mode
= rasterizer_
->GetPrepareTilesMode();
353 // TODO(hendrikw): Consider moving some of this code to the rasterizer.
354 if (prepare_tiles_mode
!= PrepareTilesMode::PREPARE_NONE
) {
355 // We need to call CheckForCompletedTasks() once in-between each call
356 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
357 if (!did_check_for_completed_tasks_since_last_schedule_tasks_
) {
358 tile_task_runner_
->CheckForCompletedTasks();
359 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
362 FreeResourcesForReleasedTiles();
363 CleanUpReleasedTiles();
365 TileVector tiles_that_need_to_be_rasterized
;
366 scoped_ptr
<RasterTilePriorityQueue
> raster_priority_queue(
367 client_
->BuildRasterQueue(global_state_
.tree_priority
,
368 RasterTilePriorityQueue::Type::ALL
));
369 AssignGpuMemoryToTiles(raster_priority_queue
.get(),
370 scheduled_raster_task_limit_
,
371 &tiles_that_need_to_be_rasterized
);
373 // Inform the client that will likely require a draw if the highest priority
374 // tile that will be rasterized is required for draw.
375 client_
->SetIsLikelyToRequireADraw(
376 !tiles_that_need_to_be_rasterized
.empty() &&
377 (*tiles_that_need_to_be_rasterized
.begin())->required_for_draw());
379 // Schedule tile tasks.
380 ScheduleTasks(tiles_that_need_to_be_rasterized
);
382 did_notify_ready_to_activate_
= false;
383 did_notify_ready_to_draw_
= false;
385 if (global_state_
.hard_memory_limit_in_bytes
== 0) {
386 resource_pool_
->CheckBusyResources(false);
387 MemoryUsage
memory_limit(0, 0);
388 MemoryUsage
memory_usage(resource_pool_
->acquired_memory_usage_bytes(),
389 resource_pool_
->acquired_resource_count());
390 FreeTileResourcesUntilUsageIsWithinLimit(nullptr, memory_limit
,
394 did_notify_ready_to_activate_
= false;
395 did_notify_ready_to_draw_
= false;
396 ready_to_activate_notifier_
.Schedule();
397 ready_to_draw_notifier_
.Schedule();
400 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD
,
401 "state", BasicStateAsValue());
403 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
404 resource_pool_
->total_memory_usage_bytes() -
405 resource_pool_
->acquired_memory_usage_bytes());
408 void TileManager::SynchronouslyRasterizeTiles(
409 const GlobalStateThatImpactsTilePriority
& state
) {
410 TRACE_EVENT0("cc", "TileManager::SynchronouslyRasterizeTiles");
412 DCHECK(rasterizer_
->GetPrepareTilesMode() !=
413 PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES
);
415 global_state_
= state
;
417 FreeResourcesForReleasedTiles();
418 CleanUpReleasedTiles();
420 scoped_ptr
<RasterTilePriorityQueue
> required_for_draw_queue(
421 client_
->BuildRasterQueue(
422 global_state_
.tree_priority
,
423 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW
));
424 TileVector tiles_that_need_to_be_rasterized
;
425 AssignGpuMemoryToTiles(required_for_draw_queue
.get(),
426 std::numeric_limits
<size_t>::max(),
427 &tiles_that_need_to_be_rasterized
);
429 // We must reduce the amount of unused resources before calling
430 // RunTasks to prevent usage from rising above limits.
431 resource_pool_
->ReduceResourceUsage();
433 // Run and complete all raster task synchronously.
434 rasterizer_
->RasterizeTiles(
435 tiles_that_need_to_be_rasterized
, resource_pool_
,
436 tile_task_runner_
->GetResourceFormat(),
437 base::Bind(&TileManager::UpdateTileDrawInfo
, base::Unretained(this)));
439 // Use on-demand raster for any required-for-draw tiles that have not been
440 // assigned memory after reaching a steady memory state.
441 // TODO(hendrikw): Figure out why this would improve jank on some tests - See
443 required_for_draw_queue
= client_
->BuildRasterQueue(
444 global_state_
.tree_priority
,
445 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW
);
447 // Change to OOM mode for any tiles that have not been been assigned memory.
448 // This ensures that we draw even when OOM.
449 for (; !required_for_draw_queue
->IsEmpty(); required_for_draw_queue
->Pop()) {
450 Tile
* tile
= required_for_draw_queue
->Top();
451 tile
->draw_info().set_oom();
452 client_
->NotifyTileStateChanged(tile
);
455 TRACE_EVENT_INSTANT1("cc", "DidRasterize", TRACE_EVENT_SCOPE_THREAD
, "state",
456 BasicStateAsValue());
458 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
459 resource_pool_
->total_memory_usage_bytes() -
460 resource_pool_
->acquired_memory_usage_bytes());
463 void TileManager::UpdateVisibleTiles(
464 const GlobalStateThatImpactsTilePriority
& state
) {
465 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
467 tile_task_runner_
->CheckForCompletedTasks();
470 PrepareTilesMode prepare_tiles_mode
= rasterizer_
->GetPrepareTilesMode();
471 if (prepare_tiles_mode
!= PrepareTilesMode::RASTERIZE_PRIORITIZED_TILES
)
472 SynchronouslyRasterizeTiles(state
);
474 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
476 TRACE_EVENT_INSTANT1(
478 "DidUpdateVisibleTiles",
479 TRACE_EVENT_SCOPE_THREAD
,
481 RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_
));
482 update_visible_tiles_stats_
= RasterTaskCompletionStats();
485 scoped_refptr
<base::trace_event::ConvertableToTraceFormat
>
486 TileManager::BasicStateAsValue() const {
487 scoped_refptr
<base::trace_event::TracedValue
> value
=
488 new base::trace_event::TracedValue();
489 BasicStateAsValueInto(value
.get());
493 void TileManager::BasicStateAsValueInto(
494 base::trace_event::TracedValue
* state
) const {
495 state
->SetInteger("tile_count", tiles_
.size());
496 state
->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_
);
497 state
->BeginDictionary("global_state");
498 global_state_
.AsValueInto(state
);
499 state
->EndDictionary();
502 scoped_ptr
<EvictionTilePriorityQueue
>
503 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
504 scoped_ptr
<EvictionTilePriorityQueue
> eviction_priority_queue
,
505 const MemoryUsage
& limit
,
506 MemoryUsage
* usage
) {
507 while (usage
->Exceeds(limit
)) {
508 if (!eviction_priority_queue
) {
509 eviction_priority_queue
=
510 client_
->BuildEvictionQueue(global_state_
.tree_priority
);
512 if (eviction_priority_queue
->IsEmpty())
515 Tile
* tile
= eviction_priority_queue
->Top();
516 *usage
-= MemoryUsage::FromTile(tile
);
517 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile
);
518 eviction_priority_queue
->Pop();
520 return eviction_priority_queue
;
523 scoped_ptr
<EvictionTilePriorityQueue
>
524 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
525 scoped_ptr
<EvictionTilePriorityQueue
> eviction_priority_queue
,
526 const MemoryUsage
& limit
,
527 const TilePriority
& other_priority
,
528 MemoryUsage
* usage
) {
529 while (usage
->Exceeds(limit
)) {
530 if (!eviction_priority_queue
) {
531 eviction_priority_queue
=
532 client_
->BuildEvictionQueue(global_state_
.tree_priority
);
534 if (eviction_priority_queue
->IsEmpty())
537 Tile
* tile
= eviction_priority_queue
->Top();
538 if (!other_priority
.IsHigherPriorityThan(tile
->combined_priority()))
541 *usage
-= MemoryUsage::FromTile(tile
);
542 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile
);
543 eviction_priority_queue
->Pop();
545 return eviction_priority_queue
;
548 bool TileManager::TilePriorityViolatesMemoryPolicy(
549 const TilePriority
& priority
) {
550 switch (global_state_
.memory_limit_policy
) {
553 case ALLOW_ABSOLUTE_MINIMUM
:
554 return priority
.priority_bin
> TilePriority::NOW
;
555 case ALLOW_PREPAINT_ONLY
:
556 return priority
.priority_bin
> TilePriority::SOON
;
558 return priority
.distance_to_visible
==
559 std::numeric_limits
<float>::infinity();
565 void TileManager::AssignGpuMemoryToTiles(
566 RasterTilePriorityQueue
* raster_priority_queue
,
567 size_t scheduled_raster_task_limit
,
568 TileVector
* tiles_that_need_to_be_rasterized
) {
569 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
571 // Maintain the list of released resources that can potentially be re-used
572 // or deleted. If this operation becomes expensive too, only do this after
573 // some resource(s) was returned. Note that in that case, one also need to
574 // invalidate when releasing some resource from the pool.
575 resource_pool_
->CheckBusyResources(false);
577 // Now give memory out to the tiles until we're out, and build
578 // the needs-to-be-rasterized queue.
579 unsigned schedule_priority
= 1u;
580 all_tiles_that_need_to_be_rasterized_are_scheduled_
= true;
581 bool had_enough_memory_to_schedule_tiles_needed_now
= true;
583 MemoryUsage
hard_memory_limit(global_state_
.hard_memory_limit_in_bytes
,
584 global_state_
.num_resources_limit
);
585 MemoryUsage
soft_memory_limit(global_state_
.soft_memory_limit_in_bytes
,
586 global_state_
.num_resources_limit
);
587 MemoryUsage
memory_usage(resource_pool_
->acquired_memory_usage_bytes(),
588 resource_pool_
->acquired_resource_count());
590 scoped_ptr
<EvictionTilePriorityQueue
> eviction_priority_queue
;
591 for (; !raster_priority_queue
->IsEmpty(); raster_priority_queue
->Pop()) {
592 Tile
* tile
= raster_priority_queue
->Top();
593 TilePriority priority
= tile
->combined_priority();
595 if (TilePriorityViolatesMemoryPolicy(priority
)) {
596 TRACE_EVENT_INSTANT0(
597 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
598 TRACE_EVENT_SCOPE_THREAD
);
602 // We won't be able to schedule this tile, so break out early.
603 if (tiles_that_need_to_be_rasterized
->size() >=
604 scheduled_raster_task_limit
) {
605 all_tiles_that_need_to_be_rasterized_are_scheduled_
= false;
609 TileDrawInfo
& draw_info
= tile
->draw_info();
610 tile
->scheduled_priority_
= schedule_priority
++;
612 DCHECK_IMPLIES(draw_info
.mode() != TileDrawInfo::OOM_MODE
,
613 !draw_info
.IsReadyToDraw());
615 // If the tile already has a raster_task, then the memory used by it is
616 // already accounted for in memory_usage. Otherwise, we'll have to acquire
617 // more memory to create a raster task.
618 MemoryUsage memory_required_by_tile_to_be_scheduled
;
619 if (!tile
->raster_task_
.get()) {
620 memory_required_by_tile_to_be_scheduled
= MemoryUsage::FromConfig(
621 tile
->desired_texture_size(), tile_task_runner_
->GetResourceFormat());
624 bool tile_is_needed_now
= priority
.priority_bin
== TilePriority::NOW
;
626 // This is the memory limit that will be used by this tile. Depending on
627 // the tile priority, it will be one of hard_memory_limit or
628 // soft_memory_limit.
629 MemoryUsage
& tile_memory_limit
=
630 tile_is_needed_now
? hard_memory_limit
: soft_memory_limit
;
632 const MemoryUsage
& scheduled_tile_memory_limit
=
633 tile_memory_limit
- memory_required_by_tile_to_be_scheduled
;
634 eviction_priority_queue
=
635 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
636 eviction_priority_queue
.Pass(), scheduled_tile_memory_limit
,
637 priority
, &memory_usage
);
638 bool memory_usage_is_within_limit
=
639 !memory_usage
.Exceeds(scheduled_tile_memory_limit
);
641 // If we couldn't fit the tile into our current memory limit, then we're
643 if (!memory_usage_is_within_limit
) {
644 if (tile_is_needed_now
)
645 had_enough_memory_to_schedule_tiles_needed_now
= false;
646 all_tiles_that_need_to_be_rasterized_are_scheduled_
= false;
650 memory_usage
+= memory_required_by_tile_to_be_scheduled
;
651 tiles_that_need_to_be_rasterized
->push_back(tile
);
654 // Note that we should try and further reduce memory in case the above loop
655 // didn't reduce memory. This ensures that we always release as many resources
656 // as possible to stay within the memory limit.
657 eviction_priority_queue
= FreeTileResourcesUntilUsageIsWithinLimit(
658 eviction_priority_queue
.Pass(), hard_memory_limit
, &memory_usage
);
660 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
661 !had_enough_memory_to_schedule_tiles_needed_now
);
662 did_oom_on_last_assign_
= !had_enough_memory_to_schedule_tiles_needed_now
;
664 memory_stats_from_last_assign_
.total_budget_in_bytes
=
665 global_state_
.hard_memory_limit_in_bytes
;
666 memory_stats_from_last_assign_
.total_bytes_used
= memory_usage
.memory_bytes();
667 memory_stats_from_last_assign_
.had_enough_memory
=
668 had_enough_memory_to_schedule_tiles_needed_now
;
670 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
671 "all_tiles_that_need_to_be_rasterized_are_scheduled",
672 all_tiles_that_need_to_be_rasterized_are_scheduled_
,
673 "had_enough_memory_to_schedule_tiles_needed_now",
674 had_enough_memory_to_schedule_tiles_needed_now
);
677 void TileManager::FreeResourcesForTile(Tile
* tile
) {
678 TileDrawInfo
& draw_info
= tile
->draw_info();
679 if (draw_info
.resource_
)
680 resource_pool_
->ReleaseResource(draw_info
.resource_
.Pass());
683 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
685 bool was_ready_to_draw
= tile
->IsReadyToDraw();
686 FreeResourcesForTile(tile
);
687 if (was_ready_to_draw
)
688 client_
->NotifyTileStateChanged(tile
);
691 void TileManager::ScheduleTasks(
692 const TileVector
& tiles_that_need_to_be_rasterized
) {
694 "TileManager::ScheduleTasks",
696 tiles_that_need_to_be_rasterized
.size());
698 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_
);
700 raster_queue_
.Reset();
702 // Build a new task queue containing all task currently needed. Tasks
703 // are added in order of priority, highest priority task first.
704 for (TileVector::const_iterator it
= tiles_that_need_to_be_rasterized
.begin();
705 it
!= tiles_that_need_to_be_rasterized
.end();
708 TileDrawInfo
& draw_info
= tile
->draw_info();
710 DCHECK(draw_info
.requires_resource());
711 DCHECK(!draw_info
.resource_
);
713 if (!tile
->raster_task_
.get())
714 tile
->raster_task_
= CreateRasterTask(tile
);
716 TaskSetCollection task_sets
;
717 if (tile
->required_for_activation())
718 task_sets
.set(REQUIRED_FOR_ACTIVATION
);
719 if (tile
->required_for_draw())
720 task_sets
.set(REQUIRED_FOR_DRAW
);
722 raster_queue_
.items
.push_back(
723 TileTaskQueue::Item(tile
->raster_task_
.get(), task_sets
));
726 // We must reduce the amount of unused resoruces before calling
727 // ScheduleTasks to prevent usage from rising above limits.
728 resource_pool_
->ReduceResourceUsage();
730 // Schedule running of |raster_queue_|. This replaces any previously
731 // scheduled tasks and effectively cancels all tasks not present
732 // in |raster_queue_|.
733 tile_task_runner_
->ScheduleTasks(&raster_queue_
);
735 // It's now safe to clean up orphan tasks as raster worker pool is not
736 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
738 orphan_raster_tasks_
.clear();
740 did_check_for_completed_tasks_since_last_schedule_tasks_
= false;
743 scoped_refptr
<ImageDecodeTask
> TileManager::CreateImageDecodeTask(
745 SkPixelRef
* pixel_ref
) {
746 return make_scoped_refptr(new ImageDecodeTaskImpl(
748 base::Bind(&TileManager::OnImageDecodeTaskCompleted
,
749 base::Unretained(this),
751 base::Unretained(pixel_ref
))));
754 scoped_refptr
<RasterTask
> TileManager::CreateRasterTask(Tile
* tile
) {
755 scoped_ptr
<ScopedResource
> resource
=
756 resource_pool_
->AcquireResource(tile
->desired_texture_size(),
757 tile_task_runner_
->GetResourceFormat());
758 const ScopedResource
* const_resource
= resource
.get();
760 // Create and queue all image decode tasks that this tile depends on.
761 ImageDecodeTask::Vector decode_tasks
;
762 PixelRefTaskMap
& existing_pixel_refs
= image_decode_tasks_
[tile
->layer_id()];
763 std::vector
<SkPixelRef
*> pixel_refs
;
764 tile
->raster_source()->GatherPixelRefs(
765 tile
->content_rect(), tile
->contents_scale(), &pixel_refs
);
766 for (SkPixelRef
* pixel_ref
: pixel_refs
) {
767 uint32_t id
= pixel_ref
->getGenerationID();
769 // Append existing image decode task if available.
770 PixelRefTaskMap::iterator decode_task_it
= existing_pixel_refs
.find(id
);
771 if (decode_task_it
!= existing_pixel_refs
.end()) {
772 decode_tasks
.push_back(decode_task_it
->second
);
776 // Create and append new image decode task for this pixel ref.
777 scoped_refptr
<ImageDecodeTask
> decode_task
=
778 CreateImageDecodeTask(tile
, pixel_ref
);
779 decode_tasks
.push_back(decode_task
);
780 existing_pixel_refs
[id
] = decode_task
;
783 return make_scoped_refptr(new RasterTaskImpl(
784 const_resource
, tile
->raster_source(), tile
->content_rect(),
785 tile
->contents_scale(), tile
->combined_priority().resolution
,
786 tile
->layer_id(), static_cast<const void*>(tile
),
787 tile
->source_frame_number(), tile
->use_picture_analysis(),
788 base::Bind(&TileManager::OnRasterTaskCompleted
, base::Unretained(this),
789 tile
->id(), base::Passed(&resource
)),
793 void TileManager::OnImageDecodeTaskCompleted(int layer_id
,
794 SkPixelRef
* pixel_ref
,
796 // If the task was canceled, we need to clean it up
797 // from |image_decode_tasks_|.
801 LayerPixelRefTaskMap::iterator layer_it
= image_decode_tasks_
.find(layer_id
);
802 if (layer_it
== image_decode_tasks_
.end())
805 PixelRefTaskMap
& pixel_ref_tasks
= layer_it
->second
;
806 PixelRefTaskMap::iterator task_it
=
807 pixel_ref_tasks
.find(pixel_ref
->getGenerationID());
809 if (task_it
!= pixel_ref_tasks
.end())
810 pixel_ref_tasks
.erase(task_it
);
813 void TileManager::OnRasterTaskCompleted(
815 scoped_ptr
<ScopedResource
> resource
,
816 const RasterSource::SolidColorAnalysis
& analysis
,
818 DCHECK(tiles_
.find(tile_id
) != tiles_
.end());
820 Tile
* tile
= tiles_
[tile_id
];
821 DCHECK(tile
->raster_task_
.get());
822 orphan_raster_tasks_
.push_back(tile
->raster_task_
);
823 tile
->raster_task_
= nullptr;
826 ++update_visible_tiles_stats_
.canceled_count
;
827 resource_pool_
->ReleaseResource(resource
.Pass());
831 UpdateTileDrawInfo(tile
, resource
.Pass(), analysis
);
834 void TileManager::UpdateTileDrawInfo(
836 scoped_ptr
<ScopedResource
> resource
,
837 const RasterSource::SolidColorAnalysis
& analysis
) {
838 TileDrawInfo
& draw_info
= tile
->draw_info();
840 ++update_visible_tiles_stats_
.completed_count
;
842 if (analysis
.is_solid_color
) {
843 draw_info
.set_solid_color(analysis
.solid_color
);
845 resource_pool_
->ReleaseResource(resource
.Pass());
848 draw_info
.set_use_resource();
849 draw_info
.resource_
= resource
.Pass();
852 client_
->NotifyTileStateChanged(tile
);
855 scoped_refptr
<Tile
> TileManager::CreateTile(
856 RasterSource
* raster_source
,
857 const gfx::Size
& desired_texture_size
,
858 const gfx::Rect
& content_rect
,
859 float contents_scale
,
861 int source_frame_number
,
863 scoped_refptr
<Tile
> tile
= make_scoped_refptr(
864 new Tile(this, raster_source
, desired_texture_size
, content_rect
,
865 contents_scale
, layer_id
, source_frame_number
, flags
));
866 DCHECK(tiles_
.find(tile
->id()) == tiles_
.end());
868 tiles_
[tile
->id()] = tile
.get();
869 used_layer_counts_
[tile
->layer_id()]++;
873 void TileManager::SetTileTaskRunnerForTesting(
874 TileTaskRunner
* tile_task_runner
) {
875 tile_task_runner_
= tile_task_runner
;
876 tile_task_runner_
->SetClient(this);
879 bool TileManager::AreRequiredTilesReadyToDraw(
880 RasterTilePriorityQueue::Type type
) const {
881 scoped_ptr
<RasterTilePriorityQueue
> raster_priority_queue(
882 client_
->BuildRasterQueue(global_state_
.tree_priority
, type
));
883 // It is insufficient to check whether the raster queue we constructed is
884 // empty. The reason for this is that there are situations (rasterize on
885 // demand) when the tile both needs raster and it's ready to draw. Hence, we
886 // have to iterate the queue to check whether the required tiles are ready to
888 for (; !raster_priority_queue
->IsEmpty(); raster_priority_queue
->Pop()) {
889 if (!raster_priority_queue
->Top()->IsReadyToDraw())
894 bool TileManager::IsReadyToActivate() const {
895 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
896 return AreRequiredTilesReadyToDraw(
897 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION
);
900 bool TileManager::IsReadyToDraw() const {
901 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
902 return AreRequiredTilesReadyToDraw(
903 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW
);
906 void TileManager::NotifyReadyToActivate() {
907 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
908 if (did_notify_ready_to_activate_
)
910 client_
->NotifyReadyToActivate();
911 did_notify_ready_to_activate_
= true;
914 void TileManager::NotifyReadyToDraw() {
915 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
916 if (did_notify_ready_to_draw_
)
918 client_
->NotifyReadyToDraw();
919 did_notify_ready_to_draw_
= true;
922 void TileManager::CheckIfReadyToActivate() {
923 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
925 tile_task_runner_
->CheckForCompletedTasks();
926 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
928 if (did_notify_ready_to_activate_
)
930 if (!IsReadyToActivate())
933 NotifyReadyToActivate();
936 void TileManager::CheckIfReadyToDraw() {
937 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
939 tile_task_runner_
->CheckForCompletedTasks();
940 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
942 if (did_notify_ready_to_draw_
)
944 if (!IsReadyToDraw())
950 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
951 tile_task_runner_
->CheckForCompletedTasks();
952 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
954 // When OOM, keep re-assigning memory until we reach a steady state
955 // where top-priority tiles are initialized.
956 TileVector tiles_that_need_to_be_rasterized
;
957 scoped_ptr
<RasterTilePriorityQueue
> raster_priority_queue(
958 client_
->BuildRasterQueue(global_state_
.tree_priority
,
959 RasterTilePriorityQueue::Type::ALL
));
960 AssignGpuMemoryToTiles(raster_priority_queue
.get(),
961 scheduled_raster_task_limit_
,
962 &tiles_that_need_to_be_rasterized
);
964 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
965 // steady memory state. Keep scheduling tasks until we reach this state.
966 if (!tiles_that_need_to_be_rasterized
.empty()) {
967 ScheduleTasks(tiles_that_need_to_be_rasterized
);
971 FreeResourcesForReleasedTiles();
973 resource_pool_
->ReduceResourceUsage();
975 // We don't reserve memory for required-for-activation tiles during
976 // accelerated gestures, so we just postpone activation when we don't
977 // have these tiles, and activate after the accelerated gesture.
978 // Likewise if we don't allow any tiles (as is the case when we're
979 // invisible), if we have tiles that aren't ready, then we shouldn't
980 // activate as activation can cause checkerboards.
981 bool wait_for_all_required_tiles
=
982 global_state_
.tree_priority
== SMOOTHNESS_TAKES_PRIORITY
||
983 global_state_
.memory_limit_policy
== ALLOW_NOTHING
;
985 // Mark any required-for-activation tiles that have not been been assigned
986 // memory after reaching a steady memory state as OOM. This ensures that we
987 // activate even when OOM. Note that we can't reuse the queue we used for
988 // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
989 // evicted some tiles that would not be picked up by the old raster queue.
990 scoped_ptr
<RasterTilePriorityQueue
> required_for_activation_queue(
991 client_
->BuildRasterQueue(
992 global_state_
.tree_priority
,
993 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION
));
995 // If we have tiles left to raster for activation, and we don't allow
996 // activating without them, then skip activation and return early.
997 if (!required_for_activation_queue
->IsEmpty() && wait_for_all_required_tiles
)
1000 // Mark required tiles as OOM so that we can activate without them.
1001 for (; !required_for_activation_queue
->IsEmpty();
1002 required_for_activation_queue
->Pop()) {
1003 Tile
* tile
= required_for_activation_queue
->Top();
1004 tile
->draw_info().set_oom();
1005 client_
->NotifyTileStateChanged(tile
);
1008 DCHECK(IsReadyToActivate());
1009 ready_to_activate_check_notifier_
.Schedule();
1012 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
1015 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes
, int resource_count
)
1016 : memory_bytes_(memory_bytes
), resource_count_(resource_count
) {
1020 TileManager::MemoryUsage
TileManager::MemoryUsage::FromConfig(
1021 const gfx::Size
& size
,
1022 ResourceFormat format
) {
1023 return MemoryUsage(Resource::MemorySizeBytes(size
, format
), 1);
1027 TileManager::MemoryUsage
TileManager::MemoryUsage::FromTile(const Tile
* tile
) {
1028 const TileDrawInfo
& draw_info
= tile
->draw_info();
1029 if (draw_info
.resource_
) {
1030 return MemoryUsage::FromConfig(draw_info
.resource_
->size(),
1031 draw_info
.resource_
->format());
1033 return MemoryUsage();
1036 TileManager::MemoryUsage
& TileManager::MemoryUsage::operator+=(
1037 const MemoryUsage
& other
) {
1038 memory_bytes_
+= other
.memory_bytes_
;
1039 resource_count_
+= other
.resource_count_
;
1043 TileManager::MemoryUsage
& TileManager::MemoryUsage::operator-=(
1044 const MemoryUsage
& other
) {
1045 memory_bytes_
-= other
.memory_bytes_
;
1046 resource_count_
-= other
.resource_count_
;
1050 TileManager::MemoryUsage
TileManager::MemoryUsage::operator-(
1051 const MemoryUsage
& other
) {
1052 MemoryUsage result
= *this;
1057 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage
& limit
) const {
1058 return memory_bytes_
> limit
.memory_bytes_
||
1059 resource_count_
> limit
.resource_count_
;