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

Side by Side Diff: src/core/SkBitmapScaler.cpp

Issue 1563183003: Refactor resize filter to go faster (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: make mitchell filter locals conform to skia style Created 4 years, 11 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 unified diff | Download patch
« no previous file with comments | « src/core/SkBitmapFilter.cpp ('k') | src/core/SkConvolver.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2015 Google Inc. 2 * Copyright 2015 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkBitmapScaler.h" 8 #include "SkBitmapScaler.h"
9 #include "SkBitmapFilter.h" 9 #include "SkBitmapFilter.h"
10 #include "SkConvolver.h" 10 #include "SkConvolver.h"
11 #include "SkImageInfo.h" 11 #include "SkImageInfo.h"
12 #include "SkPixmap.h" 12 #include "SkPixmap.h"
13 #include "SkRect.h" 13 #include "SkRect.h"
14 #include "SkScalar.h"
15 #include "SkTArray.h" 14 #include "SkTArray.h"
16 15
17 // SkResizeFilter -------------------------------------------------------------- -- 16 // SkResizeFilter -------------------------------------------------------------- --
18 17
19 // Encapsulates computation and storage of the filters required for one complete 18 // Encapsulates computation and storage of the filters required for one complete
20 // resize operation. 19 // resize operation.
21 class SkResizeFilter { 20 class SkResizeFilter {
22 public: 21 public:
23 SkResizeFilter(SkBitmapScaler::ResizeMethod method, 22 SkResizeFilter(SkBitmapScaler::ResizeMethod method,
24 int srcFullWidth, int srcFullHeight, 23 int srcFullWidth, int srcFullHeight,
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
67 66
68 fBitmapFilter = nullptr; 67 fBitmapFilter = nullptr;
69 switch(method) { 68 switch(method) {
70 case SkBitmapScaler::RESIZE_BOX: 69 case SkBitmapScaler::RESIZE_BOX:
71 fBitmapFilter = new SkBoxFilter; 70 fBitmapFilter = new SkBoxFilter;
72 break; 71 break;
73 case SkBitmapScaler::RESIZE_TRIANGLE: 72 case SkBitmapScaler::RESIZE_TRIANGLE:
74 fBitmapFilter = new SkTriangleFilter; 73 fBitmapFilter = new SkTriangleFilter;
75 break; 74 break;
76 case SkBitmapScaler::RESIZE_MITCHELL: 75 case SkBitmapScaler::RESIZE_MITCHELL:
77 fBitmapFilter = new SkMitchellFilter(1.f / 3.f, 1.f / 3.f); 76 fBitmapFilter = new SkMitchellFilter;
78 break; 77 break;
79 case SkBitmapScaler::RESIZE_HAMMING: 78 case SkBitmapScaler::RESIZE_HAMMING:
80 fBitmapFilter = new SkHammingFilter; 79 fBitmapFilter = new SkHammingFilter;
81 break; 80 break;
82 case SkBitmapScaler::RESIZE_LANCZOS3: 81 case SkBitmapScaler::RESIZE_LANCZOS3:
83 fBitmapFilter = new SkLanczosFilter; 82 fBitmapFilter = new SkLanczosFilter;
84 break; 83 break;
85 } 84 }
86 85
87 86
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
123 // means the destination pixels are much smaller than the source pixels, and 122 // means the destination pixels are much smaller than the source pixels, and
124 // that the range covered by the filter won't necessarily cover any source 123 // that the range covered by the filter won't necessarily cover any source
125 // pixel boundaries. Therefore, we use these clamped values (max of 1) for 124 // pixel boundaries. Therefore, we use these clamped values (max of 1) for
126 // some computations. 125 // some computations.
127 float clampedScale = SkTMin(1.0f, scale); 126 float clampedScale = SkTMin(1.0f, scale);
128 127
129 // This is how many source pixels from the center we need to count 128 // This is how many source pixels from the center we need to count
130 // to support the filtering function. 129 // to support the filtering function.
131 float srcSupport = fBitmapFilter->width() / clampedScale; 130 float srcSupport = fBitmapFilter->width() / clampedScale;
132 131
133 // Speed up the divisions below by turning them into multiplies.
134 float invScale = 1.0f / scale; 132 float invScale = 1.0f / scale;
135 133
136 SkTArray<float> filterValues(64); 134 SkSTArray<64, float, true> filterValuesArray;
137 SkTArray<short> fixedFilterValues(64); 135 SkSTArray<64, SkConvolutionFilter1D::ConvolutionFixed, true> fixedFilterValues Array;
138 136
139 // Loop over all pixels in the output range. We will generate one set of 137 // Loop over all pixels in the output range. We will generate one set of
140 // filter values for each one. Those values will tell us how to blend the 138 // filter values for each one. Those values will tell us how to blend the
141 // source pixels to compute the destination pixel. 139 // source pixels to compute the destination pixel.
140
141 // This is the pixel in the source directly under the pixel in the dest.
142 // Note that we base computations on the "center" of the pixels. To see
143 // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
144 // downscale should "cover" the pixels around the pixel with *its center*
145 // at coordinates (2.5, 2.5) in the source, not those around (0, 0).
146 // Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
147 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
148 int destLimit = SkScalarTruncToInt(SkScalarCeilToScalar(destSubsetHi)
149 - SkScalarFloorToScalar(destSubsetLo));
150 #else
151 destSubsetLo = SkScalarFloorToScalar(destSubsetLo);
152 destSubsetHi = SkScalarCeilToScalar(destSubsetHi);
153 float srcPixel = (destSubsetLo + 0.5f) * invScale;
154 int destLimit = SkScalarTruncToInt(destSubsetHi - destSubsetLo);
155 #endif
156 output->reserveAdditional(destLimit, SkScalarCeilToInt(destLimit * srcSupport * 2));
157 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
142 for (int destSubsetI = SkScalarFloorToInt(destSubsetLo); destSubsetI < SkScala rCeilToInt(destSubsetHi); 158 for (int destSubsetI = SkScalarFloorToInt(destSubsetLo); destSubsetI < SkScala rCeilToInt(destSubsetHi);
143 destSubsetI++) { 159 destSubsetI++)
144 // Reset the arrays. We don't declare them inside so they can re-use the 160 #else
145 // same malloc-ed buffer. 161 for (int destI = 0; destI < destLimit; srcPixel += invScale, destI++)
146 filterValues.reset(); 162 #endif
147 fixedFilterValues.reset(); 163 {
148 164 // Compute the (inclusive) range of source pixels the filter covers.
149 // This is the pixel in the source directly under the pixel in the dest. 165 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
150 // Note that we base computations on the "center" of the pixels. To see
151 // why, observe that the destination pixel at coordinates (0, 0) in a 5.0x
152 // downscale should "cover" the pixels around the pixel with *its center*
153 // at coordinates (2.5, 2.5) in the source, not those around (0, 0).
154 // Hence we need to scale coordinates (0.5, 0.5), not (0, 0).
155 float srcPixel = (static_cast<float>(destSubsetI) + 0.5f) * invScale; 166 float srcPixel = (static_cast<float>(destSubsetI) + 0.5f) * invScale;
156
157 // Compute the (inclusive) range of source pixels the filter covers.
158 int srcBegin = SkTMax(0, SkScalarFloorToInt(srcPixel - srcSupport)); 167 int srcBegin = SkTMax(0, SkScalarFloorToInt(srcPixel - srcSupport));
159 int srcEnd = SkTMin(srcSize - 1, SkScalarCeilToInt(srcPixel + srcSupport)); 168 int srcEnd = SkTMin(srcSize - 1, SkScalarCeilToInt(srcPixel + srcSupport));
169 #else
170 float srcBegin = SkTMax(0.f, SkScalarFloorToScalar(srcPixel - srcSupport));
171 float srcEnd = SkTMin(srcSize - 1.f, SkScalarCeilToScalar(srcPixel + srcSupp ort));
172 #endif
160 173
161 // Compute the unnormalized filter value at each location of the source 174 // Compute the unnormalized filter value at each location of the source
162 // it covers. 175 // it covers.
176 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
163 float filterSum = 0.0f; // Sub of the filter values for normalizing. 177 float filterSum = 0.0f; // Sub of the filter values for normalizing.
178 int filterCount = srcEnd - srcBegin + 1;
179 filterValuesArray.reset(filterCount);
164 for (int curFilterPixel = srcBegin; curFilterPixel <= srcEnd; 180 for (int curFilterPixel = srcBegin; curFilterPixel <= srcEnd;
165 curFilterPixel++) { 181 curFilterPixel++) {
166 // Distance from the center of the filter, this is the filter coordinate 182 #endif
167 // in source space. We also need to consider the center of the pixel 183 // Sum of the filter values for normalizing.
168 // when comparing distance against 'srcPixel'. In the 5x downscale 184 // Distance from the center of the filter, this is the filter coordinate
169 // example used above the distance from the center of the filter to 185 // in source space. We also need to consider the center of the pixel
170 // the pixel with coordinates (2, 2) should be 0, because its center 186 // when comparing distance against 'srcPixel'. In the 5x downscale
171 // is at (2.5, 2.5). 187 // example used above the distance from the center of the filter to
188 // the pixel with coordinates (2, 2) should be 0, because its center
189 // is at (2.5, 2.5).
190 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
172 float srcFilterDist = 191 float srcFilterDist =
173 ((static_cast<float>(curFilterPixel) + 0.5f) - srcPixel); 192 ((static_cast<float>(curFilterPixel) + 0.5f) - srcPixel);
174 193
175 // Since the filter really exists in dest space, map it there. 194 // Since the filter really exists in dest space, map it there.
176 float destFilterDist = srcFilterDist * clampedScale; 195 float destFilterDist = srcFilterDist * clampedScale;
177 196
178 // Compute the filter value at that location. 197 // Compute the filter value at that location.
179 float filterValue = fBitmapFilter->evaluate(destFilterDist); 198 float filterValue = fBitmapFilter->evaluate(destFilterDist);
180 filterValues.push_back(filterValue); 199 filterValuesArray[curFilterPixel - srcBegin] = filterValue;
181 200
182 filterSum += filterValue; 201 filterSum += filterValue;
183 } 202 }
184 SkASSERT(!filterValues.empty()); 203 #else
185 204 float destFilterDist = (srcBegin + 0.5f - srcPixel) * clampedScale;
205 int filterCount = SkScalarTruncToInt(srcEnd - srcBegin) + 1;
206 SkASSERT(filterCount > 0);
207 filterValuesArray.reset(filterCount);
208 float filterSum = fBitmapFilter->evaluate_n(destFilterDist, clampedScale, fi lterCount,
209 filterValuesArray.begin());
210 #endif
186 // The filter must be normalized so that we don't affect the brightness of 211 // The filter must be normalized so that we don't affect the brightness of
187 // the image. Convert to normalized fixed point. 212 // the image. Convert to normalized fixed point.
188 short fixedSum = 0; 213 int fixedSum = 0;
189 for (int i = 0; i < filterValues.count(); i++) { 214 fixedFilterValuesArray.reset(filterCount);
190 short curFixed = output->FloatToFixed(filterValues[i] / filterSum); 215 const float* filterValues = filterValuesArray.begin();
216 SkConvolutionFilter1D::ConvolutionFixed* fixedFilterValues = fixedFilterValu esArray.begin();
217 #ifndef SK_SUPPORT_LEGACY_BITMAP_FILTER
218 float invFilterSum = 1 / filterSum;
219 #endif
220 for (int fixedI = 0; fixedI < filterCount; fixedI++) {
221 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
222 int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] / filterSum);
223 #else
224 int curFixed = SkConvolutionFilter1D::FloatToFixed(filterValues[fixedI] * invFilterSum);
225 #endif
191 fixedSum += curFixed; 226 fixedSum += curFixed;
192 fixedFilterValues.push_back(curFixed); 227 fixedFilterValues[fixedI] = SkToS16(curFixed);
193 } 228 }
229 SkASSERT(fixedSum <= 0x7FFF);
194 230
195 // The conversion to fixed point will leave some rounding errors, which 231 // The conversion to fixed point will leave some rounding errors, which
196 // we add back in to avoid affecting the brightness of the image. We 232 // we add back in to avoid affecting the brightness of the image. We
197 // arbitrarily add this to the center of the filter array (this won't always 233 // arbitrarily add this to the center of the filter array (this won't always
198 // be the center of the filter function since it could get clipped on the 234 // be the center of the filter function since it could get clipped on the
199 // edges, but it doesn't matter enough to worry about that case). 235 // edges, but it doesn't matter enough to worry about that case).
200 short leftovers = output->FloatToFixed(1.0f) - fixedSum; 236 int leftovers = SkConvolutionFilter1D::FloatToFixed(1) - fixedSum;
201 fixedFilterValues[fixedFilterValues.count() / 2] += leftovers; 237 fixedFilterValues[filterCount / 2] += leftovers;
202 238
203 // Now it's ready to go. 239 // Now it's ready to go.
204 output->AddFilter(srcBegin, &fixedFilterValues[0], 240 #ifdef SK_SUPPORT_LEGACY_BITMAP_FILTER
205 static_cast<int>(fixedFilterValues.count())); 241 output->AddFilter(srcBegin, fixedFilterValues, filterCount);
242 #else
243 output->AddFilter(SkScalarFloorToInt(srcBegin), fixedFilterValues, filterCou nt);
244 #endif
206 } 245 }
207 246
208 if (convolveProcs.fApplySIMDPadding) { 247 if (convolveProcs.fApplySIMDPadding) {
209 convolveProcs.fApplySIMDPadding( output ); 248 convolveProcs.fApplySIMDPadding(output);
210 } 249 }
211 } 250 }
212 251
213 bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeM ethod method, 252 bool SkBitmapScaler::Resize(SkBitmap* resultPtr, const SkPixmap& source, ResizeM ethod method,
214 int destWidth, int destHeight, SkBitmap::Allocator* allocator) { 253 int destWidth, int destHeight, SkBitmap::Allocator* allocator) {
215 if (nullptr == source.addr() || source.colorType() != kN32_SkColorType || 254 if (nullptr == source.addr() || source.colorType() != kN32_SkColorType ||
216 source.width() < 1 || source.height() < 1) 255 source.width() < 1 || source.height() < 1)
217 { 256 {
218 return false; 257 return false;
219 } 258 }
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
252 convolveProcs, true)) { 291 convolveProcs, true)) {
253 return false; 292 return false;
254 } 293 }
255 294
256 *resultPtr = result; 295 *resultPtr = result;
257 resultPtr->lockPixels(); 296 resultPtr->lockPixels();
258 SkASSERT(resultPtr->getPixels()); 297 SkASSERT(resultPtr->getPixels());
259 return true; 298 return true;
260 } 299 }
261 300
OLDNEW
« no previous file with comments | « src/core/SkBitmapFilter.cpp ('k') | src/core/SkConvolver.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698