Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(913)

Unified Diff: cc/tiles/software_image_decode_controller.cc

Issue 1839833003: Add medium image quality to software predecode. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebasing. Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
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 86d1bb2c5749430e57378a3a8b49f2c00e14fcde..ab51ae5c41cf59ecc5ca8c7b2650af1aaec547d6 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()) {
+ SkScalar y_scale = 1.f;
vmpstr 2016/04/29 19:09:41 nit: i'd just do the math below unconditionally, b
cblume 2016/05/01 01:03:37 I thought I had run into a situation where this ca
+ 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);
vmpstr 2016/04/29 19:09:40 Should this be a NOTREACHED? Is this code called w
cblume 2016/05/01 01:03:37 I changed it to NOTREACHED but in our unit test of
+}
+
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 {
vmpstr 2016/04/29 19:09:40 nit: } else if (...) { } else { }
cblume 2016/05/01 01:03:37 Done.
+ 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) {
@@ -188,25 +237,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, tracing_info));
- }
- *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.
@@ -289,7 +319,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());
@@ -320,20 +349,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);
@@ -390,6 +405,28 @@ void SoftwareImageDecodeController::DecodeImage(const ImageKey& key,
}
std::unique_ptr<SoftwareImageDecodeController::DecodedImage>
+SoftwareImageDecodeController::GetMediumQualityImageDecode(
+ const ImageKey& key,
+ sk_sp<const SkImage> image) {
+ SkSize mipmap_scale = GetMipMapScaleAdjustment(key);
+ // -1 represents an invalid scale.
+ // So add 1 and compare to epsilon.
vmpstr 2016/04/29 19:09:40 Comment is still wrong :)
cblume 2016/05/01 01:03:37 Oops. I could have sworn I fixed that.
+ if (mipmap_scale.width() <= 0.f || mipmap_scale.height() <= 0.f) {
vmpstr 2016/04/29 19:09:40 Can this be a DCHECK instead? That is, are there c
cblume 2016/05/01 01:03:37 This is similar to the NOTREACHED thing above. Whe
cblume 2016/05/01 22:51:27 I switched this over to a DCHECK since it is separ
+ return nullptr;
+ }
+
+ if (mipmap_scale.width() == 1.f && mipmap_scale.height() == 1.f) {
+ return GetOriginalImageDecode(key, std::move(image));
+ } else {
+ 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, std::move(image));
+ }
+}
+
+std::unique_ptr<SoftwareImageDecodeController::DecodedImage>
SoftwareImageDecodeController::DecodeImageInternal(
const ImageKey& key,
const DrawImage& draw_image) {
@@ -405,8 +442,7 @@ SoftwareImageDecodeController::DecodeImageInternal(
case kLow_SkFilterQuality:
return GetOriginalImageDecode(key, std::move(image));
case kMedium_SkFilterQuality:
- NOTIMPLEMENTED();
- return nullptr;
+ return GetMediumQualityImageDecode(key, std::move(image));
vmpstr 2016/04/29 19:09:40 I'm a bit concerned about the fact that key and ke
cblume 2016/05/01 01:03:37 You are completely correct. This should be fixed n
case kHigh_SkFilterQuality:
return GetScaledImageDecode(key, std::move(image));
default:
@@ -425,9 +461,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);
}
@@ -605,8 +638,8 @@ SoftwareImageDecodeController::GetScaledImageDecode(
}
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");
@@ -633,7 +666,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())
@@ -700,11 +733,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_);

Powered by Google App Engine
This is Rietveld 408576698