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 <string> | 8 #include <string> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 117 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 ResourceProvider* resource_provider, | 128 ResourceProvider* resource_provider, |
129 scoped_ptr<RasterWorkerPool> raster_worker_pool, | 129 scoped_ptr<RasterWorkerPool> raster_worker_pool, |
130 size_t num_raster_threads, | 130 size_t num_raster_threads, |
131 bool use_color_estimator, | 131 bool use_color_estimator, |
132 RenderingStatsInstrumentation* rendering_stats_instrumentation, | 132 RenderingStatsInstrumentation* rendering_stats_instrumentation, |
133 bool use_map_image) | 133 bool use_map_image) |
134 : client_(client), | 134 : client_(client), |
135 resource_pool_(ResourcePool::Create(resource_provider)), | 135 resource_pool_(ResourcePool::Create(resource_provider)), |
136 raster_worker_pool_(raster_worker_pool.Pass()), | 136 raster_worker_pool_(raster_worker_pool.Pass()), |
137 manage_tiles_pending_(false), | 137 manage_tiles_pending_(false), |
| 138 manage_tiles_call_count_(0), |
138 bytes_pending_upload_(0), | 139 bytes_pending_upload_(0), |
139 has_performed_uploads_since_last_flush_(false), | 140 has_performed_uploads_since_last_flush_(false), |
140 ever_exceeded_memory_budget_(false), | 141 ever_exceeded_memory_budget_(false), |
141 rendering_stats_instrumentation_(rendering_stats_instrumentation), | 142 rendering_stats_instrumentation_(rendering_stats_instrumentation), |
142 use_color_estimator_(use_color_estimator), | 143 use_color_estimator_(use_color_estimator), |
143 did_initialize_visible_tile_(false), | 144 did_initialize_visible_tile_(false), |
| 145 pending_tasks_(0), |
144 max_pending_tasks_(kMaxNumPendingTasksPerThread * num_raster_threads) { | 146 max_pending_tasks_(kMaxNumPendingTasksPerThread * num_raster_threads) { |
145 raster_worker_pool_->SetClient(this); | 147 raster_worker_pool_->SetClient(this); |
146 } | 148 } |
147 | 149 |
148 TileManager::~TileManager() { | 150 TileManager::~TileManager() { |
149 // Reset global state and manage. This should cause | 151 // Reset global state and manage. This should cause |
150 // our memory usage to drop to zero. | 152 // our memory usage to drop to zero. |
151 global_state_ = GlobalStateThatImpactsTilePriority(); | 153 global_state_ = GlobalStateThatImpactsTilePriority(); |
152 AssignGpuMemoryToTiles(); | 154 AssignGpuMemoryToTiles(); |
153 // This should finish all pending tasks and release any uninitialized | 155 // This should finish all pending tasks and release any uninitialized |
(...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
300 TRACE_EVENT0("cc", "TileManager::SortTiles"); | 302 TRACE_EVENT0("cc", "TileManager::SortTiles"); |
301 | 303 |
302 // Sort by bin, resolution and time until needed. | 304 // Sort by bin, resolution and time until needed. |
303 std::sort(tiles_.begin(), tiles_.end(), BinComparator()); | 305 std::sort(tiles_.begin(), tiles_.end(), BinComparator()); |
304 } | 306 } |
305 | 307 |
306 void TileManager::ManageTiles() { | 308 void TileManager::ManageTiles() { |
307 TRACE_EVENT0("cc", "TileManager::ManageTiles"); | 309 TRACE_EVENT0("cc", "TileManager::ManageTiles"); |
308 | 310 |
309 manage_tiles_pending_ = false; | 311 manage_tiles_pending_ = false; |
| 312 ++manage_tiles_call_count_; |
310 | 313 |
311 AssignBinsToTiles(); | 314 AssignBinsToTiles(); |
312 SortTiles(); | 315 SortTiles(); |
313 AssignGpuMemoryToTiles(); | 316 AssignGpuMemoryToTiles(); |
314 | 317 |
315 TRACE_EVENT_INSTANT1( | 318 TRACE_EVENT_INSTANT1( |
316 "cc", "DidManage", TRACE_EVENT_SCOPE_THREAD, | 319 "cc", "DidManage", TRACE_EVENT_SCOPE_THREAD, |
317 "state", TracedValue::FromValue(BasicStateAsValue().release())); | 320 "state", TracedValue::FromValue(BasicStateAsValue().release())); |
318 | 321 |
319 // Finally, schedule rasterizer tasks. | 322 // Finally, kick the rasterizer. |
320 ScheduleTasks(); | 323 DispatchMoreTasks(); |
321 } | 324 } |
322 | 325 |
323 void TileManager::CheckForCompletedTileUploads() { | 326 void TileManager::CheckForCompletedTileUploads() { |
324 while (!tiles_with_pending_upload_.empty()) { | 327 while (!tiles_with_pending_upload_.empty()) { |
325 Tile* tile = tiles_with_pending_upload_.front(); | 328 Tile* tile = tiles_with_pending_upload_.front(); |
326 DCHECK(tile->tile_version().resource_); | 329 DCHECK(tile->tile_version().resource_); |
327 | 330 |
328 // Set pixel tasks complete in the order they are posted. | 331 // Set pixel tasks complete in the order they are posted. |
329 if (!resource_pool_->resource_provider()->DidSetPixelsComplete( | 332 if (!resource_pool_->resource_provider()->DidSetPixelsComplete( |
330 tile->tile_version().resource_->id())) { | 333 tile->tile_version().resource_->id())) { |
331 break; | 334 break; |
332 } | 335 } |
333 | 336 |
334 // It's now safe to release the pixel buffer. | 337 // It's now safe to release the pixel buffer. |
335 resource_pool_->resource_provider()->ReleasePixelBuffer( | 338 resource_pool_->resource_provider()->ReleasePixelBuffer( |
336 tile->tile_version().resource_->id()); | 339 tile->tile_version().resource_->id()); |
337 | 340 |
338 bytes_pending_upload_ -= tile->bytes_consumed_if_allocated(); | 341 bytes_pending_upload_ -= tile->bytes_consumed_if_allocated(); |
339 bool was_forced = tile->tile_version().forced_upload_; | 342 bool was_forced = tile->tile_version().forced_upload_; |
340 // Reset forced_upload_ since we now got the upload completed notification. | 343 // Reset forced_upload_ since we now got the upload completed notification. |
341 tile->tile_version().forced_upload_ = false; | 344 tile->tile_version().forced_upload_ = false; |
342 tile->tile_version().memory_state_ = USING_RELEASABLE_MEMORY; | 345 tile->tile_version().memory_state_ = USING_RELEASABLE_MEMORY; |
343 if (!was_forced) | 346 if (!was_forced) |
344 DidFinishTileInitialization(tile); | 347 DidFinishTileInitialization(tile); |
345 | 348 |
346 tiles_with_pending_upload_.pop(); | 349 tiles_with_pending_upload_.pop(); |
347 } | 350 } |
348 | 351 |
349 ScheduleTasks(); | 352 DispatchMoreTasks(); |
350 } | 353 } |
351 | 354 |
352 void TileManager::AbortPendingTileUploads() { | 355 void TileManager::AbortPendingTileUploads() { |
353 while (!tiles_with_pending_upload_.empty()) { | 356 while (!tiles_with_pending_upload_.empty()) { |
354 Tile* tile = tiles_with_pending_upload_.front(); | 357 Tile* tile = tiles_with_pending_upload_.front(); |
355 DCHECK(tile->tile_version().resource_); | 358 DCHECK(tile->tile_version().resource_); |
356 | 359 |
357 resource_pool_->resource_provider()->AbortSetPixels( | 360 resource_pool_->resource_provider()->AbortSetPixels( |
358 tile->tile_version().resource_->id()); | 361 tile->tile_version().resource_->id()); |
359 resource_pool_->resource_provider()->ReleasePixelBuffer( | 362 resource_pool_->resource_provider()->ReleasePixelBuffer( |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
459 tiles_that_need_to_be_initialized_for_activation_.insert(tile); | 462 tiles_that_need_to_be_initialized_for_activation_.insert(tile); |
460 } | 463 } |
461 | 464 |
462 void TileManager::DidFinishDispatchingWorkerPoolCompletionCallbacks() { | 465 void TileManager::DidFinishDispatchingWorkerPoolCompletionCallbacks() { |
463 // If a flush is needed, do it now before starting to dispatch more tasks. | 466 // If a flush is needed, do it now before starting to dispatch more tasks. |
464 if (has_performed_uploads_since_last_flush_) { | 467 if (has_performed_uploads_since_last_flush_) { |
465 resource_pool_->resource_provider()->ShallowFlushIfSupported(); | 468 resource_pool_->resource_provider()->ShallowFlushIfSupported(); |
466 has_performed_uploads_since_last_flush_ = false; | 469 has_performed_uploads_since_last_flush_ = false; |
467 } | 470 } |
468 | 471 |
469 ScheduleTasks(); | 472 DispatchMoreTasks(); |
470 } | 473 } |
471 | 474 |
472 void TileManager::AssignGpuMemoryToTiles() { | 475 void TileManager::AssignGpuMemoryToTiles() { |
473 TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles"); | 476 TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles"); |
474 size_t unreleasable_bytes = 0; | 477 size_t unreleasable_bytes = 0; |
475 | 478 |
476 // Now give memory out to the tiles until we're out, and build | 479 // Now give memory out to the tiles until we're out, and build |
477 // the needs-to-be-rasterized queue. | 480 // the needs-to-be-rasterized queue. |
478 tiles_that_need_to_be_rasterized_.clear(); | 481 tiles_that_need_to_be_rasterized_.clear(); |
479 tiles_that_need_to_be_initialized_for_activation_.clear(); | 482 tiles_that_need_to_be_initialized_for_activation_.clear(); |
480 | 483 |
481 // By clearing the tiles_that_need_to_be_rasterized_ vector list | 484 // By clearing the tiles_that_need_to_be_rasterized_ vector list |
482 // above we move all tiles currently waiting for raster to idle state. | 485 // above we move all tiles currently waiting for raster to idle state. |
483 // Some memory cannot be released. We figure out how much in this | 486 // Some memory cannot be released. We figure out how much in this |
484 // loop. | 487 // loop as well. |
485 for (TileVector::const_iterator it = tiles_.begin(); | 488 for (TileVector::const_iterator it = tiles_.begin(); |
486 it != tiles_.end(); | 489 it != tiles_.end(); |
487 ++it) { | 490 ++it) { |
488 const Tile* tile = *it; | 491 const Tile* tile = *it; |
489 if (tile->tile_version().memory_state_ == USING_UNRELEASABLE_MEMORY) | 492 if (tile->tile_version().memory_state_ == USING_UNRELEASABLE_MEMORY) |
490 unreleasable_bytes += tile->bytes_consumed_if_allocated(); | 493 unreleasable_bytes += tile->bytes_consumed_if_allocated(); |
491 } | 494 } |
492 | 495 |
493 // Global state's memory limit can decrease, causing | 496 // Global state's memory limit can decrease, causing |
494 // it to be less than unreleasable_bytes | 497 // it to be less than unreleasable_bytes |
495 size_t bytes_allocatable = | 498 size_t bytes_allocatable = |
496 global_state_.memory_limit_in_bytes > unreleasable_bytes ? | 499 global_state_.memory_limit_in_bytes > unreleasable_bytes ? |
497 global_state_.memory_limit_in_bytes - unreleasable_bytes : | 500 global_state_.memory_limit_in_bytes - unreleasable_bytes : |
498 0; | 501 0; |
499 size_t bytes_that_exceeded_memory_budget_in_now_bin = 0; | 502 size_t bytes_that_exceeded_memory_budget_in_now_bin = 0; |
500 size_t bytes_left = bytes_allocatable; | 503 size_t bytes_left = bytes_allocatable; |
501 size_t bytes_oom_in_now_bin_on_pending_tree = 0; | 504 size_t bytes_oom_in_now_bin_on_pending_tree = 0; |
502 TileVector tiles_requiring_memory_but_oomed; | 505 TileVector tiles_requiring_memory_but_oomed; |
503 bool higher_priority_tile_oomed = false; | |
504 for (TileVector::iterator it = tiles_.begin(); | 506 for (TileVector::iterator it = tiles_.begin(); |
505 it != tiles_.end(); | 507 it != tiles_.end(); |
506 ++it) { | 508 ++it) { |
507 Tile* tile = *it; | 509 Tile* tile = *it; |
508 ManagedTileState& mts = tile->managed_state(); | 510 ManagedTileState& mts = tile->managed_state(); |
509 ManagedTileState::TileVersion& tile_version = tile->tile_version(); | 511 ManagedTileState::TileVersion& tile_version = tile->tile_version(); |
510 | 512 |
511 // If this tile doesn't need a resource, then nothing to do. | 513 // If this tile doesn't need a resource, then nothing to do. |
512 if (!tile_version.requires_resource()) | 514 if (!tile_version.requires_resource()) |
513 continue; | 515 continue; |
514 | 516 |
515 size_t tile_bytes = tile->bytes_consumed_if_allocated(); | 517 // If the memory is unreleasable, then we do not need to do anything. |
516 // Memory is already reserved for tile with unreleasable memory | 518 if (tile_version.memory_state_ == USING_UNRELEASABLE_MEMORY) { |
517 // so adding it to |tiles_that_need_to_be_rasterized_| doesn't | 519 if (tile->required_for_activation()) { |
518 // affect bytes_allocatable. | 520 AddRequiredTileForActivation(tile); |
519 if (tile_version.memory_state_ == USING_UNRELEASABLE_MEMORY) | 521 // If after rasterizing, this tile has become required or the client has |
520 tile_bytes = 0; | 522 // changed its mind about forcing tiles, do that now. |
521 | 523 if (!tile->tile_version().forced_upload_ && |
522 // If the tile is not needed, free it up. | 524 client_->ShouldForceTileUploadsRequiredForActivationToComplete()) { |
523 if (mts.is_in_never_bin_on_both_trees()) { | 525 ForceTileUploadToComplete(tile); |
524 if (tile_version.memory_state_ != USING_UNRELEASABLE_MEMORY) { | 526 } |
525 FreeResourcesForTile(tile); | |
526 tile_version.memory_state_ = NOT_ALLOWED_TO_USE_MEMORY; | |
527 } | 527 } |
528 continue; | 528 continue; |
529 } | 529 } |
530 | 530 |
| 531 size_t tile_bytes = tile->bytes_consumed_if_allocated(); |
| 532 // If the tile is not needed, free it up. |
| 533 if (mts.is_in_never_bin_on_both_trees()) { |
| 534 FreeResourcesForTile(tile); |
| 535 tile_version.memory_state_ = NOT_ALLOWED_TO_USE_MEMORY; |
| 536 continue; |
| 537 } |
531 // Tile is OOM. | 538 // Tile is OOM. |
532 if (tile_bytes > bytes_left) { | 539 if (tile_bytes > bytes_left) { |
| 540 FreeResourcesForTile(tile); |
533 tile->tile_version().set_rasterize_on_demand(); | 541 tile->tile_version().set_rasterize_on_demand(); |
534 if (mts.tree_bin[PENDING_TREE] == NOW_BIN) { | 542 if (mts.tree_bin[PENDING_TREE] == NOW_BIN) { |
535 tiles_requiring_memory_but_oomed.push_back(tile); | 543 tiles_requiring_memory_but_oomed.push_back(tile); |
536 bytes_oom_in_now_bin_on_pending_tree += tile_bytes; | 544 bytes_oom_in_now_bin_on_pending_tree += tile_bytes; |
537 } | 545 } |
538 FreeResourcesForTile(tile); | |
539 higher_priority_tile_oomed = true; | |
540 continue; | 546 continue; |
541 } | 547 } |
542 | |
543 tile_version.set_use_resource(); | 548 tile_version.set_use_resource(); |
544 bytes_left -= tile_bytes; | 549 bytes_left -= tile_bytes; |
545 | 550 if (!tile_version.resource_ && |
546 // Tile shouldn't be rasterized if we've failed to assign | 551 tile_version.memory_state_ == CAN_USE_MEMORY) { |
547 // gpu memory to a higher priority tile. This is important for | |
548 // two reasons: | |
549 // 1. Tile size should not impact raster priority. | |
550 // 2. Tile with unreleasable memory could otherwise incorrectly | |
551 // be added as it's not affected by |bytes_allocatable|. | |
552 if (higher_priority_tile_oomed) | |
553 continue; | |
554 | |
555 if (!tile_version.resource_) | |
556 tiles_that_need_to_be_rasterized_.push_back(tile); | 552 tiles_that_need_to_be_rasterized_.push_back(tile); |
557 | 553 } |
558 if (!tile_version.resource_ && tile->required_for_activation()) | 554 if (!tile_version.resource_ && tile->required_for_activation()) |
559 AddRequiredTileForActivation(tile); | 555 AddRequiredTileForActivation(tile); |
560 | |
561 if (tile_version.memory_state_ == USING_UNRELEASABLE_MEMORY && | |
562 tile->required_for_activation()) { | |
563 // If after rasterizing, this tile has become required or the client has | |
564 // changed its mind about forcing tiles, do that now. | |
565 if (!tile->tile_version().forced_upload_ && | |
566 client_->ShouldForceTileUploadsRequiredForActivationToComplete()) { | |
567 ForceTileUploadToComplete(tile); | |
568 } | |
569 } | |
570 } | 556 } |
571 | 557 |
572 // In OOM situation, we iterate tiles_, remove the memory for active tree | 558 // In OOM situation, we iterate tiles_, remove the memory for active tree |
573 // and not the now bin. And give them to bytes_oom_in_now_bin_on_pending_tree | 559 // and not the now bin. And give them to bytes_oom_in_now_bin_on_pending_tree |
574 if (!tiles_requiring_memory_but_oomed.empty()) { | 560 if (!tiles_requiring_memory_but_oomed.empty()) { |
575 size_t bytes_freed = 0; | 561 size_t bytes_freed = 0; |
576 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { | 562 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
577 Tile* tile = *it; | 563 Tile* tile = *it; |
578 ManagedTileState& mts = tile->managed_state(); | 564 ManagedTileState& mts = tile->managed_state(); |
579 ManagedTileState::TileVersion& tile_version = tile->tile_version(); | 565 ManagedTileState::TileVersion& tile_version = tile->tile_version(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
618 "budget", global_state_.memory_limit_in_bytes, | 604 "budget", global_state_.memory_limit_in_bytes, |
619 "over", bytes_that_exceeded_memory_budget_in_now_bin); | 605 "over", bytes_that_exceeded_memory_budget_in_now_bin); |
620 } | 606 } |
621 memory_stats_from_last_assign_.total_budget_in_bytes = | 607 memory_stats_from_last_assign_.total_budget_in_bytes = |
622 global_state_.memory_limit_in_bytes; | 608 global_state_.memory_limit_in_bytes; |
623 memory_stats_from_last_assign_.bytes_allocated = | 609 memory_stats_from_last_assign_.bytes_allocated = |
624 bytes_allocatable - bytes_left; | 610 bytes_allocatable - bytes_left; |
625 memory_stats_from_last_assign_.bytes_unreleasable = unreleasable_bytes; | 611 memory_stats_from_last_assign_.bytes_unreleasable = unreleasable_bytes; |
626 memory_stats_from_last_assign_.bytes_over = | 612 memory_stats_from_last_assign_.bytes_over = |
627 bytes_that_exceeded_memory_budget_in_now_bin; | 613 bytes_that_exceeded_memory_budget_in_now_bin; |
| 614 |
| 615 // Reverse two tiles_that_need_* vectors such that pop_back gets |
| 616 // the highest priority tile. |
| 617 std::reverse( |
| 618 tiles_that_need_to_be_rasterized_.begin(), |
| 619 tiles_that_need_to_be_rasterized_.end()); |
628 } | 620 } |
629 | 621 |
630 void TileManager::FreeResourcesForTile(Tile* tile) { | 622 void TileManager::FreeResourcesForTile(Tile* tile) { |
631 DCHECK_NE(USING_UNRELEASABLE_MEMORY, tile->tile_version().memory_state_); | 623 DCHECK(tile->tile_version().memory_state_ != USING_UNRELEASABLE_MEMORY); |
632 if (tile->tile_version().resource_) { | 624 if (tile->tile_version().resource_) { |
633 resource_pool_->ReleaseResource( | 625 resource_pool_->ReleaseResource( |
634 tile->tile_version().resource_.Pass()); | 626 tile->tile_version().resource_.Pass()); |
635 } | 627 } |
636 tile->tile_version().memory_state_ = NOT_ALLOWED_TO_USE_MEMORY; | 628 tile->tile_version().memory_state_ = NOT_ALLOWED_TO_USE_MEMORY; |
637 } | 629 } |
638 | 630 |
639 void TileManager::ScheduleTasks() { | 631 bool TileManager::CanDispatchRasterTask(Tile* tile) const { |
640 TRACE_EVENT0("cc", "TileManager::ScheduleTasks"); | 632 if (pending_tasks_ >= max_pending_tasks_) |
641 RasterWorkerPool::Task::Queue tasks; | 633 return false; |
| 634 size_t new_bytes_pending = bytes_pending_upload_; |
| 635 new_bytes_pending += tile->bytes_consumed_if_allocated(); |
| 636 return new_bytes_pending <= kMaxPendingUploadBytes && |
| 637 tiles_with_pending_upload_.size() < kMaxPendingUploads; |
| 638 } |
642 | 639 |
643 size_t bytes_pending_upload = bytes_pending_upload_; | 640 void TileManager::DispatchMoreTasks() { |
644 unsigned pending_tasks = 0; | 641 TileVector tiles_with_image_decoding_tasks; |
645 | 642 |
646 // Build a new task queue containing all task currently needed. Tasks | 643 // Process all tiles in the need_to_be_rasterized queue: |
647 // are added in order of priority, highest priority task first. | 644 // 1. Dispatch image decode tasks. |
648 for (TileVector::iterator it = tiles_that_need_to_be_rasterized_.begin(); | 645 // 2. If the image decode isn't done, save the tile for later processing. |
649 it != tiles_that_need_to_be_rasterized_.end(); | 646 // 3. Attempt to dispatch a raster task, or break out of the loop. |
650 ++it) { | 647 while (!tiles_that_need_to_be_rasterized_.empty()) { |
651 Tile* tile = *it; | 648 Tile* tile = tiles_that_need_to_be_rasterized_.back(); |
652 ManagedTileState& mts = tile->managed_state(); | |
653 | 649 |
654 // Skip tile if determined to not require resource. | 650 DCHECK(tile->tile_version().requires_resource()); |
655 if (!tile->tile_version().requires_resource()) | |
656 continue; | |
657 | 651 |
658 // Skip tile if already rasterized. | 652 if (DispatchImageDecodeTasksForTile(tile)) { |
659 if (tile->tile_version().resource_) | 653 tiles_with_image_decoding_tasks.push_back(tile); |
660 continue; | 654 } else if (!CanDispatchRasterTask(tile)) { |
661 | 655 break; |
662 // TODO(reveman): Remove throttling based on max pending tasks. | 656 } else { |
663 if (pending_tasks >= max_pending_tasks_) | 657 DispatchOneRasterTask(tile); |
664 break; | 658 } |
665 | 659 tiles_that_need_to_be_rasterized_.pop_back(); |
666 // TODO(reveman): Remove throttling based on max pending uploads. | |
667 if (tiles_with_pending_upload_.size() >= kMaxPendingUploads) | |
668 break; | |
669 | |
670 // TODO(reveman): Throttle based on shared memory usage rather | |
671 // than bytes pending upload. | |
672 size_t new_bytes_pending = bytes_pending_upload; | |
673 new_bytes_pending += tile->bytes_consumed_if_allocated(); | |
674 if (new_bytes_pending > kMaxPendingUploadBytes) | |
675 break; | |
676 bytes_pending_upload = new_bytes_pending; | |
677 | |
678 // Create raster task for this tile if necessary. | |
679 if (mts.raster_task.is_null()) | |
680 mts.raster_task = CreateRasterTask(tile); | |
681 | |
682 // Finally append raster task. | |
683 tasks.Append(mts.raster_task); | |
684 pending_tasks++; | |
685 } | 660 } |
686 | 661 |
687 if (!tasks.empty()) { | 662 // Put the saved tiles back into the queue. The order is reversed |
688 RasterWorkerPool::Task root(&tasks); | 663 // to preserve original ordering. |
689 | 664 tiles_that_need_to_be_rasterized_.insert( |
690 // Schedule running of |tasks|. This replaces any previously | 665 tiles_that_need_to_be_rasterized_.end(), |
691 // scheduled tasks and effectively cancels all tasks not present | 666 tiles_with_image_decoding_tasks.rbegin(), |
692 // in |tasks|. | 667 tiles_with_image_decoding_tasks.rend()); |
693 raster_worker_pool_->ScheduleTasks(&root); | |
694 } else { | |
695 raster_worker_pool_->ScheduleTasks(NULL); | |
696 } | |
697 | 668 |
698 if (did_initialize_visible_tile_) { | 669 if (did_initialize_visible_tile_) { |
699 did_initialize_visible_tile_ = false; | 670 did_initialize_visible_tile_ = false; |
700 client_->DidInitializeVisibleTile(); | 671 client_->DidInitializeVisibleTile(); |
701 } | 672 } |
702 } | 673 } |
703 | 674 |
704 RasterWorkerPool::Task TileManager::CreateImageDecodeTask( | 675 bool TileManager::DispatchImageDecodeTasksForTile(Tile* tile) { |
705 Tile* tile, skia::LazyPixelRef* pixel_ref) { | 676 TRACE_EVENT0("cc", "TileManager::DispatchImageDecodeTasksForTile"); |
706 TRACE_EVENT0("cc", "TileManager::CreateImageDecodeTask"); | 677 ManagedTileState& mts = tile->managed_state(); |
| 678 bool pending_decode_tasks = false; |
707 | 679 |
708 return RasterWorkerPool::Task( | |
709 base::Bind(&TileManager::RunImageDecodeTask, | |
710 pixel_ref, | |
711 tile->layer_id(), | |
712 rendering_stats_instrumentation_), | |
713 base::Bind(&TileManager::OnImageDecodeTaskCompleted, | |
714 base::Unretained(this), | |
715 make_scoped_refptr(tile), | |
716 pixel_ref->getGenerationID())); | |
717 } | |
718 | |
719 void TileManager::OnImageDecodeTaskCompleted(scoped_refptr<Tile> tile, | |
720 uint32_t pixel_ref_id, | |
721 bool was_canceled) { | |
722 TRACE_EVENT0("cc", "TileManager::OnImageDecodeTaskCompleted"); | |
723 DCHECK(pending_decode_tasks_.find(pixel_ref_id) != | |
724 pending_decode_tasks_.end()); | |
725 pending_decode_tasks_.erase(pixel_ref_id); | |
726 } | |
727 | |
728 TileManager::RasterTaskMetadata TileManager::GetRasterTaskMetadata( | |
729 const Tile& tile) const { | |
730 RasterTaskMetadata metadata; | |
731 const ManagedTileState& mts = tile.managed_state(); | |
732 metadata.is_tile_in_pending_tree_now_bin = | |
733 mts.tree_bin[PENDING_TREE] == NOW_BIN; | |
734 metadata.tile_resolution = mts.resolution; | |
735 metadata.layer_id = tile.layer_id(); | |
736 metadata.tile_id = &tile; | |
737 metadata.source_frame_number = tile.source_frame_number(); | |
738 return metadata; | |
739 } | |
740 | |
741 RasterWorkerPool::Task TileManager::CreateRasterTask(Tile* tile) { | |
742 TRACE_EVENT0("cc", "TileManager::CreateRasterTask"); | |
743 | |
744 scoped_ptr<ResourcePool::Resource> resource = | |
745 resource_pool_->AcquireResource( | |
746 tile->tile_size_.size(), | |
747 tile->tile_version().resource_format_); | |
748 resource_pool_->resource_provider()->AcquirePixelBuffer(resource->id()); | |
749 | |
750 DCHECK_EQ(CAN_USE_MEMORY, tile->tile_version().memory_state_); | |
751 tile->tile_version().memory_state_ = USING_UNRELEASABLE_MEMORY; | |
752 | |
753 PicturePileImpl::Analysis* analysis = new PicturePileImpl::Analysis; | |
754 | |
755 // MapPixelBuffer() returns NULL if context was lost at the time | |
756 // AcquirePixelBuffer() was called. For simplicity we still create | |
757 // a raster task that is essentially a noop in these situations. | |
758 uint8* buffer = resource_pool_->resource_provider()->MapPixelBuffer( | |
759 resource->id()); | |
760 | |
761 // Create and queue all image decode tasks that this tile depends on. | |
762 RasterWorkerPool::Task::Queue decode_tasks; | |
763 for (PicturePileImpl::PixelRefIterator iter(tile->content_rect(), | 680 for (PicturePileImpl::PixelRefIterator iter(tile->content_rect(), |
764 tile->contents_scale(), | 681 tile->contents_scale(), |
765 tile->picture_pile()); | 682 tile->picture_pile()); |
766 iter; ++iter) { | 683 iter; ++iter) { |
767 skia::LazyPixelRef* pixel_ref = *iter; | 684 skia::LazyPixelRef* pixel_ref = *iter; |
768 uint32_t id = pixel_ref->getGenerationID(); | 685 uint32_t id = pixel_ref->getGenerationID(); |
769 | 686 |
770 // Append existing image decode task if available. | 687 // Check if image has already been decoded. |
771 PixelRefMap::iterator decode_task_it = pending_decode_tasks_.find(id); | 688 if (mts.decoded_pixel_refs.find(id) != mts.decoded_pixel_refs.end()) |
772 if (decode_task_it != pending_decode_tasks_.end()) { | 689 continue; |
773 decode_tasks.Append(decode_task_it->second); | 690 |
| 691 // Check if decode task is already pending. |
| 692 if (pending_decode_tasks_.find(id) != pending_decode_tasks_.end()) { |
| 693 pending_decode_tasks = true; |
774 continue; | 694 continue; |
775 } | 695 } |
776 | 696 |
777 // TODO(qinmin): passing correct image size to PrepareToDecode(). | 697 // TODO(qinmin): passing correct image size to PrepareToDecode(). |
778 if (pixel_ref->PrepareToDecode(skia::LazyPixelRef::PrepareParams())) { | 698 if (pixel_ref->PrepareToDecode(skia::LazyPixelRef::PrepareParams())) { |
779 rendering_stats_instrumentation_->IncrementDeferredImageCacheHitCount(); | 699 rendering_stats_instrumentation_->IncrementDeferredImageCacheHitCount(); |
| 700 mts.decoded_pixel_refs.insert(id); |
780 continue; | 701 continue; |
781 } | 702 } |
782 | 703 |
783 // Create and append new image decode task for this pixel ref. | 704 if (pending_tasks_ >= max_pending_tasks_) |
784 RasterWorkerPool::Task decode_task = CreateImageDecodeTask( | 705 break; |
785 tile, pixel_ref); | 706 |
786 decode_tasks.Append(decode_task); | 707 DispatchOneImageDecodeTask(tile, pixel_ref); |
787 pending_decode_tasks_[id] = decode_task; | 708 pending_decode_tasks = true; |
788 } | 709 } |
789 | 710 |
790 return RasterWorkerPool::PictureTask( | 711 return pending_decode_tasks; |
| 712 } |
| 713 |
| 714 void TileManager::DispatchOneImageDecodeTask( |
| 715 scoped_refptr<Tile> tile, skia::LazyPixelRef* pixel_ref) { |
| 716 TRACE_EVENT0("cc", "TileManager::DispatchOneImageDecodeTask"); |
| 717 uint32_t pixel_ref_id = pixel_ref->getGenerationID(); |
| 718 DCHECK(pending_decode_tasks_.end() == |
| 719 pending_decode_tasks_.find(pixel_ref_id)); |
| 720 pending_decode_tasks_.insert(pixel_ref_id); |
| 721 |
| 722 raster_worker_pool_->PostTaskAndReply( |
| 723 base::Bind(&TileManager::RunImageDecodeTask, |
| 724 pixel_ref, |
| 725 tile->layer_id(), |
| 726 rendering_stats_instrumentation_), |
| 727 base::Bind(&TileManager::OnImageDecodeTaskCompleted, |
| 728 base::Unretained(this), |
| 729 tile, |
| 730 pixel_ref_id)); |
| 731 pending_tasks_++; |
| 732 } |
| 733 |
| 734 void TileManager::OnImageDecodeTaskCompleted( |
| 735 scoped_refptr<Tile> tile, uint32_t pixel_ref_id) { |
| 736 TRACE_EVENT0("cc", "TileManager::OnImageDecodeTaskCompleted"); |
| 737 ManagedTileState& mts = tile->managed_state(); |
| 738 mts.decoded_pixel_refs.insert(pixel_ref_id); |
| 739 pending_decode_tasks_.erase(pixel_ref_id); |
| 740 pending_tasks_--; |
| 741 } |
| 742 |
| 743 scoped_ptr<ResourcePool::Resource> TileManager::PrepareTileForRaster( |
| 744 Tile* tile) { |
| 745 scoped_ptr<ResourcePool::Resource> resource = resource_pool_->AcquireResource( |
| 746 tile->tile_size_.size(), |
| 747 tile->tile_version().resource_format_); |
| 748 resource_pool_->resource_provider()->AcquirePixelBuffer(resource->id()); |
| 749 |
| 750 tile->tile_version().memory_state_ = USING_UNRELEASABLE_MEMORY; |
| 751 |
| 752 return resource.Pass(); |
| 753 } |
| 754 |
| 755 void TileManager::DispatchOneRasterTask(scoped_refptr<Tile> tile) { |
| 756 TRACE_EVENT0("cc", "TileManager::DispatchOneRasterTask"); |
| 757 scoped_ptr<ResourcePool::Resource> resource = PrepareTileForRaster(tile); |
| 758 ResourceProvider::ResourceId resource_id = resource->id(); |
| 759 PicturePileImpl::Analysis* analysis = new PicturePileImpl::Analysis; |
| 760 |
| 761 // MapPixelBuffer() returns NULL if context was lost at the time |
| 762 // AcquirePixelBuffer() was called. For simplicity we still post |
| 763 // a raster task that is essentially a noop in these situations. |
| 764 uint8* buffer = resource_pool_->resource_provider()->MapPixelBuffer( |
| 765 resource_id); |
| 766 |
| 767 // skia requires that our buffer be 4-byte aligned |
| 768 CHECK(!(reinterpret_cast<intptr_t>(buffer) & 3)); |
| 769 |
| 770 raster_worker_pool_->PostRasterTaskAndReply( |
791 tile->picture_pile(), | 771 tile->picture_pile(), |
792 base::Bind(&TileManager::RunAnalyzeAndRasterTask, | 772 base::Bind(&TileManager::RunAnalyzeAndRasterTask, |
793 base::Bind(&TileManager::RunAnalyzeTask, | 773 base::Bind(&TileManager::RunAnalyzeTask, |
794 analysis, | 774 analysis, |
795 tile->content_rect(), | 775 tile->content_rect(), |
796 tile->contents_scale(), | 776 tile->contents_scale(), |
797 use_color_estimator_, | 777 use_color_estimator_, |
798 GetRasterTaskMetadata(*tile), | 778 GetRasterTaskMetadata(*tile), |
799 rendering_stats_instrumentation_), | 779 rendering_stats_instrumentation_), |
800 base::Bind(&TileManager::RunRasterTask, | 780 base::Bind(&TileManager::RunRasterTask, |
801 buffer, | 781 buffer, |
802 analysis, | 782 analysis, |
803 tile->content_rect(), | 783 tile->content_rect(), |
804 tile->contents_scale(), | 784 tile->contents_scale(), |
805 GetRasterTaskMetadata(*tile), | 785 GetRasterTaskMetadata(*tile), |
806 rendering_stats_instrumentation_)), | 786 rendering_stats_instrumentation_)), |
807 base::Bind(&TileManager::OnRasterTaskCompleted, | 787 base::Bind(&TileManager::OnRasterTaskCompleted, |
808 base::Unretained(this), | 788 base::Unretained(this), |
809 make_scoped_refptr(tile), | 789 tile, |
810 base::Passed(&resource), | 790 base::Passed(&resource), |
811 base::Owned(analysis)), | 791 base::Owned(analysis), |
812 &decode_tasks); | 792 manage_tiles_call_count_)); |
| 793 pending_tasks_++; |
| 794 } |
| 795 |
| 796 TileManager::RasterTaskMetadata TileManager::GetRasterTaskMetadata( |
| 797 const Tile& tile) const { |
| 798 RasterTaskMetadata metadata; |
| 799 const ManagedTileState& mts = tile.managed_state(); |
| 800 metadata.is_tile_in_pending_tree_now_bin = |
| 801 mts.tree_bin[PENDING_TREE] == NOW_BIN; |
| 802 metadata.tile_resolution = mts.resolution; |
| 803 metadata.layer_id = tile.layer_id(); |
| 804 metadata.tile_id = &tile; |
| 805 metadata.source_frame_number = tile.source_frame_number(); |
| 806 return metadata; |
813 } | 807 } |
814 | 808 |
815 void TileManager::OnRasterTaskCompleted( | 809 void TileManager::OnRasterTaskCompleted( |
816 scoped_refptr<Tile> tile, | 810 scoped_refptr<Tile> tile, |
817 scoped_ptr<ResourcePool::Resource> resource, | 811 scoped_ptr<ResourcePool::Resource> resource, |
818 PicturePileImpl::Analysis* analysis, | 812 PicturePileImpl::Analysis* analysis, |
819 bool was_canceled) { | 813 int manage_tiles_call_count_when_dispatched) { |
820 TRACE_EVENT0("cc", "TileManager::OnRasterTaskCompleted"); | 814 TRACE_EVENT0("cc", "TileManager::OnRasterTaskCompleted"); |
821 | 815 |
822 ManagedTileState& mts = tile->managed_state(); | 816 pending_tasks_--; |
823 DCHECK(!mts.raster_task.is_null()); | |
824 mts.raster_task.Reset(); | |
825 | |
826 // Tile resources can't be freed until upload has completed. | |
827 DCHECK_EQ(USING_UNRELEASABLE_MEMORY, tile->tile_version().memory_state_); | |
828 | 817 |
829 // Release raster resources. | 818 // Release raster resources. |
830 resource_pool_->resource_provider()->UnmapPixelBuffer(resource->id()); | 819 resource_pool_->resource_provider()->UnmapPixelBuffer(resource->id()); |
831 | 820 |
832 if (was_canceled) { | 821 tile->tile_version().memory_state_ = USING_RELEASABLE_MEMORY; |
833 tile->tile_version().memory_state_ = CAN_USE_MEMORY; | |
834 resource_pool_->resource_provider()->ReleasePixelBuffer(resource->id()); | |
835 resource_pool_->ReleaseResource(resource.Pass()); | |
836 return; | |
837 } | |
838 | 822 |
839 mts.picture_pile_analysis = *analysis; | 823 ManagedTileState& managed_tile_state = tile->managed_state(); |
840 mts.picture_pile_analyzed = true; | 824 managed_tile_state.picture_pile_analysis = *analysis; |
| 825 managed_tile_state.picture_pile_analyzed = true; |
841 | 826 |
842 if (analysis->is_solid_color) { | 827 if (analysis->is_solid_color) { |
843 tile->tile_version().set_solid_color(analysis->solid_color); | 828 tile->tile_version().set_solid_color(analysis->solid_color); |
844 resource_pool_->resource_provider()->ReleasePixelBuffer(resource->id()); | 829 resource_pool_->resource_provider()->ReleasePixelBuffer(resource->id()); |
845 resource_pool_->ReleaseResource(resource.Pass()); | 830 resource_pool_->ReleaseResource(resource.Pass()); |
846 DidFinishTileInitialization(tile); | 831 DidFinishTileInitialization(tile); |
847 return; | 832 return; |
848 } | 833 } |
849 | 834 |
850 resource_pool_->resource_provider()->BeginSetPixels(resource->id()); | 835 // Tile can be freed after the completion of the raster task. Call |
851 has_performed_uploads_since_last_flush_ = true; | 836 // AssignGpuMemoryToTiles() to re-assign gpu memory to highest priority |
| 837 // tiles if ManageTiles() was called since task was dispatched. The result |
| 838 // of this could be that this tile is no longer allowed to use gpu |
| 839 // memory and in that case we need to abort initialization and free all |
| 840 // associated resources before calling DispatchMoreTasks(). |
| 841 if (manage_tiles_call_count_when_dispatched != manage_tiles_call_count_) |
| 842 AssignGpuMemoryToTiles(); |
852 | 843 |
853 tile->tile_version().resource_ = resource.Pass(); | 844 // Finish resource initialization we're still using memory. |
| 845 if (tile->tile_version().memory_state_ == USING_RELEASABLE_MEMORY) { |
| 846 // Tile resources can't be freed until upload has completed. |
| 847 tile->tile_version().memory_state_ = USING_UNRELEASABLE_MEMORY; |
854 | 848 |
855 bytes_pending_upload_ += tile->bytes_consumed_if_allocated(); | 849 resource_pool_->resource_provider()->BeginSetPixels(resource->id()); |
856 tiles_with_pending_upload_.push(tile); | 850 has_performed_uploads_since_last_flush_ = true; |
857 | 851 |
858 if (tile->required_for_activation() && | 852 tile->tile_version().resource_ = resource.Pass(); |
859 client_->ShouldForceTileUploadsRequiredForActivationToComplete()) | 853 |
860 ForceTileUploadToComplete(tile); | 854 bytes_pending_upload_ += tile->bytes_consumed_if_allocated(); |
| 855 tiles_with_pending_upload_.push(tile); |
| 856 |
| 857 if (tile->required_for_activation() && |
| 858 client_->ShouldForceTileUploadsRequiredForActivationToComplete()) |
| 859 ForceTileUploadToComplete(tile); |
| 860 } else { |
| 861 resource_pool_->resource_provider()->ReleasePixelBuffer(resource->id()); |
| 862 resource_pool_->ReleaseResource(resource.Pass()); |
| 863 } |
861 } | 864 } |
862 | 865 |
863 void TileManager::DidFinishTileInitialization(Tile* tile) { | 866 void TileManager::DidFinishTileInitialization(Tile* tile) { |
864 if (tile->priority(ACTIVE_TREE).distance_to_visible_in_pixels == 0) | 867 if (tile->priority(ACTIVE_TREE).distance_to_visible_in_pixels == 0) |
865 did_initialize_visible_tile_ = true; | 868 did_initialize_visible_tile_ = true; |
866 if (tile->required_for_activation()) { | 869 if (tile->required_for_activation()) { |
867 // It's possible that a tile required for activation is not in this list | 870 // It's possible that a tile required for activation is not in this list |
868 // if it was marked as being required after being dispatched for | 871 // if it was marked as being required after being dispatched for |
869 // rasterization but before AssignGPUMemory was called again. | 872 // rasterization but before AssignGPUMemory was called again. |
870 tiles_that_need_to_be_initialized_for_activation_.erase(tile); | 873 tiles_that_need_to_be_initialized_for_activation_.erase(tile); |
871 } | 874 } |
872 } | 875 } |
873 | 876 |
874 void TileManager::DidTileTreeBinChange(Tile* tile, | 877 void TileManager::DidTileTreeBinChange(Tile* tile, |
875 TileManagerBin new_tree_bin, | 878 TileManagerBin new_tree_bin, |
876 WhichTree tree) { | 879 WhichTree tree) { |
877 ManagedTileState& mts = tile->managed_state(); | 880 ManagedTileState& mts = tile->managed_state(); |
878 mts.tree_bin[tree] = new_tree_bin; | 881 mts.tree_bin[tree] = new_tree_bin; |
879 } | 882 } |
880 | 883 |
881 // static | 884 // static |
882 void TileManager::RunImageDecodeTask( | |
883 skia::LazyPixelRef* pixel_ref, | |
884 int layer_id, | |
885 RenderingStatsInstrumentation* stats_instrumentation) { | |
886 TRACE_EVENT0("cc", "TileManager::RunImageDecodeTask"); | |
887 devtools_instrumentation::ScopedLayerTask image_decode_task( | |
888 devtools_instrumentation::kImageDecodeTask, layer_id); | |
889 base::TimeTicks start_time = stats_instrumentation->StartRecording(); | |
890 pixel_ref->Decode(); | |
891 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); | |
892 stats_instrumentation->AddDeferredImageDecode(duration); | |
893 } | |
894 | |
895 // static | |
896 void TileManager::RunAnalyzeAndRasterTask( | 885 void TileManager::RunAnalyzeAndRasterTask( |
897 const RasterWorkerPool::PictureTask::Callback& analyze_task, | 886 const RasterWorkerPool::RasterCallback& analyze_task, |
898 const RasterWorkerPool::PictureTask::Callback& raster_task, | 887 const RasterWorkerPool::RasterCallback& raster_task, |
899 PicturePileImpl* picture_pile) { | 888 PicturePileImpl* picture_pile) { |
900 analyze_task.Run(picture_pile); | 889 analyze_task.Run(picture_pile); |
901 raster_task.Run(picture_pile); | 890 raster_task.Run(picture_pile); |
902 } | 891 } |
903 | 892 |
904 // static | 893 // static |
905 void TileManager::RunAnalyzeTask( | 894 void TileManager::RunAnalyzeTask( |
906 PicturePileImpl::Analysis* analysis, | 895 PicturePileImpl::Analysis* analysis, |
907 gfx::Rect rect, | 896 gfx::Rect rect, |
908 float contents_scale, | 897 float contents_scale, |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
984 "Renderer4.PictureRasterTimeUS", | 973 "Renderer4.PictureRasterTimeUS", |
985 raster_stats.total_rasterize_time.InMicroseconds(), | 974 raster_stats.total_rasterize_time.InMicroseconds(), |
986 0, | 975 0, |
987 100000, | 976 100000, |
988 100); | 977 100); |
989 } else { | 978 } else { |
990 picture_pile->RasterToBitmap(&canvas, rect, contents_scale, NULL); | 979 picture_pile->RasterToBitmap(&canvas, rect, contents_scale, NULL); |
991 } | 980 } |
992 } | 981 } |
993 | 982 |
| 983 // static |
| 984 void TileManager::RunImageDecodeTask( |
| 985 skia::LazyPixelRef* pixel_ref, |
| 986 int layer_id, |
| 987 RenderingStatsInstrumentation* stats_instrumentation) { |
| 988 TRACE_EVENT0("cc", "TileManager::RunImageDecodeTask"); |
| 989 devtools_instrumentation::ScopedLayerTask image_decode_task( |
| 990 devtools_instrumentation::kImageDecodeTask, layer_id); |
| 991 base::TimeTicks start_time = stats_instrumentation->StartRecording(); |
| 992 pixel_ref->Decode(); |
| 993 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); |
| 994 stats_instrumentation->AddDeferredImageDecode(duration); |
| 995 } |
| 996 |
994 } // namespace cc | 997 } // namespace cc |
OLD | NEW |