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 |
| 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 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 545 // Now we know that we don't have a locked image, and we seem to be the first | 477 // Now we know that we don't have a locked image, and we seem to be the first |
| 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 const SkImage* image = draw_image.image(); |
| 488 if (key.can_use_original_decode()) { | |
|
ericrk
2016/03/24 16:06:59
If we unify the two by calling DecodeImageInternal
ericrk
2016/03/24 16:06:59
Can't we just call DecodeImageInternal here? Seems
cblume
2016/03/24 18:45:10
I began removing it and noticed GetScaleAdjustment
cblume
2016/03/24 18:45:10
Done.
cblume
2016/03/24 18:46:49
Running the tests, the low quality test and none q
| |
| 489 scoped_decoded_image = GetOriginalImageDecode(key, *image); | |
| 490 } else { | |
| 491 auto decoded_image_result = DecodeImageOrUseCache(key, *image); | |
| 492 if (!decoded_image_result.decoded_pixmap_.addr()) { | |
| 493 scoped_decoded_image = nullptr; | |
| 494 } else { | |
| 495 scoped_decoded_image = ScaleImage(key, decoded_image_result); | |
| 496 } | |
| 497 } | |
| 498 | |
| 556 decoded_image = scoped_decoded_image.get(); | 499 decoded_image = scoped_decoded_image.get(); |
| 557 | 500 |
| 558 // Skip the image if we couldn't decode it. | 501 // Skip the image if we couldn't decode it. |
| 559 if (!decoded_image) | 502 if (!decoded_image) |
| 560 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); | 503 return DecodedDrawImage(nullptr, kNone_SkFilterQuality); |
| 561 check_at_raster_cache = true; | 504 check_at_raster_cache = true; |
| 562 } | 505 } |
| 563 | 506 |
| 564 DCHECK(decoded_image == scoped_decoded_image.get()); | 507 DCHECK(decoded_image == scoped_decoded_image.get()); |
| 565 | 508 |
| (...skipping 20 matching lines...) Expand all Loading... | |
| 586 DCHECK(decoded_image->is_locked()); | 529 DCHECK(decoded_image->is_locked()); |
| 587 RefAtRasterImage(key); | 530 RefAtRasterImage(key); |
| 588 SanityCheckState(__LINE__, true); | 531 SanityCheckState(__LINE__, true); |
| 589 auto decoded_draw_image = | 532 auto decoded_draw_image = |
| 590 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(), | 533 DecodedDrawImage(decoded_image->image(), decoded_image->src_rect_offset(), |
| 591 GetScaleAdjustment(key), GetDecodedFilterQuality(key)); | 534 GetScaleAdjustment(key), GetDecodedFilterQuality(key)); |
| 592 decoded_draw_image.set_at_raster_decode(true); | 535 decoded_draw_image.set_at_raster_decode(true); |
| 593 return decoded_draw_image; | 536 return decoded_draw_image; |
| 594 } | 537 } |
| 595 | 538 |
| 539 SoftwareImageDecodeController::DecodedImageResult::DecodedImageResult( | |
| 540 SkPixmap decoded_pixmap, | |
| 541 DrawImage original_size_draw_image, | |
| 542 DecodedDrawImage decoded_draw_image) | |
| 543 : decoded_pixmap_(decoded_pixmap), | |
| 544 original_size_draw_image_(original_size_draw_image), | |
| 545 decoded_draw_image_(decoded_draw_image) {} | |
| 546 | |
| 547 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 548 SoftwareImageDecodeController::GetOriginalImageDecode(const ImageKey& key, | |
| 549 const SkImage& image) { | |
| 550 TRACE_EVENT1("disabled-by-default-cc.debug", | |
| 551 "SoftwareImageDecodeController::GetOriginalImageDecode", "key", | |
| 552 key.ToString()); | |
| 553 DCHECK(key.can_use_original_decode()); | |
| 554 SkImageInfo decoded_info = | |
| 555 CreateImageInfo(image.width(), image.height(), format_); | |
| 556 scoped_ptr<base::DiscardableMemory> decoded_pixels; | |
| 557 { | |
| 558 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 559 "SoftwareImageDecodeController::GetOriginalImageDecode - " | |
| 560 "allocate decoded pixels"); | |
| 561 decoded_pixels = | |
| 562 base::DiscardableMemoryAllocator::GetInstance() | |
| 563 ->AllocateLockedDiscardableMemory(decoded_info.minRowBytes() * | |
| 564 decoded_info.height()); | |
| 565 } | |
| 566 { | |
| 567 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 568 "SoftwareImageDecodeController::GetOriginalImageDecode - " | |
| 569 "read pixels"); | |
| 570 bool result = image.readPixels(decoded_info, decoded_pixels->data(), | |
| 571 decoded_info.minRowBytes(), 0, 0, | |
| 572 SkImage::kDisallow_CachingHint); | |
| 573 | |
| 574 if (!result) { | |
| 575 decoded_pixels->Unlock(); | |
| 576 return nullptr; | |
| 577 } | |
| 578 } | |
| 579 | |
| 580 return make_scoped_ptr(new DecodedImage( | |
| 581 decoded_info, std::move(decoded_pixels), SkSize::Make(0, 0))); | |
| 582 } | |
| 583 | |
| 584 SoftwareImageDecodeController::DecodedImageResult | |
| 585 SoftwareImageDecodeController::DecodeImageOrUseCache(const ImageKey& key, | |
| 586 const SkImage& image) { | |
| 587 // Construct a key to use in GetDecodedImageForDrawInternal(). | |
| 588 // This allows us to reuse an image in any cache if available. | |
| 589 gfx::Rect full_image_rect(image.width(), image.height()); | |
| 590 DrawImage original_size_draw_image(&image, | |
| 591 gfx::RectToSkIRect(full_image_rect), | |
| 592 kNone_SkFilterQuality, SkMatrix::I()); | |
| 593 ImageKey original_size_key = | |
| 594 ImageKey::FromDrawImage(original_size_draw_image); | |
| 595 // Sanity checks. | |
| 596 DCHECK(original_size_key.can_use_original_decode()); | |
| 597 DCHECK(full_image_rect.size() == original_size_key.target_size()); | |
| 598 | |
| 599 auto decoded_draw_image = GetDecodedImageForDrawInternal( | |
| 600 original_size_key, original_size_draw_image); | |
| 601 if (!decoded_draw_image.image()) { | |
| 602 DrawWithImageFinished(original_size_draw_image, decoded_draw_image); | |
| 603 return DecodedImageResult(SkPixmap(), DrawImage(), | |
| 604 DecodedDrawImage(nullptr, kNone_SkFilterQuality)); | |
| 605 } | |
| 606 | |
| 607 SkPixmap decoded_pixmap; | |
| 608 bool result = decoded_draw_image.image()->peekPixels(&decoded_pixmap); | |
| 609 DCHECK(result); | |
| 610 if (key.src_rect() != full_image_rect) { | |
| 611 result = decoded_pixmap.extractSubset(&decoded_pixmap, | |
| 612 gfx::RectToSkIRect(key.src_rect())); | |
| 613 DCHECK(result); | |
| 614 } | |
| 615 | |
| 616 return DecodedImageResult(decoded_pixmap, original_size_draw_image, | |
| 617 decoded_draw_image); | |
| 618 } | |
| 619 | |
| 620 scoped_ptr<SoftwareImageDecodeController::DecodedImage> | |
| 621 SoftwareImageDecodeController::ScaleImage( | |
| 622 const ImageKey& key, | |
| 623 const DecodedImageResult& decoded_image_result) { | |
| 624 DCHECK(!key.target_size().IsEmpty()); | |
| 625 SkImageInfo scaled_info = CreateImageInfo( | |
| 626 key.target_size().width(), key.target_size().height(), format_); | |
| 627 scoped_ptr<base::DiscardableMemory> scaled_pixels; | |
| 628 { | |
| 629 TRACE_EVENT0( | |
| 630 "disabled-by-default-cc.debug", | |
| 631 "SoftwareImageDecodeController::ScaleImage - allocate scaled pixels"); | |
| 632 scaled_pixels = base::DiscardableMemoryAllocator::GetInstance() | |
| 633 ->AllocateLockedDiscardableMemory( | |
| 634 scaled_info.minRowBytes() * scaled_info.height()); | |
| 635 } | |
| 636 SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), | |
| 637 scaled_info.minRowBytes()); | |
| 638 // TODO(vmpstr): Start handling more than just high filter quality. | |
| 639 DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality()); | |
| 640 { | |
| 641 TRACE_EVENT0("disabled-by-default-cc.debug", | |
| 642 "SoftwareImageDecodeController::ScaleImage - scale pixels"); | |
| 643 bool result = decoded_image_result.decoded_pixmap_.scalePixels( | |
| 644 scaled_pixmap, key.filter_quality()); | |
| 645 DCHECK(result); | |
| 646 } | |
| 647 | |
| 648 // Release the original sized decode. Any other intermediate result to release | |
| 649 // would be the subrect memory. However, that's in a scoped_ptr and will be | |
| 650 // deleted automatically when we return. | |
| 651 DrawWithImageFinished(decoded_image_result.original_size_draw_image_, | |
| 652 decoded_image_result.decoded_draw_image_); | |
| 653 | |
| 654 return make_scoped_ptr( | |
| 655 new DecodedImage(scaled_info, std::move(scaled_pixels), | |
| 656 SkSize::Make(-key.src_rect().x(), -key.src_rect().y()))); | |
| 657 } | |
| 658 | |
| 596 void SoftwareImageDecodeController::DrawWithImageFinished( | 659 void SoftwareImageDecodeController::DrawWithImageFinished( |
| 597 const DrawImage& image, | 660 const DrawImage& image, |
| 598 const DecodedDrawImage& decoded_image) { | 661 const DecodedDrawImage& decoded_image) { |
| 599 TRACE_EVENT1("disabled-by-default-cc.debug", | 662 TRACE_EVENT1("disabled-by-default-cc.debug", |
| 600 "SoftwareImageDecodeController::DrawWithImageFinished", "key", | 663 "SoftwareImageDecodeController::DrawWithImageFinished", "key", |
| 601 ImageKey::FromDrawImage(image).ToString()); | 664 ImageKey::FromDrawImage(image).ToString()); |
| 602 ImageKey key = ImageKey::FromDrawImage(image); | 665 ImageKey key = ImageKey::FromDrawImage(image); |
| 603 if (!decoded_image.image() || !CanHandleImage(key)) | 666 if (!decoded_image.image() || !CanHandleImage(key)) |
| 604 return; | 667 return; |
| 605 | 668 |
| (...skipping 281 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 887 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { | 950 void SoftwareImageDecodeController::MemoryBudget::ResetUsage() { |
| 888 current_usage_bytes_ = 0; | 951 current_usage_bytes_ = 0; |
| 889 } | 952 } |
| 890 | 953 |
| 891 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() | 954 size_t SoftwareImageDecodeController::MemoryBudget::GetCurrentUsageSafe() |
| 892 const { | 955 const { |
| 893 return current_usage_bytes_.ValueOrDie(); | 956 return current_usage_bytes_.ValueOrDie(); |
| 894 } | 957 } |
| 895 | 958 |
| 896 } // namespace cc | 959 } // namespace cc |
| OLD | NEW |