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

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

Issue 1705203002: Add bilerp filtering. (Closed) Base URL: https://skia.googlesource.com/skia.git@fp-simple-linear-20160217
Patch Set: Created 4 years, 10 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/SkLinearBitmapPipeline.h ('k') | tests/SkLinearBitmapPipelineTest.cpp » ('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 2016 Google Inc. 2 * Copyright 2016 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 "SkLinearBitmapPipeline.h" 8 #include "SkLinearBitmapPipeline.h"
9 9
10 struct X { 10 struct X {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
48 Sk4f newYs = ys; 48 Sk4f newYs = ys;
49 fStrategy.processPoints(&newXs, &newYs); 49 fStrategy.processPoints(&newXs, &newYs);
50 fNext->pointList4(newXs, newYs); 50 fNext->pointList4(newXs, newYs);
51 } 51 }
52 52
53 private: 53 private:
54 Next* const fNext; 54 Next* const fNext;
55 Strategy fStrategy; 55 Strategy fStrategy;
56 }; 56 };
57 57
58 class SkippedStage final : public PointProcessorInterface { 58 template<typename Strategy, typename Next>
59 class BilerpProcessor : public BilerpProcessorInterface {
mtklein 2016/02/17 20:25:09 final (and PointProcessor too)?
herb_g 2016/02/17 23:40:43 Done.
60 public:
61 template <typename... Args>
62 BilerpProcessor(Next* next, Args&&... args)
63 : fNext{next}
64 , fStrategy{std::forward<Args>(args)...}{ }
65
59 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { 66 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
60 SkFAIL("Abort tiler."); 67 Sk4f newXs = xs;
mtklein 2016/02/17 20:25:09 This is so sad. :(
herb_g 2016/02/17 23:40:44 Acknowledged.
68 Sk4f newYs = ys;
69 fStrategy.processPoints(&newXs, &newYs);
70 fNext->pointListFew(n, newXs, newYs);
71 }
72
73 void pointList4(Sk4fArg xs, Sk4fArg ys) override {
74 Sk4f newXs = xs;
75 Sk4f newYs = ys;
76 fStrategy.processPoints(&newXs, &newYs);
77 fNext->pointList4(newXs, newYs);
78 }
79
80 void bilerpList(Sk4fArg xs, Sk4fArg ys) override {
81 Sk4f newXs = xs;
82 Sk4f newYs = ys;
83 fStrategy.processPoints(&newXs, &newYs);
84 fNext->bilerpList(newXs, newYs);
85 }
86
87 private:
88 Next* const fNext;
89 Strategy fStrategy;
90 };
91
92 class SkippedStage final : public BilerpProcessorInterface {
93 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
94 SkFAIL("Skipped stage.");
61 } 95 }
62 void pointList4(Sk4fArg Xs, Sk4fArg Ys) override { 96 void pointList4(Sk4fArg Xs, Sk4fArg Ys) override {
63 SkFAIL("Abort point processor."); 97 SkFAIL("Skipped stage.");
98 }
99 virtual void bilerpList(Sk4fArg xs, Sk4fArg ys) override {
mtklein 2016/02/17 20:25:09 I think override's plenty.
herb_g 2016/02/17 23:40:44 Done.
100 SkFAIL("Skipped stage.");
64 } 101 }
65 }; 102 };
66 103
67 class TranslateMatrixStrategy { 104 class TranslateMatrixStrategy {
68 public: 105 public:
69 TranslateMatrixStrategy(SkVector offset) 106 TranslateMatrixStrategy(SkVector offset)
70 : fXOffset{X(offset)} 107 : fXOffset{X(offset)}
71 , fYOffset{Y(offset)} { } 108 , fYOffset{Y(offset)} { }
72 void processPoints(Sk4f* xs, Sk4f* ys) { 109 void processPoints(Sk4f* xs, Sk4f* ys) {
73 *xs = *xs + fXOffset; 110 *xs = *xs + fXOffset;
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after
140 matrixProc->Initialize<TranslateMatrix<>>( 177 matrixProc->Initialize<TranslateMatrix<>>(
141 next, 178 next,
142 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); 179 SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
143 } else { 180 } else {
144 matrixProc->Initialize<SkippedStage>(); 181 matrixProc->Initialize<SkippedStage>();
145 return next; 182 return next;
146 } 183 }
147 return matrixProc->get(); 184 return matrixProc->get();
148 } 185 }
149 186
187 template <typename Next = BilerpProcessorInterface>
188 class ExpandBilerp final : public PointProcessorInterface {
189 public:
190 ExpandBilerp(Next* next) : fNext{next} { }
191
192 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
193 SkASSERT(n > 0 && n <= 4);
mtklein 2016/02/17 20:25:09 This seems awkward. It's a bug if we call pointLi
herb_g 2016/02/17 23:40:43 Done.
194 if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYO ffsets);
195 if (n >= 2) fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYO ffsets);
196 if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYO ffsets);
197 if (n == 4) fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYO ffsets);
198 }
199
200 void pointList4(Sk4fArg xs, Sk4fArg ys) override {
201 pointListFew(4, xs, ys);
mtklein 2016/02/17 20:25:09 self calls usually have a this->
herb_g 2016/02/17 23:40:44 Removed
202 }
mtklein 2016/02/17 20:25:09 Is this why we distinguish PointProcessor and Bile
herb_g 2016/02/17 23:40:44 There is no sensible bilerp here or at the matrix
203
204 private:
205 static const Sk4f kXOffsets;
206 static const Sk4f kYOffsets;
207 Next* const fNext;
208 };
209
210 template <typename Next>
211 const Sk4f ExpandBilerp<Next>::kXOffsets = {0.0f, 1.0f, 0.0f, 1.0f};
mtklein 2016/02/17 20:25:09 This is all sort of awkward and boilerplate-y. Le
herb_g 2016/02/17 23:40:43 Done.
212 template <typename Next>
213 const Sk4f ExpandBilerp<Next>::kYOffsets = {0.0f, 0.0f, 1.0f, 1.0f};
214
215 static PointProcessorInterface* choose_filter(
216 BilerpProcessorInterface* next,
217 SkFilterQuality filterQuailty,
218 SkLinearBitmapPipeline::FilterStage* filterProc) {
219 if (filterQuailty >= SkFilterQuality::kLow_SkFilterQuality) {
mtklein 2016/02/17 20:25:09 Might wanna write as: none -> skipped else -
herb_g 2016/02/17 23:40:43 Done.
220 filterProc->Initialize<ExpandBilerp<>>(next);
221 return filterProc->get();
222 } else {
223 filterProc->Initialize<SkippedStage>();
224 return next;
225 }
226 }
227
150 class ClampStrategy { 228 class ClampStrategy {
151 public: 229 public:
152 ClampStrategy(X max) 230 ClampStrategy(X max)
153 : fXMin{0.0f} 231 : fXMin{0.0f}
154 , fXMax{max - 1.0f} { } 232 , fXMax{max - 1.0f} { }
155 ClampStrategy(Y max) 233 ClampStrategy(Y max)
156 : fYMin{0.0f} 234 : fYMin{0.0f}
157 , fYMax{max - 1.0f} { } 235 , fYMax{max - 1.0f} { }
158 ClampStrategy(SkSize max) 236 ClampStrategy(SkSize max)
159 : fXMin{0.0f} 237 : fXMin{0.0f}
160 , fYMin{0.0f} 238 , fYMin{0.0f}
161 , fXMax{X(max) - 1.0f} 239 , fXMax{X(max) - 1.0f}
162 , fYMax{Y(max) - 1.0f} { } 240 , fYMax{Y(max) - 1.0f} { }
163 241
164 void processPoints(Sk4f* xs, Sk4f* ys) { 242 void processPoints(Sk4f* xs, Sk4f* ys) {
165 *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax); 243 *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax);
166 *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax); 244 *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax);
167 } 245 }
168 246
169 private: 247 private:
170 const Sk4f fXMin{SK_FloatNegativeInfinity}; 248 const Sk4f fXMin{SK_FloatNegativeInfinity};
171 const Sk4f fYMin{SK_FloatNegativeInfinity}; 249 const Sk4f fYMin{SK_FloatNegativeInfinity};
172 const Sk4f fXMax{SK_FloatInfinity}; 250 const Sk4f fXMax{SK_FloatInfinity};
173 const Sk4f fYMax{SK_FloatInfinity}; 251 const Sk4f fYMax{SK_FloatInfinity};
174 }; 252 };
175 template <typename Next = PointProcessorInterface> 253 template <typename Next = BilerpProcessorInterface>
176 using Clamp = PointProcessor<ClampStrategy, Next>; 254 using Clamp = BilerpProcessor<ClampStrategy, Next>;
177 255
178 class RepeatStrategy { 256 class RepeatStrategy {
179 public: 257 public:
180 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } 258 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { }
181 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } 259 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { }
182 RepeatStrategy(SkSize max) 260 RepeatStrategy(SkSize max)
183 : fXMax{X(max)} 261 : fXMax{X(max)}
184 , fXInvMax{1.0f / X(max)} 262 , fXInvMax{1.0f / X(max)}
185 , fYMax{Y(max)} 263 , fYMax{Y(max)}
186 , fYInvMax{1.0f / Y(max)} { } 264 , fYInvMax{1.0f / Y(max)} { }
187 265
188 void processPoints(Sk4f* xs, Sk4f* ys) { 266 void processPoints(Sk4f* xs, Sk4f* ys) {
189 Sk4f divX = (*xs * fXInvMax).floor(); 267 Sk4f divX = (*xs * fXInvMax).floor();
190 Sk4f divY = (*ys * fYInvMax).floor(); 268 Sk4f divY = (*ys * fYInvMax).floor();
191 Sk4f baseX = (divX * fXMax); 269 Sk4f baseX = (divX * fXMax);
192 Sk4f baseY = (divY * fYMax); 270 Sk4f baseY = (divY * fYMax);
193 *xs = *xs - baseX; 271 *xs = *xs - baseX;
194 *ys = *ys - baseY; 272 *ys = *ys - baseY;
195 } 273 }
196 274
197 private: 275 private:
198 const Sk4f fXMax{0.0f}; 276 const Sk4f fXMax{0.0f};
199 const Sk4f fXInvMax{0.0f}; 277 const Sk4f fXInvMax{0.0f};
200 const Sk4f fYMax{0.0f}; 278 const Sk4f fYMax{0.0f};
201 const Sk4f fYInvMax{0.0f}; 279 const Sk4f fYInvMax{0.0f};
202 }; 280 };
203 281
204 template <typename Next = PointProcessorInterface> 282 template <typename Next = BilerpProcessorInterface>
205 using Repeat = PointProcessor<RepeatStrategy, Next>; 283 using Repeat = BilerpProcessor<RepeatStrategy, Next>;
206 284
207 static PointProcessorInterface* choose_tiler( 285 static BilerpProcessorInterface* choose_tiler(
208 PointProcessorInterface* next, 286 BilerpProcessorInterface* next,
209 SkSize dimensions, 287 SkSize dimensions,
210 SkShader::TileMode xMode, 288 SkShader::TileMode xMode,
211 SkShader::TileMode yMode, 289 SkShader::TileMode yMode,
212 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth, 290 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth,
213 SkLinearBitmapPipeline::TileStage* tileProcY) { 291 SkLinearBitmapPipeline::TileStage* tileProcY) {
214 if (xMode == yMode) { 292 if (xMode == yMode) {
215 switch (xMode) { 293 switch (xMode) {
216 case SkShader::kClamp_TileMode: 294 case SkShader::kClamp_TileMode:
217 tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions); 295 tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions);
218 break; 296 break;
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
300 pixel = pixel * Sk4f{1.0f/255.0f}; 378 pixel = pixel * Sk4f{1.0f/255.0f};
301 if (colorProfile == kSRGB_SkColorProfileType) { 379 if (colorProfile == kSRGB_SkColorProfileType) {
302 pixel = sRGBFast::sRGBToLinear(pixel); 380 pixel = sRGBFast::sRGBToLinear(pixel);
303 } 381 }
304 return pixel; 382 return pixel;
305 } 383 }
306 const uint32_t* const fSrc; 384 const uint32_t* const fSrc;
307 const Sk4i fWidth; 385 const Sk4i fWidth;
308 }; 386 };
309 387
388 inline Sk4f bilerp4(SkPoint pt, Sk4f pixel00, Sk4f pixel01,
mtklein 2016/02/17 20:25:09 It's a good habit to get into writing static on al
herb_g 2016/02/17 23:40:44 Done.
389 Sk4f pixel10, Sk4f pixel11) {
390 Sk4f Xs{X(pt) - std::floor(X(pt))};
mtklein 2016/02/17 20:25:09 If we're using std:: stuff, might want to consider
herb_g 2016/02/17 23:40:43 Redid whole function.
391 Sk4f Ys{Y(pt) - std::floor(Y(pt))};
392 Sk4f XYs{Xs * Ys};
393 Sk4f sum = pixel11 * XYs;
394 sum = sum + pixel01 * (Xs - XYs);
395 sum = sum + pixel10 * (Ys - XYs);
396 sum = sum + pixel00 * (Sk4f{1.0f} - Xs - Ys + XYs);
mtklein 2016/02/17 20:25:09 This would be a really great place for an ASCII ar
herb_g 2016/02/17 23:40:43 Done.
397 return sum;
398 }
399
310 template <typename SourceStrategy> 400 template <typename SourceStrategy>
311 class Sampler final : public PointProcessorInterface { 401 class Sampler final : public BilerpProcessorInterface {
312 public: 402 public:
313 template <typename... Args> 403 template <typename... Args>
314 Sampler(PixelPlacerInterface* next, Args&&... args) 404 Sampler(PixelPlacerInterface* next, Args&&... args)
315 : fNext{next} 405 : fNext{next}
316 , fStrategy{std::forward<Args>(args)...} { } 406 , fStrategy{std::forward<Args>(args)...} { }
317 407
318 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override { 408 void pointListFew(int n, Sk4fArg xs, Sk4fArg ys) override {
319 SkASSERT(0 < n && n < 4); 409 SkASSERT(0 < n && n < 4);
320 Sk4f px0, px1, px2; 410 Sk4f px0, px1, px2;
321 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); 411 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2);
322 if (n >= 1) fNext->placePixel(px0); 412 if (n >= 1) fNext->placePixel(px0);
323 if (n >= 2) fNext->placePixel(px1); 413 if (n >= 2) fNext->placePixel(px1);
324 if (n >= 3) fNext->placePixel(px2); 414 if (n >= 3) fNext->placePixel(px2);
325 } 415 }
326 416
327 void pointList4(Sk4fArg xs, Sk4fArg ys) override { 417 void pointList4(Sk4fArg xs, Sk4fArg ys) override {
328 Sk4f px0, px1, px2, px3; 418 Sk4f px0, px1, px2, px3;
329 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); 419 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
330 fNext->place4Pixels(px0, px1, px2, px3); 420 fNext->place4Pixels(px0, px1, px2, px3);
331 } 421 }
332 422
423 void bilerpList(Sk4fArg xs, Sk4fArg ys) override {
424 SkPoint referencePoint{xs[0], ys[0]};
mtklein 2016/02/17 20:25:09 Do these all have the same fractional parts? I'm
herb_g 2016/02/17 23:40:43 Done.
425 Sk4f px0, px1, px2, px3;
426 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
427 Sk4f pixel = bilerp4(referencePoint, px0, px1, px2, px3);
428 fNext->placePixel(pixel);
429 }
430
333 private: 431 private:
334 PixelPlacerInterface* const fNext; 432 PixelPlacerInterface* const fNext;
335 SourceStrategy fStrategy; 433 SourceStrategy fStrategy;
336 }; 434 };
337 435
338 static PointProcessorInterface* choose_pixel_sampler( 436 static BilerpProcessorInterface* choose_pixel_sampler(
339 PixelPlacerInterface* next, 437 PixelPlacerInterface* next,
340 const SkImageInfo& imageInfo, 438 const SkImageInfo& imageInfo,
341 const void* imageData, 439 const void* imageData,
342 SkLinearBitmapPipeline::SampleStage* sampleStage) { 440 SkLinearBitmapPipeline::SampleStage* sampleStage) {
343 switch (imageInfo.colorType()) { 441 switch (imageInfo.colorType()) {
344 case kRGBA_8888_SkColorType: 442 case kRGBA_8888_SkColorType:
345 case kBGRA_8888_SkColorType: 443 case kBGRA_8888_SkColorType:
346 if (kN32_SkColorType == imageInfo.colorType()) { 444 if (kN32_SkColorType == imageInfo.colorType()) {
347 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { 445 if (imageInfo.profileType() == kSRGB_SkColorProfileType) {
348 sampleStage->Initialize<Sampler<Passthrough8888<kSRGB_SkColo rProfileType>>>( 446 sampleStage->Initialize<Sampler<Passthrough8888<kSRGB_SkColo rProfileType>>>(
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
408 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(); 506 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>();
409 } else { 507 } else {
410 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType 508 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
411 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(); 509 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>();
412 } 510 }
413 return placerStage->get(); 511 return placerStage->get();
414 } 512 }
415 513
416 SkLinearBitmapPipeline::SkLinearBitmapPipeline( 514 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
417 const SkMatrix& inverse, 515 const SkMatrix& inverse,
516 SkFilterQuality filterQuality,
418 SkShader::TileMode xTile, SkShader::TileMode yTile, 517 SkShader::TileMode xTile, SkShader::TileMode yTile,
419 const SkImageInfo& srcImageInfo, 518 const SkImageInfo& srcImageInfo,
420 const void* srcImageData) { 519 const void* srcImageData) {
421 SkSize size; 520 SkSize size;
422 size = srcImageInfo.dimensions(); 521 size = srcImageInfo.dimensions();
423 522
424 // As the stages are built, the chooser function may skip a stage. For examp le, with the 523 // As the stages are built, the chooser function may skip a stage. For examp le, with the
425 // identity matrix, the matrix stage is skipped, and the tilerStage is the f irst stage. 524 // identity matrix, the matrix stage is skipped, and the tilerStage is the f irst stage.
426 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS tage); 525 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS tage);
427 auto samplerStage = choose_pixel_sampler(placementStage, srcImageInfo, 526 auto samplerStage = choose_pixel_sampler(placementStage, srcImageInfo,
428 srcImageData, &fSampleStage); 527 srcImageData, &fSampleStage);
429 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage, 528 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage,
430 &fTileYStage); 529 &fTileYStage);
431 fFirstStage = choose_matrix(tilerStage, inverse, &fMatrixStage); 530 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage );
531 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage);
432 } 532 }
433 533
434 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { 534 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
435 fPixelStage->setDestination(dst); 535 fPixelStage->setDestination(dst);
436 536
437 Sk4f Xs = Sk4f(x) + Sk4f{0.5f, 1.5f, 2.5f, 3.5f}; 537 Sk4f Xs = Sk4f(x) + Sk4f{0.5f, 1.5f, 2.5f, 3.5f};
438 Sk4f Ys(y); 538 Sk4f Ys(y);
439 Sk4f fours{4.0f}; 539 Sk4f fours{4.0f};
440 540
441 while (count >= 4) { 541 while (count >= 4) {
442 fFirstStage->pointList4(Xs, Ys); 542 fFirstStage->pointList4(Xs, Ys);
443 Xs = Xs + fours; 543 Xs = Xs + fours;
444 count -= 4; 544 count -= 4;
445 } 545 }
446 if (count > 0) { 546 if (count > 0) {
447 fFirstStage->pointListFew(count, Xs, Ys); 547 fFirstStage->pointListFew(count, Xs, Ys);
448 } 548 }
449 } 549 }
OLDNEW
« no previous file with comments | « src/core/SkLinearBitmapPipeline.h ('k') | tests/SkLinearBitmapPipelineTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698