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 "cc/debug/devtools_instrumentation.h"
16 #include "cc/debug/frame_viewer_instrumentation.h"
17 #include "cc/debug/traced_value.h"
18 #include "cc/layers/picture_layer_impl.h"
19 #include "cc/resources/raster_worker_pool.h"
20 #include "cc/resources/tile.h"
21 #include "skia/ext/paint_simplifier.h"
22 #include "third_party/skia/include/core/SkBitmap.h"
23 #include "third_party/skia/include/core/SkPixelRef.h"
24 #include "ui/gfx/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 DisableLCDTextFilter
: public SkDrawFilter
{
35 // SkDrawFilter interface.
36 virtual bool filter(SkPaint
* paint
, SkDrawFilter::Type type
) OVERRIDE
{
37 if (type
!= SkDrawFilter::kText_Type
)
40 paint
->setLCDRenderText(false);
45 class RasterTaskImpl
: public RasterTask
{
48 const Resource
* resource
,
49 PicturePileImpl
* picture_pile
,
50 const gfx::Rect
& content_rect
,
52 RasterMode raster_mode
,
53 TileResolution tile_resolution
,
56 int source_frame_number
,
58 RenderingStatsInstrumentation
* rendering_stats
,
59 const base::Callback
<void(const PicturePileImpl::Analysis
&, bool)>& reply
,
60 ImageDecodeTask::Vector
* dependencies
)
61 : RasterTask(resource
, dependencies
),
62 picture_pile_(picture_pile
),
63 content_rect_(content_rect
),
64 contents_scale_(contents_scale
),
65 raster_mode_(raster_mode
),
66 tile_resolution_(tile_resolution
),
69 source_frame_number_(source_frame_number
),
70 analyze_picture_(analyze_picture
),
71 rendering_stats_(rendering_stats
),
75 // Overridden from Task:
76 virtual void RunOnWorkerThread() OVERRIDE
{
77 TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
79 DCHECK(picture_pile_
);
81 AnalyzeAndRaster(picture_pile_
->GetCloneForDrawingOnThread(
82 RasterWorkerPool::GetPictureCloneIndexForCurrentThread()));
86 // Overridden from RasterizerTask:
87 virtual void ScheduleOnOriginThread(RasterizerTaskClient
* client
) OVERRIDE
{
89 canvas_
= client
->AcquireCanvasForRaster(this);
91 virtual void CompleteOnOriginThread(RasterizerTaskClient
* client
) OVERRIDE
{
93 client
->ReleaseCanvasForRaster(this);
95 virtual void RunReplyOnOriginThread() OVERRIDE
{
97 reply_
.Run(analysis_
, !HasFinishedRunning());
101 virtual ~RasterTaskImpl() { DCHECK(!canvas_
); }
104 void AnalyzeAndRaster(PicturePileImpl
* picture_pile
) {
105 DCHECK(picture_pile
);
108 if (analyze_picture_
) {
109 Analyze(picture_pile
);
110 if (analysis_
.is_solid_color
)
114 Raster(picture_pile
);
117 void Analyze(PicturePileImpl
* picture_pile
) {
118 frame_viewer_instrumentation::ScopedAnalyzeTask
analyze_task(
119 tile_id_
, tile_resolution_
, source_frame_number_
, layer_id_
);
121 DCHECK(picture_pile
);
123 picture_pile
->AnalyzeInRect(
124 content_rect_
, contents_scale_
, &analysis_
, rendering_stats_
);
126 // Record the solid color prediction.
127 UMA_HISTOGRAM_BOOLEAN("Renderer4.SolidColorTilesAnalyzed",
128 analysis_
.is_solid_color
);
130 // Clear the flag if we're not using the estimator.
131 analysis_
.is_solid_color
&= kUseColorEstimator
;
134 void Raster(PicturePileImpl
* picture_pile
) {
135 frame_viewer_instrumentation::ScopedRasterTask
raster_task(
138 source_frame_number_
,
141 devtools_instrumentation::ScopedLayerTask
layer_task(
142 devtools_instrumentation::kRasterTask
, layer_id_
);
144 skia::RefPtr
<SkDrawFilter
> draw_filter
;
145 switch (raster_mode_
) {
146 case LOW_QUALITY_RASTER_MODE
:
147 draw_filter
= skia::AdoptRef(new skia::PaintSimplifier
);
149 case HIGH_QUALITY_NO_LCD_RASTER_MODE
:
150 draw_filter
= skia::AdoptRef(new DisableLCDTextFilter
);
152 case HIGH_QUALITY_RASTER_MODE
:
154 case NUM_RASTER_MODES
:
158 canvas_
->setDrawFilter(draw_filter
.get());
160 base::TimeDelta prev_rasterize_time
=
161 rendering_stats_
->impl_thread_rendering_stats().rasterize_time
;
163 // Only record rasterization time for highres tiles, because
164 // lowres tiles are not required for activation and therefore
165 // introduce noise in the measurement (sometimes they get rasterized
166 // before we draw and sometimes they aren't)
167 RenderingStatsInstrumentation
* stats
=
168 tile_resolution_
== HIGH_RESOLUTION
? rendering_stats_
: NULL
;
169 DCHECK(picture_pile
);
170 picture_pile
->RasterToBitmap(
171 canvas_
, content_rect_
, contents_scale_
, stats
);
173 if (rendering_stats_
->record_rendering_stats()) {
174 base::TimeDelta current_rasterize_time
=
175 rendering_stats_
->impl_thread_rendering_stats().rasterize_time
;
176 HISTOGRAM_CUSTOM_COUNTS(
177 "Renderer4.PictureRasterTimeUS",
178 (current_rasterize_time
- prev_rasterize_time
).InMicroseconds(),
185 PicturePileImpl::Analysis analysis_
;
186 scoped_refptr
<PicturePileImpl
> picture_pile_
;
187 gfx::Rect content_rect_
;
188 float contents_scale_
;
189 RasterMode raster_mode_
;
190 TileResolution tile_resolution_
;
192 const void* tile_id_
;
193 int source_frame_number_
;
194 bool analyze_picture_
;
195 RenderingStatsInstrumentation
* rendering_stats_
;
196 const base::Callback
<void(const PicturePileImpl::Analysis
&, bool)> reply_
;
199 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl
);
202 class ImageDecodeTaskImpl
: public ImageDecodeTask
{
204 ImageDecodeTaskImpl(SkPixelRef
* pixel_ref
,
206 RenderingStatsInstrumentation
* rendering_stats
,
207 const base::Callback
<void(bool was_canceled
)>& reply
)
208 : pixel_ref_(skia::SharePtr(pixel_ref
)),
210 rendering_stats_(rendering_stats
),
213 // Overridden from Task:
214 virtual void RunOnWorkerThread() OVERRIDE
{
215 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
217 devtools_instrumentation::ScopedImageDecodeTask
image_decode_task(
219 // This will cause the image referred to by pixel ref to be decoded.
220 pixel_ref_
->lockPixels();
221 pixel_ref_
->unlockPixels();
224 // Overridden from RasterizerTask:
225 virtual void ScheduleOnOriginThread(RasterizerTaskClient
* client
) OVERRIDE
{}
226 virtual void CompleteOnOriginThread(RasterizerTaskClient
* client
) OVERRIDE
{}
227 virtual void RunReplyOnOriginThread() OVERRIDE
{
228 reply_
.Run(!HasFinishedRunning());
232 virtual ~ImageDecodeTaskImpl() {}
235 skia::RefPtr
<SkPixelRef
> pixel_ref_
;
237 RenderingStatsInstrumentation
* rendering_stats_
;
238 const base::Callback
<void(bool was_canceled
)> reply_
;
240 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl
);
243 const size_t kScheduledRasterTasksLimit
= 32u;
245 // Memory limit policy works by mapping some bin states to the NEVER bin.
246 const ManagedTileBin kBinPolicyMap
[NUM_TILE_MEMORY_LIMIT_POLICIES
][NUM_BINS
] = {
248 {NEVER_BIN
, // [NOW_AND_READY_TO_DRAW_BIN]
249 NEVER_BIN
, // [NOW_BIN]
250 NEVER_BIN
, // [SOON_BIN]
251 NEVER_BIN
, // [EVENTUALLY_AND_ACTIVE_BIN]
252 NEVER_BIN
, // [EVENTUALLY_BIN]
253 NEVER_BIN
, // [AT_LAST_AND_ACTIVE_BIN]
254 NEVER_BIN
, // [AT_LAST_BIN]
255 NEVER_BIN
// [NEVER_BIN]
257 // [ALLOW_ABSOLUTE_MINIMUM]
258 {NOW_AND_READY_TO_DRAW_BIN
, // [NOW_AND_READY_TO_DRAW_BIN]
259 NOW_BIN
, // [NOW_BIN]
260 NEVER_BIN
, // [SOON_BIN]
261 NEVER_BIN
, // [EVENTUALLY_AND_ACTIVE_BIN]
262 NEVER_BIN
, // [EVENTUALLY_BIN]
263 NEVER_BIN
, // [AT_LAST_AND_ACTIVE_BIN]
264 NEVER_BIN
, // [AT_LAST_BIN]
265 NEVER_BIN
// [NEVER_BIN]
267 // [ALLOW_PREPAINT_ONLY]
268 {NOW_AND_READY_TO_DRAW_BIN
, // [NOW_AND_READY_TO_DRAW_BIN]
269 NOW_BIN
, // [NOW_BIN]
270 SOON_BIN
, // [SOON_BIN]
271 NEVER_BIN
, // [EVENTUALLY_AND_ACTIVE_BIN]
272 NEVER_BIN
, // [EVENTUALLY_BIN]
273 NEVER_BIN
, // [AT_LAST_AND_ACTIVE_BIN]
274 NEVER_BIN
, // [AT_LAST_BIN]
275 NEVER_BIN
// [NEVER_BIN]
278 {NOW_AND_READY_TO_DRAW_BIN
, // [NOW_AND_READY_TO_DRAW_BIN]
279 NOW_BIN
, // [NOW_BIN]
280 SOON_BIN
, // [SOON_BIN]
281 EVENTUALLY_AND_ACTIVE_BIN
, // [EVENTUALLY_AND_ACTIVE_BIN]
282 EVENTUALLY_BIN
, // [EVENTUALLY_BIN]
283 AT_LAST_AND_ACTIVE_BIN
, // [AT_LAST_AND_ACTIVE_BIN]
284 AT_LAST_BIN
, // [AT_LAST_BIN]
285 NEVER_BIN
// [NEVER_BIN]
288 // Ready to draw works by mapping NOW_BIN to NOW_AND_READY_TO_DRAW_BIN.
289 const ManagedTileBin kBinReadyToDrawMap
[2][NUM_BINS
] = {
291 {NOW_AND_READY_TO_DRAW_BIN
, // [NOW_AND_READY_TO_DRAW_BIN]
292 NOW_BIN
, // [NOW_BIN]
293 SOON_BIN
, // [SOON_BIN]
294 EVENTUALLY_AND_ACTIVE_BIN
, // [EVENTUALLY_AND_ACTIVE_BIN]
295 EVENTUALLY_BIN
, // [EVENTUALLY_BIN]
296 AT_LAST_AND_ACTIVE_BIN
, // [AT_LAST_AND_ACTIVE_BIN]
297 AT_LAST_BIN
, // [AT_LAST_BIN]
298 NEVER_BIN
// [NEVER_BIN]
301 {NOW_AND_READY_TO_DRAW_BIN
, // [NOW_AND_READY_TO_DRAW_BIN]
302 NOW_AND_READY_TO_DRAW_BIN
, // [NOW_BIN]
303 SOON_BIN
, // [SOON_BIN]
304 EVENTUALLY_AND_ACTIVE_BIN
, // [EVENTUALLY_AND_ACTIVE_BIN]
305 EVENTUALLY_BIN
, // [EVENTUALLY_BIN]
306 AT_LAST_AND_ACTIVE_BIN
, // [AT_LAST_AND_ACTIVE_BIN]
307 AT_LAST_BIN
, // [AT_LAST_BIN]
308 NEVER_BIN
// [NEVER_BIN]
311 // Active works by mapping some bin stats to equivalent _ACTIVE_BIN state.
312 const ManagedTileBin kBinIsActiveMap
[2][NUM_BINS
] = {
314 {NOW_AND_READY_TO_DRAW_BIN
, // [NOW_AND_READY_TO_DRAW_BIN]
315 NOW_BIN
, // [NOW_BIN]
316 SOON_BIN
, // [SOON_BIN]
317 EVENTUALLY_AND_ACTIVE_BIN
, // [EVENTUALLY_AND_ACTIVE_BIN]
318 EVENTUALLY_BIN
, // [EVENTUALLY_BIN]
319 AT_LAST_AND_ACTIVE_BIN
, // [AT_LAST_AND_ACTIVE_BIN]
320 AT_LAST_BIN
, // [AT_LAST_BIN]
321 NEVER_BIN
// [NEVER_BIN]
324 {NOW_AND_READY_TO_DRAW_BIN
, // [NOW_AND_READY_TO_DRAW_BIN]
325 NOW_BIN
, // [NOW_BIN]
326 SOON_BIN
, // [SOON_BIN]
327 EVENTUALLY_AND_ACTIVE_BIN
, // [EVENTUALLY_AND_ACTIVE_BIN]
328 EVENTUALLY_AND_ACTIVE_BIN
, // [EVENTUALLY_BIN]
329 AT_LAST_AND_ACTIVE_BIN
, // [AT_LAST_AND_ACTIVE_BIN]
330 AT_LAST_AND_ACTIVE_BIN
, // [AT_LAST_BIN]
331 NEVER_BIN
// [NEVER_BIN]
334 // Determine bin based on three categories of tiles: things we need now,
335 // things we need soon, and eventually.
336 inline ManagedTileBin
BinFromTilePriority(const TilePriority
& prio
) {
337 if (prio
.priority_bin
== TilePriority::NOW
)
340 if (prio
.priority_bin
== TilePriority::SOON
)
343 if (prio
.distance_to_visible
== std::numeric_limits
<float>::infinity())
346 return EVENTUALLY_BIN
;
351 RasterTaskCompletionStats::RasterTaskCompletionStats()
352 : completed_count(0u), canceled_count(0u) {}
354 scoped_ptr
<base::Value
> RasterTaskCompletionStatsAsValue(
355 const RasterTaskCompletionStats
& stats
) {
356 scoped_ptr
<base::DictionaryValue
> state(new base::DictionaryValue());
357 state
->SetInteger("completed_count", stats
.completed_count
);
358 state
->SetInteger("canceled_count", stats
.canceled_count
);
359 return state
.PassAs
<base::Value
>();
363 scoped_ptr
<TileManager
> TileManager::Create(
364 TileManagerClient
* client
,
365 base::SequencedTaskRunner
* task_runner
,
366 ResourcePool
* resource_pool
,
367 Rasterizer
* rasterizer
,
368 RenderingStatsInstrumentation
* rendering_stats_instrumentation
) {
369 return make_scoped_ptr(new TileManager(client
,
373 rendering_stats_instrumentation
));
376 TileManager::TileManager(
377 TileManagerClient
* client
,
378 base::SequencedTaskRunner
* task_runner
,
379 ResourcePool
* resource_pool
,
380 Rasterizer
* rasterizer
,
381 RenderingStatsInstrumentation
* rendering_stats_instrumentation
)
383 task_runner_(task_runner
),
384 resource_pool_(resource_pool
),
385 rasterizer_(rasterizer
),
386 prioritized_tiles_dirty_(false),
387 all_tiles_that_need_to_be_rasterized_have_memory_(true),
388 all_tiles_required_for_activation_have_memory_(true),
389 memory_required_bytes_(0),
390 memory_nice_to_have_bytes_(0),
391 bytes_releasable_(0),
392 resources_releasable_(0),
393 ever_exceeded_memory_budget_(false),
394 rendering_stats_instrumentation_(rendering_stats_instrumentation
),
395 did_initialize_visible_tile_(false),
396 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
397 ready_to_activate_check_notifier_(
399 base::Bind(&TileManager::CheckIfReadyToActivate
,
400 base::Unretained(this))) {
401 rasterizer_
->SetClient(this);
404 TileManager::~TileManager() {
405 // Reset global state and manage. This should cause
406 // our memory usage to drop to zero.
407 global_state_
= GlobalStateThatImpactsTilePriority();
409 CleanUpReleasedTiles();
410 DCHECK_EQ(0u, tiles_
.size());
412 RasterTaskQueue empty
;
413 rasterizer_
->ScheduleTasks(&empty
);
414 orphan_raster_tasks_
.clear();
416 // This should finish all pending tasks and release any uninitialized
418 rasterizer_
->Shutdown();
419 rasterizer_
->CheckForCompletedTasks();
421 DCHECK_EQ(0u, bytes_releasable_
);
422 DCHECK_EQ(0u, resources_releasable_
);
424 for (std::vector
<PictureLayerImpl
*>::iterator it
= layers_
.begin();
427 (*it
)->DidUnregisterLayer();
432 void TileManager::Release(Tile
* tile
) {
433 prioritized_tiles_dirty_
= true;
434 released_tiles_
.push_back(tile
);
437 void TileManager::DidChangeTilePriority(Tile
* tile
) {
438 prioritized_tiles_dirty_
= true;
441 bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const {
442 return global_state_
.tree_priority
!= SMOOTHNESS_TAKES_PRIORITY
;
445 void TileManager::CleanUpReleasedTiles() {
446 for (std::vector
<Tile
*>::iterator it
= released_tiles_
.begin();
447 it
!= released_tiles_
.end();
450 ManagedTileState
& mts
= tile
->managed_state();
452 for (int mode
= 0; mode
< NUM_RASTER_MODES
; ++mode
) {
453 FreeResourceForTile(tile
, static_cast<RasterMode
>(mode
));
454 orphan_raster_tasks_
.push_back(mts
.tile_versions
[mode
].raster_task_
);
457 DCHECK(tiles_
.find(tile
->id()) != tiles_
.end());
458 tiles_
.erase(tile
->id());
460 LayerCountMap::iterator layer_it
=
461 used_layer_counts_
.find(tile
->layer_id());
462 DCHECK_GT(layer_it
->second
, 0);
463 if (--layer_it
->second
== 0) {
464 used_layer_counts_
.erase(layer_it
);
465 image_decode_tasks_
.erase(tile
->layer_id());
471 released_tiles_
.clear();
474 void TileManager::UpdatePrioritizedTileSetIfNeeded() {
475 if (!prioritized_tiles_dirty_
)
478 CleanUpReleasedTiles();
480 prioritized_tiles_
.Clear();
481 GetTilesWithAssignedBins(&prioritized_tiles_
);
482 prioritized_tiles_dirty_
= false;
485 void TileManager::DidFinishRunningTasks() {
486 TRACE_EVENT0("cc", "TileManager::DidFinishRunningTasks");
488 bool memory_usage_above_limit
= resource_pool_
->total_memory_usage_bytes() >
489 global_state_
.soft_memory_limit_in_bytes
;
491 // When OOM, keep re-assigning memory until we reach a steady state
492 // where top-priority tiles are initialized.
493 if (all_tiles_that_need_to_be_rasterized_have_memory_
&&
494 !memory_usage_above_limit
)
497 rasterizer_
->CheckForCompletedTasks();
498 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
500 TileVector tiles_that_need_to_be_rasterized
;
501 AssignGpuMemoryToTiles(&prioritized_tiles_
,
502 &tiles_that_need_to_be_rasterized
);
504 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
505 // steady memory state. Keep scheduling tasks until we reach this state.
506 if (!tiles_that_need_to_be_rasterized
.empty()) {
507 ScheduleTasks(tiles_that_need_to_be_rasterized
);
511 resource_pool_
->ReduceResourceUsage();
513 // We don't reserve memory for required-for-activation tiles during
514 // accelerated gestures, so we just postpone activation when we don't
515 // have these tiles, and activate after the accelerated gesture.
516 bool allow_rasterize_on_demand
=
517 global_state_
.tree_priority
!= SMOOTHNESS_TAKES_PRIORITY
;
519 // Use on-demand raster for any required-for-activation tiles that have not
520 // been been assigned memory after reaching a steady memory state. This
521 // ensures that we activate even when OOM.
522 for (TileMap::iterator it
= tiles_
.begin(); it
!= tiles_
.end(); ++it
) {
523 Tile
* tile
= it
->second
;
524 ManagedTileState
& mts
= tile
->managed_state();
525 ManagedTileState::TileVersion
& tile_version
=
526 mts
.tile_versions
[mts
.raster_mode
];
528 if (tile
->required_for_activation() && !tile_version
.IsReadyToDraw()) {
529 // If we can't raster on demand, give up early (and don't activate).
530 if (!allow_rasterize_on_demand
)
533 tile_version
.set_rasterize_on_demand();
534 client_
->NotifyTileStateChanged(tile
);
538 DCHECK(IsReadyToActivate());
539 ready_to_activate_check_notifier_
.Schedule();
542 void TileManager::DidFinishRunningTasksRequiredForActivation() {
543 // This is only a true indication that all tiles required for
544 // activation are initialized when no tiles are OOM. We need to
545 // wait for DidFinishRunningTasks() to be called, try to re-assign
546 // memory and in worst case use on-demand raster when tiles
547 // required for activation are OOM.
548 if (!all_tiles_required_for_activation_have_memory_
)
551 ready_to_activate_check_notifier_
.Schedule();
554 void TileManager::GetTilesWithAssignedBins(PrioritizedTileSet
* tiles
) {
555 TRACE_EVENT0("cc", "TileManager::GetTilesWithAssignedBins");
557 // Compute new stats to be return by GetMemoryStats().
558 memory_required_bytes_
= 0;
559 memory_nice_to_have_bytes_
= 0;
561 const TileMemoryLimitPolicy memory_policy
= global_state_
.memory_limit_policy
;
562 const TreePriority tree_priority
= global_state_
.tree_priority
;
564 // For each tree, bin into different categories of tiles.
565 for (TileMap::const_iterator it
= tiles_
.begin(); it
!= tiles_
.end(); ++it
) {
566 Tile
* tile
= it
->second
;
567 ManagedTileState
& mts
= tile
->managed_state();
569 const ManagedTileState::TileVersion
& tile_version
=
570 tile
->GetTileVersionForDrawing();
571 bool tile_is_ready_to_draw
= tile_version
.IsReadyToDraw();
572 bool tile_is_active
= tile_is_ready_to_draw
||
573 mts
.tile_versions
[mts
.raster_mode
].raster_task_
;
575 // Get the active priority and bin.
576 TilePriority active_priority
= tile
->priority(ACTIVE_TREE
);
577 ManagedTileBin active_bin
= BinFromTilePriority(active_priority
);
579 // Get the pending priority and bin.
580 TilePriority pending_priority
= tile
->priority(PENDING_TREE
);
581 ManagedTileBin pending_bin
= BinFromTilePriority(pending_priority
);
583 bool pending_is_low_res
= pending_priority
.resolution
== LOW_RESOLUTION
;
584 bool pending_is_non_ideal
=
585 pending_priority
.resolution
== NON_IDEAL_RESOLUTION
;
586 bool active_is_non_ideal
=
587 active_priority
.resolution
== NON_IDEAL_RESOLUTION
;
589 // Adjust bin state based on if ready to draw.
590 active_bin
= kBinReadyToDrawMap
[tile_is_ready_to_draw
][active_bin
];
591 pending_bin
= kBinReadyToDrawMap
[tile_is_ready_to_draw
][pending_bin
];
593 // Adjust bin state based on if active.
594 active_bin
= kBinIsActiveMap
[tile_is_active
][active_bin
];
595 pending_bin
= kBinIsActiveMap
[tile_is_active
][pending_bin
];
597 // We never want to paint new non-ideal tiles, as we always have
598 // a high-res tile covering that content (paint that instead).
599 if (!tile_is_ready_to_draw
&& active_is_non_ideal
)
600 active_bin
= NEVER_BIN
;
601 if (!tile_is_ready_to_draw
&& pending_is_non_ideal
)
602 pending_bin
= NEVER_BIN
;
604 if (!tile_is_ready_to_draw
|| tile_version
.requires_resource()) {
605 // The bin that the tile would have if the GPU memory manager had
606 // a maximally permissive policy, send to the GPU memory manager
607 // to determine policy.
608 ManagedTileBin gpu_memmgr_stats_bin
= std::min(active_bin
, pending_bin
);
609 if ((gpu_memmgr_stats_bin
== NOW_BIN
) ||
610 (gpu_memmgr_stats_bin
== NOW_AND_READY_TO_DRAW_BIN
))
611 memory_required_bytes_
+= BytesConsumedIfAllocated(tile
);
612 if (gpu_memmgr_stats_bin
!= NEVER_BIN
)
613 memory_nice_to_have_bytes_
+= BytesConsumedIfAllocated(tile
);
616 ManagedTileBin tree_bin
[NUM_TREES
];
617 tree_bin
[ACTIVE_TREE
] = kBinPolicyMap
[memory_policy
][active_bin
];
618 tree_bin
[PENDING_TREE
] = kBinPolicyMap
[memory_policy
][pending_bin
];
620 // Adjust pending bin state for low res tiles. This prevents pending tree
621 // low-res tiles from being initialized before high-res tiles.
622 if (pending_is_low_res
)
623 tree_bin
[PENDING_TREE
] = std::max(tree_bin
[PENDING_TREE
], EVENTUALLY_BIN
);
625 TilePriority tile_priority
;
626 switch (tree_priority
) {
627 case SAME_PRIORITY_FOR_BOTH_TREES
:
628 mts
.bin
= std::min(tree_bin
[ACTIVE_TREE
], tree_bin
[PENDING_TREE
]);
629 tile_priority
= tile
->combined_priority();
631 case SMOOTHNESS_TAKES_PRIORITY
:
632 mts
.bin
= tree_bin
[ACTIVE_TREE
];
633 tile_priority
= active_priority
;
635 case NEW_CONTENT_TAKES_PRIORITY
:
636 mts
.bin
= tree_bin
[PENDING_TREE
];
637 tile_priority
= pending_priority
;
641 // Bump up the priority if we determined it's NEVER_BIN on one tree,
642 // but is still required on the other tree.
643 bool is_in_never_bin_on_both_trees
= tree_bin
[ACTIVE_TREE
] == NEVER_BIN
&&
644 tree_bin
[PENDING_TREE
] == NEVER_BIN
;
646 if (mts
.bin
== NEVER_BIN
&& !is_in_never_bin_on_both_trees
)
647 mts
.bin
= tile_is_active
? AT_LAST_AND_ACTIVE_BIN
: AT_LAST_BIN
;
649 mts
.resolution
= tile_priority
.resolution
;
650 mts
.priority_bin
= tile_priority
.priority_bin
;
651 mts
.distance_to_visible
= tile_priority
.distance_to_visible
;
652 mts
.required_for_activation
= tile_priority
.required_for_activation
;
654 mts
.visible_and_ready_to_draw
=
655 tree_bin
[ACTIVE_TREE
] == NOW_AND_READY_TO_DRAW_BIN
;
657 // Tiles that are required for activation shouldn't be in NEVER_BIN unless
658 // smoothness takes priority or memory policy allows nothing to be
660 DCHECK(!mts
.required_for_activation
|| mts
.bin
!= NEVER_BIN
||
661 tree_priority
== SMOOTHNESS_TAKES_PRIORITY
||
662 memory_policy
== ALLOW_NOTHING
);
664 // If the tile is in NEVER_BIN and it does not have an active task, then we
665 // can release the resources early. If it does have the task however, we
666 // should keep it in the prioritized tile set to ensure that AssignGpuMemory
668 if (mts
.bin
== NEVER_BIN
&&
669 !mts
.tile_versions
[mts
.raster_mode
].raster_task_
) {
670 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile
);
674 // Insert the tile into a priority set.
675 tiles
->InsertTile(tile
, mts
.bin
);
679 void TileManager::CleanUpLayers() {
680 for (size_t i
= 0; i
< layers_
.size(); ++i
) {
681 if (layers_
[i
]->IsDrawnRenderSurfaceLayerListMember())
684 layers_
[i
]->DidUnregisterLayer();
685 std::swap(layers_
[i
], layers_
.back());
688 prioritized_tiles_dirty_
= true;
692 void TileManager::ManageTiles(const GlobalStateThatImpactsTilePriority
& state
) {
693 TRACE_EVENT0("cc", "TileManager::ManageTiles");
695 // Update internal state.
696 if (state
!= global_state_
) {
697 global_state_
= state
;
698 prioritized_tiles_dirty_
= true;
703 // We need to call CheckForCompletedTasks() once in-between each call
704 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
705 if (!did_check_for_completed_tasks_since_last_schedule_tasks_
) {
706 rasterizer_
->CheckForCompletedTasks();
707 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
710 UpdatePrioritizedTileSetIfNeeded();
712 TileVector tiles_that_need_to_be_rasterized
;
713 AssignGpuMemoryToTiles(&prioritized_tiles_
,
714 &tiles_that_need_to_be_rasterized
);
716 // Finally, schedule rasterizer tasks.
717 ScheduleTasks(tiles_that_need_to_be_rasterized
);
719 TRACE_EVENT_INSTANT1("cc",
721 TRACE_EVENT_SCOPE_THREAD
,
723 TracedValue::FromValue(BasicStateAsValue().release()));
725 TRACE_COUNTER_ID1("cc",
726 "unused_memory_bytes",
728 resource_pool_
->total_memory_usage_bytes() -
729 resource_pool_
->acquired_memory_usage_bytes());
732 bool TileManager::UpdateVisibleTiles() {
733 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
735 rasterizer_
->CheckForCompletedTasks();
736 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
738 TRACE_EVENT_INSTANT1(
740 "DidUpdateVisibleTiles",
741 TRACE_EVENT_SCOPE_THREAD
,
743 TracedValue::FromValue(RasterTaskCompletionStatsAsValue(
744 update_visible_tiles_stats_
).release()));
745 update_visible_tiles_stats_
= RasterTaskCompletionStats();
747 bool did_initialize_visible_tile
= did_initialize_visible_tile_
;
748 did_initialize_visible_tile_
= false;
749 return did_initialize_visible_tile
;
752 void TileManager::GetMemoryStats(size_t* memory_required_bytes
,
753 size_t* memory_nice_to_have_bytes
,
754 size_t* memory_allocated_bytes
,
755 size_t* memory_used_bytes
) const {
756 *memory_required_bytes
= memory_required_bytes_
;
757 *memory_nice_to_have_bytes
= memory_nice_to_have_bytes_
;
758 *memory_allocated_bytes
= resource_pool_
->total_memory_usage_bytes();
759 *memory_used_bytes
= resource_pool_
->acquired_memory_usage_bytes();
762 scoped_ptr
<base::Value
> TileManager::BasicStateAsValue() const {
763 scoped_ptr
<base::DictionaryValue
> state(new base::DictionaryValue());
764 state
->SetInteger("tile_count", tiles_
.size());
765 state
->Set("global_state", global_state_
.AsValue().release());
766 state
->Set("memory_requirements", GetMemoryRequirementsAsValue().release());
767 return state
.PassAs
<base::Value
>();
770 scoped_ptr
<base::Value
> TileManager::AllTilesAsValue() const {
771 scoped_ptr
<base::ListValue
> state(new base::ListValue());
772 for (TileMap::const_iterator it
= tiles_
.begin(); it
!= tiles_
.end(); ++it
)
773 state
->Append(it
->second
->AsValue().release());
775 return state
.PassAs
<base::Value
>();
778 scoped_ptr
<base::Value
> TileManager::GetMemoryRequirementsAsValue() const {
779 scoped_ptr
<base::DictionaryValue
> requirements(new base::DictionaryValue());
781 size_t memory_required_bytes
;
782 size_t memory_nice_to_have_bytes
;
783 size_t memory_allocated_bytes
;
784 size_t memory_used_bytes
;
785 GetMemoryStats(&memory_required_bytes
,
786 &memory_nice_to_have_bytes
,
787 &memory_allocated_bytes
,
789 requirements
->SetInteger("memory_required_bytes", memory_required_bytes
);
790 requirements
->SetInteger("memory_nice_to_have_bytes",
791 memory_nice_to_have_bytes
);
792 requirements
->SetInteger("memory_allocated_bytes", memory_allocated_bytes
);
793 requirements
->SetInteger("memory_used_bytes", memory_used_bytes
);
794 return requirements
.PassAs
<base::Value
>();
797 void TileManager::AssignGpuMemoryToTiles(
798 PrioritizedTileSet
* tiles
,
799 TileVector
* tiles_that_need_to_be_rasterized
) {
800 TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles");
802 // Maintain the list of released resources that can potentially be re-used
804 // If this operation becomes expensive too, only do this after some
805 // resource(s) was returned. Note that in that case, one also need to
806 // invalidate when releasing some resource from the pool.
807 resource_pool_
->CheckBusyResources();
809 // Now give memory out to the tiles until we're out, and build
810 // the needs-to-be-rasterized queue.
811 all_tiles_that_need_to_be_rasterized_have_memory_
= true;
812 all_tiles_required_for_activation_have_memory_
= true;
814 // Cast to prevent overflow.
815 int64 soft_bytes_available
=
816 static_cast<int64
>(bytes_releasable_
) +
817 static_cast<int64
>(global_state_
.soft_memory_limit_in_bytes
) -
818 static_cast<int64
>(resource_pool_
->acquired_memory_usage_bytes());
819 int64 hard_bytes_available
=
820 static_cast<int64
>(bytes_releasable_
) +
821 static_cast<int64
>(global_state_
.hard_memory_limit_in_bytes
) -
822 static_cast<int64
>(resource_pool_
->acquired_memory_usage_bytes());
823 int resources_available
= resources_releasable_
+
824 global_state_
.num_resources_limit
-
825 resource_pool_
->acquired_resource_count();
826 size_t soft_bytes_allocatable
=
827 std::max(static_cast<int64
>(0), soft_bytes_available
);
828 size_t hard_bytes_allocatable
=
829 std::max(static_cast<int64
>(0), hard_bytes_available
);
830 size_t resources_allocatable
= std::max(0, resources_available
);
832 size_t bytes_that_exceeded_memory_budget
= 0;
833 size_t soft_bytes_left
= soft_bytes_allocatable
;
834 size_t hard_bytes_left
= hard_bytes_allocatable
;
836 size_t resources_left
= resources_allocatable
;
837 bool oomed_soft
= false;
838 bool oomed_hard
= false;
839 bool have_hit_soft_memory
= false; // Soft memory comes after hard.
841 unsigned schedule_priority
= 1u;
842 for (PrioritizedTileSet::Iterator
it(tiles
, true); it
; ++it
) {
844 ManagedTileState
& mts
= tile
->managed_state();
846 mts
.scheduled_priority
= schedule_priority
++;
848 mts
.raster_mode
= tile
->DetermineOverallRasterMode();
850 ManagedTileState::TileVersion
& tile_version
=
851 mts
.tile_versions
[mts
.raster_mode
];
853 // If this tile doesn't need a resource, then nothing to do.
854 if (!tile_version
.requires_resource())
857 // If the tile is not needed, free it up.
858 if (mts
.bin
== NEVER_BIN
) {
859 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile
);
863 const bool tile_uses_hard_limit
= mts
.bin
<= NOW_BIN
;
864 const size_t bytes_if_allocated
= BytesConsumedIfAllocated(tile
);
865 const size_t tile_bytes_left
=
866 (tile_uses_hard_limit
) ? hard_bytes_left
: soft_bytes_left
;
868 // Hard-limit is reserved for tiles that would cause a calamity
869 // if they were to go away, so by definition they are the highest
870 // priority memory, and must be at the front of the list.
871 DCHECK(!(have_hit_soft_memory
&& tile_uses_hard_limit
));
872 have_hit_soft_memory
|= !tile_uses_hard_limit
;
874 size_t tile_bytes
= 0;
875 size_t tile_resources
= 0;
877 // It costs to maintain a resource.
878 for (int mode
= 0; mode
< NUM_RASTER_MODES
; ++mode
) {
879 if (mts
.tile_versions
[mode
].resource_
) {
880 tile_bytes
+= bytes_if_allocated
;
885 // Allow lower priority tiles with initialized resources to keep
886 // their memory by only assigning memory to new raster tasks if
887 // they can be scheduled.
888 bool reached_scheduled_raster_tasks_limit
=
889 tiles_that_need_to_be_rasterized
->size() >= kScheduledRasterTasksLimit
;
890 if (!reached_scheduled_raster_tasks_limit
) {
891 // If we don't have the required version, and it's not in flight
892 // then we'll have to pay to create a new task.
893 if (!tile_version
.resource_
&& !tile_version
.raster_task_
) {
894 tile_bytes
+= bytes_if_allocated
;
900 if (tile_bytes
> tile_bytes_left
|| tile_resources
> resources_left
) {
901 bool was_ready_to_draw
= tile
->IsReadyToDraw();
903 FreeResourcesForTile(tile
);
905 // This tile was already on screen and now its resources have been
906 // released. In order to prevent checkerboarding, set this tile as
907 // rasterize on demand immediately.
908 if (mts
.visible_and_ready_to_draw
)
909 tile_version
.set_rasterize_on_demand();
911 if (was_ready_to_draw
)
912 client_
->NotifyTileStateChanged(tile
);
915 if (tile_uses_hard_limit
) {
917 bytes_that_exceeded_memory_budget
+= tile_bytes
;
920 resources_left
-= tile_resources
;
921 hard_bytes_left
-= tile_bytes
;
923 (soft_bytes_left
> tile_bytes
) ? soft_bytes_left
- tile_bytes
: 0;
924 if (tile_version
.resource_
)
928 DCHECK(!tile_version
.resource_
);
930 // Tile shouldn't be rasterized if |tiles_that_need_to_be_rasterized|
931 // has reached it's limit or we've failed to assign gpu memory to this
932 // or any higher priority tile. Preventing tiles that fit into memory
933 // budget to be rasterized when higher priority tile is oom is
934 // important for two reasons:
935 // 1. Tile size should not impact raster priority.
936 // 2. Tiles with existing raster task could otherwise incorrectly
937 // be added as they are not affected by |bytes_allocatable|.
938 bool can_schedule_tile
=
939 !oomed_soft
&& !reached_scheduled_raster_tasks_limit
;
941 if (!can_schedule_tile
) {
942 all_tiles_that_need_to_be_rasterized_have_memory_
= false;
943 if (tile
->required_for_activation())
944 all_tiles_required_for_activation_have_memory_
= false;
945 it
.DisablePriorityOrdering();
949 tiles_that_need_to_be_rasterized
->push_back(tile
);
952 // OOM reporting uses hard-limit, soft-OOM is normal depending on limit.
953 ever_exceeded_memory_budget_
|= oomed_hard
;
954 if (ever_exceeded_memory_budget_
) {
955 TRACE_COUNTER_ID2("cc",
956 "over_memory_budget",
959 global_state_
.hard_memory_limit_in_bytes
,
961 bytes_that_exceeded_memory_budget
);
963 memory_stats_from_last_assign_
.total_budget_in_bytes
=
964 global_state_
.hard_memory_limit_in_bytes
;
965 memory_stats_from_last_assign_
.bytes_allocated
=
966 hard_bytes_allocatable
- hard_bytes_left
;
967 memory_stats_from_last_assign_
.bytes_unreleasable
=
968 resource_pool_
->acquired_memory_usage_bytes() - bytes_releasable_
;
969 memory_stats_from_last_assign_
.bytes_over
= bytes_that_exceeded_memory_budget
;
972 void TileManager::FreeResourceForTile(Tile
* tile
, RasterMode mode
) {
973 ManagedTileState
& mts
= tile
->managed_state();
974 if (mts
.tile_versions
[mode
].resource_
) {
975 resource_pool_
->ReleaseResource(mts
.tile_versions
[mode
].resource_
.Pass());
977 DCHECK_GE(bytes_releasable_
, BytesConsumedIfAllocated(tile
));
978 DCHECK_GE(resources_releasable_
, 1u);
980 bytes_releasable_
-= BytesConsumedIfAllocated(tile
);
981 --resources_releasable_
;
985 void TileManager::FreeResourcesForTile(Tile
* tile
) {
986 for (int mode
= 0; mode
< NUM_RASTER_MODES
; ++mode
) {
987 FreeResourceForTile(tile
, static_cast<RasterMode
>(mode
));
991 void TileManager::FreeUnusedResourcesForTile(Tile
* tile
) {
992 DCHECK(tile
->IsReadyToDraw());
993 ManagedTileState
& mts
= tile
->managed_state();
994 RasterMode used_mode
= HIGH_QUALITY_NO_LCD_RASTER_MODE
;
995 for (int mode
= 0; mode
< NUM_RASTER_MODES
; ++mode
) {
996 if (mts
.tile_versions
[mode
].IsReadyToDraw()) {
997 used_mode
= static_cast<RasterMode
>(mode
);
1002 for (int mode
= 0; mode
< NUM_RASTER_MODES
; ++mode
) {
1003 if (mode
!= used_mode
)
1004 FreeResourceForTile(tile
, static_cast<RasterMode
>(mode
));
1008 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
1010 bool was_ready_to_draw
= tile
->IsReadyToDraw();
1011 FreeResourcesForTile(tile
);
1012 if (was_ready_to_draw
)
1013 client_
->NotifyTileStateChanged(tile
);
1016 void TileManager::ScheduleTasks(
1017 const TileVector
& tiles_that_need_to_be_rasterized
) {
1019 "TileManager::ScheduleTasks",
1021 tiles_that_need_to_be_rasterized
.size());
1023 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_
);
1025 raster_queue_
.Reset();
1027 // Build a new task queue containing all task currently needed. Tasks
1028 // are added in order of priority, highest priority task first.
1029 for (TileVector::const_iterator it
= tiles_that_need_to_be_rasterized
.begin();
1030 it
!= tiles_that_need_to_be_rasterized
.end();
1033 ManagedTileState
& mts
= tile
->managed_state();
1034 ManagedTileState::TileVersion
& tile_version
=
1035 mts
.tile_versions
[mts
.raster_mode
];
1037 DCHECK(tile_version
.requires_resource());
1038 DCHECK(!tile_version
.resource_
);
1040 if (!tile_version
.raster_task_
)
1041 tile_version
.raster_task_
= CreateRasterTask(tile
);
1043 raster_queue_
.items
.push_back(RasterTaskQueue::Item(
1044 tile_version
.raster_task_
.get(), tile
->required_for_activation()));
1045 raster_queue_
.required_for_activation_count
+=
1046 tile
->required_for_activation();
1049 // We must reduce the amount of unused resoruces before calling
1050 // ScheduleTasks to prevent usage from rising above limits.
1051 resource_pool_
->ReduceResourceUsage();
1053 // Schedule running of |raster_tasks_|. This replaces any previously
1054 // scheduled tasks and effectively cancels all tasks not present
1055 // in |raster_tasks_|.
1056 rasterizer_
->ScheduleTasks(&raster_queue_
);
1058 // It's now safe to clean up orphan tasks as raster worker pool is not
1059 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
1061 orphan_raster_tasks_
.clear();
1063 did_check_for_completed_tasks_since_last_schedule_tasks_
= false;
1066 scoped_refptr
<ImageDecodeTask
> TileManager::CreateImageDecodeTask(
1068 SkPixelRef
* pixel_ref
) {
1069 return make_scoped_refptr(new ImageDecodeTaskImpl(
1072 rendering_stats_instrumentation_
,
1073 base::Bind(&TileManager::OnImageDecodeTaskCompleted
,
1074 base::Unretained(this),
1076 base::Unretained(pixel_ref
))));
1079 scoped_refptr
<RasterTask
> TileManager::CreateRasterTask(Tile
* tile
) {
1080 ManagedTileState
& mts
= tile
->managed_state();
1082 scoped_ptr
<ScopedResource
> resource
=
1083 resource_pool_
->AcquireResource(tile
->tile_size_
.size());
1084 const ScopedResource
* const_resource
= resource
.get();
1086 // Create and queue all image decode tasks that this tile depends on.
1087 ImageDecodeTask::Vector decode_tasks
;
1088 PixelRefTaskMap
& existing_pixel_refs
= image_decode_tasks_
[tile
->layer_id()];
1089 for (PicturePileImpl::PixelRefIterator
iter(
1090 tile
->content_rect(), tile
->contents_scale(), tile
->picture_pile());
1093 SkPixelRef
* pixel_ref
= *iter
;
1094 uint32_t id
= pixel_ref
->getGenerationID();
1096 // Append existing image decode task if available.
1097 PixelRefTaskMap::iterator decode_task_it
= existing_pixel_refs
.find(id
);
1098 if (decode_task_it
!= existing_pixel_refs
.end()) {
1099 decode_tasks
.push_back(decode_task_it
->second
);
1103 // Create and append new image decode task for this pixel ref.
1104 scoped_refptr
<ImageDecodeTask
> decode_task
=
1105 CreateImageDecodeTask(tile
, pixel_ref
);
1106 decode_tasks
.push_back(decode_task
);
1107 existing_pixel_refs
[id
] = decode_task
;
1110 return make_scoped_refptr(
1111 new RasterTaskImpl(const_resource
,
1112 tile
->picture_pile(),
1113 tile
->content_rect(),
1114 tile
->contents_scale(),
1118 static_cast<const void*>(tile
),
1119 tile
->source_frame_number(),
1120 tile
->use_picture_analysis(),
1121 rendering_stats_instrumentation_
,
1122 base::Bind(&TileManager::OnRasterTaskCompleted
,
1123 base::Unretained(this),
1125 base::Passed(&resource
),
1130 void TileManager::OnImageDecodeTaskCompleted(int layer_id
,
1131 SkPixelRef
* pixel_ref
,
1132 bool was_canceled
) {
1133 // If the task was canceled, we need to clean it up
1134 // from |image_decode_tasks_|.
1138 LayerPixelRefTaskMap::iterator layer_it
= image_decode_tasks_
.find(layer_id
);
1139 if (layer_it
== image_decode_tasks_
.end())
1142 PixelRefTaskMap
& pixel_ref_tasks
= layer_it
->second
;
1143 PixelRefTaskMap::iterator task_it
=
1144 pixel_ref_tasks
.find(pixel_ref
->getGenerationID());
1146 if (task_it
!= pixel_ref_tasks
.end())
1147 pixel_ref_tasks
.erase(task_it
);
1150 void TileManager::OnRasterTaskCompleted(
1152 scoped_ptr
<ScopedResource
> resource
,
1153 RasterMode raster_mode
,
1154 const PicturePileImpl::Analysis
& analysis
,
1155 bool was_canceled
) {
1156 TileMap::iterator it
= tiles_
.find(tile_id
);
1157 if (it
== tiles_
.end()) {
1158 ++update_visible_tiles_stats_
.canceled_count
;
1159 resource_pool_
->ReleaseResource(resource
.Pass());
1163 Tile
* tile
= it
->second
;
1164 ManagedTileState
& mts
= tile
->managed_state();
1165 ManagedTileState::TileVersion
& tile_version
= mts
.tile_versions
[raster_mode
];
1166 DCHECK(tile_version
.raster_task_
);
1167 orphan_raster_tasks_
.push_back(tile_version
.raster_task_
);
1168 tile_version
.raster_task_
= NULL
;
1171 ++update_visible_tiles_stats_
.canceled_count
;
1172 resource_pool_
->ReleaseResource(resource
.Pass());
1176 ++update_visible_tiles_stats_
.completed_count
;
1178 tile_version
.set_has_text(analysis
.has_text
);
1179 if (analysis
.is_solid_color
) {
1180 tile_version
.set_solid_color(analysis
.solid_color
);
1181 resource_pool_
->ReleaseResource(resource
.Pass());
1183 tile_version
.set_use_resource();
1184 tile_version
.resource_
= resource
.Pass();
1186 bytes_releasable_
+= BytesConsumedIfAllocated(tile
);
1187 ++resources_releasable_
;
1190 FreeUnusedResourcesForTile(tile
);
1191 if (tile
->priority(ACTIVE_TREE
).distance_to_visible
== 0.f
)
1192 did_initialize_visible_tile_
= true;
1194 client_
->NotifyTileStateChanged(tile
);
1197 scoped_refptr
<Tile
> TileManager::CreateTile(PicturePileImpl
* picture_pile
,
1198 const gfx::Size
& tile_size
,
1199 const gfx::Rect
& content_rect
,
1200 const gfx::Rect
& opaque_rect
,
1201 float contents_scale
,
1203 int source_frame_number
,
1205 scoped_refptr
<Tile
> tile
= make_scoped_refptr(new Tile(this,
1212 source_frame_number
,
1214 DCHECK(tiles_
.find(tile
->id()) == tiles_
.end());
1216 tiles_
[tile
->id()] = tile
;
1217 used_layer_counts_
[tile
->layer_id()]++;
1218 prioritized_tiles_dirty_
= true;
1222 void TileManager::RegisterPictureLayerImpl(PictureLayerImpl
* layer
) {
1223 DCHECK(std::find(layers_
.begin(), layers_
.end(), layer
) == layers_
.end());
1224 layers_
.push_back(layer
);
1227 void TileManager::UnregisterPictureLayerImpl(PictureLayerImpl
* layer
) {
1228 std::vector
<PictureLayerImpl
*>::iterator it
=
1229 std::find(layers_
.begin(), layers_
.end(), layer
);
1230 DCHECK(it
!= layers_
.end());
1234 void TileManager::GetPairedPictureLayers(
1235 std::vector
<PairedPictureLayer
>* paired_layers
) const {
1236 paired_layers
->clear();
1237 // Reserve a maximum possible paired layers.
1238 paired_layers
->reserve(layers_
.size());
1240 for (std::vector
<PictureLayerImpl
*>::const_iterator it
= layers_
.begin();
1241 it
!= layers_
.end();
1243 PictureLayerImpl
* layer
= *it
;
1245 // This is a recycle tree layer, we can safely skip since the tiles on this
1246 // layer have to be accessible via the active tree.
1247 if (!layer
->IsOnActiveOrPendingTree())
1250 PictureLayerImpl
* twin_layer
= layer
->GetTwinLayer();
1252 // If the twin layer is recycled, it is not a valid twin.
1253 if (twin_layer
&& !twin_layer
->IsOnActiveOrPendingTree())
1256 PairedPictureLayer paired_layer
;
1257 WhichTree tree
= layer
->GetTree();
1259 // If the current tree is ACTIVE_TREE, then always generate a paired_layer.
1260 // If current tree is PENDING_TREE, then only generate a paired_layer if
1261 // there is no twin layer.
1262 if (tree
== ACTIVE_TREE
) {
1263 DCHECK(!twin_layer
|| twin_layer
->GetTree() == PENDING_TREE
);
1264 paired_layer
.active_layer
= layer
;
1265 paired_layer
.pending_layer
= twin_layer
;
1266 paired_layers
->push_back(paired_layer
);
1267 } else if (!twin_layer
) {
1268 paired_layer
.active_layer
= NULL
;
1269 paired_layer
.pending_layer
= layer
;
1270 paired_layers
->push_back(paired_layer
);
1275 TileManager::PairedPictureLayer::PairedPictureLayer()
1276 : active_layer(NULL
), pending_layer(NULL
) {}
1278 TileManager::PairedPictureLayer::~PairedPictureLayer() {}
1280 TileManager::RasterTileIterator::RasterTileIterator(TileManager
* tile_manager
,
1281 TreePriority tree_priority
)
1282 : tree_priority_(tree_priority
), comparator_(tree_priority
) {
1283 std::vector
<TileManager::PairedPictureLayer
> paired_layers
;
1284 tile_manager
->GetPairedPictureLayers(&paired_layers
);
1285 bool prioritize_low_res
= tree_priority_
== SMOOTHNESS_TAKES_PRIORITY
;
1287 paired_iterators_
.reserve(paired_layers
.size());
1288 iterator_heap_
.reserve(paired_layers
.size());
1289 for (std::vector
<TileManager::PairedPictureLayer
>::iterator it
=
1290 paired_layers
.begin();
1291 it
!= paired_layers
.end();
1293 PairedPictureLayerIterator paired_iterator
;
1294 if (it
->active_layer
) {
1295 paired_iterator
.active_iterator
=
1296 PictureLayerImpl::LayerRasterTileIterator(it
->active_layer
,
1297 prioritize_low_res
);
1300 if (it
->pending_layer
) {
1301 paired_iterator
.pending_iterator
=
1302 PictureLayerImpl::LayerRasterTileIterator(it
->pending_layer
,
1303 prioritize_low_res
);
1306 if (paired_iterator
.PeekTile(tree_priority_
) != NULL
) {
1307 paired_iterators_
.push_back(paired_iterator
);
1308 iterator_heap_
.push_back(&paired_iterators_
.back());
1312 std::make_heap(iterator_heap_
.begin(), iterator_heap_
.end(), comparator_
);
1315 TileManager::RasterTileIterator::~RasterTileIterator() {}
1317 TileManager::RasterTileIterator
& TileManager::RasterTileIterator::operator++() {
1320 std::pop_heap(iterator_heap_
.begin(), iterator_heap_
.end(), comparator_
);
1321 PairedPictureLayerIterator
* paired_iterator
= iterator_heap_
.back();
1322 iterator_heap_
.pop_back();
1324 paired_iterator
->PopTile(tree_priority_
);
1325 if (paired_iterator
->PeekTile(tree_priority_
) != NULL
) {
1326 iterator_heap_
.push_back(paired_iterator
);
1327 std::push_heap(iterator_heap_
.begin(), iterator_heap_
.end(), comparator_
);
1332 TileManager::RasterTileIterator::operator bool() const {
1333 return !iterator_heap_
.empty();
1336 Tile
* TileManager::RasterTileIterator::operator*() {
1338 return iterator_heap_
.front()->PeekTile(tree_priority_
);
1341 TileManager::RasterTileIterator::PairedPictureLayerIterator::
1342 PairedPictureLayerIterator() {}
1344 TileManager::RasterTileIterator::PairedPictureLayerIterator::
1345 ~PairedPictureLayerIterator() {}
1347 Tile
* TileManager::RasterTileIterator::PairedPictureLayerIterator::PeekTile(
1348 TreePriority tree_priority
) {
1349 PictureLayerImpl::LayerRasterTileIterator
* next_iterator
=
1350 NextTileIterator(tree_priority
).first
;
1354 DCHECK(*next_iterator
);
1355 DCHECK(std::find(returned_shared_tiles
.begin(),
1356 returned_shared_tiles
.end(),
1357 **next_iterator
) == returned_shared_tiles
.end());
1358 return **next_iterator
;
1361 void TileManager::RasterTileIterator::PairedPictureLayerIterator::PopTile(
1362 TreePriority tree_priority
) {
1363 PictureLayerImpl::LayerRasterTileIterator
* next_iterator
=
1364 NextTileIterator(tree_priority
).first
;
1365 DCHECK(next_iterator
);
1366 DCHECK(*next_iterator
);
1367 returned_shared_tiles
.push_back(**next_iterator
);
1370 next_iterator
= NextTileIterator(tree_priority
).first
;
1371 while (next_iterator
&&
1372 std::find(returned_shared_tiles
.begin(),
1373 returned_shared_tiles
.end(),
1374 **next_iterator
) != returned_shared_tiles
.end()) {
1376 next_iterator
= NextTileIterator(tree_priority
).first
;
1380 std::pair
<PictureLayerImpl::LayerRasterTileIterator
*, WhichTree
>
1381 TileManager::RasterTileIterator::PairedPictureLayerIterator::NextTileIterator(
1382 TreePriority tree_priority
) {
1383 // If both iterators are out of tiles, return NULL.
1384 if (!active_iterator
&& !pending_iterator
) {
1385 return std::pair
<PictureLayerImpl::LayerRasterTileIterator
*, WhichTree
>(
1389 // If we only have one iterator with tiles, return it.
1390 if (!active_iterator
)
1391 return std::make_pair(&pending_iterator
, PENDING_TREE
);
1392 if (!pending_iterator
)
1393 return std::make_pair(&active_iterator
, ACTIVE_TREE
);
1395 // Now both iterators have tiles, so we have to decide based on tree priority.
1396 switch (tree_priority
) {
1397 case SMOOTHNESS_TAKES_PRIORITY
:
1398 return std::make_pair(&active_iterator
, ACTIVE_TREE
);
1399 case NEW_CONTENT_TAKES_PRIORITY
:
1400 return std::make_pair(&pending_iterator
, ACTIVE_TREE
);
1401 case SAME_PRIORITY_FOR_BOTH_TREES
: {
1402 Tile
* active_tile
= *active_iterator
;
1403 Tile
* pending_tile
= *pending_iterator
;
1404 if (active_tile
== pending_tile
)
1405 return std::make_pair(&active_iterator
, ACTIVE_TREE
);
1407 const TilePriority
& active_priority
= active_tile
->priority(ACTIVE_TREE
);
1408 const TilePriority
& pending_priority
=
1409 pending_tile
->priority(PENDING_TREE
);
1411 if (active_priority
.IsHigherPriorityThan(pending_priority
))
1412 return std::make_pair(&active_iterator
, ACTIVE_TREE
);
1413 return std::make_pair(&pending_iterator
, PENDING_TREE
);
1418 // Keep the compiler happy.
1419 return std::pair
<PictureLayerImpl::LayerRasterTileIterator
*, WhichTree
>(
1423 TileManager::RasterTileIterator::RasterOrderComparator::RasterOrderComparator(
1424 TreePriority tree_priority
)
1425 : tree_priority_(tree_priority
) {}
1427 bool TileManager::RasterTileIterator::RasterOrderComparator::operator()(
1428 PairedPictureLayerIterator
* a
,
1429 PairedPictureLayerIterator
* b
) const {
1430 std::pair
<PictureLayerImpl::LayerRasterTileIterator
*, WhichTree
> a_pair
=
1431 a
->NextTileIterator(tree_priority_
);
1432 DCHECK(a_pair
.first
);
1433 DCHECK(*a_pair
.first
);
1435 std::pair
<PictureLayerImpl::LayerRasterTileIterator
*, WhichTree
> b_pair
=
1436 b
->NextTileIterator(tree_priority_
);
1437 DCHECK(b_pair
.first
);
1438 DCHECK(*b_pair
.first
);
1440 Tile
* a_tile
= **a_pair
.first
;
1441 Tile
* b_tile
= **b_pair
.first
;
1443 const TilePriority
& a_priority
=
1444 a_tile
->priority_for_tree_priority(tree_priority_
);
1445 const TilePriority
& b_priority
=
1446 b_tile
->priority_for_tree_priority(tree_priority_
);
1447 bool prioritize_low_res
= tree_priority_
== SMOOTHNESS_TAKES_PRIORITY
;
1449 if (b_priority
.resolution
!= a_priority
.resolution
) {
1450 return (prioritize_low_res
&& b_priority
.resolution
== LOW_RESOLUTION
) ||
1451 (!prioritize_low_res
&& b_priority
.resolution
== HIGH_RESOLUTION
) ||
1452 (a_priority
.resolution
== NON_IDEAL_RESOLUTION
);
1455 return b_priority
.IsHigherPriorityThan(a_priority
);
1458 TileManager::EvictionTileIterator::EvictionTileIterator()
1459 : comparator_(SAME_PRIORITY_FOR_BOTH_TREES
) {}
1461 TileManager::EvictionTileIterator::EvictionTileIterator(
1462 TileManager
* tile_manager
,
1463 TreePriority tree_priority
)
1464 : tree_priority_(tree_priority
), comparator_(tree_priority
) {
1465 std::vector
<TileManager::PairedPictureLayer
> paired_layers
;
1467 tile_manager
->GetPairedPictureLayers(&paired_layers
);
1469 paired_iterators_
.reserve(paired_layers
.size());
1470 iterator_heap_
.reserve(paired_layers
.size());
1471 for (std::vector
<TileManager::PairedPictureLayer
>::iterator it
=
1472 paired_layers
.begin();
1473 it
!= paired_layers
.end();
1475 PairedPictureLayerIterator paired_iterator
;
1476 if (it
->active_layer
) {
1477 paired_iterator
.active_iterator
=
1478 PictureLayerImpl::LayerEvictionTileIterator(it
->active_layer
,
1482 if (it
->pending_layer
) {
1483 paired_iterator
.pending_iterator
=
1484 PictureLayerImpl::LayerEvictionTileIterator(it
->pending_layer
,
1488 if (paired_iterator
.PeekTile(tree_priority_
) != NULL
) {
1489 paired_iterators_
.push_back(paired_iterator
);
1490 iterator_heap_
.push_back(&paired_iterators_
.back());
1494 std::make_heap(iterator_heap_
.begin(), iterator_heap_
.end(), comparator_
);
1497 TileManager::EvictionTileIterator::~EvictionTileIterator() {}
1499 TileManager::EvictionTileIterator
& TileManager::EvictionTileIterator::
1501 std::pop_heap(iterator_heap_
.begin(), iterator_heap_
.end(), comparator_
);
1502 PairedPictureLayerIterator
* paired_iterator
= iterator_heap_
.back();
1503 iterator_heap_
.pop_back();
1505 paired_iterator
->PopTile(tree_priority_
);
1506 if (paired_iterator
->PeekTile(tree_priority_
) != NULL
) {
1507 iterator_heap_
.push_back(paired_iterator
);
1508 std::push_heap(iterator_heap_
.begin(), iterator_heap_
.end(), comparator_
);
1513 TileManager::EvictionTileIterator::operator bool() const {
1514 return !iterator_heap_
.empty();
1517 Tile
* TileManager::EvictionTileIterator::operator*() {
1519 return iterator_heap_
.front()->PeekTile(tree_priority_
);
1522 TileManager::EvictionTileIterator::PairedPictureLayerIterator::
1523 PairedPictureLayerIterator() {}
1525 TileManager::EvictionTileIterator::PairedPictureLayerIterator::
1526 ~PairedPictureLayerIterator() {}
1528 Tile
* TileManager::EvictionTileIterator::PairedPictureLayerIterator::PeekTile(
1529 TreePriority tree_priority
) {
1530 PictureLayerImpl::LayerEvictionTileIterator
* next_iterator
=
1531 NextTileIterator(tree_priority
);
1535 DCHECK(*next_iterator
);
1536 DCHECK(std::find(returned_shared_tiles
.begin(),
1537 returned_shared_tiles
.end(),
1538 **next_iterator
) == returned_shared_tiles
.end());
1539 return **next_iterator
;
1542 void TileManager::EvictionTileIterator::PairedPictureLayerIterator::PopTile(
1543 TreePriority tree_priority
) {
1544 PictureLayerImpl::LayerEvictionTileIterator
* next_iterator
=
1545 NextTileIterator(tree_priority
);
1546 DCHECK(next_iterator
);
1547 DCHECK(*next_iterator
);
1548 returned_shared_tiles
.push_back(**next_iterator
);
1551 next_iterator
= NextTileIterator(tree_priority
);
1552 while (next_iterator
&&
1553 std::find(returned_shared_tiles
.begin(),
1554 returned_shared_tiles
.end(),
1555 **next_iterator
) != returned_shared_tiles
.end()) {
1557 next_iterator
= NextTileIterator(tree_priority
);
1561 PictureLayerImpl::LayerEvictionTileIterator
*
1562 TileManager::EvictionTileIterator::PairedPictureLayerIterator::NextTileIterator(
1563 TreePriority tree_priority
) {
1564 // If both iterators are out of tiles, return NULL.
1565 if (!active_iterator
&& !pending_iterator
)
1568 // If we only have one iterator with tiles, return it.
1569 if (!active_iterator
)
1570 return &pending_iterator
;
1571 if (!pending_iterator
)
1572 return &active_iterator
;
1574 Tile
* active_tile
= *active_iterator
;
1575 Tile
* pending_tile
= *pending_iterator
;
1576 if (active_tile
== pending_tile
)
1577 return &active_iterator
;
1579 const TilePriority
& active_priority
=
1580 active_tile
->priority_for_tree_priority(tree_priority
);
1581 const TilePriority
& pending_priority
=
1582 pending_tile
->priority_for_tree_priority(tree_priority
);
1584 if (pending_priority
.IsHigherPriorityThan(active_priority
))
1585 return &active_iterator
;
1586 return &pending_iterator
;
1589 TileManager::EvictionTileIterator::EvictionOrderComparator::
1590 EvictionOrderComparator(TreePriority tree_priority
)
1591 : tree_priority_(tree_priority
) {}
1593 bool TileManager::EvictionTileIterator::EvictionOrderComparator::operator()(
1594 PairedPictureLayerIterator
* a
,
1595 PairedPictureLayerIterator
* b
) const {
1596 PictureLayerImpl::LayerEvictionTileIterator
* a_iterator
=
1597 a
->NextTileIterator(tree_priority_
);
1599 DCHECK(*a_iterator
);
1601 PictureLayerImpl::LayerEvictionTileIterator
* b_iterator
=
1602 b
->NextTileIterator(tree_priority_
);
1604 DCHECK(*b_iterator
);
1606 Tile
* a_tile
= **a_iterator
;
1607 Tile
* b_tile
= **b_iterator
;
1609 const TilePriority
& a_priority
=
1610 a_tile
->priority_for_tree_priority(tree_priority_
);
1611 const TilePriority
& b_priority
=
1612 b_tile
->priority_for_tree_priority(tree_priority_
);
1613 bool prioritize_low_res
= tree_priority_
!= SMOOTHNESS_TAKES_PRIORITY
;
1615 if (b_priority
.resolution
!= a_priority
.resolution
) {
1616 return (prioritize_low_res
&& b_priority
.resolution
== LOW_RESOLUTION
) ||
1617 (!prioritize_low_res
&& b_priority
.resolution
== HIGH_RESOLUTION
) ||
1618 (a_priority
.resolution
== NON_IDEAL_RESOLUTION
);
1620 return a_priority
.IsHigherPriorityThan(b_priority
);
1623 void TileManager::SetRasterizerForTesting(Rasterizer
* rasterizer
) {
1624 rasterizer_
= rasterizer
;
1625 rasterizer_
->SetClient(this);
1628 bool TileManager::IsReadyToActivate() const {
1629 for (std::vector
<PictureLayerImpl
*>::const_iterator it
= layers_
.begin();
1630 it
!= layers_
.end();
1632 if (!(*it
)->AllTilesRequiredForActivationAreReadyToDraw())
1639 void TileManager::CheckIfReadyToActivate() {
1640 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
1642 rasterizer_
->CheckForCompletedTasks();
1643 did_check_for_completed_tasks_since_last_schedule_tasks_
= true;
1645 if (IsReadyToActivate())
1646 client_
->NotifyReadyToActivate();