1 /*
2  * Copyright 2016 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkLinearBitmapPipeline.h"
9 #include "SkPM4f.h"
10 
11 #include <algorithm>
12 #include <cmath>
13 #include <limits>
14 #include "SkColor.h"
15 #include "SkSize.h"
16 
17 // Tweak ABI of functions that pass Sk4f by value to pass them via registers.
18 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
19      #define VECTORCALL __vectorcall
20  #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON)
21      #define VECTORCALL __attribute__((pcs("aapcs-vfp")))
22  #else
23      #define VECTORCALL
24  #endif
25 
26 class SkLinearBitmapPipeline::PointProcessorInterface {
27 public:
~PointProcessorInterface()28     virtual ~PointProcessorInterface() { }
29     virtual void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) = 0;
30     virtual void VECTORCALL pointList4(Sk4f xs, Sk4f ys) = 0;
31 
32     // The pointSpan method efficiently process horizontal spans of pixels.
33     // * start - the point where to start the span.
34     // * length - the number of pixels to traverse in source space.
35     // * count - the number of pixels to produce in destination space.
36     // Both start and length are mapped through the inversion matrix to produce values in source
37     // space. After the matrix operation, the tilers may break the spans up into smaller spans.
38     // The tilers can produce spans that seem nonsensical.
39     // * The clamp tiler can create spans with length of 0. This indicates to copy an edge pixel out
40     //   to the edge of the destination scan.
41     // * The mirror tiler can produce spans with negative length. This indicates that the source
42     //   should be traversed in the opposite direction to the destination pixels.
43     virtual void pointSpan(SkPoint start, SkScalar length, int count) = 0;
44 };
45 
46 class SkLinearBitmapPipeline::BilerpProcessorInterface
47     : public SkLinearBitmapPipeline::PointProcessorInterface {
48 public:
49     // The x's and y's are setup in the following order:
50     // +--------+--------+
51     // |        |        |
52     // |  px00  |  px10  |
53     // |    0   |    1   |
54     // +--------+--------+
55     // |        |        |
56     // |  px01  |  px11  |
57     // |    2   |    3   |
58     // +--------+--------+
59     // These pixels coordinates are arranged in the following order in xs and ys:
60     // px00  px10  px01  px11
61     virtual void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) = 0;
62 };
63 
64 class SkLinearBitmapPipeline::PixelPlacerInterface {
65 public:
~PixelPlacerInterface()66     virtual ~PixelPlacerInterface() { }
67     virtual void setDestination(SkPM4f* dst) = 0;
68     virtual void VECTORCALL placePixel(Sk4f pixel0) = 0;
69     virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0;
70 };
71 
72 namespace  {
73 
74 struct X {
X__anon16939db40111::X75     explicit X(SkScalar val) : fVal{val} { }
X__anon16939db40111::X76     explicit X(SkPoint pt)   : fVal{pt.fX} { }
X__anon16939db40111::X77     explicit X(SkSize s)     : fVal{s.fWidth} { }
X__anon16939db40111::X78     explicit X(SkISize s)    : fVal(s.fWidth) { }
operator float__anon16939db40111::X79     operator float () const {return fVal;}
80 private:
81     float fVal;
82 };
83 
84 struct Y {
Y__anon16939db40111::Y85     explicit Y(SkScalar val) : fVal{val} { }
Y__anon16939db40111::Y86     explicit Y(SkPoint pt)   : fVal{pt.fY} { }
Y__anon16939db40111::Y87     explicit Y(SkSize s)     : fVal{s.fHeight} { }
Y__anon16939db40111::Y88     explicit Y(SkISize s)    : fVal(s.fHeight) { }
operator float__anon16939db40111::Y89     operator float () const {return fVal;}
90 private:
91     float fVal;
92 };
93 
94 template <typename Stage>
span_fallback(SkPoint start,SkScalar length,int count,Stage * stage)95 void span_fallback(SkPoint start, SkScalar length, int count, Stage* stage) {
96     // If count == 1 use PointListFew instead.
97     SkASSERT(count > 1);
98 
99     float dx = length / (count - 1);
100     Sk4f Xs = Sk4f(X(start)) + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * Sk4f{dx};
101     Sk4f Ys{Y(start)};
102     Sk4f fourDx = {4.0f * dx};
103 
104     while (count >= 4) {
105         stage->pointList4(Xs, Ys);
106         Xs = Xs + fourDx;
107         count -= 4;
108     }
109     if (count > 0) {
110         stage->pointListFew(count, Xs, Ys);
111     }
112 }
113 
114 // PointProcessor uses a strategy to help complete the work of the different stages. The strategy
115 // must implement the following methods:
116 // * processPoints(xs, ys) - must mutate the xs and ys for the stage.
117 // * maybeProcessSpan(start, length, count) - This represents a horizontal series of pixels
118 //   to work over.
119 //   start - is the starting pixel. This is in destination space before the matrix stage, and in
120 //           source space after the matrix stage.
121 //   length - is this distance between the first pixel center and the last pixel center. Like start,
122 //           this is in destination space before the matrix stage, and in source space after.
123 //   count - the number of pixels in source space to produce.
124 //   next - a pointer to the next stage.
125 //   maybeProcessSpan - returns false if it can not process the span and needs to fallback to
126 //                      point lists for processing.
127 template<typename Strategy, typename Next>
128 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterface {
129 public:
130     template <typename... Args>
PointProcessor(Next * next,Args &&...args)131     PointProcessor(Next* next, Args&&... args)
132         : fNext{next}
133         , fStrategy{std::forward<Args>(args)...}{ }
134 
pointListFew(int n,Sk4f xs,Sk4f ys)135     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
136         fStrategy.processPoints(&xs, &ys);
137         fNext->pointListFew(n, xs, ys);
138     }
139 
pointList4(Sk4f xs,Sk4f ys)140     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
141         fStrategy.processPoints(&xs, &ys);
142         fNext->pointList4(xs, ys);
143     }
144 
pointSpan(SkPoint start,SkScalar length,int count)145     void pointSpan(SkPoint start, SkScalar length, int count) override {
146         if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) {
147             span_fallback(start, length, count, this);
148         }
149     }
150 
151 private:
152     Next* const fNext;
153     Strategy fStrategy;
154 };
155 
156 // See PointProcessor for responsibilities of Strategy.
157 template<typename Strategy, typename Next>
158 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInterface  {
159 public:
160     template <typename... Args>
BilerpProcessor(Next * next,Args &&...args)161     BilerpProcessor(Next* next, Args&&... args)
162         : fNext{next}
163         , fStrategy{std::forward<Args>(args)...}{ }
164 
pointListFew(int n,Sk4f xs,Sk4f ys)165     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
166         fStrategy.processPoints(&xs, &ys);
167         fNext->pointListFew(n, xs, ys);
168     }
169 
pointList4(Sk4f xs,Sk4f ys)170     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
171         fStrategy.processPoints(&xs, &ys);
172         fNext->pointList4(xs, ys);
173     }
174 
bilerpList(Sk4f xs,Sk4f ys)175     void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
176         fStrategy.processPoints(&xs, &ys);
177         fNext->bilerpList(xs, ys);
178     }
179 
pointSpan(SkPoint start,SkScalar length,int count)180     void pointSpan(SkPoint start, SkScalar length, int count) override {
181         if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) {
182             span_fallback(start, length, count, this);
183         }
184     }
185 
186 private:
187     Next* const fNext;
188     Strategy fStrategy;
189 };
190 
191 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterface {
pointListFew(int n,Sk4f xs,Sk4f ys)192     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
193         SkFAIL("Skipped stage.");
194     }
pointList4(Sk4f xs,Sk4f ys)195     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
196         SkFAIL("Skipped stage.");
197     }
bilerpList(Sk4f xs,Sk4f ys)198     void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
199         SkFAIL("Skipped stage.");
200     }
pointSpan(SkPoint start,SkScalar length,int count)201     void pointSpan(SkPoint start, SkScalar length, int count) override {
202         SkFAIL("Skipped stage.");
203     }
204 };
205 
206 class TranslateMatrixStrategy {
207 public:
TranslateMatrixStrategy(SkVector offset)208     TranslateMatrixStrategy(SkVector offset)
209         : fXOffset{X(offset)}
210         , fYOffset{Y(offset)} { }
211 
processPoints(Sk4f * xs,Sk4f * ys)212     void processPoints(Sk4f* xs, Sk4f* ys) {
213         *xs = *xs + fXOffset;
214         *ys = *ys + fYOffset;
215     }
216 
217     template <typename Next>
maybeProcessSpan(SkPoint start,SkScalar length,int count,Next * next)218     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
219         next->pointSpan(start + SkPoint{fXOffset[0], fYOffset[0]}, length, count);
220         return true;
221     }
222 
223 private:
224     const Sk4f fXOffset, fYOffset;
225 };
226 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
227 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>;
228 
229 class ScaleMatrixStrategy {
230 public:
ScaleMatrixStrategy(SkVector offset,SkVector scale)231     ScaleMatrixStrategy(SkVector offset, SkVector scale)
232         : fXOffset{X(offset)}, fYOffset{Y(offset)}
233         ,  fXScale{X(scale)},   fYScale{Y(scale)} { }
processPoints(Sk4f * xs,Sk4f * ys)234     void processPoints(Sk4f* xs, Sk4f* ys) {
235         *xs = *xs * fXScale + fXOffset;
236         *ys = *ys * fYScale + fYOffset;
237     }
238 
239     template <typename Next>
maybeProcessSpan(SkPoint start,SkScalar length,int count,Next * next)240     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
241         SkPoint newStart =
242             SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]};
243         SkScalar newLength = length * fXScale[0];
244         next->pointSpan(newStart, newLength, count);
245         return true;
246     }
247 
248 private:
249     const Sk4f fXOffset, fYOffset;
250     const Sk4f fXScale, fYScale;
251 };
252 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
253 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>;
254 
255 class AffineMatrixStrategy {
256 public:
AffineMatrixStrategy(SkVector offset,SkVector scale,SkVector skew)257     AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew)
258         : fXOffset{X(offset)}, fYOffset{Y(offset)}
259         , fXScale{X(scale)},   fYScale{Y(scale)}
260         , fXSkew{X(skew)},     fYSkew{Y(skew)} { }
processPoints(Sk4f * xs,Sk4f * ys)261     void processPoints(Sk4f* xs, Sk4f* ys) {
262         Sk4f newXs = fXScale * *xs +  fXSkew * *ys + fXOffset;
263         Sk4f newYs =  fYSkew * *xs + fYScale * *ys + fYOffset;
264 
265         *xs = newXs;
266         *ys = newYs;
267     }
268 
269     template <typename Next>
maybeProcessSpan(SkPoint start,SkScalar length,int count,Next * next)270     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
271         return false;
272     }
273 
274 private:
275     const Sk4f fXOffset, fYOffset;
276     const Sk4f fXScale,  fYScale;
277     const Sk4f fXSkew,   fYSkew;
278 };
279 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
280 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>;
281 
choose_matrix(SkLinearBitmapPipeline::PointProcessorInterface * next,const SkMatrix & inverse,SkLinearBitmapPipeline::MatrixStage * matrixProc)282 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix(
283     SkLinearBitmapPipeline::PointProcessorInterface* next,
284     const SkMatrix& inverse,
285     SkLinearBitmapPipeline::MatrixStage* matrixProc) {
286     if (inverse.hasPerspective()) {
287         SkFAIL("Not implemented.");
288     } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
289         matrixProc->Initialize<AffineMatrix<>>(
290             next,
291             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
292             SkVector{inverse.getScaleX(), inverse.getScaleY()},
293             SkVector{inverse.getSkewX(), inverse.getSkewY()});
294     } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
295         matrixProc->Initialize<ScaleMatrix<>>(
296             next,
297             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
298             SkVector{inverse.getScaleX(), inverse.getScaleY()});
299     } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
300         matrixProc->Initialize<TranslateMatrix<>>(
301             next,
302             SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
303     } else {
304         matrixProc->Initialize<SkippedStage>();
305         return next;
306     }
307     return matrixProc->get();
308 }
309 
310 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
311 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterface {
312 public:
ExpandBilerp(Next * next)313     ExpandBilerp(Next* next) : fNext{next} { }
314 
pointListFew(int n,Sk4f xs,Sk4f ys)315     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
316         SkASSERT(0 < n && n < 4);
317         //                    px00   px10   px01  px11
318         const Sk4f kXOffsets{-0.5f,  0.5f, -0.5f, 0.5f},
319                    kYOffsets{-0.5f, -0.5f,  0.5f, 0.5f};
320         if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets);
321         if (n >= 2) fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets);
322         if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets);
323     }
324 
pointList4(Sk4f xs,Sk4f ys)325     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
326         //                    px00   px10   px01  px11
327         const Sk4f kXOffsets{-0.5f,  0.5f, -0.5f, 0.5f},
328                    kYOffsets{-0.5f, -0.5f,  0.5f, 0.5f};
329         fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets);
330         fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets);
331         fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets);
332         fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets);
333     }
334 
pointSpan(SkPoint start,SkScalar length,int count)335     void pointSpan(SkPoint start, SkScalar length, int count) override {
336         span_fallback(start, length, count, this);
337     }
338 
339 private:
340     Next* const fNext;
341 };
342 
choose_filter(SkLinearBitmapPipeline::BilerpProcessorInterface * next,SkFilterQuality filterQuailty,SkLinearBitmapPipeline::FilterStage * filterProc)343 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter(
344     SkLinearBitmapPipeline::BilerpProcessorInterface* next,
345     SkFilterQuality filterQuailty,
346     SkLinearBitmapPipeline::FilterStage* filterProc) {
347     if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) {
348         filterProc->Initialize<SkippedStage>();
349         return next;
350     } else {
351         filterProc->Initialize<ExpandBilerp<>>(next);
352         return filterProc->get();
353     }
354 }
355 
356 class ClampStrategy {
357 public:
ClampStrategy(X max)358     ClampStrategy(X max)
359         : fXMin{0.0f}
360         , fXMax{max - 1.0f} { }
ClampStrategy(Y max)361     ClampStrategy(Y max)
362         : fYMin{0.0f}
363         , fYMax{max - 1.0f} { }
ClampStrategy(SkSize max)364     ClampStrategy(SkSize max)
365         : fXMin{0.0f}
366         , fYMin{0.0f}
367         , fXMax{X(max) - 1.0f}
368         , fYMax{Y(max) - 1.0f} { }
369 
processPoints(Sk4f * xs,Sk4f * ys)370     void processPoints(Sk4f* xs, Sk4f* ys) {
371         *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax);
372         *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax);
373     }
374 
375     template <typename Next>
maybeProcessSpan(SkPoint start,SkScalar length,int count,Next * next)376     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
377         return false;
378     }
379 
380 private:
381     const Sk4f fXMin{SK_FloatNegativeInfinity};
382     const Sk4f fYMin{SK_FloatNegativeInfinity};
383     const Sk4f fXMax{SK_FloatInfinity};
384     const Sk4f fYMax{SK_FloatInfinity};
385 };
386 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
387 using Clamp = BilerpProcessor<ClampStrategy, Next>;
388 
389 class RepeatStrategy {
390 public:
RepeatStrategy(X max)391     RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { }
RepeatStrategy(Y max)392     RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { }
RepeatStrategy(SkSize max)393     RepeatStrategy(SkSize max)
394         : fXMax{X(max)}
395         , fXInvMax{1.0f / X(max)}
396         , fYMax{Y(max)}
397         , fYInvMax{1.0f / Y(max)} { }
398 
processPoints(Sk4f * xs,Sk4f * ys)399     void processPoints(Sk4f* xs, Sk4f* ys) {
400         Sk4f divX = (*xs * fXInvMax).floor();
401         Sk4f divY = (*ys * fYInvMax).floor();
402         Sk4f baseX = (divX * fXMax);
403         Sk4f baseY = (divY * fYMax);
404         *xs = *xs - baseX;
405         *ys = *ys - baseY;
406     }
407 
408     template <typename Next>
maybeProcessSpan(SkPoint start,SkScalar length,int count,Next * next)409     bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) {
410         return false;
411     }
412 
413 private:
414     const Sk4f fXMax{0.0f};
415     const Sk4f fXInvMax{0.0f};
416     const Sk4f fYMax{0.0f};
417     const Sk4f fYInvMax{0.0f};
418 };
419 
420 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
421 using Repeat = BilerpProcessor<RepeatStrategy, Next>;
422 
choose_tiler(SkLinearBitmapPipeline::BilerpProcessorInterface * next,SkSize dimensions,SkShader::TileMode xMode,SkShader::TileMode yMode,SkLinearBitmapPipeline::TileStage * tileProcXOrBoth,SkLinearBitmapPipeline::TileStage * tileProcY)423 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler(
424     SkLinearBitmapPipeline::BilerpProcessorInterface* next,
425     SkSize dimensions,
426     SkShader::TileMode xMode,
427     SkShader::TileMode yMode,
428     SkLinearBitmapPipeline::TileStage* tileProcXOrBoth,
429     SkLinearBitmapPipeline::TileStage* tileProcY) {
430     if (xMode == yMode) {
431         switch (xMode) {
432             case SkShader::kClamp_TileMode:
433                 tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions);
434                 break;
435             case SkShader::kRepeat_TileMode:
436                 tileProcXOrBoth->Initialize<Repeat<>>(next, dimensions);
437                 break;
438             case SkShader::kMirror_TileMode:
439                 SkFAIL("Not implemented.");
440                 break;
441         }
442         tileProcY->Initialize<SkippedStage>();
443     } else {
444         switch (yMode) {
445             case SkShader::kClamp_TileMode:
446                 tileProcY->Initialize<Clamp<>>(next, Y(dimensions));
447                 break;
448             case SkShader::kRepeat_TileMode:
449                 tileProcY->Initialize<Repeat<>>(next, Y(dimensions));
450                 break;
451             case SkShader::kMirror_TileMode:
452                 SkFAIL("Not implemented.");
453                 break;
454         }
455         switch (xMode) {
456             case SkShader::kClamp_TileMode:
457                 tileProcXOrBoth->Initialize<Clamp<>>(tileProcY->get(), X(dimensions));
458                 break;
459             case SkShader::kRepeat_TileMode:
460                 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimensions));
461                 break;
462             case SkShader::kMirror_TileMode:
463                 SkFAIL("Not implemented.");
464                 break;
465         }
466     }
467     return tileProcXOrBoth->get();
468 }
469 
470 class sRGBFast {
471 public:
sRGBToLinear(Sk4f pixel)472     static Sk4f VECTORCALL sRGBToLinear(Sk4f pixel) {
473         Sk4f l = pixel * pixel;
474         return Sk4f{l[0], l[1], l[2], pixel[3]};
475     }
476 };
477 
478 template <SkColorProfileType colorProfile>
479 class Passthrough8888 {
480 public:
Passthrough8888(int width,const uint32_t * src)481     Passthrough8888(int width, const uint32_t* src)
482         : fSrc{src}, fWidth{width}{ }
483 
getFewPixels(int n,Sk4f xs,Sk4f ys,Sk4f * px0,Sk4f * px1,Sk4f * px2)484     void VECTORCALL getFewPixels(int n, Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) {
485         Sk4i XIs = SkNx_cast<int, float>(xs);
486         Sk4i YIs = SkNx_cast<int, float>(ys);
487         Sk4i bufferLoc = YIs * fWidth + XIs;
488         switch (n) {
489             case 3:
490                 *px2 = getPixel(fSrc, bufferLoc[2]);
491             case 2:
492                 *px1 = getPixel(fSrc, bufferLoc[1]);
493             case 1:
494                 *px0 = getPixel(fSrc, bufferLoc[0]);
495             default:
496                 break;
497         }
498     }
499 
get4Pixels(Sk4f xs,Sk4f ys,Sk4f * px0,Sk4f * px1,Sk4f * px2,Sk4f * px3)500     void VECTORCALL get4Pixels(Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2, Sk4f* px3) {
501         Sk4i XIs = SkNx_cast<int, float>(xs);
502         Sk4i YIs = SkNx_cast<int, float>(ys);
503         Sk4i bufferLoc = YIs * fWidth + XIs;
504         *px0 = getPixel(fSrc, bufferLoc[0]);
505         *px1 = getPixel(fSrc, bufferLoc[1]);
506         *px2 = getPixel(fSrc, bufferLoc[2]);
507         *px3 = getPixel(fSrc, bufferLoc[3]);
508     }
509 
row(int y)510     const uint32_t* row(int y) { return fSrc + y * fWidth[0]; }
511 
512 private:
getPixel(const uint32_t * src,int index)513     Sk4f getPixel(const uint32_t* src, int index) {
514         Sk4b bytePixel = Sk4b::Load((uint8_t *)(&src[index]));
515         Sk4f pixel = SkNx_cast<float, uint8_t>(bytePixel);
516         pixel = pixel * Sk4f{1.0f/255.0f};
517         if (colorProfile == kSRGB_SkColorProfileType) {
518             pixel = sRGBFast::sRGBToLinear(pixel);
519         }
520         return pixel;
521     }
522     const uint32_t* const fSrc;
523     const Sk4i fWidth;
524 };
525 
526 // Explaination of the math:
527 //              1 - x      x
528 //           +--------+--------+
529 //           |        |        |
530 //  1 - y    |  px00  |  px10  |
531 //           |        |        |
532 //           +--------+--------+
533 //           |        |        |
534 //    y      |  px01  |  px11  |
535 //           |        |        |
536 //           +--------+--------+
537 //
538 //
539 // Given a pixelxy each is multiplied by a different factor derived from the fractional part of x
540 // and y:
541 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy
542 // * px10 -> x(1 - y) = x - xy
543 // * px01 -> (1 - x)y = y - xy
544 // * px11 -> xy
545 // So x * y is calculated first and then used to calculate all the other factors.
bilerp4(Sk4f xs,Sk4f ys,Sk4f px00,Sk4f px10,Sk4f px01,Sk4f px11)546 static Sk4f VECTORCALL bilerp4(Sk4f xs, Sk4f ys, Sk4f px00, Sk4f px10,
547                                                  Sk4f px01, Sk4f px11) {
548     // Calculate fractional xs and ys.
549     Sk4f fxs = xs - xs.floor();
550     Sk4f fys = ys - ys.floor();
551     Sk4f fxys{fxs * fys};
552     Sk4f sum =  px11 * fxys;
553     sum = sum + px01 * (fys - fxys);
554     sum = sum + px10 * (fxs - fxys);
555     sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys);
556     return sum;
557 }
558 
559 template <typename SourceStrategy>
560 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface {
561 public:
562     template <typename... Args>
Sampler(SkLinearBitmapPipeline::PixelPlacerInterface * next,Args &&...args)563     Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args)
564         : fNext{next}
565         , fStrategy{std::forward<Args>(args)...} { }
566 
pointListFew(int n,Sk4f xs,Sk4f ys)567     void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override {
568         SkASSERT(0 < n && n < 4);
569         Sk4f px0, px1, px2;
570         fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2);
571         if (n >= 1) fNext->placePixel(px0);
572         if (n >= 2) fNext->placePixel(px1);
573         if (n >= 3) fNext->placePixel(px2);
574     }
575 
pointList4(Sk4f xs,Sk4f ys)576     void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override {
577         Sk4f px0, px1, px2, px3;
578         fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3);
579         fNext->place4Pixels(px0, px1, px2, px3);
580     }
581 
bilerpList(Sk4f xs,Sk4f ys)582     void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override {
583         Sk4f px00, px10, px01, px11;
584         fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11);
585         Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11);
586         fNext->placePixel(pixel);
587     }
588 
pointSpan(SkPoint start,SkScalar length,int count)589     void pointSpan(SkPoint start, SkScalar length, int count) override {
590         span_fallback(start, length, count, this);
591     }
592 
593 private:
594     SkLinearBitmapPipeline::PixelPlacerInterface* const fNext;
595     SourceStrategy fStrategy;
596 };
597 
choose_pixel_sampler(SkLinearBitmapPipeline::PixelPlacerInterface * next,const SkPixmap & srcPixmap,SkLinearBitmapPipeline::SampleStage * sampleStage)598 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler(
599     SkLinearBitmapPipeline::PixelPlacerInterface* next,
600     const SkPixmap& srcPixmap,
601     SkLinearBitmapPipeline::SampleStage* sampleStage) {
602     const SkImageInfo& imageInfo = srcPixmap.info();
603     switch (imageInfo.colorType()) {
604         case kRGBA_8888_SkColorType:
605         case kBGRA_8888_SkColorType:
606             if (kN32_SkColorType == imageInfo.colorType()) {
607                 if (imageInfo.profileType() == kSRGB_SkColorProfileType) {
608                     sampleStage->Initialize<Sampler<Passthrough8888<kSRGB_SkColorProfileType>>>(
609                         next, static_cast<int>(srcPixmap.rowBytes() / 4),
610                         srcPixmap.addr32());
611                 } else {
612                     sampleStage->Initialize<Sampler<Passthrough8888<kLinear_SkColorProfileType>>>(
613                         next, static_cast<int>(srcPixmap.rowBytes() / 4),
614                         srcPixmap.addr32());
615                 }
616             } else {
617                 SkFAIL("Not implemented. No 8888 Swizzle");
618             }
619             break;
620         default:
621             SkFAIL("Not implemented. Unsupported src");
622             break;
623     }
624     return sampleStage->get();
625 }
626 
627 template <SkAlphaType alphaType>
628 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface {
629 public:
placePixel(Sk4f pixel)630     void VECTORCALL placePixel(Sk4f pixel) override {
631         PlacePixel(fDst, pixel, 0);
632         fDst += 1;
633     }
634 
place4Pixels(Sk4f p0,Sk4f p1,Sk4f p2,Sk4f p3)635     void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
636         SkPM4f* dst = fDst;
637         PlacePixel(dst, p0, 0);
638         PlacePixel(dst, p1, 1);
639         PlacePixel(dst, p2, 2);
640         PlacePixel(dst, p3, 3);
641         fDst += 4;
642     }
643 
setDestination(SkPM4f * dst)644     void setDestination(SkPM4f* dst) override {
645         fDst = dst;
646     }
647 
648 private:
PlacePixel(SkPM4f * dst,Sk4f pixel,int index)649     static void VECTORCALL PlacePixel(SkPM4f* dst, Sk4f pixel, int index) {
650         Sk4f newPixel = pixel;
651         if (alphaType == kUnpremul_SkAlphaType) {
652             newPixel = Premultiply(pixel);
653         }
654         newPixel.store(dst + index);
655     }
Premultiply(Sk4f pixel)656     static Sk4f VECTORCALL Premultiply(Sk4f pixel) {
657         float alpha = pixel[3];
658         return pixel * Sk4f{alpha, alpha, alpha, 1.0f};
659     }
660 
661     SkPM4f* fDst;
662 };
663 
choose_pixel_placer(SkAlphaType alphaType,SkLinearBitmapPipeline::PixelStage * placerStage)664 static SkLinearBitmapPipeline::PixelPlacerInterface* choose_pixel_placer(
665     SkAlphaType alphaType,
666     SkLinearBitmapPipeline::PixelStage* placerStage) {
667     if (alphaType == kUnpremul_SkAlphaType) {
668         placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>();
669     } else {
670         // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
671         placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>();
672     }
673     return placerStage->get();
674 }
675 }  // namespace
676 
~SkLinearBitmapPipeline()677 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
678 
SkLinearBitmapPipeline(const SkMatrix & inverse,SkFilterQuality filterQuality,SkShader::TileMode xTile,SkShader::TileMode yTile,const SkPixmap & srcPixmap)679 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
680     const SkMatrix& inverse,
681     SkFilterQuality filterQuality,
682     SkShader::TileMode xTile, SkShader::TileMode yTile,
683     const SkPixmap& srcPixmap) {
684     SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height());
685     const SkImageInfo& srcImageInfo = srcPixmap.info();
686 
687     // As the stages are built, the chooser function may skip a stage. For example, with the
688     // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
689     auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelStage);
690     auto samplerStage   = choose_pixel_sampler(placementStage, srcPixmap, &fSampleStage);
691     auto tilerStage     = choose_tiler(samplerStage, size, xTile, yTile, &fTileXOrBothStage,
692                                        &fTileYStage);
693     auto filterStage    = choose_filter(tilerStage, filterQuality, &fFilterStage);
694     fFirstStage         = choose_matrix(filterStage, inverse, &fMatrixStage);
695 }
696 
shadeSpan4f(int x,int y,SkPM4f * dst,int count)697 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
698     SkASSERT(count > 0);
699     fPixelStage->setDestination(dst);
700     // Adjust points by 0.5, 0.5 to sample from the center of the pixels.
701     if (count == 1) {
702         fFirstStage->pointListFew(1, Sk4f{x + 0.5f}, Sk4f{y + 0.5f});
703     } else {
704         // The count and length arguments start out in a precise relation in order to keep the
705         // math correct through the different stages. Count is the number of pixel to produce.
706         // Since the code samples at pixel centers, length is the distance from the center of the
707         // first pixel to the center of the last pixel. This implies that length is count-1.
708         fFirstStage->pointSpan(SkPoint{x + 0.5f, y + 0.5f}, count - 1, count);
709     }
710 }
711