Chromium Code Reviews| Index: cc/tiles/software_image_decode_controller.cc |
| diff --git a/cc/tiles/software_image_decode_controller.cc b/cc/tiles/software_image_decode_controller.cc |
| index c074af98857be59b59f895bd53b380b75ca746ea..9b05964c23072fe6d42dd004f209011de56cd60b 100644 |
| --- a/cc/tiles/software_image_decode_controller.cc |
| +++ b/cc/tiles/software_image_decode_controller.cc |
| @@ -6,6 +6,7 @@ |
| #include <stdint.h> |
| +#include <algorithm> |
| #include <functional> |
| #include "base/format_macros.h" |
| @@ -96,17 +97,65 @@ class ImageDecodeTaskImpl : public TileTask { |
| DISALLOW_COPY_AND_ASSIGN(ImageDecodeTaskImpl); |
| }; |
| +// Most images are scaled from the source image's size to the target size. |
| +// But in the case of mipmaps, we are scaling from the mip level which is |
| +// larger than we need. |
| +// This function gets the scale of the mip level which will be used. |
| +SkSize GetMipMapScaleAdjustment( |
| + const SoftwareImageDecodeController::ImageKey& key) { |
| + gfx::Rect src_rect = key.src_rect(); |
| + int src_height = src_rect.height(); |
| + int src_width = src_rect.width(); |
| + |
| + int next_mip_height = src_height; |
| + int next_mip_width = src_width; |
| + for (int current_mip_level = 0;; current_mip_level++) { |
| + int mip_height = next_mip_height; |
| + int mip_width = next_mip_width; |
| + |
| + next_mip_height = std::max(1, src_height / (1 << (current_mip_level + 1))); |
| + next_mip_width = std::max(1, src_width / (1 << (current_mip_level + 1))); |
| + |
| + // Check if an axis on the next mip level would be smaller than the target. |
| + // If so, use the current mip level. |
| + // This effectively always uses the larger image and always scales down. |
| + if (next_mip_height < key.target_size().height() || |
| + next_mip_width < key.target_size().width()) { |
|
ericrk
2016/04/23 00:25:48
I think this hits an edge case if you actually wan
cblume
2016/04/27 08:10:36
Done.
|
| + SkScalar y_scale = 1.f; |
| + SkScalar x_scale = 1.f; |
| + if (current_mip_level != 0) { |
| + y_scale = static_cast<float>(mip_height) / src_height; |
| + x_scale = static_cast<float>(mip_width) / src_width; |
| + } |
| + |
| + return SkSize::Make(x_scale, y_scale); |
| + } |
| + |
| + if (mip_height == 1 && mip_width == 1) { |
| + // We have reached the final mip level |
| + break; |
| + } |
| + } |
| + |
| + return SkSize::Make(-1.f, -1.f); |
| +} |
| + |
| SkSize GetScaleAdjustment(const ImageDecodeControllerKey& key) { |
| // If the requested filter quality did not require scale, then the adjustment |
| // is identity. |
| - if (key.can_use_original_decode()) |
| + if (key.can_use_original_decode()) { |
| return SkSize::Make(1.f, 1.f); |
| - |
| - float x_scale = |
| - key.target_size().width() / static_cast<float>(key.src_rect().width()); |
| - float y_scale = |
| - key.target_size().height() / static_cast<float>(key.src_rect().height()); |
| - return SkSize::Make(x_scale, y_scale); |
| + } else { |
| + if (key.filter_quality() == kMedium_SkFilterQuality) { |
| + return GetMipMapScaleAdjustment(key); |
| + } else { |
| + float x_scale = key.target_size().width() / |
| + static_cast<float>(key.src_rect().width()); |
| + float y_scale = key.target_size().height() / |
| + static_cast<float>(key.src_rect().height()); |
| + return SkSize::Make(x_scale, y_scale); |
| + } |
| + } |
| } |
| SkFilterQuality GetDecodedFilterQuality(const ImageDecodeControllerKey& key) { |
| @@ -173,25 +222,6 @@ bool SoftwareImageDecodeController::GetTaskForImageAndRef( |
| return false; |
| } |
| - // If we're not going to do a scale, we will just create a task to preroll the |
| - // image the first time we see it. This doesn't need to account for memory. |
| - // TODO(vmpstr): We can also lock the original sized image, in which case it |
| - // does require memory bookkeeping. |
| - if (!CanHandleImage(key)) { |
| - base::AutoLock lock(lock_); |
| - if (prerolled_images_.count(key.image_id()) == 0) { |
| - scoped_refptr<TileTask>& existing_task = pending_image_tasks_[key]; |
| - if (!existing_task) { |
| - existing_task = make_scoped_refptr( |
| - new ImageDecodeTaskImpl(this, key, image, prepare_tiles_id)); |
| - } |
| - *task = existing_task; |
| - } else { |
| - *task = nullptr; |
| - } |
| - return false; |
| - } |
| - |
| base::AutoLock lock(lock_); |
| // If we already have the image in cache, then we can return it. |
| @@ -263,7 +293,6 @@ void SoftwareImageDecodeController::UnrefImage(const DrawImage& image) { |
| // it yet (or failed to decode it). |
| // 2b. Unlock the image but keep it in list. |
| const ImageKey& key = ImageKey::FromDrawImage(image); |
| - DCHECK(CanHandleImage(key)) << key.ToString(); |
| TRACE_EVENT1("disabled-by-default-cc.debug", |
| "SoftwareImageDecodeController::UnrefImage", "key", |
| key.ToString()); |
| @@ -294,20 +323,6 @@ void SoftwareImageDecodeController::DecodeImage(const ImageKey& key, |
| const DrawImage& image) { |
| TRACE_EVENT1("cc", "SoftwareImageDecodeController::DecodeImage", "key", |
| key.ToString()); |
| - if (!CanHandleImage(key)) { |
| - image.image()->preroll(); |
| - |
| - base::AutoLock lock(lock_); |
| - prerolled_images_.insert(key.image_id()); |
| - // Erase the pending task from the queue, since the task won't be doing |
| - // anything useful after this function terminates. Since we don't preroll |
| - // images twice, this is actually not necessary but it behaves similar to |
| - // the other code path: when this function finishes, the task isn't in the |
| - // pending_image_tasks_ list. |
| - pending_image_tasks_.erase(key); |
| - return; |
| - } |
| - |
| base::AutoLock lock(lock_); |
| AutoRemoveKeyFromTaskMap remove_key_from_task_map(&pending_image_tasks_, key); |
| @@ -364,6 +379,24 @@ void SoftwareImageDecodeController::DecodeImage(const ImageKey& key, |
| } |
| std::unique_ptr<SoftwareImageDecodeController::DecodedImage> |
| +SoftwareImageDecodeController::GetMediumQualityImageDecode( |
| + const ImageKey& key, |
| + const SkImage& image) { |
| + SkSize mipmap_scale = GetMipMapScaleAdjustment(key); |
| + // -1 represents an invalid scale. |
| + // So add 1 and compare to epsilon. |
|
vmpstr
2016/04/22 18:17:10
Comment is incorrect
cblume
2016/04/27 08:10:36
Done.
|
| + if (mipmap_scale.width() == -1.f || mipmap_scale.height() == -1.f) { |
|
vmpstr
2016/04/22 18:17:10
I understand your reasoning, but I think changing
vmpstr
2016/04/25 18:27:21
Also... The situation in which this can happen is
cblume
2016/04/27 08:10:36
Done.
|
| + return nullptr; |
| + } |
| + |
| + DrawImage mip_image( |
| + &image, gfx::RectToSkIRect(key.src_rect()), kMedium_SkFilterQuality, |
| + SkMatrix::MakeScale(mipmap_scale.width(), mipmap_scale.height())); |
| + auto mip_key = ImageKey::FromDrawImage(mip_image); |
| + return GetScaledImageDecode(mip_key, image); |
| +} |
| + |
| +std::unique_ptr<SoftwareImageDecodeController::DecodedImage> |
| SoftwareImageDecodeController::DecodeImageInternal( |
| const ImageKey& key, |
| const DrawImage& draw_image) { |
| @@ -379,8 +412,7 @@ SoftwareImageDecodeController::DecodeImageInternal( |
| case kLow_SkFilterQuality: |
| return GetOriginalImageDecode(key, *image); |
| case kMedium_SkFilterQuality: |
| - NOTIMPLEMENTED(); |
| - return nullptr; |
| + return GetMediumQualityImageDecode(key, *image); |
| case kHigh_SkFilterQuality: |
| return GetScaledImageDecode(key, *image); |
| default: |
| @@ -399,9 +431,6 @@ DecodedDrawImage SoftwareImageDecodeController::GetDecodedImageForDraw( |
| if (key.target_size().IsEmpty()) |
| return DecodedDrawImage(nullptr, kNone_SkFilterQuality); |
| - if (!CanHandleImage(key)) |
| - return DecodedDrawImage(draw_image.image(), draw_image.filter_quality()); |
| - |
| return GetDecodedImageForDrawInternal(key, draw_image); |
| } |
| @@ -577,8 +606,8 @@ SoftwareImageDecodeController::GetScaledImageDecode(const ImageKey& key, |
| } |
| SkPixmap scaled_pixmap(scaled_info, scaled_pixels->data(), |
| scaled_info.minRowBytes()); |
| - // TODO(vmpstr): Start handling more than just high filter quality. |
| - DCHECK_EQ(kHigh_SkFilterQuality, key.filter_quality()); |
| + DCHECK(key.filter_quality() == kHigh_SkFilterQuality || |
| + key.filter_quality() == kMedium_SkFilterQuality); |
| { |
| TRACE_EVENT0("disabled-by-default-cc.debug", |
| "SoftwareImageDecodeController::ScaleImage - scale pixels"); |
| @@ -605,7 +634,7 @@ void SoftwareImageDecodeController::DrawWithImageFinished( |
| "SoftwareImageDecodeController::DrawWithImageFinished", "key", |
| ImageKey::FromDrawImage(image).ToString()); |
| ImageKey key = ImageKey::FromDrawImage(image); |
| - if (!decoded_image.image() || !CanHandleImage(key)) |
| + if (!decoded_image.image()) |
| return; |
| if (decoded_image.is_at_raster_decode()) |
| @@ -672,11 +701,6 @@ void SoftwareImageDecodeController::UnrefAtRasterImage(const ImageKey& key) { |
| } |
| } |
| -bool SoftwareImageDecodeController::CanHandleImage(const ImageKey& key) { |
| - // TODO(vmpstr): Start handling medium filter quality as well. |
| - return key.filter_quality() != kMedium_SkFilterQuality; |
| -} |
| - |
| void SoftwareImageDecodeController::ReduceCacheUsage() { |
| TRACE_EVENT0("cc", "SoftwareImageDecodeController::ReduceCacheUsage"); |
| base::AutoLock lock(lock_); |