| 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" |
| 11 #include "base/json/json_writer.h" | 11 #include "base/json/json_writer.h" |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/metrics/histogram.h" | 13 #include "base/metrics/histogram.h" |
| 14 #include "cc/debug/devtools_instrumentation.h" | 14 #include "cc/debug/devtools_instrumentation.h" |
| 15 #include "cc/debug/traced_value.h" | 15 #include "cc/debug/traced_value.h" |
| 16 #include "cc/resources/raster_worker_pool.h" | 16 #include "cc/resources/image_raster_worker_pool.h" |
| 17 #include "cc/resources/resource_pool.h" | 17 #include "cc/resources/pixel_buffer_raster_worker_pool.h" |
| 18 #include "cc/resources/tile.h" | 18 #include "cc/resources/tile.h" |
| 19 #include "third_party/skia/include/core/SkDevice.h" | 19 #include "third_party/skia/include/core/SkCanvas.h" |
| 20 #include "ui/gfx/rect_conversions.h" | 20 #include "ui/gfx/rect_conversions.h" |
| 21 | 21 |
| 22 namespace cc { | 22 namespace cc { |
| 23 | 23 |
| 24 namespace { | 24 namespace { |
| 25 | 25 |
| 26 // If we raster too fast we become upload bound, and pending | |
| 27 // uploads consume memory. For maximum upload throughput, we would | |
| 28 // want to allow for upload_throughput * pipeline_time of pending | |
| 29 // uploads, after which we are just wasting memory. Since we don't | |
| 30 // know our upload throughput yet, this just caps our memory usage. | |
| 31 #if defined(OS_ANDROID) | |
| 32 // For reference, the Nexus10 can upload 1MB in about 2.5ms. | |
| 33 // Assuming a three frame deep pipeline this implies ~20MB. | |
| 34 const size_t kMaxPendingUploadBytes = 20 * 1024 * 1024; | |
| 35 // TODO(epenner): We should remove this upload limit (crbug.com/176197) | |
| 36 const size_t kMaxPendingUploads = 72; | |
| 37 #else | |
| 38 const size_t kMaxPendingUploadBytes = 100 * 1024 * 1024; | |
| 39 const size_t kMaxPendingUploads = 1000; | |
| 40 #endif | |
| 41 | |
| 42 #if defined(OS_ANDROID) | |
| 43 const int kMaxNumPendingTasksPerThread = 8; | |
| 44 #else | |
| 45 const int kMaxNumPendingTasksPerThread = 40; | |
| 46 #endif | |
| 47 | |
| 48 // Determine bin based on three categories of tiles: things we need now, | 26 // Determine bin based on three categories of tiles: things we need now, |
| 49 // things we need soon, and eventually. | 27 // things we need soon, and eventually. |
| 50 inline TileManagerBin BinFromTilePriority(const TilePriority& prio) { | 28 inline TileManagerBin BinFromTilePriority(const TilePriority& prio) { |
| 51 // The amount of time for which we want to have prepainting coverage. | 29 // The amount of time for which we want to have prepainting coverage. |
| 52 const float kPrepaintingWindowTimeSeconds = 1.0f; | 30 const float kPrepaintingWindowTimeSeconds = 1.0f; |
| 53 const float kBackflingGuardDistancePixels = 314.0f; | 31 const float kBackflingGuardDistancePixels = 314.0f; |
| 54 | 32 |
| 55 if (prio.time_to_visible_in_seconds == 0) | 33 if (prio.time_to_visible_in_seconds == 0) |
| 56 return NOW_BIN; | 34 return NOW_BIN; |
| 57 | 35 |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 105 } | 83 } |
| 106 | 84 |
| 107 // static | 85 // static |
| 108 scoped_ptr<TileManager> TileManager::Create( | 86 scoped_ptr<TileManager> TileManager::Create( |
| 109 TileManagerClient* client, | 87 TileManagerClient* client, |
| 110 ResourceProvider* resource_provider, | 88 ResourceProvider* resource_provider, |
| 111 size_t num_raster_threads, | 89 size_t num_raster_threads, |
| 112 bool use_color_estimator, | 90 bool use_color_estimator, |
| 113 RenderingStatsInstrumentation* rendering_stats_instrumentation, | 91 RenderingStatsInstrumentation* rendering_stats_instrumentation, |
| 114 bool use_map_image) { | 92 bool use_map_image) { |
| 115 scoped_ptr<RasterWorkerPool> raster_worker_pool = | 93 return make_scoped_ptr( |
| 116 RasterWorkerPool::Create(num_raster_threads); | 94 new TileManager(client, |
| 117 return make_scoped_ptr(new TileManager(client, | 95 resource_provider, |
| 118 resource_provider, | 96 use_map_image ? |
| 119 raster_worker_pool.Pass(), | 97 ImageRasterWorkerPool::Create( |
| 120 num_raster_threads, | 98 resource_provider, num_raster_threads) : |
| 121 use_color_estimator, | 99 PixelBufferRasterWorkerPool::Create( |
| 122 rendering_stats_instrumentation, | 100 resource_provider, num_raster_threads), |
| 123 use_map_image)); | 101 num_raster_threads, |
| 102 use_color_estimator, |
| 103 rendering_stats_instrumentation)); |
| 124 } | 104 } |
| 125 | 105 |
| 126 TileManager::TileManager( | 106 TileManager::TileManager( |
| 127 TileManagerClient* client, | 107 TileManagerClient* client, |
| 128 ResourceProvider* resource_provider, | 108 ResourceProvider* resource_provider, |
| 129 scoped_ptr<RasterWorkerPool> raster_worker_pool, | 109 scoped_ptr<RasterWorkerPool> raster_worker_pool, |
| 130 size_t num_raster_threads, | 110 size_t num_raster_threads, |
| 131 bool use_color_estimator, | 111 bool use_color_estimator, |
| 132 RenderingStatsInstrumentation* rendering_stats_instrumentation, | 112 RenderingStatsInstrumentation* rendering_stats_instrumentation) |
| 133 bool use_map_image) | |
| 134 : client_(client), | 113 : client_(client), |
| 135 resource_pool_(ResourcePool::Create(resource_provider)), | 114 resource_pool_(ResourcePool::Create(resource_provider)), |
| 136 raster_worker_pool_(raster_worker_pool.Pass()), | 115 raster_worker_pool_(raster_worker_pool.Pass()), |
| 137 manage_tiles_pending_(false), | 116 manage_tiles_pending_(false), |
| 138 bytes_pending_upload_(0), | |
| 139 has_performed_uploads_since_last_flush_(false), | |
| 140 ever_exceeded_memory_budget_(false), | 117 ever_exceeded_memory_budget_(false), |
| 141 rendering_stats_instrumentation_(rendering_stats_instrumentation), | 118 rendering_stats_instrumentation_(rendering_stats_instrumentation), |
| 142 use_color_estimator_(use_color_estimator), | 119 use_color_estimator_(use_color_estimator), |
| 143 did_initialize_visible_tile_(false), | 120 did_initialize_visible_tile_(false) { |
| 144 max_pending_tasks_(kMaxNumPendingTasksPerThread * num_raster_threads) { | |
| 145 raster_worker_pool_->SetClient(this); | |
| 146 } | 121 } |
| 147 | 122 |
| 148 TileManager::~TileManager() { | 123 TileManager::~TileManager() { |
| 149 // Reset global state and manage. This should cause | 124 // Reset global state and manage. This should cause |
| 150 // our memory usage to drop to zero. | 125 // our memory usage to drop to zero. |
| 151 global_state_ = GlobalStateThatImpactsTilePriority(); | 126 global_state_ = GlobalStateThatImpactsTilePriority(); |
| 152 AssignGpuMemoryToTiles(); | 127 AssignGpuMemoryToTiles(); |
| 153 // This should finish all pending tasks and release any uninitialized | 128 // This should finish all pending tasks and release any uninitialized |
| 154 // resources. | 129 // resources. |
| 155 raster_worker_pool_->Shutdown(); | 130 raster_worker_pool_->Shutdown(); |
| 156 AbortPendingTileUploads(); | 131 raster_worker_pool_->CheckForCompletedTasks(); |
| 157 DCHECK_EQ(0u, tiles_with_pending_upload_.size()); | |
| 158 DCHECK_EQ(0u, tiles_.size()); | 132 DCHECK_EQ(0u, tiles_.size()); |
| 159 } | 133 } |
| 160 | 134 |
| 161 void TileManager::SetGlobalState( | 135 void TileManager::SetGlobalState( |
| 162 const GlobalStateThatImpactsTilePriority& global_state) { | 136 const GlobalStateThatImpactsTilePriority& global_state) { |
| 163 global_state_ = global_state; | 137 global_state_ = global_state; |
| 164 resource_pool_->SetMaxMemoryUsageBytes( | 138 resource_pool_->SetMaxMemoryUsageBytes( |
| 165 global_state_.memory_limit_in_bytes, | 139 global_state_.memory_limit_in_bytes, |
| 166 global_state_.unused_memory_limit_in_bytes); | 140 global_state_.unused_memory_limit_in_bytes); |
| 167 ScheduleManageTiles(); | 141 ScheduleManageTiles(); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 314 | 288 |
| 315 TRACE_EVENT_INSTANT1( | 289 TRACE_EVENT_INSTANT1( |
| 316 "cc", "DidManage", TRACE_EVENT_SCOPE_THREAD, | 290 "cc", "DidManage", TRACE_EVENT_SCOPE_THREAD, |
| 317 "state", TracedValue::FromValue(BasicStateAsValue().release())); | 291 "state", TracedValue::FromValue(BasicStateAsValue().release())); |
| 318 | 292 |
| 319 // Finally, schedule rasterizer tasks. | 293 // Finally, schedule rasterizer tasks. |
| 320 ScheduleTasks(); | 294 ScheduleTasks(); |
| 321 } | 295 } |
| 322 | 296 |
| 323 void TileManager::CheckForCompletedTileUploads() { | 297 void TileManager::CheckForCompletedTileUploads() { |
| 324 while (!tiles_with_pending_upload_.empty()) { | 298 raster_worker_pool_->CheckForCompletedTasks(); |
| 325 Tile* tile = tiles_with_pending_upload_.front(); | |
| 326 DCHECK(tile->tile_version().resource_); | |
| 327 | 299 |
| 328 // Set pixel tasks complete in the order they are posted. | 300 if (!client_->ShouldForceTileUploadsRequiredForActivationToComplete()) |
| 329 if (!resource_pool_->resource_provider()->DidSetPixelsComplete( | 301 return; |
| 330 tile->tile_version().resource_->id())) { | 302 |
| 331 break; | 303 TileSet initialized_tiles; |
| 304 for (TileSet::iterator it = |
| 305 tiles_that_need_to_be_initialized_for_activation_.begin(); |
| 306 it != tiles_that_need_to_be_initialized_for_activation_.end(); |
| 307 ++it) { |
| 308 Tile* tile = *it; |
| 309 if (!tile->managed_state().raster_task.is_null() && |
| 310 tile->tile_version().memory_state_ == USING_UNRELEASABLE_MEMORY && |
| 311 !tile->tile_version().forced_upload_) { |
| 312 if (!raster_worker_pool_->ForceUploadToComplete( |
| 313 tile->managed_state().raster_task)) |
| 314 continue; |
| 315 |
| 316 // Setting |forced_upload_| to true makes this tile ready to draw. |
| 317 tile->tile_version().forced_upload_ = true; |
| 318 initialized_tiles.insert(tile); |
| 332 } | 319 } |
| 333 | |
| 334 // It's now safe to release the pixel buffer. | |
| 335 resource_pool_->resource_provider()->ReleasePixelBuffer( | |
| 336 tile->tile_version().resource_->id()); | |
| 337 | |
| 338 bytes_pending_upload_ -= tile->bytes_consumed_if_allocated(); | |
| 339 bool was_forced = tile->tile_version().forced_upload_; | |
| 340 // Reset forced_upload_ since we now got the upload completed notification. | |
| 341 tile->tile_version().forced_upload_ = false; | |
| 342 tile->tile_version().memory_state_ = USING_RELEASABLE_MEMORY; | |
| 343 if (!was_forced) | |
| 344 DidFinishTileInitialization(tile); | |
| 345 | |
| 346 tiles_with_pending_upload_.pop(); | |
| 347 } | 320 } |
| 348 | 321 |
| 349 ScheduleTasks(); | 322 for (TileSet::iterator it = initialized_tiles.begin(); |
| 350 } | 323 it != initialized_tiles.end(); |
| 351 | 324 ++it) { |
| 352 void TileManager::AbortPendingTileUploads() { | 325 Tile* tile = *it; |
| 353 while (!tiles_with_pending_upload_.empty()) { | |
| 354 Tile* tile = tiles_with_pending_upload_.front(); | |
| 355 DCHECK(tile->tile_version().resource_); | |
| 356 | |
| 357 resource_pool_->resource_provider()->AbortSetPixels( | |
| 358 tile->tile_version().resource_->id()); | |
| 359 resource_pool_->resource_provider()->ReleasePixelBuffer( | |
| 360 tile->tile_version().resource_->id()); | |
| 361 tile->tile_version().memory_state_ = USING_RELEASABLE_MEMORY; | |
| 362 | |
| 363 FreeResourcesForTile(tile); | |
| 364 | |
| 365 bytes_pending_upload_ -= tile->bytes_consumed_if_allocated(); | |
| 366 tiles_with_pending_upload_.pop(); | |
| 367 } | |
| 368 } | |
| 369 | |
| 370 void TileManager::ForceTileUploadToComplete(Tile* tile) { | |
| 371 DCHECK(tile); | |
| 372 if (tile->tile_version().resource_ && | |
| 373 tile->tile_version().memory_state_ == USING_UNRELEASABLE_MEMORY && | |
| 374 !tile->tile_version().forced_upload_) { | |
| 375 resource_pool_->resource_provider()-> | |
| 376 ForceSetPixelsToComplete(tile->tile_version().resource_->id()); | |
| 377 | |
| 378 // We have to set the memory state to be unreleasable, to ensure | |
| 379 // that the tile will not be freed until we get the upload finished | |
| 380 // notification. However, setting |forced_upload_| to true makes | |
| 381 // this tile ready to draw. | |
| 382 tile->tile_version().memory_state_ = USING_UNRELEASABLE_MEMORY; | |
| 383 tile->tile_version().forced_upload_ = true; | |
| 384 DidFinishTileInitialization(tile); | 326 DidFinishTileInitialization(tile); |
| 385 DCHECK(tile->tile_version().IsReadyToDraw()); | 327 DCHECK(tile->tile_version().IsReadyToDraw()); |
| 386 } | 328 } |
| 387 } | 329 } |
| 388 | 330 |
| 389 void TileManager::GetMemoryStats( | 331 void TileManager::GetMemoryStats( |
| 390 size_t* memory_required_bytes, | 332 size_t* memory_required_bytes, |
| 391 size_t* memory_nice_to_have_bytes, | 333 size_t* memory_nice_to_have_bytes, |
| 392 size_t* memory_used_bytes) const { | 334 size_t* memory_used_bytes) const { |
| 393 *memory_required_bytes = 0; | 335 *memory_required_bytes = 0; |
| (...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 447 } | 389 } |
| 448 | 390 |
| 449 void TileManager::AddRequiredTileForActivation(Tile* tile) { | 391 void TileManager::AddRequiredTileForActivation(Tile* tile) { |
| 450 DCHECK(std::find(tiles_that_need_to_be_initialized_for_activation_.begin(), | 392 DCHECK(std::find(tiles_that_need_to_be_initialized_for_activation_.begin(), |
| 451 tiles_that_need_to_be_initialized_for_activation_.end(), | 393 tiles_that_need_to_be_initialized_for_activation_.end(), |
| 452 tile) == | 394 tile) == |
| 453 tiles_that_need_to_be_initialized_for_activation_.end()); | 395 tiles_that_need_to_be_initialized_for_activation_.end()); |
| 454 tiles_that_need_to_be_initialized_for_activation_.insert(tile); | 396 tiles_that_need_to_be_initialized_for_activation_.insert(tile); |
| 455 } | 397 } |
| 456 | 398 |
| 457 void TileManager::DidFinishDispatchingWorkerPoolCompletionCallbacks() { | |
| 458 // If a flush is needed, do it now before starting to dispatch more tasks. | |
| 459 if (has_performed_uploads_since_last_flush_) { | |
| 460 resource_pool_->resource_provider()->ShallowFlushIfSupported(); | |
| 461 has_performed_uploads_since_last_flush_ = false; | |
| 462 } | |
| 463 | |
| 464 ScheduleTasks(); | |
| 465 } | |
| 466 | |
| 467 void TileManager::AssignGpuMemoryToTiles() { | 399 void TileManager::AssignGpuMemoryToTiles() { |
| 468 TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles"); | 400 TRACE_EVENT0("cc", "TileManager::AssignGpuMemoryToTiles"); |
| 469 size_t unreleasable_bytes = 0; | 401 size_t unreleasable_bytes = 0; |
| 470 | 402 |
| 471 // Now give memory out to the tiles until we're out, and build | 403 // Now give memory out to the tiles until we're out, and build |
| 472 // the needs-to-be-rasterized queue. | 404 // the needs-to-be-rasterized queue. |
| 473 tiles_that_need_to_be_rasterized_.clear(); | 405 tiles_that_need_to_be_rasterized_.clear(); |
| 474 tiles_that_need_to_be_initialized_for_activation_.clear(); | 406 tiles_that_need_to_be_initialized_for_activation_.clear(); |
| 475 | 407 |
| 476 // By clearing the tiles_that_need_to_be_rasterized_ vector list | 408 // By clearing the tiles_that_need_to_be_rasterized_ vector list |
| (...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 545 // 2. Tile with unreleasable memory could otherwise incorrectly | 477 // 2. Tile with unreleasable memory could otherwise incorrectly |
| 546 // be added as it's not affected by |bytes_allocatable|. | 478 // be added as it's not affected by |bytes_allocatable|. |
| 547 if (higher_priority_tile_oomed) | 479 if (higher_priority_tile_oomed) |
| 548 continue; | 480 continue; |
| 549 | 481 |
| 550 if (!tile_version.resource_) | 482 if (!tile_version.resource_) |
| 551 tiles_that_need_to_be_rasterized_.push_back(tile); | 483 tiles_that_need_to_be_rasterized_.push_back(tile); |
| 552 | 484 |
| 553 if (!tile_version.resource_ && tile->required_for_activation()) | 485 if (!tile_version.resource_ && tile->required_for_activation()) |
| 554 AddRequiredTileForActivation(tile); | 486 AddRequiredTileForActivation(tile); |
| 555 | |
| 556 if (tile_version.memory_state_ == USING_UNRELEASABLE_MEMORY && | |
| 557 tile->required_for_activation()) { | |
| 558 // If after rasterizing, this tile has become required or the client has | |
| 559 // changed its mind about forcing tiles, do that now. | |
| 560 if (!tile->tile_version().forced_upload_ && | |
| 561 client_->ShouldForceTileUploadsRequiredForActivationToComplete()) { | |
| 562 ForceTileUploadToComplete(tile); | |
| 563 } | |
| 564 } | |
| 565 } | 487 } |
| 566 | 488 |
| 567 // In OOM situation, we iterate tiles_, remove the memory for active tree | 489 // In OOM situation, we iterate tiles_, remove the memory for active tree |
| 568 // and not the now bin. And give them to bytes_oom_in_now_bin_on_pending_tree | 490 // and not the now bin. And give them to bytes_oom_in_now_bin_on_pending_tree |
| 569 if (!tiles_requiring_memory_but_oomed.empty()) { | 491 if (!tiles_requiring_memory_but_oomed.empty()) { |
| 570 size_t bytes_freed = 0; | 492 size_t bytes_freed = 0; |
| 571 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { | 493 for (TileVector::iterator it = tiles_.begin(); it != tiles_.end(); ++it) { |
| 572 Tile* tile = *it; | 494 Tile* tile = *it; |
| 573 ManagedTileState& mts = tile->managed_state(); | 495 ManagedTileState& mts = tile->managed_state(); |
| 574 ManagedTileState::TileVersion& tile_version = tile->tile_version(); | 496 ManagedTileState::TileVersion& tile_version = tile->tile_version(); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 626 DCHECK_NE(USING_UNRELEASABLE_MEMORY, tile->tile_version().memory_state_); | 548 DCHECK_NE(USING_UNRELEASABLE_MEMORY, tile->tile_version().memory_state_); |
| 627 if (tile->tile_version().resource_) { | 549 if (tile->tile_version().resource_) { |
| 628 resource_pool_->ReleaseResource( | 550 resource_pool_->ReleaseResource( |
| 629 tile->tile_version().resource_.Pass()); | 551 tile->tile_version().resource_.Pass()); |
| 630 } | 552 } |
| 631 tile->tile_version().memory_state_ = NOT_ALLOWED_TO_USE_MEMORY; | 553 tile->tile_version().memory_state_ = NOT_ALLOWED_TO_USE_MEMORY; |
| 632 } | 554 } |
| 633 | 555 |
| 634 void TileManager::ScheduleTasks() { | 556 void TileManager::ScheduleTasks() { |
| 635 TRACE_EVENT0("cc", "TileManager::ScheduleTasks"); | 557 TRACE_EVENT0("cc", "TileManager::ScheduleTasks"); |
| 636 RasterWorkerPool::Task::Queue tasks; | 558 RasterWorkerPool::RasterTask::Queue tasks; |
| 637 | |
| 638 size_t bytes_pending_upload = bytes_pending_upload_; | |
| 639 unsigned pending_tasks = 0; | |
| 640 | 559 |
| 641 // Build a new task queue containing all task currently needed. Tasks | 560 // Build a new task queue containing all task currently needed. Tasks |
| 642 // are added in order of priority, highest priority task first. | 561 // are added in order of priority, highest priority task first. |
| 643 for (TileVector::iterator it = tiles_that_need_to_be_rasterized_.begin(); | 562 for (TileVector::iterator it = tiles_that_need_to_be_rasterized_.begin(); |
| 644 it != tiles_that_need_to_be_rasterized_.end(); | 563 it != tiles_that_need_to_be_rasterized_.end(); |
| 645 ++it) { | 564 ++it) { |
| 646 Tile* tile = *it; | 565 Tile* tile = *it; |
| 647 ManagedTileState& mts = tile->managed_state(); | 566 ManagedTileState& mts = tile->managed_state(); |
| 648 | 567 |
| 649 // Skip tile if determined to not require resource. | 568 DCHECK(tile->tile_version().requires_resource()); |
| 650 if (!tile->tile_version().requires_resource()) | 569 DCHECK(!tile->tile_version().resource_); |
| 651 continue; | |
| 652 | |
| 653 // Skip tile if already rasterized. | |
| 654 if (tile->tile_version().resource_) | |
| 655 continue; | |
| 656 | |
| 657 // TODO(reveman): Remove throttling based on max pending tasks. | |
| 658 if (pending_tasks >= max_pending_tasks_) | |
| 659 break; | |
| 660 | |
| 661 // TODO(reveman): Remove throttling based on max pending uploads. | |
| 662 if (tiles_with_pending_upload_.size() >= kMaxPendingUploads) | |
| 663 break; | |
| 664 | |
| 665 // TODO(reveman): Throttle based on shared memory usage rather | |
| 666 // than bytes pending upload. | |
| 667 size_t new_bytes_pending = bytes_pending_upload; | |
| 668 new_bytes_pending += tile->bytes_consumed_if_allocated(); | |
| 669 if (new_bytes_pending > kMaxPendingUploadBytes) | |
| 670 break; | |
| 671 bytes_pending_upload = new_bytes_pending; | |
| 672 | 570 |
| 673 // Create raster task for this tile if necessary. | 571 // Create raster task for this tile if necessary. |
| 674 if (mts.raster_task.is_null()) | 572 if (mts.raster_task.is_null()) |
| 675 mts.raster_task = CreateRasterTask(tile); | 573 mts.raster_task = CreateRasterTask(tile); |
| 676 | 574 |
| 677 // Finally append raster task. | 575 // Finally append raster task. |
| 678 tasks.Append(mts.raster_task); | 576 tasks.Append(mts.raster_task); |
| 679 pending_tasks++; | |
| 680 } | 577 } |
| 681 | 578 |
| 682 if (!tasks.empty()) { | 579 // Schedule running of |tasks|. This replaces any previously |
| 683 RasterWorkerPool::Task root(&tasks); | 580 // scheduled tasks and effectively cancels all tasks not present |
| 684 | 581 // in |tasks|. |
| 685 // Schedule running of |tasks|. This replaces any previously | 582 raster_worker_pool_->ScheduleTasks(&tasks); |
| 686 // scheduled tasks and effectively cancels all tasks not present | |
| 687 // in |tasks|. | |
| 688 raster_worker_pool_->ScheduleTasks(&root); | |
| 689 } else { | |
| 690 raster_worker_pool_->ScheduleTasks(NULL); | |
| 691 } | |
| 692 | |
| 693 if (did_initialize_visible_tile_) { | |
| 694 did_initialize_visible_tile_ = false; | |
| 695 client_->DidInitializeVisibleTile(); | |
| 696 } | |
| 697 } | 583 } |
| 698 | 584 |
| 699 RasterWorkerPool::Task TileManager::CreateImageDecodeTask( | 585 RasterWorkerPool::Task TileManager::CreateImageDecodeTask( |
| 700 Tile* tile, skia::LazyPixelRef* pixel_ref) { | 586 Tile* tile, skia::LazyPixelRef* pixel_ref) { |
| 701 TRACE_EVENT0("cc", "TileManager::CreateImageDecodeTask"); | 587 TRACE_EVENT0("cc", "TileManager::CreateImageDecodeTask"); |
| 702 | 588 |
| 703 return RasterWorkerPool::Task( | 589 return RasterWorkerPool::Task( |
| 704 base::Bind(&TileManager::RunImageDecodeTask, | 590 base::Bind(&TileManager::RunImageDecodeTask, |
| 705 pixel_ref, | 591 pixel_ref, |
| 706 tile->layer_id(), | 592 tile->layer_id(), |
| 707 rendering_stats_instrumentation_), | 593 rendering_stats_instrumentation_), |
| 708 base::Bind(&TileManager::OnImageDecodeTaskCompleted, | 594 base::Bind(&TileManager::OnImageDecodeTaskCompleted, |
| 709 base::Unretained(this), | 595 base::Unretained(this), |
| 710 make_scoped_refptr(tile), | 596 make_scoped_refptr(tile), |
| 711 pixel_ref->getGenerationID())); | 597 pixel_ref->getGenerationID())); |
| 712 } | 598 } |
| 713 | 599 |
| 714 void TileManager::OnImageDecodeTaskCompleted(scoped_refptr<Tile> tile, | 600 void TileManager::OnImageDecodeTaskCompleted(scoped_refptr<Tile> tile, |
| 715 uint32_t pixel_ref_id, | 601 uint32_t pixel_ref_id) { |
| 716 bool was_canceled) { | |
| 717 TRACE_EVENT0("cc", "TileManager::OnImageDecodeTaskCompleted"); | 602 TRACE_EVENT0("cc", "TileManager::OnImageDecodeTaskCompleted"); |
| 718 DCHECK(pending_decode_tasks_.find(pixel_ref_id) != | 603 DCHECK(pending_decode_tasks_.find(pixel_ref_id) != |
| 719 pending_decode_tasks_.end()); | 604 pending_decode_tasks_.end()); |
| 720 pending_decode_tasks_.erase(pixel_ref_id); | 605 pending_decode_tasks_.erase(pixel_ref_id); |
| 721 } | 606 } |
| 722 | 607 |
| 723 TileManager::RasterTaskMetadata TileManager::GetRasterTaskMetadata( | 608 TileManager::RasterTaskMetadata TileManager::GetRasterTaskMetadata( |
| 724 const Tile& tile) const { | 609 const Tile& tile) const { |
| 725 RasterTaskMetadata metadata; | 610 RasterTaskMetadata metadata; |
| 726 const ManagedTileState& mts = tile.managed_state(); | 611 const ManagedTileState& mts = tile.managed_state(); |
| 727 metadata.is_tile_in_pending_tree_now_bin = | 612 metadata.is_tile_in_pending_tree_now_bin = |
| 728 mts.tree_bin[PENDING_TREE] == NOW_BIN; | 613 mts.tree_bin[PENDING_TREE] == NOW_BIN; |
| 729 metadata.tile_resolution = mts.resolution; | 614 metadata.tile_resolution = mts.resolution; |
| 730 metadata.layer_id = tile.layer_id(); | 615 metadata.layer_id = tile.layer_id(); |
| 731 metadata.tile_id = &tile; | 616 metadata.tile_id = &tile; |
| 732 metadata.source_frame_number = tile.source_frame_number(); | 617 metadata.source_frame_number = tile.source_frame_number(); |
| 733 return metadata; | 618 return metadata; |
| 734 } | 619 } |
| 735 | 620 |
| 736 RasterWorkerPool::Task TileManager::CreateRasterTask(Tile* tile) { | 621 RasterWorkerPool::RasterTask TileManager::CreateRasterTask(Tile* tile) { |
| 737 TRACE_EVENT0("cc", "TileManager::CreateRasterTask"); | 622 TRACE_EVENT0("cc", "TileManager::CreateRasterTask"); |
| 738 | 623 |
| 739 scoped_ptr<ResourcePool::Resource> resource = | 624 scoped_ptr<ResourcePool::Resource> resource = |
| 740 resource_pool_->AcquireResource( | 625 resource_pool_->AcquireResource( |
| 741 tile->tile_size_.size(), | 626 tile->tile_size_.size(), |
| 742 tile->tile_version().resource_format_); | 627 tile->tile_version().resource_format_); |
| 743 resource_pool_->resource_provider()->AcquirePixelBuffer(resource->id()); | 628 const Resource* const_resource = resource.get(); |
| 744 | 629 |
| 745 DCHECK_EQ(CAN_USE_MEMORY, tile->tile_version().memory_state_); | 630 DCHECK_EQ(CAN_USE_MEMORY, tile->tile_version().memory_state_); |
| 746 tile->tile_version().memory_state_ = USING_UNRELEASABLE_MEMORY; | 631 tile->tile_version().memory_state_ = USING_UNRELEASABLE_MEMORY; |
| 632 tile->tile_version().resource_id_ = resource->id(); |
| 747 | 633 |
| 748 PicturePileImpl::Analysis* analysis = new PicturePileImpl::Analysis; | 634 PicturePileImpl::Analysis* analysis = new PicturePileImpl::Analysis; |
| 749 | 635 |
| 750 // MapPixelBuffer() returns NULL if context was lost at the time | |
| 751 // AcquirePixelBuffer() was called. For simplicity we still create | |
| 752 // a raster task that is essentially a noop in these situations. | |
| 753 uint8* buffer = resource_pool_->resource_provider()->MapPixelBuffer( | |
| 754 resource->id()); | |
| 755 | |
| 756 // Create and queue all image decode tasks that this tile depends on. | 636 // Create and queue all image decode tasks that this tile depends on. |
| 757 RasterWorkerPool::Task::Queue decode_tasks; | 637 RasterWorkerPool::Task::Set decode_tasks; |
| 758 for (PicturePileImpl::PixelRefIterator iter(tile->content_rect(), | 638 for (PicturePileImpl::PixelRefIterator iter(tile->content_rect(), |
| 759 tile->contents_scale(), | 639 tile->contents_scale(), |
| 760 tile->picture_pile()); | 640 tile->picture_pile()); |
| 761 iter; ++iter) { | 641 iter; ++iter) { |
| 762 skia::LazyPixelRef* pixel_ref = *iter; | 642 skia::LazyPixelRef* pixel_ref = *iter; |
| 763 uint32_t id = pixel_ref->getGenerationID(); | 643 uint32_t id = pixel_ref->getGenerationID(); |
| 764 | 644 |
| 765 // Append existing image decode task if available. | 645 // Append existing image decode task if available. |
| 766 PixelRefMap::iterator decode_task_it = pending_decode_tasks_.find(id); | 646 PixelRefMap::iterator decode_task_it = pending_decode_tasks_.find(id); |
| 767 if (decode_task_it != pending_decode_tasks_.end()) { | 647 if (decode_task_it != pending_decode_tasks_.end()) { |
| 768 decode_tasks.Append(decode_task_it->second); | 648 decode_tasks.Insert(decode_task_it->second); |
| 769 continue; | 649 continue; |
| 770 } | 650 } |
| 771 | 651 |
| 772 // TODO(qinmin): passing correct image size to PrepareToDecode(). | 652 // TODO(qinmin): passing correct image size to PrepareToDecode(). |
| 773 if (pixel_ref->PrepareToDecode(skia::LazyPixelRef::PrepareParams())) { | 653 if (pixel_ref->PrepareToDecode(skia::LazyPixelRef::PrepareParams())) { |
| 774 rendering_stats_instrumentation_->IncrementDeferredImageCacheHitCount(); | 654 rendering_stats_instrumentation_->IncrementDeferredImageCacheHitCount(); |
| 775 continue; | 655 continue; |
| 776 } | 656 } |
| 777 | 657 |
| 778 // Create and append new image decode task for this pixel ref. | 658 // Create and append new image decode task for this pixel ref. |
| 779 RasterWorkerPool::Task decode_task = CreateImageDecodeTask( | 659 RasterWorkerPool::Task decode_task = CreateImageDecodeTask( |
| 780 tile, pixel_ref); | 660 tile, pixel_ref); |
| 781 decode_tasks.Append(decode_task); | 661 decode_tasks.Insert(decode_task); |
| 782 pending_decode_tasks_[id] = decode_task; | 662 pending_decode_tasks_[id] = decode_task; |
| 783 } | 663 } |
| 784 | 664 |
| 785 return RasterWorkerPool::PictureTask( | 665 return RasterWorkerPool::RasterTask( |
| 786 tile->picture_pile(), | 666 tile->picture_pile(), |
| 667 const_resource, |
| 787 base::Bind(&TileManager::RunAnalyzeAndRasterTask, | 668 base::Bind(&TileManager::RunAnalyzeAndRasterTask, |
| 788 base::Bind(&TileManager::RunAnalyzeTask, | 669 base::Bind(&TileManager::RunAnalyzeTask, |
| 789 analysis, | 670 analysis, |
| 790 tile->content_rect(), | 671 tile->content_rect(), |
| 791 tile->contents_scale(), | 672 tile->contents_scale(), |
| 792 use_color_estimator_, | 673 use_color_estimator_, |
| 793 GetRasterTaskMetadata(*tile), | 674 GetRasterTaskMetadata(*tile), |
| 794 rendering_stats_instrumentation_), | 675 rendering_stats_instrumentation_), |
| 795 base::Bind(&TileManager::RunRasterTask, | 676 base::Bind(&TileManager::RunRasterTask, |
| 796 buffer, | |
| 797 analysis, | 677 analysis, |
| 798 tile->content_rect(), | 678 tile->content_rect(), |
| 799 tile->contents_scale(), | 679 tile->contents_scale(), |
| 800 GetRasterTaskMetadata(*tile), | 680 GetRasterTaskMetadata(*tile), |
| 801 rendering_stats_instrumentation_)), | 681 rendering_stats_instrumentation_)), |
| 802 base::Bind(&TileManager::OnRasterTaskCompleted, | 682 base::Bind(&TileManager::OnRasterTaskCompleted, |
| 803 base::Unretained(this), | 683 base::Unretained(this), |
| 804 make_scoped_refptr(tile), | 684 make_scoped_refptr(tile), |
| 805 base::Passed(&resource), | 685 base::Passed(&resource), |
| 806 base::Owned(analysis)), | 686 base::Owned(analysis)), |
| 807 &decode_tasks); | 687 &decode_tasks); |
| 808 } | 688 } |
| 809 | 689 |
| 810 void TileManager::OnRasterTaskCompleted( | 690 void TileManager::OnRasterTaskCompleted( |
| 811 scoped_refptr<Tile> tile, | 691 scoped_refptr<Tile> tile, |
| 812 scoped_ptr<ResourcePool::Resource> resource, | 692 scoped_ptr<ResourcePool::Resource> resource, |
| 813 PicturePileImpl::Analysis* analysis, | 693 PicturePileImpl::Analysis* analysis, |
| 814 bool was_canceled) { | 694 bool was_canceled) { |
| 815 TRACE_EVENT0("cc", "TileManager::OnRasterTaskCompleted"); | 695 TRACE_EVENT1("cc", "TileManager::OnRasterTaskCompleted", |
| 696 "was_canceled", was_canceled); |
| 816 | 697 |
| 817 ManagedTileState& mts = tile->managed_state(); | 698 ManagedTileState& mts = tile->managed_state(); |
| 818 DCHECK(!mts.raster_task.is_null()); | 699 DCHECK(!mts.raster_task.is_null()); |
| 819 mts.raster_task.Reset(); | 700 mts.raster_task.Reset(); |
| 820 | 701 |
| 821 // Tile resources can't be freed until upload has completed. | 702 // Tile resources can't be freed until task has completed. |
| 822 DCHECK_EQ(USING_UNRELEASABLE_MEMORY, tile->tile_version().memory_state_); | 703 DCHECK_EQ(USING_UNRELEASABLE_MEMORY, tile->tile_version().memory_state_); |
| 823 | 704 |
| 824 // Release raster resources. | |
| 825 resource_pool_->resource_provider()->UnmapPixelBuffer(resource->id()); | |
| 826 | |
| 827 if (was_canceled) { | 705 if (was_canceled) { |
| 828 tile->tile_version().memory_state_ = CAN_USE_MEMORY; | 706 tile->tile_version().memory_state_ = CAN_USE_MEMORY; |
| 829 resource_pool_->resource_provider()->ReleasePixelBuffer(resource->id()); | |
| 830 resource_pool_->ReleaseResource(resource.Pass()); | 707 resource_pool_->ReleaseResource(resource.Pass()); |
| 831 return; | 708 return; |
| 832 } | 709 } |
| 833 | 710 |
| 834 mts.picture_pile_analysis = *analysis; | 711 mts.picture_pile_analysis = *analysis; |
| 835 mts.picture_pile_analyzed = true; | 712 mts.picture_pile_analyzed = true; |
| 836 | 713 |
| 837 if (analysis->is_solid_color) { | 714 if (analysis->is_solid_color) { |
| 838 tile->tile_version().set_solid_color(analysis->solid_color); | 715 tile->tile_version().set_solid_color(analysis->solid_color); |
| 839 resource_pool_->resource_provider()->ReleasePixelBuffer(resource->id()); | |
| 840 resource_pool_->ReleaseResource(resource.Pass()); | 716 resource_pool_->ReleaseResource(resource.Pass()); |
| 841 DidFinishTileInitialization(tile); | 717 } else { |
| 842 return; | 718 tile->tile_version().memory_state_ = USING_RELEASABLE_MEMORY; |
| 719 tile->tile_version().resource_ = resource.Pass(); |
| 843 } | 720 } |
| 844 | 721 |
| 845 resource_pool_->resource_provider()->BeginSetPixels(resource->id()); | 722 DidFinishTileInitialization(tile); |
| 846 has_performed_uploads_since_last_flush_ = true; | |
| 847 | |
| 848 tile->tile_version().resource_ = resource.Pass(); | |
| 849 | |
| 850 bytes_pending_upload_ += tile->bytes_consumed_if_allocated(); | |
| 851 tiles_with_pending_upload_.push(tile); | |
| 852 | |
| 853 if (tile->required_for_activation() && | |
| 854 client_->ShouldForceTileUploadsRequiredForActivationToComplete()) | |
| 855 ForceTileUploadToComplete(tile); | |
| 856 } | 723 } |
| 857 | 724 |
| 858 void TileManager::DidFinishTileInitialization(Tile* tile) { | 725 void TileManager::DidFinishTileInitialization(Tile* tile) { |
| 859 if (tile->priority(ACTIVE_TREE).distance_to_visible_in_pixels == 0) | 726 if (tile->priority(ACTIVE_TREE).distance_to_visible_in_pixels == 0) |
| 860 did_initialize_visible_tile_ = true; | 727 did_initialize_visible_tile_ = true; |
| 861 if (tile->required_for_activation()) { | 728 if (tile->required_for_activation()) { |
| 862 // It's possible that a tile required for activation is not in this list | 729 // It's possible that a tile required for activation is not in this list |
| 863 // if it was marked as being required after being dispatched for | 730 // if it was marked as being required after being dispatched for |
| 864 // rasterization but before AssignGPUMemory was called again. | 731 // rasterization but before AssignGPUMemory was called again. |
| 865 tiles_that_need_to_be_initialized_for_activation_.erase(tile); | 732 tiles_that_need_to_be_initialized_for_activation_.erase(tile); |
| (...skipping 15 matching lines...) Expand all Loading... |
| 881 TRACE_EVENT0("cc", "TileManager::RunImageDecodeTask"); | 748 TRACE_EVENT0("cc", "TileManager::RunImageDecodeTask"); |
| 882 devtools_instrumentation::ScopedLayerTask image_decode_task( | 749 devtools_instrumentation::ScopedLayerTask image_decode_task( |
| 883 devtools_instrumentation::kImageDecodeTask, layer_id); | 750 devtools_instrumentation::kImageDecodeTask, layer_id); |
| 884 base::TimeTicks start_time = stats_instrumentation->StartRecording(); | 751 base::TimeTicks start_time = stats_instrumentation->StartRecording(); |
| 885 pixel_ref->Decode(); | 752 pixel_ref->Decode(); |
| 886 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); | 753 base::TimeDelta duration = stats_instrumentation->EndRecording(start_time); |
| 887 stats_instrumentation->AddDeferredImageDecode(duration); | 754 stats_instrumentation->AddDeferredImageDecode(duration); |
| 888 } | 755 } |
| 889 | 756 |
| 890 // static | 757 // static |
| 891 void TileManager::RunAnalyzeAndRasterTask( | 758 bool TileManager::RunAnalyzeAndRasterTask( |
| 892 const RasterWorkerPool::PictureTask::Callback& analyze_task, | 759 const base::Callback<void(PicturePileImpl* picture_pile)>& analyze_task, |
| 893 const RasterWorkerPool::PictureTask::Callback& raster_task, | 760 const RasterWorkerPool::RasterTask::Callback& raster_task, |
| 761 SkDevice* device, |
| 894 PicturePileImpl* picture_pile) { | 762 PicturePileImpl* picture_pile) { |
| 895 analyze_task.Run(picture_pile); | 763 analyze_task.Run(picture_pile); |
| 896 raster_task.Run(picture_pile); | 764 return raster_task.Run(device, picture_pile); |
| 897 } | 765 } |
| 898 | 766 |
| 899 // static | 767 // static |
| 900 void TileManager::RunAnalyzeTask( | 768 void TileManager::RunAnalyzeTask( |
| 901 PicturePileImpl::Analysis* analysis, | 769 PicturePileImpl::Analysis* analysis, |
| 902 gfx::Rect rect, | 770 gfx::Rect rect, |
| 903 float contents_scale, | 771 float contents_scale, |
| 904 bool use_color_estimator, | 772 bool use_color_estimator, |
| 905 const RasterTaskMetadata& metadata, | 773 const RasterTaskMetadata& metadata, |
| 906 RenderingStatsInstrumentation* stats_instrumentation, | 774 RenderingStatsInstrumentation* stats_instrumentation, |
| (...skipping 22 matching lines...) Expand all Loading... |
| 929 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); | 797 scoped_ptr<base::DictionaryValue> res(new base::DictionaryValue()); |
| 930 res->Set("tile_id", TracedValue::CreateIDRef(tile_id).release()); | 798 res->Set("tile_id", TracedValue::CreateIDRef(tile_id).release()); |
| 931 res->SetBoolean("is_tile_in_pending_tree_now_bin", | 799 res->SetBoolean("is_tile_in_pending_tree_now_bin", |
| 932 is_tile_in_pending_tree_now_bin); | 800 is_tile_in_pending_tree_now_bin); |
| 933 res->Set("resolution", TileResolutionAsValue(tile_resolution).release()); | 801 res->Set("resolution", TileResolutionAsValue(tile_resolution).release()); |
| 934 res->SetInteger("source_frame_number", source_frame_number); | 802 res->SetInteger("source_frame_number", source_frame_number); |
| 935 return res.PassAs<base::Value>(); | 803 return res.PassAs<base::Value>(); |
| 936 } | 804 } |
| 937 | 805 |
| 938 // static | 806 // static |
| 939 void TileManager::RunRasterTask( | 807 bool TileManager::RunRasterTask( |
| 940 uint8* buffer, | |
| 941 PicturePileImpl::Analysis* analysis, | 808 PicturePileImpl::Analysis* analysis, |
| 942 gfx::Rect rect, | 809 gfx::Rect rect, |
| 943 float contents_scale, | 810 float contents_scale, |
| 944 const RasterTaskMetadata& metadata, | 811 const RasterTaskMetadata& metadata, |
| 945 RenderingStatsInstrumentation* stats_instrumentation, | 812 RenderingStatsInstrumentation* stats_instrumentation, |
| 813 SkDevice* device, |
| 946 PicturePileImpl* picture_pile) { | 814 PicturePileImpl* picture_pile) { |
| 947 TRACE_EVENT1( | 815 TRACE_EVENT1( |
| 948 "cc", "TileManager::RunRasterTask", | 816 "cc", "TileManager::RunRasterTask", |
| 949 "metadata", TracedValue::FromValue(metadata.AsValue().release())); | 817 "metadata", TracedValue::FromValue(metadata.AsValue().release())); |
| 950 devtools_instrumentation::ScopedLayerTask raster_task( | 818 devtools_instrumentation::ScopedLayerTask raster_task( |
| 951 devtools_instrumentation::kRasterTask, metadata.layer_id); | 819 devtools_instrumentation::kRasterTask, metadata.layer_id); |
| 952 | 820 |
| 953 DCHECK(picture_pile); | 821 DCHECK(picture_pile); |
| 954 DCHECK(analysis); | 822 DCHECK(analysis); |
| 955 | 823 DCHECK(device); |
| 956 // |buffer| can be NULL in lost context situations. | |
| 957 if (!buffer) | |
| 958 return; | |
| 959 | 824 |
| 960 if (analysis->is_solid_color) | 825 if (analysis->is_solid_color) |
| 961 return; | 826 return false; |
| 962 | 827 |
| 963 SkBitmap bitmap; | 828 SkCanvas canvas(device); |
| 964 bitmap.setConfig(SkBitmap::kARGB_8888_Config, rect.width(), rect.height()); | |
| 965 bitmap.setPixels(buffer); | |
| 966 SkDevice device(bitmap); | |
| 967 SkCanvas canvas(&device); | |
| 968 | 829 |
| 969 if (stats_instrumentation->record_rendering_stats()) { | 830 if (stats_instrumentation->record_rendering_stats()) { |
| 970 PicturePileImpl::RasterStats raster_stats; | 831 PicturePileImpl::RasterStats raster_stats; |
| 971 picture_pile->RasterToBitmap(&canvas, rect, contents_scale, &raster_stats); | 832 picture_pile->RasterToBitmap(&canvas, rect, contents_scale, &raster_stats); |
| 972 stats_instrumentation->AddRaster( | 833 stats_instrumentation->AddRaster( |
| 973 raster_stats.total_rasterize_time, | 834 raster_stats.total_rasterize_time, |
| 974 raster_stats.best_rasterize_time, | 835 raster_stats.best_rasterize_time, |
| 975 raster_stats.total_pixels_rasterized, | 836 raster_stats.total_pixels_rasterized, |
| 976 metadata.is_tile_in_pending_tree_now_bin); | 837 metadata.is_tile_in_pending_tree_now_bin); |
| 977 | 838 |
| 978 HISTOGRAM_CUSTOM_COUNTS( | 839 HISTOGRAM_CUSTOM_COUNTS( |
| 979 "Renderer4.PictureRasterTimeUS", | 840 "Renderer4.PictureRasterTimeUS", |
| 980 raster_stats.total_rasterize_time.InMicroseconds(), | 841 raster_stats.total_rasterize_time.InMicroseconds(), |
| 981 0, | 842 0, |
| 982 100000, | 843 100000, |
| 983 100); | 844 100); |
| 984 } else { | 845 } else { |
| 985 picture_pile->RasterToBitmap(&canvas, rect, contents_scale, NULL); | 846 picture_pile->RasterToBitmap(&canvas, rect, contents_scale, NULL); |
| 986 } | 847 } |
| 848 |
| 849 return true; |
| 987 } | 850 } |
| 988 | 851 |
| 989 } // namespace cc | 852 } // namespace cc |
| OLD | NEW |