Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 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/tiles/software_image_decode_controller.h" | 5 #include "cc/tiles/software_image_decode_controller.h" |
| 6 | 6 |
| 7 #include <stdint.h> | 7 #include <stdint.h> |
| 8 | 8 |
| 9 #include <functional> | 9 #include <functional> |
| 10 | 10 |
| (...skipping 154 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 165 "SoftwareImageDecodeController::GetTaskForImageAndRef", "key", | 165 "SoftwareImageDecodeController::GetTaskForImageAndRef", "key", |
| 166 key.ToString()); | 166 key.ToString()); |
| 167 | 167 |
| 168 // If the target size is empty, we can skip this image during draw (and thus | 168 // If the target size is empty, we can skip this image during draw (and thus |
| 169 // we don't need to decode it or ref it). | 169 // we don't need to decode it or ref it). |
| 170 if (key.target_size().IsEmpty()) { | 170 if (key.target_size().IsEmpty()) { |
| 171 *task = nullptr; | 171 *task = nullptr; |
| 172 return false; | 172 return false; |
| 173 } | 173 } |
| 174 | 174 |
| 175 // If we're not going to do a scale, we will just create a task to preroll the | |
| 176 // image the first time we see it. This doesn't need to account for memory. | |
| 177 // TODO(vmpstr): We can also lock the original sized image, in which case it | |
| 178 // does require memory bookkeeping. | |
| 179 if (!CanHandleImage(key)) { | |
| 180 base::AutoLock lock(lock_); | |
| 181 if (prerolled_images_.count(key.image_id()) == 0) { | |
| 182 scoped_refptr<ImageDecodeTask>& existing_task = pending_image_tasks_[key]; | |
| 183 if (!existing_task) { | |
| 184 existing_task = make_scoped_refptr( | |
| 185 new ImageDecodeTaskImpl(this, key, image, prepare_tiles_id)); | |
| 186 } | |
| 187 *task = existing_task; | |
| 188 } else { | |
| 189 *task = nullptr; | |
| 190 } | |
| 191 return false; | |
| 192 } | |
| 193 | |
| 194 base::AutoLock lock(lock_); | 175 base::AutoLock lock(lock_); |
| 195 | 176 |
| 196 // If we already have the image in cache, then we can return it. | 177 // If we already have the image in cache, then we can return it. |
| 197 auto decoded_it = decoded_images_.Get(key); | 178 auto decoded_it = decoded_images_.Get(key); |
| 198 bool new_image_fits_in_memory = | 179 bool new_image_fits_in_memory = |
| 199 locked_images_budget_.AvailableMemoryBytes() >= key.locked_bytes(); | 180 locked_images_budget_.AvailableMemoryBytes() >= key.locked_bytes(); |
| 200 if (decoded_it != decoded_images_.end()) { | 181 if (decoded_it != decoded_images_.end()) { |
| 201 if (decoded_it->second->is_locked() || | 182 if (decoded_it->second->is_locked() || |
| 202 (new_image_fits_in_memory && decoded_it->second->Lock())) { | 183 (new_image_fits_in_memory && decoded_it->second->Lock())) { |
| 203 RefImage(key); | 184 RefImage(key); |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 255 } | 236 } |
| 256 | 237 |
| 257 void SoftwareImageDecodeController::UnrefImage(const DrawImage& image) { | 238 void SoftwareImageDecodeController::UnrefImage(const DrawImage& image) { |
| 258 // When we unref the image, there are several situations we need to consider: | 239 // When we unref the image, there are several situations we need to consider: |
| 259 // 1. The ref did not reach 0, which means we have to keep the image locked. | 240 // 1. The ref did not reach 0, which means we have to keep the image locked. |
| 260 // 2. The ref reached 0, we should unlock it. | 241 // 2. The ref reached 0, we should unlock it. |
| 261 // 2a. The image isn't in the locked cache because we didn't get to decode | 242 // 2a. The image isn't in the locked cache because we didn't get to decode |
| 262 // it yet (or failed to decode it). | 243 // it yet (or failed to decode it). |
| 263 // 2b. Unlock the image but keep it in list. | 244 // 2b. Unlock the image but keep it in list. |
| 264 const ImageKey& key = ImageKey::FromDrawImage(image); | 245 const ImageKey& key = ImageKey::FromDrawImage(image); |
| 265 DCHECK(CanHandleImage(key)) << key.ToString(); | |
| 266 TRACE_EVENT1("disabled-by-default-cc.debug", | 246 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 267 "SoftwareImageDecodeController::UnrefImage", "key", | 247 "SoftwareImageDecodeController::UnrefImage", "key", |
| 268 key.ToString()); | 248 key.ToString()); |
| 269 | 249 |
| 270 base::AutoLock lock(lock_); | 250 base::AutoLock lock(lock_); |
| 271 auto ref_count_it = decoded_images_ref_counts_.find(key); | 251 auto ref_count_it = decoded_images_ref_counts_.find(key); |
| 272 DCHECK(ref_count_it != decoded_images_ref_counts_.end()); | 252 DCHECK(ref_count_it != decoded_images_ref_counts_.end()); |
| 273 | 253 |
| 274 --ref_count_it->second; | 254 --ref_count_it->second; |
| 275 if (ref_count_it->second == 0) { | 255 if (ref_count_it->second == 0) { |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 286 DCHECK(decoded_image_it->second->is_locked()); | 266 DCHECK(decoded_image_it->second->is_locked()); |
| 287 decoded_image_it->second->Unlock(); | 267 decoded_image_it->second->Unlock(); |
| 288 } | 268 } |
| 289 SanityCheckState(__LINE__, true); | 269 SanityCheckState(__LINE__, true); |
| 290 } | 270 } |
| 291 | 271 |
| 292 void SoftwareImageDecodeController::DecodeImage(const ImageKey& key, | 272 void SoftwareImageDecodeController::DecodeImage(const ImageKey& key, |
| 293 const DrawImage& image) { | 273 const DrawImage& image) { |
| 294 TRACE_EVENT1("cc", "SoftwareImageDecodeController::DecodeImage", "key", | 274 TRACE_EVENT1("cc", "SoftwareImageDecodeController::DecodeImage", "key", |
| 295 key.ToString()); | 275 key.ToString()); |
| 296 if (!CanHandleImage(key)) { | |
| 297 image.image()->preroll(); | |
| 298 | |
| 299 base::AutoLock lock(lock_); | |
| 300 prerolled_images_.insert(key.image_id()); | |
| 301 // Erase the pending task from the queue, since the task won't be doing | |
| 302 // anything useful after this function terminates. Since we don't preroll | |
| 303 // images twice, this is actually not necessary but it behaves similar to | |
| 304 // the other code path: when this function finishes, the task isn't in the | |
| 305 // pending_image_tasks_ list. | |
| 306 pending_image_tasks_.erase(key); | |
| 307 return; | |
| 308 } | |
| 309 | |
| 310 base::AutoLock lock(lock_); | 276 base::AutoLock lock(lock_); |
| 311 AutoRemoveKeyFromTaskMap remove_key_from_task_map(&pending_image_tasks_, key); | 277 AutoRemoveKeyFromTaskMap remove_key_from_task_map(&pending_image_tasks_, key); |
| 312 | 278 |
| 313 // We could have finished all of the raster tasks (cancelled) while the task | 279 // We could have finished all of the raster tasks (cancelled) while the task |
| 314 // was just starting to run. Since this task already started running, it | 280 // was just starting to run. Since this task already started running, it |
| 315 // wasn't cancelled. So, if the ref count for the image is 0 then we can just | 281 // wasn't cancelled. So, if the ref count for the image is 0 then we can just |
| 316 // abort. | 282 // abort. |
| 317 if (decoded_images_ref_counts_.find(key) == | 283 if (decoded_images_ref_counts_.find(key) == |
| 318 decoded_images_ref_counts_.end()) { | 284 decoded_images_ref_counts_.end()) { |
| 319 return; | 285 return; |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 371 key.ToString()); | 337 key.ToString()); |
| 372 const SkImage* image = draw_image.image(); | 338 const SkImage* image = draw_image.image(); |
| 373 if (!image) | 339 if (!image) |
| 374 return nullptr; | 340 return nullptr; |
| 375 | 341 |
| 376 switch (key.filter_quality()) { | 342 switch (key.filter_quality()) { |
| 377 case kNone_SkFilterQuality: | 343 case kNone_SkFilterQuality: |
| 378 case kLow_SkFilterQuality: | 344 case kLow_SkFilterQuality: |
| 379 return GetOriginalImageDecode(key, *image); | 345 return GetOriginalImageDecode(key, *image); |
| 380 case kMedium_SkFilterQuality: | 346 case kMedium_SkFilterQuality: |
| 381 NOTIMPLEMENTED(); | |
| 382 return nullptr; | |
| 383 case kHigh_SkFilterQuality: | 347 case kHigh_SkFilterQuality: |
| 384 return GetScaledImageDecode(key, *image); | 348 return GetScaledImageDecode(key, *image); |
| 385 default: | 349 default: |
| 386 NOTREACHED(); | 350 NOTREACHED(); |
| 387 return nullptr; | 351 return nullptr; |
| 388 } | 352 } |
| 389 } | 353 } |
| 390 | 354 |
| 391 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw( | 355 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw( |
| 392 const DrawImage& draw_image) { | 356 const DrawImage& draw_image) { |
| 393 ImageKey key = ImageKey::FromDrawImage(draw_image); | 357 ImageKey key = ImageKey::FromDrawImage(draw_image); |
| 394 TRACE_EVENT1("disabled-by-default-cc.debug", | 358 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 395 "SoftwareImageDecodeController::GetDecodedImageForDraw", "key", | 359 "SoftwareImageDecodeController::GetDecodedImageForDraw", "key", |
| 396 key.ToString()); | 360 key.ToString()); |
| 397 // If the target size is empty, we can skip this image draw. | 361 // If the target size is empty, we can skip this image draw. |
| 398 if (key.target_size().IsEmpty()) | 362 if (key.target_size().IsEmpty()) |
| 399 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); | 363 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); |
| 400 | 364 |
| 401 if (!CanHandleImage(key)) | |
| 402 return DecodedDrawImage(draw_image.image(), draw_image.filter_quality()); | |
| 403 | |
| 404 return GetDecodedImageForDrawInternal(key, draw_image); | 365 return GetDecodedImageForDrawInternal(key, draw_image); |
| 405 } | 366 } |
| 406 | 367 |
| 407 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDrawInternal( | 368 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDrawInternal( |
| 408 const ImageKey& key, | 369 const ImageKey& key, |
| 409 const DrawImage& draw_image) { | 370 const DrawImage& draw_image) { |
| 410 TRACE_EVENT1("disabled-by-default-cc.debug", | 371 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 411 "SoftwareImageDecodeController::GetDecodedImageForDrawInternal", | 372 "SoftwareImageDecodeController::GetDecodedImageForDrawInternal", |
| 412 "key", key.ToString()); | 373 "key", key.ToString()); |
| 413 base::AutoLock lock(lock_); | 374 base::AutoLock lock(lock_); |
| (...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 569 { | 530 { |
| 570 TRACE_EVENT0( | 531 TRACE_EVENT0( |
| 571 "disabled-by-default-cc.debug", | 532 "disabled-by-default-cc.debug", |
| 572 "SoftwareImageDecodeController::ScaleImage - allocate scaled pixels"); | 533 "SoftwareImageDecodeController::ScaleImage - allocate scaled pixels"); |
| 573 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() | 534 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() |
| 574 ->AllocateLockedDiscardableMemory( | 535 ->AllocateLockedDiscardableMemory( |
| 575 scaled_info.minRowBytes() * scaled_info.height()); | 536 scaled_info.minRowBytes() * scaled_info.height()); |
| 576 } | 537 } |
| 577 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), | 538 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), |
| 578 scaled_info.minRowBytes()); | 539 scaled_info.minRowBytes()); |
| 579 // TODO(vmpstr): Start handling more than just high filter quality. | |
| 580 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality()); | |
| 581 { | 540 { |
| 582 TRACE_EVENT0("disabled-by-default-cc.debug", | 541 TRACE_EVENT0("disabled-by-default-cc.debug", |
| 583 "SoftwareImageDecodeController::ScaleImage - scale pixels"); | 542 "SoftwareImageDecodeController::ScaleImage - scale pixels"); |
| 584 bool result = | 543 bool result = |
| 585 decoded_pixmap.scalePixels(scaled_pixmap, key.filter_quality()); | 544 decoded_pixmap.scalePixels(scaled_pixmap, key.filter_quality()); |
|
vmpstr
2016/04/19 23:04:57
So... we don't actually cache the mip level in thi
cblume
2016/04/21 19:28:11
Oh, I made a mistake here.
Skia does mipmapping in
vmpstr
2016/04/21 20:11:30
Which 3 param version? I don't think SkPixmap has
cblume
2016/04/22 01:40:14
Oh sorry. I was looking at SkImage::scalePixels, w
| |
| 586 DCHECK(result) << key.ToString(); | 545 DCHECK(result) << key.ToString(); |
| 587 } | 546 } |
| 588 | 547 |
| 589 // Release the original sized decode. Any other intermediate result to release | 548 // Release the original sized decode. Any other intermediate result to release |
| 590 // would be the subrect memory. However, that's in a scoped_ptr and will be | 549 // would be the subrect memory. However, that's in a scoped_ptr and will be |
| 591 // deleted automatically when we return. | 550 // deleted automatically when we return. |
| 592 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); | 551 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); |
| 593 | 552 |
| 594 return base::WrapUnique( | 553 return base::WrapUnique( |
| 595 new DecodedImage(scaled_info, std::move(scaled_pixels), | 554 new DecodedImage(scaled_info, std::move(scaled_pixels), |
| 596 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()), | 555 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()), |
| 597 next_tracing_id_.GetNext())); | 556 next_tracing_id_.GetNext())); |
| 598 } | 557 } |
| 599 | 558 |
| 600 void SoftwareImageDecodeController::DrawWithImageFinished( | 559 void SoftwareImageDecodeController::DrawWithImageFinished( |
| 601 const DrawImage& image, | 560 const DrawImage& image, |
| 602 const DecodedDrawImage& decoded_image) { | 561 const DecodedDrawImage& decoded_image) { |
| 603 TRACE_EVENT1("disabled-by-default-cc.debug", | 562 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 604 "SoftwareImageDecodeController::DrawWithImageFinished", "key", | 563 "SoftwareImageDecodeController::DrawWithImageFinished", "key", |
| 605 ImageKey::FromDrawImage(image).ToString()); | 564 ImageKey::FromDrawImage(image).ToString()); |
| 606 ImageKey key = ImageKey::FromDrawImage(image); | 565 ImageKey key = ImageKey::FromDrawImage(image); |
| 607 if (!decoded_image.image() || !CanHandleImage(key)) | 566 if (!decoded_image.image()) |
| 608 return; | 567 return; |
| 609 | 568 |
| 610 if (decoded_image.is_at_raster_decode()) | 569 if (decoded_image.is_at_raster_decode()) |
| 611 UnrefAtRasterImage(key); | 570 UnrefAtRasterImage(key); |
| 612 else | 571 else |
| 613 UnrefImage(image); | 572 UnrefImage(image); |
| 614 SanityCheckState(__LINE__, false); | 573 SanityCheckState(__LINE__, false); |
| 615 } | 574 } |
| 616 | 575 |
| 617 void SoftwareImageDecodeController::RefAtRasterImage(const ImageKey& key) { | 576 void SoftwareImageDecodeController::RefAtRasterImage(const ImageKey& key) { |
| (...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 664 DCHECK(decoded_images_ref_counts_.find(key) == | 623 DCHECK(decoded_images_ref_counts_.find(key) == |
| 665 decoded_images_ref_counts_.end()); | 624 decoded_images_ref_counts_.end()); |
| 666 at_raster_image_it->second->Unlock(); | 625 at_raster_image_it->second->Unlock(); |
| 667 decoded_images_.Erase(image_it); | 626 decoded_images_.Erase(image_it); |
| 668 decoded_images_.Put(key, std::move(at_raster_image_it->second)); | 627 decoded_images_.Put(key, std::move(at_raster_image_it->second)); |
| 669 } | 628 } |
| 670 at_raster_decoded_images_.Erase(at_raster_image_it); | 629 at_raster_decoded_images_.Erase(at_raster_image_it); |
| 671 } | 630 } |
| 672 } | 631 } |
| 673 | 632 |
| 674 bool SoftwareImageDecodeController::CanHandleImage(const ImageKey& key) { | |
| 675 // TODO(vmpstr): Start handling medium filter quality as well. | |
| 676 return key.filter_quality() != kMedium_SkFilterQuality; | |
| 677 } | |
| 678 | |
| 679 void SoftwareImageDecodeController::ReduceCacheUsage() { | 633 void SoftwareImageDecodeController::ReduceCacheUsage() { |
| 680 TRACE_EVENT0("cc", "SoftwareImageDecodeController::ReduceCacheUsage"); | 634 TRACE_EVENT0("cc", "SoftwareImageDecodeController::ReduceCacheUsage"); |
| 681 base::AutoLock lock(lock_); | 635 base::AutoLock lock(lock_); |
| 682 size_t num_to_remove = (decoded_images_.size() > kMaxItemsInCache) | 636 size_t num_to_remove = (decoded_images_.size() > kMaxItemsInCache) |
| 683 ? (decoded_images_.size() - kMaxItemsInCache) | 637 ? (decoded_images_.size() - kMaxItemsInCache) |
| 684 : 0; | 638 : 0; |
| 685 for (auto it = decoded_images_.rbegin(); | 639 for (auto it = decoded_images_.rbegin(); |
| 686 num_to_remove != 0 && it != decoded_images_.rend();) { | 640 num_to_remove != 0 && it != decoded_images_.rend();) { |
| 687 if (it->second->is_locked()) { | 641 if (it->second->is_locked()) { |
| 688 ++it; | 642 ++it; |
| (...skipping 243 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 932 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { | 886 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { |
| 933 current_usage_bytes_ = 0; | 887 current_usage_bytes_ = 0; |
| 934 } | 888 } |
| 935 | 889 |
| 936 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() | 890 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() |
| 937 const { | 891 const { |
| 938 return current_usage_bytes_.ValueOrDie(); | 892 return current_usage_bytes_.ValueOrDie(); |
| 939 } | 893 } |
| 940 | 894 |
| 941 } // namespace cc | 895 } // namespace cc |
| OLD | NEW |