OLD | NEW |
1 // Copyright 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "cc/resources/tile_manager.h" | 5 #include "cc/resources/tile_manager.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <limits> | 8 #include <limits> |
9 #include <string> | 9 #include <string> |
10 | 10 |
(...skipping 222 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
233 task_runner_.get(), | 233 task_runner_.get(), |
234 base::Bind(&TileManager::CheckIfReadyToActivate, | 234 base::Bind(&TileManager::CheckIfReadyToActivate, |
235 base::Unretained(this))), | 235 base::Unretained(this))), |
236 ready_to_draw_check_notifier_( | 236 ready_to_draw_check_notifier_( |
237 task_runner_.get(), | 237 task_runner_.get(), |
238 base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))), | 238 base::Bind(&TileManager::CheckIfReadyToDraw, base::Unretained(this))), |
239 more_tiles_need_prepare_check_notifier_( | 239 more_tiles_need_prepare_check_notifier_( |
240 task_runner_.get(), | 240 task_runner_.get(), |
241 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared, | 241 base::Bind(&TileManager::CheckIfMoreTilesNeedToBePrepared, |
242 base::Unretained(this))), | 242 base::Unretained(this))), |
243 eviction_priority_queue_is_up_to_date_(false), | |
244 did_notify_ready_to_activate_(false), | 243 did_notify_ready_to_activate_(false), |
245 did_notify_ready_to_draw_(false) { | 244 did_notify_ready_to_draw_(false) { |
246 tile_task_runner_->SetClient(this); | 245 tile_task_runner_->SetClient(this); |
247 } | 246 } |
248 | 247 |
249 TileManager::~TileManager() { | 248 TileManager::~TileManager() { |
250 // Reset global state and manage. This should cause | 249 // Reset global state and manage. This should cause |
251 // our memory usage to drop to zero. | 250 // our memory usage to drop to zero. |
252 global_state_ = GlobalStateThatImpactsTilePriority(); | 251 global_state_ = GlobalStateThatImpactsTilePriority(); |
253 | 252 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
367 scheduled_raster_task_limit_, | 366 scheduled_raster_task_limit_, |
368 &tiles_that_need_to_be_rasterized); | 367 &tiles_that_need_to_be_rasterized); |
369 | 368 |
370 // Schedule tile tasks. | 369 // Schedule tile tasks. |
371 ScheduleTasks(tiles_that_need_to_be_rasterized); | 370 ScheduleTasks(tiles_that_need_to_be_rasterized); |
372 | 371 |
373 did_notify_ready_to_activate_ = false; | 372 did_notify_ready_to_activate_ = false; |
374 did_notify_ready_to_draw_ = false; | 373 did_notify_ready_to_draw_ = false; |
375 } else { | 374 } else { |
376 if (global_state_.hard_memory_limit_in_bytes == 0) { | 375 if (global_state_.hard_memory_limit_in_bytes == 0) { |
377 // TODO(vmpstr): Add a function to unconditionally create an eviction | |
378 // queue and guard the rest of the calls sites with this flag, instead of | |
379 // clearing here and building, which is a bit awkward. | |
380 eviction_priority_queue_is_up_to_date_ = false; | |
381 resource_pool_->CheckBusyResources(false); | 376 resource_pool_->CheckBusyResources(false); |
382 MemoryUsage memory_limit(0, 0); | 377 MemoryUsage memory_limit(0, 0); |
383 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(), | 378 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(), |
384 resource_pool_->acquired_resource_count()); | 379 resource_pool_->acquired_resource_count()); |
385 FreeTileResourcesUntilUsageIsWithinLimit(memory_limit, &memory_usage); | 380 FreeTileResourcesUntilUsageIsWithinLimit(nullptr, memory_limit, |
| 381 &memory_usage); |
386 } | 382 } |
387 | 383 |
388 did_notify_ready_to_activate_ = false; | 384 did_notify_ready_to_activate_ = false; |
389 did_notify_ready_to_draw_ = false; | 385 did_notify_ready_to_draw_ = false; |
390 ready_to_activate_notifier_.Schedule(); | 386 ready_to_activate_notifier_.Schedule(); |
391 ready_to_draw_notifier_.Schedule(); | 387 ready_to_draw_notifier_.Schedule(); |
392 } | 388 } |
393 | 389 |
394 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD, | 390 TRACE_EVENT_INSTANT1("cc", "DidPrepareTiles", TRACE_EVENT_SCOPE_THREAD, |
395 "state", BasicStateAsValue()); | 391 "state", BasicStateAsValue()); |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
484 } | 480 } |
485 | 481 |
486 void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const { | 482 void TileManager::BasicStateAsValueInto(base::debug::TracedValue* state) const { |
487 state->SetInteger("tile_count", tiles_.size()); | 483 state->SetInteger("tile_count", tiles_.size()); |
488 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_); | 484 state->SetBoolean("did_oom_on_last_assign", did_oom_on_last_assign_); |
489 state->BeginDictionary("global_state"); | 485 state->BeginDictionary("global_state"); |
490 global_state_.AsValueInto(state); | 486 global_state_.AsValueInto(state); |
491 state->EndDictionary(); | 487 state->EndDictionary(); |
492 } | 488 } |
493 | 489 |
494 void TileManager::RebuildEvictionQueueIfNeeded() { | 490 scoped_ptr<EvictionTilePriorityQueue> |
495 TRACE_EVENT1("cc", | 491 TileManager::FreeTileResourcesUntilUsageIsWithinLimit( |
496 "TileManager::RebuildEvictionQueueIfNeeded", | 492 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue, |
497 "eviction_priority_queue_is_up_to_date", | |
498 eviction_priority_queue_is_up_to_date_); | |
499 if (eviction_priority_queue_is_up_to_date_) | |
500 return; | |
501 | |
502 eviction_priority_queue_.Reset(); | |
503 client_->BuildEvictionQueue(&eviction_priority_queue_, | |
504 global_state_.tree_priority); | |
505 eviction_priority_queue_is_up_to_date_ = true; | |
506 } | |
507 | |
508 bool TileManager::FreeTileResourcesUntilUsageIsWithinLimit( | |
509 const MemoryUsage& limit, | 493 const MemoryUsage& limit, |
510 MemoryUsage* usage) { | 494 MemoryUsage* usage) { |
511 while (usage->Exceeds(limit)) { | 495 while (usage->Exceeds(limit)) { |
512 RebuildEvictionQueueIfNeeded(); | 496 if (!eviction_priority_queue) { |
513 if (eviction_priority_queue_.IsEmpty()) | 497 eviction_priority_queue = |
514 return false; | 498 client_->BuildEvictionQueue(global_state_.tree_priority); |
| 499 } |
| 500 if (eviction_priority_queue->IsEmpty()) |
| 501 break; |
515 | 502 |
516 Tile* tile = eviction_priority_queue_.Top(); | 503 Tile* tile = eviction_priority_queue->Top(); |
517 *usage -= MemoryUsage::FromTile(tile); | 504 *usage -= MemoryUsage::FromTile(tile); |
518 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); | 505 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); |
519 eviction_priority_queue_.Pop(); | 506 eviction_priority_queue->Pop(); |
520 } | 507 } |
521 return true; | 508 return eviction_priority_queue; |
522 } | 509 } |
523 | 510 |
524 bool TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( | 511 scoped_ptr<EvictionTilePriorityQueue> |
| 512 TileManager::FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( |
| 513 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue, |
525 const MemoryUsage& limit, | 514 const MemoryUsage& limit, |
526 const TilePriority& other_priority, | 515 const TilePriority& other_priority, |
527 MemoryUsage* usage) { | 516 MemoryUsage* usage) { |
528 while (usage->Exceeds(limit)) { | 517 while (usage->Exceeds(limit)) { |
529 RebuildEvictionQueueIfNeeded(); | 518 if (!eviction_priority_queue) { |
530 if (eviction_priority_queue_.IsEmpty()) | 519 eviction_priority_queue = |
531 return false; | 520 client_->BuildEvictionQueue(global_state_.tree_priority); |
| 521 } |
| 522 if (eviction_priority_queue->IsEmpty()) |
| 523 break; |
532 | 524 |
533 Tile* tile = eviction_priority_queue_.Top(); | 525 Tile* tile = eviction_priority_queue->Top(); |
534 if (!other_priority.IsHigherPriorityThan(tile->combined_priority())) | 526 if (!other_priority.IsHigherPriorityThan(tile->combined_priority())) |
535 return false; | 527 break; |
536 | 528 |
537 *usage -= MemoryUsage::FromTile(tile); | 529 *usage -= MemoryUsage::FromTile(tile); |
538 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); | 530 FreeResourcesForTileAndNotifyClientIfTileWasReadyToDraw(tile); |
539 eviction_priority_queue_.Pop(); | 531 eviction_priority_queue->Pop(); |
540 } | 532 } |
541 return true; | 533 return eviction_priority_queue; |
542 } | 534 } |
543 | 535 |
544 bool TileManager::TilePriorityViolatesMemoryPolicy( | 536 bool TileManager::TilePriorityViolatesMemoryPolicy( |
545 const TilePriority& priority) { | 537 const TilePriority& priority) { |
546 switch (global_state_.memory_limit_policy) { | 538 switch (global_state_.memory_limit_policy) { |
547 case ALLOW_NOTHING: | 539 case ALLOW_NOTHING: |
548 return true; | 540 return true; |
549 case ALLOW_ABSOLUTE_MINIMUM: | 541 case ALLOW_ABSOLUTE_MINIMUM: |
550 return priority.priority_bin > TilePriority::NOW; | 542 return priority.priority_bin > TilePriority::NOW; |
551 case ALLOW_PREPAINT_ONLY: | 543 case ALLOW_PREPAINT_ONLY: |
(...skipping 24 matching lines...) Expand all Loading... |
576 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true; | 568 all_tiles_that_need_to_be_rasterized_are_scheduled_ = true; |
577 bool had_enough_memory_to_schedule_tiles_needed_now = true; | 569 bool had_enough_memory_to_schedule_tiles_needed_now = true; |
578 | 570 |
579 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes, | 571 MemoryUsage hard_memory_limit(global_state_.hard_memory_limit_in_bytes, |
580 global_state_.num_resources_limit); | 572 global_state_.num_resources_limit); |
581 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes, | 573 MemoryUsage soft_memory_limit(global_state_.soft_memory_limit_in_bytes, |
582 global_state_.num_resources_limit); | 574 global_state_.num_resources_limit); |
583 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(), | 575 MemoryUsage memory_usage(resource_pool_->acquired_memory_usage_bytes(), |
584 resource_pool_->acquired_resource_count()); | 576 resource_pool_->acquired_resource_count()); |
585 | 577 |
586 eviction_priority_queue_is_up_to_date_ = false; | 578 scoped_ptr<EvictionTilePriorityQueue> eviction_priority_queue; |
587 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) { | 579 for (; !raster_priority_queue->IsEmpty(); raster_priority_queue->Pop()) { |
588 Tile* tile = raster_priority_queue->Top(); | 580 Tile* tile = raster_priority_queue->Top(); |
589 TilePriority priority = tile->combined_priority(); | 581 TilePriority priority = tile->combined_priority(); |
590 | 582 |
591 if (TilePriorityViolatesMemoryPolicy(priority)) { | 583 if (TilePriorityViolatesMemoryPolicy(priority)) { |
592 TRACE_EVENT_INSTANT0( | 584 TRACE_EVENT_INSTANT0( |
593 "cc", "TileManager::AssignGpuMemory tile violates memory policy", | 585 "cc", "TileManager::AssignGpuMemory tile violates memory policy", |
594 TRACE_EVENT_SCOPE_THREAD); | 586 TRACE_EVENT_SCOPE_THREAD); |
595 break; | 587 break; |
596 } | 588 } |
(...skipping 21 matching lines...) Expand all Loading... |
618 } | 610 } |
619 | 611 |
620 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW; | 612 bool tile_is_needed_now = priority.priority_bin == TilePriority::NOW; |
621 | 613 |
622 // This is the memory limit that will be used by this tile. Depending on | 614 // This is the memory limit that will be used by this tile. Depending on |
623 // the tile priority, it will be one of hard_memory_limit or | 615 // the tile priority, it will be one of hard_memory_limit or |
624 // soft_memory_limit. | 616 // soft_memory_limit. |
625 MemoryUsage& tile_memory_limit = | 617 MemoryUsage& tile_memory_limit = |
626 tile_is_needed_now ? hard_memory_limit : soft_memory_limit; | 618 tile_is_needed_now ? hard_memory_limit : soft_memory_limit; |
627 | 619 |
| 620 const MemoryUsage& scheduled_tile_memory_limit = |
| 621 tile_memory_limit - memory_required_by_tile_to_be_scheduled; |
| 622 eviction_priority_queue = |
| 623 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( |
| 624 eviction_priority_queue.Pass(), scheduled_tile_memory_limit, |
| 625 priority, &memory_usage); |
628 bool memory_usage_is_within_limit = | 626 bool memory_usage_is_within_limit = |
629 FreeTileResourcesWithLowerPriorityUntilUsageIsWithinLimit( | 627 !memory_usage.Exceeds(scheduled_tile_memory_limit); |
630 tile_memory_limit - memory_required_by_tile_to_be_scheduled, | |
631 priority, &memory_usage); | |
632 | 628 |
633 // If we couldn't fit the tile into our current memory limit, then we're | 629 // If we couldn't fit the tile into our current memory limit, then we're |
634 // done. | 630 // done. |
635 if (!memory_usage_is_within_limit) { | 631 if (!memory_usage_is_within_limit) { |
636 if (tile_is_needed_now) | 632 if (tile_is_needed_now) |
637 had_enough_memory_to_schedule_tiles_needed_now = false; | 633 had_enough_memory_to_schedule_tiles_needed_now = false; |
638 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false; | 634 all_tiles_that_need_to_be_rasterized_are_scheduled_ = false; |
639 break; | 635 break; |
640 } | 636 } |
641 | 637 |
642 memory_usage += memory_required_by_tile_to_be_scheduled; | 638 memory_usage += memory_required_by_tile_to_be_scheduled; |
643 tiles_that_need_to_be_rasterized->push_back(tile); | 639 tiles_that_need_to_be_rasterized->push_back(tile); |
644 } | 640 } |
645 | 641 |
646 // Note that we should try and further reduce memory in case the above loop | 642 // Note that we should try and further reduce memory in case the above loop |
647 // didn't reduce memory. This ensures that we always release as many resources | 643 // didn't reduce memory. This ensures that we always release as many resources |
648 // as possible to stay within the memory limit. | 644 // as possible to stay within the memory limit. |
649 FreeTileResourcesUntilUsageIsWithinLimit(hard_memory_limit, &memory_usage); | 645 eviction_priority_queue = FreeTileResourcesUntilUsageIsWithinLimit( |
| 646 eviction_priority_queue.Pass(), hard_memory_limit, &memory_usage); |
650 | 647 |
651 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget", | 648 UMA_HISTOGRAM_BOOLEAN("TileManager.ExceededMemoryBudget", |
652 !had_enough_memory_to_schedule_tiles_needed_now); | 649 !had_enough_memory_to_schedule_tiles_needed_now); |
653 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now; | 650 did_oom_on_last_assign_ = !had_enough_memory_to_schedule_tiles_needed_now; |
654 | 651 |
655 memory_stats_from_last_assign_.total_budget_in_bytes = | 652 memory_stats_from_last_assign_.total_budget_in_bytes = |
656 global_state_.hard_memory_limit_in_bytes; | 653 global_state_.hard_memory_limit_in_bytes; |
657 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes(); | 654 memory_stats_from_last_assign_.total_bytes_used = memory_usage.memory_bytes(); |
658 memory_stats_from_last_assign_.had_enough_memory = | 655 memory_stats_from_last_assign_.had_enough_memory = |
659 had_enough_memory_to_schedule_tiles_needed_now; | 656 had_enough_memory_to_schedule_tiles_needed_now; |
(...skipping 383 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1043 result -= other; | 1040 result -= other; |
1044 return result; | 1041 return result; |
1045 } | 1042 } |
1046 | 1043 |
1047 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const { | 1044 bool TileManager::MemoryUsage::Exceeds(const MemoryUsage& limit) const { |
1048 return memory_bytes_ > limit.memory_bytes_ || | 1045 return memory_bytes_ > limit.memory_bytes_ || |
1049 resource_count_ > limit.resource_count_; | 1046 resource_count_ > limit.resource_count_; |
1050 } | 1047 } |
1051 | 1048 |
1052 } // namespace cc | 1049 } // namespace cc |
OLD | NEW |