aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/SkBitmapScaler.cpp
diff options
context:
space:
mode:
authorGravatar caryclark <caryclark@google.com>2016-01-12 10:44:02 -0800
committerGravatar Commit bot <commit-bot@chromium.org>2016-01-12 10:44:02 -0800
commit368342ccb5b88568974f66d1a36bbec667efcc4e (patch)
tree89e8d22eed8f067ad48c4dc5052f89df7b422ed4 /src/core/SkBitmapScaler.cpp
parent05dcb4c7a9fe350af495e4cc53f8ad0cc9b79052 (diff)
Refactor resize filter to go faster
Part of this CL improves the speed by using dynamic arrays more effectively. Part uses SIMD and more concise float expressions for speed. Some unused code was deleted. The latter changes are guarded by: SK_SUPPORT_LEGACY_BITMAP_FILTER until this lands and the corresponding layout changes in chrome can be relanded. With the legacy flag defined, no Skia or Chrome test results change. Without the flag defined in Skia, only 0.01% - 0.02% of the pixels change, and then by (1,1,1) in 8888. codereview.chromium.org/1583533002 adds the guard to Chrome. R=reed@google.com BUG=skia:2261 GOLD_TRYBOT_URL= https://gold.skia.org/search2?unt=true&query=source_type%3Dgm&master=false&issue=1563183003 Review URL: https://codereview.chromium.org/1563183003
Diffstat (limited to 'src/core/SkBitmapScaler.cpp')
-rw-r--r--src/core/SkBitmapScaler.cpp113
1 files changed, 76 insertions, 37 deletions
diff --git a/src/core/SkBitmapScaler.cpp b/src/core/SkBitmapScaler.cpp
index 965955a2dc..44ed83c8a2 100644
--- a/src/core/SkBitmapScaler.cpp
+++ b/src/core/SkBitmapScaler.cpp
@@ -11,7 +11,6 @@
#include "SkImageInfo.h"
#include "SkPixmap.h"
#include "SkRect.h"
-#include "SkScalar.h"
#include "SkTArray.h"
// SkResizeFilter ----------------------------------------------------------------
@@ -74,7 +73,7 @@ SkResizeFilter::SkResizeFilter(SkBitmapScaler::ResizeMethod method,
fBitmapFilter = new SkTriangleFilter;
break;
case SkBitmapScaler::RESIZE_MITCHELL:
- fBitmapFilter = new SkMitchellFilter(1.f / 3.f, 1.f / 3.f);
+ fBitmapFilter = new SkMitchellFilter;
break;
case SkBitmapScaler::RESIZE_HAMMING:
fBitmapFilter = new SkHammingFilter;
@@ -130,45 +129,65 @@ void SkResizeFilter::computeFilters(int srcSize,
// to support the filtering function.
float srcSupport = fBitmapFilter->width() / clampedScale;
- // Speed up the divisions below by turning them into multiplies.
float invScale = 1.0f / scale;
- SkTArray<float> filterValues(64);
- SkTArray<short> fixedFilterValues(64);
+ SkSTArray<64, float, true> filterValuesArray;
+ SkSTArray<64, SkConvolutionFilter1D::ConvolutionFixed, true> fixedFilterValuesArray;
// Loop over all pixels in the output range. We will generate one set of
// filter values for each one. Those values will tell us how to blend the
// source pixels to compute the destination pixel.
- for (int destSubsetI = SkScalarFloorToInt(destSubsetLo); destSubsetI < SkScalarCeilToInt(destSubsetHi);
- destSubsetI++) {
- // Reset the arrays. We don't declare them inside so they can re-use the
- // same malloc-ed buffer.
- filterValues.reset();
- fixedFilterValues.reset();
-
- // This is the pixel in the source directly under the pixel in the dest.
- // Note that we base computations on the "center" of the pixels. To see
- // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
- // downscale should "cover" the pixels around the pixel with *its center*
- // at coordinates (2.5, 2.5) in the source, not those around (0, 0).
- // Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
- float srcPixel = (static_cast<float>(destSubsetI) + 0.5f) * invScale;
+ // This is the pixel in the source directly under the pixel in the dest.
+ // Note that we base computations on the "center" of the pixels. To see
+ // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
+ // downscale should "cover" the pixels around the pixel with *its center*
+ // at coordinates (2.5, 2.5) in the source, not those around (0, 0).
+ // Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
+#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
+ int destLimit = SkScalarTruncToInt(SkScalarCeilToScalar(destSubsetHi)
+ - SkScalarFloorToScalar(destSubsetLo));
+#else
+ destSubsetLo = SkScalarFloorToScalar(destSubsetLo);
+ destSubsetHi = SkScalarCeilToScalar(destSubsetHi);
+ float srcPixel = (destSubsetLo + 0.5f) * invScale;
+ int destLimit = SkScalarTruncToInt(destSubsetHi - destSubsetLo);
+#endif
+ output->reserveAdditional(destLimit, SkScalarCeilToInt(destLimit * srcSupport * 2));
+#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
+ for (int destSubsetI = SkScalarFloorToInt(destSubsetLo); destSubsetI < SkScalarCeilToInt(destSubsetHi);
+ destSubsetI++)
+#else
+ for (int destI = 0; destI < destLimit; srcPixel += invScale, destI++)
+#endif
+ {
// Compute the (inclusive) range of source pixels the filter covers.
+#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
+ float srcPixel = (static_cast<float>(destSubsetI) + 0.5f) * invScale;
int srcBegin = SkTMax(0, SkScalarFloorToInt(srcPixel - srcSupport));
int srcEnd = SkTMin(srcSize - 1, SkScalarCeilToInt(srcPixel + srcSupport));
+#else
+ float srcBegin = SkTMax(0.f, SkScalarFloorToScalar(srcPixel - srcSupport));
+ float srcEnd = SkTMin(srcSize - 1.f, SkScalarCeilToScalar(srcPixel + srcSupport));
+#endif
// Compute the unnormalized filter value at each location of the source
// it covers.
+#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
float filterSum = 0.0f; // Sub of the filter values for normalizing.
+ int filterCount = srcEnd - srcBegin + 1;
+ filterValuesArray.reset(filterCount);
for (int curFilterPixel = srcBegin; curFilterPixel <= srcEnd;
curFilterPixel++) {
- // Distance from the center of the filter, this is the filter coordinate
- // in source space. We also need to consider the center of the pixel
- // when comparing distance against 'srcPixel'. In the 5x downscale
- // example used above the distance from the center of the filter to
- // the pixel with coordinates (2, 2) should be 0, because its center
- // is at (2.5, 2.5).
+#endif
+ // Sum of the filter values for normalizing.
+ // Distance from the center of the filter, this is the filter coordinate
+ // in source space. We also need to consider the center of the pixel
+ // when comparing distance against 'srcPixel'. In the 5x downscale
+ // example used above the distance from the center of the filter to
+ // the pixel with coordinates (2, 2) should be 0, because its center
+ // is at (2.5, 2.5).
+#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
float srcFilterDist =
((static_cast<float>(curFilterPixel) + 0.5f) - srcPixel);
@@ -177,36 +196,56 @@ void SkResizeFilter::computeFilters(int srcSize,
// Compute the filter value at that location.
float filterValue = fBitmapFilter->evaluate(destFilterDist);
- filterValues.push_back(filterValue);
+ filterValuesArray[curFilterPixel - srcBegin] = filterValue;
filterSum += filterValue;
}
- SkASSERT(!filterValues.empty());
-
+#else
+ float destFilterDist = (srcBegin + 0.5f - srcPixel) * clampedScale;
+ int filterCount = SkScalarTruncToInt(srcEnd - srcBegin) + 1;
+ SkASSERT(filterCount > 0);
+ filterValuesArray.reset(filterCount);
+ float filterSum = fBitmapFilter->evaluate_n(destFilterDist, clampedScale, filterCount,
+ filterValuesArray.begin());
+#endif
// The filter must be normalized so that we don't affect the brightness of
// the image. Convert to normalized fixed point.
- short fixedSum = 0;
- for (int i = 0; i < filterValues.count(); i++) {
- short curFixed = output->FloatToFixed(filterValues[i] / filterSum);
+ int fixedSum = 0;
+ fixedFilterValuesArray.reset(filterCount);
+ const float* filterValues = filterValuesArray.begin();
+ SkConvolutionFilter1D::ConvolutionFixed* fixedFilterValues = fixedFilterValuesArray.begin();
+#ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER
+ float invFilterSum = 1 / filterSum;
+#endif
+ for (int fixedI = 0; fixedI < filterCount; fixedI++) {
+#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
+ int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] / filterSum);
+#else
+ int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] * invFilterSum);
+#endif
fixedSum += curFixed;
- fixedFilterValues.push_back(curFixed);
+ fixedFilterValues[fixedI] = SkToS16(curFixed);
}
+ SkASSERT(fixedSum <= 0x7FFF);
// The conversion to fixed point will leave some rounding errors, which
// we add back in to avoid affecting the brightness of the image. We
// arbitrarily add this to the center of the filter array (this won't always
// be the center of the filter function since it could get clipped on the
// edges, but it doesn't matter enough to worry about that case).
- short leftovers = output->FloatToFixed(1.0f) - fixedSum;
- fixedFilterValues[fixedFilterValues.count() / 2] += leftovers;
+ int leftovers = SkConvolutionFilter1D::FloatToFixed(1) - fixedSum;
+ fixedFilterValues[filterCount / 2] += leftovers;
// Now it's ready to go.
- output->AddFilter(srcBegin, &fixedFilterValues[0],
- static_cast<int>(fixedFilterValues.count()));
+#ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
+ output->AddFilter(srcBegin, fixedFilterValues, filterCount);
+#else
+ output->AddFilter(SkScalarFloorToInt(srcBegin), fixedFilterValues, filterCount);
+#endif
}
if (convolveProcs.fApplySIMDPadding) {
- convolveProcs.fApplySIMDPadding( output );
+ convolveProcs.fApplySIMDPadding(output);
}
}