Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(393)

Side by Side Diff: cc/resources/tile_manager.cc

Issue 1144693002: cc: Move files out of cc/resources/. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: resources: android Created 5 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/resources/tile_manager.h ('k') | cc/resources/tile_manager_perftest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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.
4
5 #include "cc/resources/tile_manager.h"
6
7 #include <algorithm>
8 #include <limits>
9 #include <string>
10
11 #include "base/bind.h"
12 #include "base/json/json_writer.h"
13 #include "base/logging.h"
14 #include "base/metrics/histogram.h"
15 #include "base/trace_event/trace_event_argument.h"
16 #include "cc/debug/devtools_instrumentation.h"
17 #include "cc/debug/frame_viewer_instrumentation.h"
18 #include "cc/debug/traced_value.h"
19 #include "cc/layers/picture_layer_impl.h"
20 #include "cc/resources/raster_buffer.h"
21 #include "cc/resources/tile.h"
22 #include "cc/resources/tile_task_runner.h"
23 #include "ui/gfx/geometry/rect_conversions.h"
24
25 namespace cc {
26 namespace {
27
28 // Flag to indicate whether we should try and detect that
29 // a tile is of solid color.
30 const bool kUseColorEstimator = true;
31
32 class RasterTaskImpl : public RasterTask {
33 public:
34 RasterTaskImpl(
35 const Resource* resource,
36 RasterSource* raster_source,
37 const gfx::Rect& content_rect,
38 float contents_scale,
39 TileResolution tile_resolution,
40 int layer_id,
41 const void* tile_id,
42 int source_frame_number,
43 bool analyze_picture,
44 const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>&
45 reply,
46 ImageDecodeTask::Vector* dependencies)
47 : RasterTask(resource, dependencies),
48 raster_source_(raster_source),
49 content_rect_(content_rect),
50 contents_scale_(contents_scale),
51 tile_resolution_(tile_resolution),
52 layer_id_(layer_id),
53 tile_id_(tile_id),
54 source_frame_number_(source_frame_number),
55 analyze_picture_(analyze_picture),
56 reply_(reply) {}
57
58 // Overridden from Task:
59 void RunOnWorkerThread() override {
60 TRACE_EVENT0("cc", "RasterizerTaskImpl::RunOnWorkerThread");
61
62 DCHECK(raster_source_.get());
63 DCHECK(raster_buffer_);
64
65 if (analyze_picture_) {
66 Analyze(raster_source_.get());
67 if (analysis_.is_solid_color)
68 return;
69 }
70
71 Raster(raster_source_.get());
72 }
73
74 // Overridden from TileTask:
75 void ScheduleOnOriginThread(TileTaskClient* client) override {
76 DCHECK(!raster_buffer_);
77 raster_buffer_ = client->AcquireBufferForRaster(resource());
78 }
79 void CompleteOnOriginThread(TileTaskClient* client) override {
80 client->ReleaseBufferForRaster(raster_buffer_.Pass());
81 }
82 void RunReplyOnOriginThread() override {
83 DCHECK(!raster_buffer_);
84 reply_.Run(analysis_, !HasFinishedRunning());
85 }
86
87 protected:
88 ~RasterTaskImpl() override { DCHECK(!raster_buffer_); }
89
90 private:
91 void Analyze(const RasterSource* raster_source) {
92 frame_viewer_instrumentation::ScopedAnalyzeTask analyze_task(
93 tile_id_, tile_resolution_, source_frame_number_, layer_id_);
94
95 DCHECK(raster_source);
96
97 raster_source->PerformSolidColorAnalysis(content_rect_, contents_scale_,
98 &analysis_);
99 // Clear the flag if we're not using the estimator.
100 analysis_.is_solid_color &= kUseColorEstimator;
101 }
102
103 void Raster(const RasterSource* raster_source) {
104 frame_viewer_instrumentation::ScopedRasterTask raster_task(
105 tile_id_, tile_resolution_, source_frame_number_, layer_id_);
106
107 DCHECK(raster_source);
108
109 raster_buffer_->Playback(raster_source_.get(), content_rect_,
110 contents_scale_);
111 }
112
113 RasterSource::SolidColorAnalysis analysis_;
114 scoped_refptr<RasterSource> raster_source_;
115 gfx::Rect content_rect_;
116 float contents_scale_;
117 TileResolution tile_resolution_;
118 int layer_id_;
119 const void* tile_id_;
120 int source_frame_number_;
121 bool analyze_picture_;
122 const base::Callback<void(const RasterSource::SolidColorAnalysis&, bool)>
123 reply_;
124 scoped_ptr<RasterBuffer> raster_buffer_;
125
126 DISALLOW_COPY_AND_ASSIGN(RasterTaskImpl);
127 };
128
129 class ImageDecodeTaskImpl : public ImageDecodeTask {
130 public:
131 ImageDecodeTaskImpl(SkPixelRef* pixel_ref,
132 const base::Callback<void(bool was_canceled)>& reply)
133 : pixel_ref_(skia::SharePtr(pixel_ref)),
134 reply_(reply) {}
135
136 // Overridden from Task:
137 void RunOnWorkerThread() override {
138 TRACE_EVENT0("cc", "ImageDecodeTaskImpl::RunOnWorkerThread");
139
140 devtools_instrumentation::ScopedImageDecodeTask image_decode_task(
141 pixel_ref_.get());
142 // This will cause the image referred to by pixel ref to be decoded.
143 pixel_ref_->lockPixels();
144 pixel_ref_->unlockPixels();
145
146 // Release the reference after decoding image to ensure that it is not
147 // kept alive unless needed.
148 pixel_ref_.clear();
149 }
150
151 // Overridden from TileTask:
152 void ScheduleOnOriginThread(TileTaskClient* client) override {}
153 void CompleteOnOriginThread(TileTaskClient* client) override {}
154 void RunReplyOnOriginThread() override { reply_.Run(!HasFinishedRunning()); }
155
156 protected:
157 ~ImageDecodeTaskImpl() override {}
158
159 private:
160 skia::RefPtr<SkPixelRef> pixel_ref_;
161 const base::Callback<void(bool was_canceled)> reply_;
162
163 DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl);
164 };
165
166 const char* TaskSetName(TaskSet task_set) {
167 switch (task_set) {
168 case TileManager::ALL:
169 return "ALL";
170 case TileManager::REQUIRED_FOR_ACTIVATION:
171 return "REQUIRED_FOR_ACTIVATION";
172 case TileManager::REQUIRED_FOR_DRAW:
173 return "REQUIRED_FOR_DRAW";
174 }
175
176 NOTREACHED();
177 return "Invalid TaskSet";
178 }
179
180 } // namespace
181
182 RasterTaskCompletionStats::RasterTaskCompletionStats()
183 : completed_count(0u), canceled_count(0u) {}
184
185 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
186 RasterTaskCompletionStatsAsValue(const RasterTaskCompletionStats& stats) {
187 scoped_refptr<base::trace_event::TracedValue> state =
188 new base::trace_event::TracedValue();
189 state->SetInteger("completed_count", stats.completed_count);
190 state->SetInteger("canceled_count", stats.canceled_count);
191 return state;
192 }
193
194 // static
195 scoped_ptr<TileManager> TileManager::Create(
196 TileManagerClient* client,
197 base::SequencedTaskRunner* task_runner,
198 ResourcePool* resource_pool,
199 TileTaskRunner* tile_task_runner,
200 size_t scheduled_raster_task_limit) {
201 return make_scoped_ptr(new TileManager(client, task_runner, resource_pool,
202 tile_task_runner,
203 scheduled_raster_task_limit));
204 }
205
206 TileManager::TileManager(
207 TileManagerClient* client,
208 const scoped_refptr<base::SequencedTaskRunner>& task_runner,
209 ResourcePool* resource_pool,
210 TileTaskRunner* tile_task_runner,
211 size_t scheduled_raster_task_limit)
212 : client_(client),
213 task_runner_(task_runner),
214 resource_pool_(resource_pool),
215 tile_task_runner_(tile_task_runner),
216 scheduled_raster_task_limit_(scheduled_raster_task_limit),
217 all_tiles_that_need_to_be_rasterized_are_scheduled_(true),
218 did_check_for_completed_tasks_since_last_schedule_tasks_(true),
219 did_oom_on_last_assign_(false),
220 ready_to_activate_check_notifier_(
221 task_runner_.get(),
222 base::Bind(&TileManager::CheckIfReadyToActivate,
223 base::Unretained(this))),
224 ready_to_draw_check_notifier_(
225 task_runner_.get(),
226 base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))),
227 more_tiles_need_prepare_check_notifier_(
228 task_runner_.get(),
229 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared,
230 base::Unretained(this))),
231 did_notify_ready_to_activate_(false),
232 did_notify_ready_to_draw_(false) {
233 tile_task_runner_->SetClient(this);
234 }
235
236 TileManager::~TileManager() {
237 // Reset global state and manage. This should cause
238 // our memory usage to drop to zero.
239 global_state_ = GlobalStateThatImpactsTilePriority();
240
241 TileTaskQueue empty;
242 tile_task_runner_->ScheduleTasks(&empty);
243 orphan_raster_tasks_.clear();
244
245 // This should finish all pending tasks and release any uninitialized
246 // resources.
247 tile_task_runner_->Shutdown();
248 tile_task_runner_->CheckForCompletedTasks();
249
250 FreeResourcesForReleasedTiles();
251 CleanUpReleasedTiles();
252 }
253
254 void TileManager::Release(Tile* tile) {
255 released_tiles_.push_back(tile);
256 }
257
258 TaskSetCollection TileManager::TasksThatShouldBeForcedToComplete() const {
259 TaskSetCollection tasks_that_should_be_forced_to_complete;
260 if (global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY)
261 tasks_that_should_be_forced_to_complete[REQUIRED_FOR_ACTIVATION] = true;
262 return tasks_that_should_be_forced_to_complete;
263 }
264
265 void TileManager::FreeResourcesForReleasedTiles() {
266 for (auto* tile : released_tiles_)
267 FreeResourcesForTile(tile);
268 }
269
270 void TileManager::CleanUpReleasedTiles() {
271 std::vector<Tile*> tiles_to_retain;
272 for (auto* tile : released_tiles_) {
273 if (tile->HasRasterTask()) {
274 tiles_to_retain.push_back(tile);
275 continue;
276 }
277
278 DCHECK(!tile->draw_info().has_resource());
279 DCHECK(tiles_.find(tile->id()) != tiles_.end());
280 tiles_.erase(tile->id());
281
282 LayerCountMap::iterator layer_it =
283 used_layer_counts_.find(tile->layer_id());
284 DCHECK_GT(layer_it->second, 0);
285 if (--layer_it->second == 0) {
286 used_layer_counts_.erase(layer_it);
287 image_decode_tasks_.erase(tile->layer_id());
288 }
289
290 delete tile;
291 }
292 released_tiles_.swap(tiles_to_retain);
293 }
294
295 void TileManager::DidFinishRunningTileTasks(TaskSet task_set) {
296 TRACE_EVENT1("cc", "TileManager::DidFinishRunningTileTasks", "task_set",
297 TaskSetName(task_set));
298
299 switch (task_set) {
300 case ALL: {
301 bool memory_usage_above_limit =
302 resource_pool_->total_memory_usage_bytes() >
303 global_state_.soft_memory_limit_in_bytes;
304
305 if (all_tiles_that_need_to_be_rasterized_are_scheduled_ &&
306 !memory_usage_above_limit)
307 return;
308
309 more_tiles_need_prepare_check_notifier_.Schedule();
310 return;
311 }
312 case REQUIRED_FOR_ACTIVATION:
313 ready_to_activate_check_notifier_.Schedule();
314 return;
315 case REQUIRED_FOR_DRAW:
316 ready_to_draw_check_notifier_.Schedule();
317 return;
318 }
319
320 NOTREACHED();
321 }
322
323 void TileManager::PrepareTiles(
324 const GlobalStateThatImpactsTilePriority& state) {
325 TRACE_EVENT0("cc", "TileManager::PrepareTiles");
326
327 global_state_ = state;
328
329 // We need to call CheckForCompletedTasks() once in-between each call
330 // to ScheduleTasks() to prevent canceled tasks from being scheduled.
331 if (!did_check_for_completed_tasks_since_last_schedule_tasks_) {
332 tile_task_runner_->CheckForCompletedTasks();
333 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
334 }
335
336 FreeResourcesForReleasedTiles();
337 CleanUpReleasedTiles();
338
339 PrioritizedTileVector tiles_that_need_to_be_rasterized;
340 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
341 client_->BuildRasterQueue(global_state_.tree_priority,
342 RasterTilePriorityQueue::Type::ALL));
343 AssignGpuMemoryToTiles(raster_priority_queue.get(),
344 scheduled_raster_task_limit_,
345 &tiles_that_need_to_be_rasterized);
346
347 // Inform the client that will likely require a draw if the highest priority
348 // tile that will be rasterized is required for draw.
349 client_->SetIsLikelyToRequireADraw(
350 !tiles_that_need_to_be_rasterized.empty() &&
351 tiles_that_need_to_be_rasterized.front().tile()->required_for_draw());
352
353 // Schedule tile tasks.
354 ScheduleTasks(tiles_that_need_to_be_rasterized);
355
356 did_notify_ready_to_activate_ = false;
357 did_notify_ready_to_draw_ = false;
358
359 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD,
360 "state", BasicStateAsValue());
361
362 TRACE_COUNTER_ID1("cc", "unused_memory_bytes", this,
363 resource_pool_->total_memory_usage_bytes() -
364 resource_pool_->acquired_memory_usage_bytes());
365 }
366
367 void TileManager::UpdateVisibleTiles(
368 const GlobalStateThatImpactsTilePriority& state) {
369 TRACE_EVENT0("cc", "TileManager::UpdateVisibleTiles");
370
371 tile_task_runner_->CheckForCompletedTasks();
372
373 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
374
375 TRACE_EVENT_INSTANT1(
376 "cc",
377 "DidUpdateVisibleTiles",
378 TRACE_EVENT_SCOPE_THREAD,
379 "stats",
380 RasterTaskCompletionStatsAsValue(update_visible_tiles_stats_));
381 update_visible_tiles_stats_ = RasterTaskCompletionStats();
382 }
383
384 scoped_refptr<base::trace_event::ConvertableToTraceFormat>
385 TileManager::BasicStateAsValue() const {
386 scoped_refptr<base::trace_event::TracedValue> value =
387 new base::trace_event::TracedValue();
388 BasicStateAsValueInto(value.get());
389 return value;
390 }
391
392 void TileManager::BasicStateAsValueInto(
393 base::trace_event::TracedValue* state) const {
394 state->SetInteger("tile_count", tiles_.size());
395 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_);
396 state->BeginDictionary("global_state");
397 global_state_.AsValueInto(state);
398 state->EndDictionary();
399 }
400
401 scoped_ptr<EvictionTilePriorityQueue>
402 TileManager::FreeTileResourcesUntilUsageIsWithinLimit(
403 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
404 const MemoryUsage& limit,
405 MemoryUsage* usage) {
406 while (usage->Exceeds(limit)) {
407 if (!eviction_priority_queue) {
408 eviction_priority_queue =
409 client_->BuildEvictionQueue(global_state_.tree_priority);
410 }
411 if (eviction_priority_queue->IsEmpty())
412 break;
413
414 Tile* tile = eviction_priority_queue->Top().tile();
415 *usage -= MemoryUsage::FromTile(tile);
416 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
417 eviction_priority_queue->Pop();
418 }
419 return eviction_priority_queue;
420 }
421
422 scoped_ptr<EvictionTilePriorityQueue>
423 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
424 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue,
425 const MemoryUsage& limit,
426 const TilePriority& other_priority,
427 MemoryUsage* usage) {
428 while (usage->Exceeds(limit)) {
429 if (!eviction_priority_queue) {
430 eviction_priority_queue =
431 client_->BuildEvictionQueue(global_state_.tree_priority);
432 }
433 if (eviction_priority_queue->IsEmpty())
434 break;
435
436 const PrioritizedTile& prioritized_tile = eviction_priority_queue->Top();
437 if (!other_priority.IsHigherPriorityThan(prioritized_tile.priority()))
438 break;
439
440 Tile* tile = prioritized_tile.tile();
441 *usage -= MemoryUsage::FromTile(tile);
442 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile);
443 eviction_priority_queue->Pop();
444 }
445 return eviction_priority_queue;
446 }
447
448 bool TileManager::TilePriorityViolatesMemoryPolicy(
449 const TilePriority& priority) {
450 switch (global_state_.memory_limit_policy) {
451 case ALLOW_NOTHING:
452 return true;
453 case ALLOW_ABSOLUTE_MINIMUM:
454 return priority.priority_bin > TilePriority::NOW;
455 case ALLOW_PREPAINT_ONLY:
456 return priority.priority_bin > TilePriority::SOON;
457 case ALLOW_ANYTHING:
458 return priority.distance_to_visible ==
459 std::numeric_limits<float>::infinity();
460 }
461 NOTREACHED();
462 return true;
463 }
464
465 void TileManager::AssignGpuMemoryToTiles(
466 RasterTilePriorityQueue* raster_priority_queue,
467 size_t scheduled_raster_task_limit,
468 PrioritizedTileVector* tiles_that_need_to_be_rasterized) {
469 TRACE_EVENT_BEGIN0("cc", "TileManager::AssignGpuMemoryToTiles");
470
471 // Maintain the list of released resources that can potentially be re-used
472 // or deleted. If this operation becomes expensive too, only do this after
473 // some resource(s) was returned. Note that in that case, one also need to
474 // invalidate when releasing some resource from the pool.
475 resource_pool_->CheckBusyResources(false);
476
477 // Now give memory out to the tiles until we're out, and build
478 // the needs-to-be-rasterized queue.
479 unsigned schedule_priority = 1u;
480 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true;
481 bool had_enough_memory_to_schedule_tiles_needed_now = true;
482
483 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes,
484 global_state_.num_resources_limit);
485 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes,
486 global_state_.num_resources_limit);
487 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(),
488 resource_pool_->acquired_resource_count());
489
490 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue;
491 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
492 const PrioritizedTile& prioritized_tile = raster_priority_queue->Top();
493 Tile* tile = prioritized_tile.tile();
494 TilePriority priority = prioritized_tile.priority();
495
496 if (TilePriorityViolatesMemoryPolicy(priority)) {
497 TRACE_EVENT_INSTANT0(
498 "cc", "TileManager::AssignGpuMemory tile violates memory policy",
499 TRACE_EVENT_SCOPE_THREAD);
500 break;
501 }
502
503 // We won't be able to schedule this tile, so break out early.
504 if (tiles_that_need_to_be_rasterized->size() >=
505 scheduled_raster_task_limit) {
506 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
507 break;
508 }
509
510 tile->scheduled_priority_ = schedule_priority++;
511
512 DCHECK_IMPLIES(tile->draw_info().mode() != TileDrawInfo::OOM_MODE,
513 !tile->draw_info().IsReadyToDraw());
514
515 // If the tile already has a raster_task, then the memory used by it is
516 // already accounted for in memory_usage. Otherwise, we'll have to acquire
517 // more memory to create a raster task.
518 MemoryUsage memory_required_by_tile_to_be_scheduled;
519 if (!tile->raster_task_.get()) {
520 memory_required_by_tile_to_be_scheduled = MemoryUsage::FromConfig(
521 tile->desired_texture_size(), tile_task_runner_->GetResourceFormat());
522 }
523
524 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW;
525
526 // This is the memory limit that will be used by this tile. Depending on
527 // the tile priority, it will be one of hard_memory_limit or
528 // soft_memory_limit.
529 MemoryUsage& tile_memory_limit =
530 tile_is_needed_now ? hard_memory_limit : soft_memory_limit;
531
532 const MemoryUsage& scheduled_tile_memory_limit =
533 tile_memory_limit - memory_required_by_tile_to_be_scheduled;
534 eviction_priority_queue =
535 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit(
536 eviction_priority_queue.Pass(), scheduled_tile_memory_limit,
537 priority, &memory_usage);
538 bool memory_usage_is_within_limit =
539 !memory_usage.Exceeds(scheduled_tile_memory_limit);
540
541 // If we couldn't fit the tile into our current memory limit, then we're
542 // done.
543 if (!memory_usage_is_within_limit) {
544 if (tile_is_needed_now)
545 had_enough_memory_to_schedule_tiles_needed_now = false;
546 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false;
547 break;
548 }
549
550 memory_usage += memory_required_by_tile_to_be_scheduled;
551 tiles_that_need_to_be_rasterized->push_back(prioritized_tile);
552 }
553
554 // Note that we should try and further reduce memory in case the above loop
555 // didn't reduce memory. This ensures that we always release as many resources
556 // as possible to stay within the memory limit.
557 eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit(
558 eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage);
559
560 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget",
561 !had_enough_memory_to_schedule_tiles_needed_now);
562 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now;
563
564 memory_stats_from_last_assign_.total_budget_in_bytes =
565 global_state_.hard_memory_limit_in_bytes;
566 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes();
567 memory_stats_from_last_assign_.had_enough_memory =
568 had_enough_memory_to_schedule_tiles_needed_now;
569
570 TRACE_EVENT_END2("cc", "TileManager::AssignGpuMemoryToTiles",
571 "all_tiles_that_need_to_be_rasterized_are_scheduled",
572 all_tiles_that_need_to_be_rasterized_are_scheduled_,
573 "had_enough_memory_to_schedule_tiles_needed_now",
574 had_enough_memory_to_schedule_tiles_needed_now);
575 }
576
577 void TileManager::FreeResourcesForTile(Tile* tile) {
578 TileDrawInfo& draw_info = tile->draw_info();
579 if (draw_info.resource_)
580 resource_pool_->ReleaseResource(draw_info.resource_.Pass());
581 }
582
583 void TileManager::FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(
584 Tile* tile) {
585 bool was_ready_to_draw = tile->draw_info().IsReadyToDraw();
586 FreeResourcesForTile(tile);
587 if (was_ready_to_draw)
588 client_->NotifyTileStateChanged(tile);
589 }
590
591 void TileManager::ScheduleTasks(
592 const PrioritizedTileVector& tiles_that_need_to_be_rasterized) {
593 TRACE_EVENT1("cc",
594 "TileManager::ScheduleTasks",
595 "count",
596 tiles_that_need_to_be_rasterized.size());
597
598 DCHECK(did_check_for_completed_tasks_since_last_schedule_tasks_);
599
600 raster_queue_.Reset();
601
602 // Build a new task queue containing all task currently needed. Tasks
603 // are added in order of priority, highest priority task first.
604 for (auto& prioritized_tile : tiles_that_need_to_be_rasterized) {
605 Tile* tile = prioritized_tile.tile();
606
607 DCHECK(tile->draw_info().requires_resource());
608 DCHECK(!tile->draw_info().resource_);
609
610 if (!tile->raster_task_.get())
611 tile->raster_task_ = CreateRasterTask(prioritized_tile);
612
613 TaskSetCollection task_sets;
614 if (tile->required_for_activation())
615 task_sets.set(REQUIRED_FOR_ACTIVATION);
616 if (tile->required_for_draw())
617 task_sets.set(REQUIRED_FOR_DRAW);
618 task_sets.set(ALL);
619 raster_queue_.items.push_back(
620 TileTaskQueue::Item(tile->raster_task_.get(), task_sets));
621 }
622
623 // We must reduce the amount of unused resoruces before calling
624 // ScheduleTasks to prevent usage from rising above limits.
625 resource_pool_->ReduceResourceUsage();
626
627 // Schedule running of |raster_queue_|. This replaces any previously
628 // scheduled tasks and effectively cancels all tasks not present
629 // in |raster_queue_|.
630 tile_task_runner_->ScheduleTasks(&raster_queue_);
631
632 // It's now safe to clean up orphan tasks as raster worker pool is not
633 // allowed to keep around unreferenced raster tasks after ScheduleTasks() has
634 // been called.
635 orphan_raster_tasks_.clear();
636
637 did_check_for_completed_tasks_since_last_schedule_tasks_ = false;
638 }
639
640 scoped_refptr<ImageDecodeTask> TileManager::CreateImageDecodeTask(
641 Tile* tile,
642 SkPixelRef* pixel_ref) {
643 return make_scoped_refptr(new ImageDecodeTaskImpl(
644 pixel_ref,
645 base::Bind(&TileManager::OnImageDecodeTaskCompleted,
646 base::Unretained(this),
647 tile->layer_id(),
648 base::Unretained(pixel_ref))));
649 }
650
651 scoped_refptr<RasterTask> TileManager::CreateRasterTask(
652 const PrioritizedTile& prioritized_tile) {
653 Tile* tile = prioritized_tile.tile();
654 scoped_ptr<ScopedResource> resource =
655 resource_pool_->AcquireResource(tile->desired_texture_size(),
656 tile_task_runner_->GetResourceFormat());
657 const ScopedResource* const_resource = resource.get();
658
659 // Create and queue all image decode tasks that this tile depends on.
660 ImageDecodeTask::Vector decode_tasks;
661 PixelRefTaskMap& existing_pixel_refs = image_decode_tasks_[tile->layer_id()];
662 std::vector<SkPixelRef*> pixel_refs;
663 prioritized_tile.raster_source()->GatherPixelRefs(
664 tile->content_rect(), tile->contents_scale(), &pixel_refs);
665 for (SkPixelRef* pixel_ref : pixel_refs) {
666 uint32_t id = pixel_ref->getGenerationID();
667
668 // Append existing image decode task if available.
669 PixelRefTaskMap::iterator decode_task_it = existing_pixel_refs.find(id);
670 if (decode_task_it != existing_pixel_refs.end()) {
671 decode_tasks.push_back(decode_task_it->second);
672 continue;
673 }
674
675 // Create and append new image decode task for this pixel ref.
676 scoped_refptr<ImageDecodeTask> decode_task =
677 CreateImageDecodeTask(tile, pixel_ref);
678 decode_tasks.push_back(decode_task);
679 existing_pixel_refs[id] = decode_task;
680 }
681
682 return make_scoped_refptr(new RasterTaskImpl(
683 const_resource, prioritized_tile.raster_source(), tile->content_rect(),
684 tile->contents_scale(), prioritized_tile.priority().resolution,
685 tile->layer_id(), static_cast<const void*>(tile),
686 tile->source_frame_number(), tile->use_picture_analysis(),
687 base::Bind(&TileManager::OnRasterTaskCompleted, base::Unretained(this),
688 tile->id(), base::Passed(&resource)),
689 &decode_tasks));
690 }
691
692 void TileManager::OnImageDecodeTaskCompleted(int layer_id,
693 SkPixelRef* pixel_ref,
694 bool was_canceled) {
695 // If the task was canceled, we need to clean it up
696 // from |image_decode_tasks_|.
697 if (!was_canceled)
698 return;
699
700 LayerPixelRefTaskMap::iterator layer_it = image_decode_tasks_.find(layer_id);
701 if (layer_it == image_decode_tasks_.end())
702 return;
703
704 PixelRefTaskMap& pixel_ref_tasks = layer_it->second;
705 PixelRefTaskMap::iterator task_it =
706 pixel_ref_tasks.find(pixel_ref->getGenerationID());
707
708 if (task_it != pixel_ref_tasks.end())
709 pixel_ref_tasks.erase(task_it);
710 }
711
712 void TileManager::OnRasterTaskCompleted(
713 Tile::Id tile_id,
714 scoped_ptr<ScopedResource> resource,
715 const RasterSource::SolidColorAnalysis& analysis,
716 bool was_canceled) {
717 DCHECK(tiles_.find(tile_id) != tiles_.end());
718
719 Tile* tile = tiles_[tile_id];
720 DCHECK(tile->raster_task_.get());
721 orphan_raster_tasks_.push_back(tile->raster_task_);
722 tile->raster_task_ = nullptr;
723
724 if (was_canceled) {
725 ++update_visible_tiles_stats_.canceled_count;
726 resource_pool_->ReleaseResource(resource.Pass());
727 return;
728 }
729
730 UpdateTileDrawInfo(tile, resource.Pass(), analysis);
731 }
732
733 void TileManager::UpdateTileDrawInfo(
734 Tile* tile,
735 scoped_ptr<ScopedResource> resource,
736 const RasterSource::SolidColorAnalysis& analysis) {
737 TileDrawInfo& draw_info = tile->draw_info();
738
739 ++update_visible_tiles_stats_.completed_count;
740
741 if (analysis.is_solid_color) {
742 draw_info.set_solid_color(analysis.solid_color);
743 if (resource)
744 resource_pool_->ReleaseResource(resource.Pass());
745 } else {
746 DCHECK(resource);
747 draw_info.set_use_resource();
748 draw_info.resource_ = resource.Pass();
749 }
750
751 client_->NotifyTileStateChanged(tile);
752 }
753
754 ScopedTilePtr TileManager::CreateTile(const gfx::Size& desired_texture_size,
755 const gfx::Rect& content_rect,
756 float contents_scale,
757 int layer_id,
758 int source_frame_number,
759 int flags) {
760 ScopedTilePtr tile(new Tile(this, desired_texture_size, content_rect,
761 contents_scale, layer_id, source_frame_number,
762 flags));
763 DCHECK(tiles_.find(tile->id()) == tiles_.end());
764
765 tiles_[tile->id()] = tile.get();
766 used_layer_counts_[tile->layer_id()]++;
767 return tile;
768 }
769
770 void TileManager::SetTileTaskRunnerForTesting(
771 TileTaskRunner* tile_task_runner) {
772 tile_task_runner_ = tile_task_runner;
773 tile_task_runner_->SetClient(this);
774 }
775
776 bool TileManager::AreRequiredTilesReadyToDraw(
777 RasterTilePriorityQueue::Type type) const {
778 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
779 client_->BuildRasterQueue(global_state_.tree_priority, type));
780 // It is insufficient to check whether the raster queue we constructed is
781 // empty. The reason for this is that there are situations (rasterize on
782 // demand) when the tile both needs raster and it's ready to draw. Hence, we
783 // have to iterate the queue to check whether the required tiles are ready to
784 // draw.
785 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) {
786 if (!raster_priority_queue->Top().tile()->draw_info().IsReadyToDraw())
787 return false;
788 }
789
790 #if DCHECK_IS_ON()
791 scoped_ptr<RasterTilePriorityQueue> all_queue(
792 client_->BuildRasterQueue(global_state_.tree_priority, type));
793 for (; !all_queue->IsEmpty(); all_queue->Pop()) {
794 Tile* tile = all_queue->Top().tile();
795 DCHECK_IMPLIES(tile->required_for_activation(),
796 tile->draw_info().IsReadyToDraw());
797 }
798 #endif
799 return true;
800 }
801 bool TileManager::IsReadyToActivate() const {
802 TRACE_EVENT0("cc", "TileManager::IsReadyToActivate");
803 return AreRequiredTilesReadyToDraw(
804 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION);
805 }
806
807 bool TileManager::IsReadyToDraw() const {
808 TRACE_EVENT0("cc", "TileManager::IsReadyToDraw");
809 return AreRequiredTilesReadyToDraw(
810 RasterTilePriorityQueue::Type::REQUIRED_FOR_DRAW);
811 }
812
813 void TileManager::NotifyReadyToActivate() {
814 TRACE_EVENT0("cc", "TileManager::NotifyReadyToActivate");
815 if (did_notify_ready_to_activate_)
816 return;
817 client_->NotifyReadyToActivate();
818 did_notify_ready_to_activate_ = true;
819 }
820
821 void TileManager::NotifyReadyToDraw() {
822 TRACE_EVENT0("cc", "TileManager::NotifyReadyToDraw");
823 if (did_notify_ready_to_draw_)
824 return;
825 client_->NotifyReadyToDraw();
826 did_notify_ready_to_draw_ = true;
827 }
828
829 void TileManager::CheckIfReadyToActivate() {
830 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToActivate");
831
832 tile_task_runner_->CheckForCompletedTasks();
833 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
834
835 if (did_notify_ready_to_activate_)
836 return;
837 if (!IsReadyToActivate())
838 return;
839
840 NotifyReadyToActivate();
841 }
842
843 void TileManager::CheckIfReadyToDraw() {
844 TRACE_EVENT0("cc", "TileManager::CheckIfReadyToDraw");
845
846 tile_task_runner_->CheckForCompletedTasks();
847 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
848
849 if (did_notify_ready_to_draw_)
850 return;
851 if (!IsReadyToDraw())
852 return;
853
854 NotifyReadyToDraw();
855 }
856
857 void TileManager::CheckIfMoreTilesNeedToBePrepared() {
858 tile_task_runner_->CheckForCompletedTasks();
859 did_check_for_completed_tasks_since_last_schedule_tasks_ = true;
860
861 // When OOM, keep re-assigning memory until we reach a steady state
862 // where top-priority tiles are initialized.
863 PrioritizedTileVector tiles_that_need_to_be_rasterized;
864 scoped_ptr<RasterTilePriorityQueue> raster_priority_queue(
865 client_->BuildRasterQueue(global_state_.tree_priority,
866 RasterTilePriorityQueue::Type::ALL));
867 AssignGpuMemoryToTiles(raster_priority_queue.get(),
868 scheduled_raster_task_limit_,
869 &tiles_that_need_to_be_rasterized);
870
871 // Inform the client that will likely require a draw if the highest priority
872 // tile that will be rasterized is required for draw.
873 client_->SetIsLikelyToRequireADraw(
874 !tiles_that_need_to_be_rasterized.empty() &&
875 tiles_that_need_to_be_rasterized.front().tile()->required_for_draw());
876
877 // |tiles_that_need_to_be_rasterized| will be empty when we reach a
878 // steady memory state. Keep scheduling tasks until we reach this state.
879 if (!tiles_that_need_to_be_rasterized.empty()) {
880 ScheduleTasks(tiles_that_need_to_be_rasterized);
881 return;
882 }
883
884 FreeResourcesForReleasedTiles();
885
886 resource_pool_->ReduceResourceUsage();
887
888 // We don't reserve memory for required-for-activation tiles during
889 // accelerated gestures, so we just postpone activation when we don't
890 // have these tiles, and activate after the accelerated gesture.
891 // Likewise if we don't allow any tiles (as is the case when we're
892 // invisible), if we have tiles that aren't ready, then we shouldn't
893 // activate as activation can cause checkerboards.
894 bool wait_for_all_required_tiles =
895 global_state_.tree_priority == SMOOTHNESS_TAKES_PRIORITY ||
896 global_state_.memory_limit_policy == ALLOW_NOTHING;
897
898 // Mark any required-for-activation tiles that have not been been assigned
899 // memory after reaching a steady memory state as OOM. This ensures that we
900 // activate even when OOM. Note that we can't reuse the queue we used for
901 // AssignGpuMemoryToTiles, since the AssignGpuMemoryToTiles call could have
902 // evicted some tiles that would not be picked up by the old raster queue.
903 scoped_ptr<RasterTilePriorityQueue> required_for_activation_queue(
904 client_->BuildRasterQueue(
905 global_state_.tree_priority,
906 RasterTilePriorityQueue::Type::REQUIRED_FOR_ACTIVATION));
907
908 // If we have tiles left to raster for activation, and we don't allow
909 // activating without them, then skip activation and return early.
910 if (!required_for_activation_queue->IsEmpty() && wait_for_all_required_tiles)
911 return;
912
913 // Mark required tiles as OOM so that we can activate without them.
914 for (; !required_for_activation_queue->IsEmpty();
915 required_for_activation_queue->Pop()) {
916 Tile* tile = required_for_activation_queue->Top().tile();
917 tile->draw_info().set_oom();
918 client_->NotifyTileStateChanged(tile);
919 }
920
921 DCHECK(IsReadyToActivate());
922 ready_to_activate_check_notifier_.Schedule();
923 }
924
925 TileManager::MemoryUsage::MemoryUsage() : memory_bytes_(0), resource_count_(0) {
926 }
927
928 TileManager::MemoryUsage::MemoryUsage(int64 memory_bytes, int resource_count)
929 : memory_bytes_(memory_bytes), resource_count_(resource_count) {
930 }
931
932 // static
933 TileManager::MemoryUsage TileManager::MemoryUsage::FromConfig(
934 const gfx::Size& size,
935 ResourceFormat format) {
936 return MemoryUsage(Resource::MemorySizeBytes(size, format), 1);
937 }
938
939 // static
940 TileManager::MemoryUsage TileManager::MemoryUsage::FromTile(const Tile* tile) {
941 const TileDrawInfo& draw_info = tile->draw_info();
942 if (draw_info.resource_) {
943 return MemoryUsage::FromConfig(draw_info.resource_->size(),
944 draw_info.resource_->format());
945 }
946 return MemoryUsage();
947 }
948
949 TileManager::MemoryUsage& TileManager::MemoryUsage::operator+=(
950 const MemoryUsage& other) {
951 memory_bytes_ += other.memory_bytes_;
952 resource_count_ += other.resource_count_;
953 return *this;
954 }
955
956 TileManager::MemoryUsage& TileManager::MemoryUsage::operator-=(
957 const MemoryUsage& other) {
958 memory_bytes_ -= other.memory_bytes_;
959 resource_count_ -= other.resource_count_;
960 return *this;
961 }
962
963 TileManager::MemoryUsage TileManager::MemoryUsage::operator-(
964 const MemoryUsage& other) {
965 MemoryUsage result = *this;
966 result -= other;
967 return result;
968 }
969
970 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const {
971 return memory_bytes_ > limit.memory_bytes_ ||
972 resource_count_ > limit.resource_count_;
973 }
974
975 } // namespace cc
OLDNEW
« no previous file with comments | « cc/resources/tile_manager.h ('k') | cc/resources/tile_manager_perftest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698