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 350 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 361 if (decoded_images_ref_counts_.find(key) == | 361 if (decoded_images_ref_counts_.find(key) == |
| 362 decoded_images_ref_counts_.end()) { | 362 decoded_images_ref_counts_.end()) { |
| 363 decoded_image->Unlock(); | 363 decoded_image->Unlock(); |
| 364 } | 364 } |
| 365 | 365 |
| 366 decoded_images_.Put(key, std::move(decoded_image)); | 366 decoded_images_.Put(key, std::move(decoded_image)); |
| 367 SanityCheckState(__LINE__, true); | 367 SanityCheckState(__LINE__, true); |
| 368 } | 368 } |
| 369 | 369 |
| 370 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | 370 scoped_ptr<SoftwareImageDecodeController::DecodedImage> |
| 371 SoftwareImageDecodeController::DecodeImageMediumQuality(const ImageKey& key, | |
| 372 const SkImage& image) { | |
| 373 NOTIMPLEMENTED(); | |
| 374 return nullptr; | |
| 375 } | |
| 376 | |
| 377 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 378 SoftwareImageDecodeController::DecodeImageHighQuality(const ImageKey& key, | |
| 379 const SkImage& image) { | |
| 380 // If we get here, that means we couldn't use the original sized decode for | |
| 381 // whatever reason. However, in all cases we do need an original decode to | |
| 382 // either do a scale or to extract a subrect from the image. | |
| 383 auto decoded_image_result = DecodeImageOrUseCache(key, image); | |
| 384 if (!decoded_image_result.decoded_pixmap_.addr()) | |
| 385 return nullptr; | |
| 386 | |
| 387 // Now we have a decoded_pixmap which represents the src_rect at the | |
| 388 // original scale. All we need to do is scale it. | |
| 389 return ScaleImage(key, decoded_image_result); | |
| 390 } | |
| 391 | |
| 392 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 371 SoftwareImageDecodeController::DecodeImageInternal( | 393 SoftwareImageDecodeController::DecodeImageInternal( |
| 372 const ImageKey& key, | 394 const ImageKey& key, |
| 373 const DrawImage& draw_image) { | 395 const DrawImage& draw_image) { |
| 374 TRACE_EVENT1("disabled-by-default-cc.debug", | 396 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 375 "SoftwareImageDecodeController::DecodeImageInternal", "key", | 397 "SoftwareImageDecodeController::DecodeImageInternal", "key", |
| 376 key.ToString()); | 398 key.ToString()); |
| 377 const SkImage* image = draw_image.image(); | 399 const SkImage* image = draw_image.image(); |
| 378 | 400 if (!image) { |
| 379 // If we can use the original decode, then we don't need to do scaling. We can | |
| 380 // just read pixels into the final memory. | |
| 381 if (key.can_use_original_decode()) { | |
| 382 SkImageInfo decoded_info = | |
| 383 CreateImageInfo(image->width(), image->height(), format_); | |
| 384 scoped_ptr<base::DiscardableMemory> decoded_pixels; | |
| 385 { | |
| 386 TRACE_EVENT0( | |
| 387 "disabled-by-default-cc.debug", | |
| 388 "SoftwareImageDecodeController::DecodeImageInternal - allocate " | |
| 389 "decoded pixels"); | |
| 390 decoded_pixels = | |
| 391 base::DiscardableMemoryAllocator::GetInstance() | |
| 392 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() * | |
| 393 decoded_info.height()); | |
| 394 } | |
| 395 { | |
| 396 TRACE_EVENT0( | |
| 397 "disabled-by-default-cc.debug", | |
| 398 "SoftwareImageDecodeController::DecodeImageInternal - read pixels"); | |
| 399 bool result = image->readPixels(decoded_info, decoded_pixels->data(), | |
| 400 decoded_info.minRowBytes(), 0, 0, | |
| 401 SkImage::kDisallow_CachingHint); | |
| 402 | |
| 403 if (!result) { | |
| 404 decoded_pixels->Unlock(); | |
| 405 return nullptr; | |
| 406 } | |
| 407 } | |
| 408 | |
| 409 return make_scoped_ptr(new DecodedImage( | |
| 410 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0))); | |
| 411 } | |
| 412 | |
| 413 // If we get here, that means we couldn't use the original sized decode for | |
| 414 // whatever reason. However, in all cases we do need an original decode to | |
| 415 // either do a scale or to extract a subrect from the image. So, what we can | |
| 416 // do is construct a key that would require a full sized decode, then get that | |
| 417 // decode via GetDecodedImageForDrawInternal(), use it, and unref it. This | |
| 418 // ensures that if the original sized decode is already available in any of | |
| 419 // the caches, we reuse that. We also ensure that all the proper locking takes | |
| 420 // place. If, on the other hand, the decode was not available, | |
| 421 // GetDecodedImageForDrawInternal() would decode the image, and unreffing it | |
| 422 // later ensures that we will store the discardable memory unlocked in the | |
| 423 // cache to be used by future requests. | |
| 424 gfx::Rect full_image_rect(image->width(), image->height()); | |
| 425 DrawImage original_size_draw_image(image, gfx::RectToSkIRect(full_image_rect), | |
| 426 kNone_SkFilterQuality, SkMatrix::I()); | |
| 427 ImageKey original_size_key = | |
| 428 ImageKey::FromDrawImage(original_size_draw_image); | |
| 429 // Sanity checks. | |
| 430 DCHECK(original_size_key.can_use_original_decode()); | |
| 431 DCHECK(full_image_rect.size() == original_size_key.target_size()); | |
| 432 | |
| 433 auto decoded_draw_image = GetDecodedImageForDrawInternal( | |
| 434 original_size_key, original_size_draw_image); | |
| 435 if (!decoded_draw_image.image()) { | |
| 436 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); | |
| 437 return nullptr; | 401 return nullptr; |
| 438 } | 402 } |
| 439 | 403 |
| 440 SkPixmap decoded_pixmap; | 404 switch (key.filter_quality()) { |
| 441 bool result = decoded_draw_image.image()->peekPixels(&decoded_pixmap); | 405 case kNone_SkFilterQuality: |
| 442 DCHECK(result); | 406 // fall through |
|
vmpstr
2016/03/31 19:54:32
I don't think you really need this comment. That i
cblume
2016/04/09 06:48:54
Done.
| |
| 443 if (key.src_rect() != full_image_rect) { | 407 case kLow_SkFilterQuality: |
| 444 result = decoded_pixmap.extractSubset(&decoded_pixmap, | 408 return GetOriginalImageDecode(key, *image); |
| 445 gfx::RectToSkIRect(key.src_rect())); | 409 case kMedium_SkFilterQuality: |
| 446 DCHECK(result); | 410 return DecodeImageMediumQuality(key, *image); |
| 411 case kHigh_SkFilterQuality: | |
| 412 return DecodeImageHighQuality(key, *image); | |
| 413 default: | |
| 414 NOTREACHED(); | |
| 415 return nullptr; | |
| 447 } | 416 } |
| 448 | |
| 449 // Now we have a decoded_pixmap which represents the src_rect at the | |
| 450 // original scale. All we need to do is scale it. | |
| 451 DCHECK(!key.target_size().IsEmpty()); | |
| 452 SkImageInfo scaled_info = CreateImageInfo( | |
| 453 key.target_size().width(), key.target_size().height(), format_); | |
| 454 scoped_ptr<base::DiscardableMemory> scaled_pixels; | |
| 455 { | |
| 456 TRACE_EVENT0( | |
| 457 "disabled-by-default-cc.debug", | |
| 458 "SoftwareImageDecodeController::DecodeImageInternal - allocate " | |
| 459 "scaled pixels"); | |
| 460 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() | |
| 461 ->AllocateLockedDiscardableMemory( | |
| 462 scaled_info.minRowBytes() * scaled_info.height()); | |
| 463 } | |
| 464 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), | |
| 465 scaled_info.minRowBytes()); | |
| 466 // TODO(vmpstr): Start handling more than just high filter quality. | |
| 467 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality()); | |
| 468 { | |
| 469 TRACE_EVENT0( | |
| 470 "disabled-by-default-cc.debug", | |
| 471 "SoftwareImageDecodeController::DecodeImageInternal - scale pixels"); | |
| 472 bool result = | |
| 473 decoded_pixmap.scalePixels(scaled_pixmap, key.filter_quality()); | |
| 474 DCHECK(result); | |
| 475 } | |
| 476 | |
| 477 // Release the original sized decode. Any other intermediate result to release | |
| 478 // would be the subrect memory. However, that's in a scoped_ptr and will be | |
| 479 // deleted automatically when we return. | |
| 480 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); | |
| 481 | |
| 482 return make_scoped_ptr( | |
| 483 new DecodedImage(scaled_info, std::move(scaled_pixels), | |
| 484 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()))); | |
| 485 } | 417 } |
| 486 | 418 |
| 487 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw( | 419 DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw( |
| 488 const DrawImage& draw_image) { | 420 const DrawImage& draw_image) { |
| 489 ImageKey key = ImageKey::FromDrawImage(draw_image); | 421 ImageKey key = ImageKey::FromDrawImage(draw_image); |
| 490 TRACE_EVENT1("disabled-by-default-cc.debug", | 422 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 491 "SoftwareImageDecodeController::GetDecodedImageForDraw", "key", | 423 "SoftwareImageDecodeController::GetDecodedImageForDraw", "key", |
| 492 key.ToString()); | 424 key.ToString()); |
| 493 // If the target size is empty, we can skip this image draw. | 425 // If the target size is empty, we can skip this image draw. |
| 494 if (key.target_size().IsEmpty()) | 426 if (key.target_size().IsEmpty()) |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 546 // thread encountering this image (that might not be true, since other threads | 478 // thread encountering this image (that might not be true, since other threads |
| 547 // might be decoding it already). This means that we need to decode the image | 479 // might be decoding it already). This means that we need to decode the image |
| 548 // assuming we can't lock the one we found in the cache. | 480 // assuming we can't lock the one we found in the cache. |
| 549 bool check_at_raster_cache = false; | 481 bool check_at_raster_cache = false; |
| 550 if (!decoded_image || !decoded_image->Lock()) { | 482 if (!decoded_image || !decoded_image->Lock()) { |
| 551 // Note that we have to release the lock, since this lock is also accessed | 483 // Note that we have to release the lock, since this lock is also accessed |
| 552 // on the compositor thread. This means holding on to the lock might stall | 484 // on the compositor thread. This means holding on to the lock might stall |
| 553 // the compositor thread for the duration of the decode! | 485 // the compositor thread for the duration of the decode! |
| 554 base::AutoUnlock unlock(lock_); | 486 base::AutoUnlock unlock(lock_); |
| 555 scoped_decoded_image = DecodeImageInternal(key, draw_image); | 487 scoped_decoded_image = DecodeImageInternal(key, draw_image); |
| 488 | |
|
vmpstr
2016/03/31 19:54:32
unnecessary change
cblume
2016/04/09 06:48:54
Done.
| |
| 556 decoded_image = scoped_decoded_image.get(); | 489 decoded_image = scoped_decoded_image.get(); |
| 557 | 490 |
| 558 // Skip the image if we couldn't decode it. | 491 // Skip the image if we couldn't decode it. |
| 559 if (!decoded_image) | 492 if (!decoded_image) |
| 560 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); | 493 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); |
| 561 check_at_raster_cache = true; | 494 check_at_raster_cache = true; |
| 562 } | 495 } |
| 563 | 496 |
| 564 DCHECK(decoded_image == scoped_decoded_image.get()); | 497 DCHECK(decoded_image == scoped_decoded_image.get()); |
| 565 | 498 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 586 DCHECK(decoded_image->is_locked()); | 519 DCHECK(decoded_image->is_locked()); |
| 587 RefAtRasterImage(key); | 520 RefAtRasterImage(key); |
| 588 SanityCheckState(__LINE__, true); | 521 SanityCheckState(__LINE__, true); |
| 589 auto decoded_draw_image = | 522 auto decoded_draw_image = |
| 590 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(), | 523 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(), |
| 591 GetScaleAdjustment(key), GetDecodedFilterQuality(key)); | 524 GetScaleAdjustment(key), GetDecodedFilterQuality(key)); |
| 592 decoded_draw_image.set_at_raster_decode(true); | 525 decoded_draw_image.set_at_raster_decode(true); |
| 593 return decoded_draw_image; | 526 return decoded_draw_image; |
| 594 } | 527 } |
| 595 | 528 |
| 529 SoftwareImageDecodeController::DecodedImageResult::DecodedImageResult( | |
|
vmpstr
2016/03/31 19:54:32
Move this function to be after all other SoftwareI
cblume
2016/04/09 06:48:54
Done.
| |
| 530 SkPixmap decoded_pixmap, | |
| 531 DrawImage original_size_draw_image, | |
| 532 DecodedDrawImage decoded_draw_image) | |
| 533 : decoded_pixmap_(decoded_pixmap), | |
| 534 original_size_draw_image_(original_size_draw_image), | |
| 535 decoded_draw_image_(decoded_draw_image) {} | |
| 536 | |
| 537 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 538 SoftwareImageDecodeController::GetOriginalImageDecode(const ImageKey& key, | |
| 539 const SkImage& image) { | |
| 540 TRACE_EVENT1("disabled-by-default-cc.debug", | |
| 541 "SoftwareImageDecodeController::GetOriginalImageDecode", "key", | |
| 542 key.ToString()); | |
| 543 DCHECK(key.can_use_original_decode()); | |
| 544 SkImageInfo decoded_info = | |
| 545 CreateImageInfo(image.width(), image.height(), format_); | |
| 546 scoped_ptr<base::DiscardableMemory> decoded_pixels; | |
| 547 { | |
| 548 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 549 "SoftwareImageDecodeController::GetOriginalImageDecode - " | |
| 550 "allocate decoded pixels"); | |
| 551 decoded_pixels = | |
| 552 base::DiscardableMemoryAllocator::GetInstance() | |
| 553 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() * | |
| 554 decoded_info.height()); | |
| 555 } | |
| 556 { | |
| 557 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 558 "SoftwareImageDecodeController::GetOriginalImageDecode - " | |
| 559 "read pixels"); | |
| 560 bool result = image.readPixels(decoded_info, decoded_pixels->data(), | |
| 561 decoded_info.minRowBytes(), 0, 0, | |
| 562 SkImage::kDisallow_CachingHint); | |
| 563 | |
| 564 if (!result) { | |
| 565 decoded_pixels->Unlock(); | |
| 566 return nullptr; | |
| 567 } | |
| 568 } | |
| 569 | |
| 570 return make_scoped_ptr(new DecodedImage( | |
| 571 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0))); | |
| 572 } | |
| 573 | |
| 574 SoftwareImageDecodeController::DecodedImageResult | |
| 575 SoftwareImageDecodeController::DecodeImageOrUseCache(const ImageKey& key, | |
|
vmpstr
2016/03/31 19:54:32
I'm still a bit confused about DecodeImageOrUseCac
cblume
2016/04/09 06:48:54
DecodeImageInternal's old body was split into 3 fu
| |
| 576 const SkImage& image) { | |
| 577 // Construct a key to use in GetDecodedImageForDrawInternal(). | |
| 578 // This allows us to reuse an image in any cache if available. | |
| 579 gfx::Rect full_image_rect(image.width(), image.height()); | |
| 580 DrawImage original_size_draw_image(&image, | |
| 581 gfx::RectToSkIRect(full_image_rect), | |
| 582 kNone_SkFilterQuality, SkMatrix::I()); | |
| 583 ImageKey original_size_key = | |
| 584 ImageKey::FromDrawImage(original_size_draw_image); | |
| 585 // Sanity checks. | |
| 586 DCHECK(original_size_key.can_use_original_decode()); | |
| 587 DCHECK(full_image_rect.size() == original_size_key.target_size()); | |
| 588 | |
| 589 auto decoded_draw_image = GetDecodedImageForDrawInternal( | |
| 590 original_size_key, original_size_draw_image); | |
| 591 if (!decoded_draw_image.image()) { | |
| 592 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); | |
| 593 return DecodedImageResult(SkPixmap(), DrawImage(), | |
| 594 DecodedDrawImage(nullptr, kNone_SkFilterQuality)); | |
| 595 } | |
| 596 | |
| 597 SkPixmap decoded_pixmap; | |
| 598 bool result = decoded_draw_image.image()->peekPixels(&decoded_pixmap); | |
| 599 DCHECK(result); | |
| 600 if (key.src_rect() != full_image_rect) { | |
| 601 result = decoded_pixmap.extractSubset(&decoded_pixmap, | |
| 602 gfx::RectToSkIRect(key.src_rect())); | |
| 603 DCHECK(result); | |
| 604 } | |
| 605 | |
| 606 return DecodedImageResult(decoded_pixmap, original_size_draw_image, | |
| 607 decoded_draw_image); | |
| 608 } | |
| 609 | |
| 610 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 611 SoftwareImageDecodeController::ScaleImage( | |
| 612 const ImageKey& key, | |
| 613 const DecodedImageResult& decoded_image_result) { | |
| 614 DCHECK(!key.target_size().IsEmpty()); | |
| 615 SkImageInfo scaled_info = CreateImageInfo( | |
| 616 key.target_size().width(), key.target_size().height(), format_); | |
| 617 scoped_ptr<base::DiscardableMemory> scaled_pixels; | |
| 618 { | |
| 619 TRACE_EVENT0( | |
| 620 "disabled-by-default-cc.debug", | |
| 621 "SoftwareImageDecodeController::ScaleImage - allocate scaled pixels"); | |
| 622 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() | |
| 623 ->AllocateLockedDiscardableMemory( | |
| 624 scaled_info.minRowBytes() * scaled_info.height()); | |
| 625 } | |
| 626 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), | |
| 627 scaled_info.minRowBytes()); | |
| 628 // TODO(vmpstr): Start handling more than just high filter quality. | |
| 629 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality()); | |
| 630 { | |
| 631 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 632 "SoftwareImageDecodeController::ScaleImage - scale pixels"); | |
| 633 bool result = decoded_image_result.decoded_pixmap_.scalePixels( | |
| 634 scaled_pixmap, key.filter_quality()); | |
| 635 DCHECK(result); | |
| 636 } | |
| 637 | |
| 638 // Release the original sized decode. Any other intermediate result to release | |
| 639 // would be the subrect memory. However, that's in a scoped_ptr and will be | |
| 640 // deleted automatically when we return. | |
| 641 DrawWithImageFinished(decoded_image_result.original_size_draw_image_, | |
| 642 decoded_image_result.decoded_draw_image_); | |
| 643 | |
| 644 return make_scoped_ptr( | |
| 645 new DecodedImage(scaled_info, std::move(scaled_pixels), | |
| 646 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()))); | |
| 647 } | |
| 648 | |
| 596 void SoftwareImageDecodeController::DrawWithImageFinished( | 649 void SoftwareImageDecodeController::DrawWithImageFinished( |
| 597 const DrawImage& image, | 650 const DrawImage& image, |
| 598 const DecodedDrawImage& decoded_image) { | 651 const DecodedDrawImage& decoded_image) { |
| 599 TRACE_EVENT1("disabled-by-default-cc.debug", | 652 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 600 "SoftwareImageDecodeController::DrawWithImageFinished", "key", | 653 "SoftwareImageDecodeController::DrawWithImageFinished", "key", |
| 601 ImageKey::FromDrawImage(image).ToString()); | 654 ImageKey::FromDrawImage(image).ToString()); |
| 602 ImageKey key = ImageKey::FromDrawImage(image); | 655 ImageKey key = ImageKey::FromDrawImage(image); |
| 603 if (!decoded_image.image() || !CanHandleImage(key)) | 656 if (!decoded_image.image() || !CanHandleImage(key)) |
| 604 return; | 657 return; |
| 605 | 658 |
| (...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 890 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { | 943 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { |
| 891 current_usage_bytes_ = 0; | 944 current_usage_bytes_ = 0; |
| 892 } | 945 } |
| 893 | 946 |
| 894 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() | 947 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() |
| 895 const { | 948 const { |
| 896 return current_usage_bytes_.ValueOrDie(); | 949 return current_usage_bytes_.ValueOrDie(); |
| 897 } | 950 } |
| 898 | 951 |
| 899 } // namespace cc | 952 } // namespace cc |
| OLD | NEW |