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 
10 #include <algorithm>
11 #include <cmath>
12 #include <limits>
13 #include <tuple>
14 
15 #include "SkLinearBitmapPipeline_core.h"
16 #include "SkLinearBitmapPipeline_matrix.h"
17 #include "SkLinearBitmapPipeline_tile.h"
18 #include "SkLinearBitmapPipeline_sample.h"
19 #include "SkNx.h"
20 #include "SkOpts.h"
21 #include "SkPM4f.h"
22 
23 ////////////////////////////////////////////////////////////////////////////////////////////////////
24 // SkLinearBitmapPipeline::Stage
25 template<typename Base, size_t kSize, typename Next>
~Stage()26 SkLinearBitmapPipeline::Stage<Base, kSize, Next>::~Stage() {
27     if (fIsInitialized) {
28         this->get()->~Base();
29     }
30 }
31 
32 template<typename Base, size_t kSize, typename Next>
33 template<typename Variant, typename... Args>
initStage(Next * next,Args &&...args)34 void SkLinearBitmapPipeline::Stage<Base, kSize, Next>::initStage(Next* next, Args&& ... args) {
35     SkASSERTF(sizeof(Variant) <= sizeof(fSpace),
36               "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));
37 
38     new (&fSpace) Variant(next, std::forward<Args>(args)...);
39     fStageCloner = [this](Next* nextClone, void* addr) {
40         new (addr) Variant(nextClone, (const Variant&)*this->get());
41     };
42     fIsInitialized = true;
43 };
44 
45 template<typename Base, size_t kSize, typename Next>
46 template<typename Variant, typename... Args>
initSink(Args &&...args)47 void SkLinearBitmapPipeline::Stage<Base, kSize, Next>::initSink(Args&& ... args) {
48     SkASSERTF(sizeof(Variant) <= sizeof(fSpace),
49               "Size Variant: %d, Space: %d", sizeof(Variant), sizeof(fSpace));
50     new (&fSpace) Variant(std::forward<Args>(args)...);
51     fIsInitialized = true;
52 };
53 
54 template<typename Base, size_t kSize, typename Next>
55 template <typename To, typename From>
56 To* SkLinearBitmapPipeline::Stage<Base, kSize, Next>::getInterface() {
57     From* down = static_cast<From*>(this->get());
58     return static_cast<To*>(down);
59 }
60 
61 template<typename Base, size_t kSize, typename Next>
62 Base* SkLinearBitmapPipeline::Stage<Base, kSize, Next>::cloneStageTo(
63     Next* next, Stage* cloneToStage) const
64 {
65     if (!fIsInitialized) return nullptr;
66     fStageCloner(next, &cloneToStage->fSpace);
67     return cloneToStage->get();
68 }
69 
70 namespace  {
71 
72 ////////////////////////////////////////////////////////////////////////////////////////////////////
73 // Matrix Stage
74 // PointProcessor uses a strategy to help complete the work of the different stages. The strategy
75 // must implement the following methods:
76 // * processPoints(xs, ys) - must mutate the xs and ys for the stage.
77 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixels
78 //   to work over.
79 //   span - encapsulation of span.
80 //   next - a pointer to the next stage.
81 //   maybeProcessSpan - returns false if it can not process the span and needs to fallback to
82 //                      point lists for processing.
83 template<typename Strategy, typename Next>
84 class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
85 public:
86     template <typename... Args>
MatrixStage(Next * next,Args &&...args)87     MatrixStage(Next* next, Args&&... args)
88         : fNext{next}
89         , fStrategy{std::forward<Args>(args)...}{ }
90 
MatrixStage(Next * next,const MatrixStage & stage)91     MatrixStage(Next* next, const MatrixStage& stage)
92         : fNext{next}
93         , fStrategy{stage.fStrategy} { }
94 
pointListFew(int n,Sk4s xs,Sk4s ys)95     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
96         fStrategy.processPoints(&xs, &ys);
97         fNext->pointListFew(n, xs, ys);
98     }
99 
pointList4(Sk4s xs,Sk4s ys)100     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
101         fStrategy.processPoints(&xs, &ys);
102         fNext->pointList4(xs, ys);
103     }
104 
105     // The span you pass must not be empty.
pointSpan(Span span)106     void pointSpan(Span span) override {
107         SkASSERT(!span.isEmpty());
108         if (!fStrategy.maybeProcessSpan(span, fNext)) {
109             span_fallback(span, this);
110         }
111     }
112 
113 private:
114     Next* const fNext;
115     Strategy fStrategy;
116 };
117 
118 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
119 using TranslateMatrix = MatrixStage<TranslateMatrixStrategy, Next>;
120 
121 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
122 using ScaleMatrix = MatrixStage<ScaleMatrixStrategy, Next>;
123 
124 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
125 using AffineMatrix = MatrixStage<AffineMatrixStrategy, Next>;
126 
127 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
128 using PerspectiveMatrix = MatrixStage<PerspectiveMatrixStrategy, Next>;
129 
130 
choose_matrix(SkLinearBitmapPipeline::PointProcessorInterface * next,const SkMatrix & inverse,SkLinearBitmapPipeline::MatrixStage * matrixProc)131 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix(
132     SkLinearBitmapPipeline::PointProcessorInterface* next,
133     const SkMatrix& inverse,
134     SkLinearBitmapPipeline::MatrixStage* matrixProc) {
135     if (inverse.hasPerspective()) {
136         matrixProc->initStage<PerspectiveMatrix<>>(
137             next,
138             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
139             SkVector{inverse.getScaleX(), inverse.getScaleY()},
140             SkVector{inverse.getSkewX(), inverse.getSkewY()},
141             SkVector{inverse.getPerspX(), inverse.getPerspY()},
142             inverse.get(SkMatrix::kMPersp2));
143     } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
144         matrixProc->initStage<AffineMatrix<>>(
145             next,
146             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
147             SkVector{inverse.getScaleX(), inverse.getScaleY()},
148             SkVector{inverse.getSkewX(), inverse.getSkewY()});
149     } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
150         matrixProc->initStage<ScaleMatrix<>>(
151             next,
152             SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
153             SkVector{inverse.getScaleX(), inverse.getScaleY()});
154     } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
155         matrixProc->initStage<TranslateMatrix<>>(
156             next,
157             SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
158     } else {
159         return next;
160     }
161     return matrixProc->get();
162 }
163 
164 ////////////////////////////////////////////////////////////////////////////////////////////////////
165 // Tile Stage
166 
167 template<typename XStrategy, typename YStrategy, typename Next>
168 class CombinedTileStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
169 public:
CombinedTileStage(Next * next,SkISize dimensions)170     CombinedTileStage(Next* next, SkISize dimensions)
171         : fNext{next}
172         , fXStrategy{dimensions.width()}
173         , fYStrategy{dimensions.height()}{ }
174 
CombinedTileStage(Next * next,const CombinedTileStage & stage)175     CombinedTileStage(Next* next, const CombinedTileStage& stage)
176         : fNext{next}
177         , fXStrategy{stage.fXStrategy}
178         , fYStrategy{stage.fYStrategy} { }
179 
pointListFew(int n,Sk4s xs,Sk4s ys)180     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
181         fXStrategy.tileXPoints(&xs);
182         fYStrategy.tileYPoints(&ys);
183         fNext->pointListFew(n, xs, ys);
184     }
185 
pointList4(Sk4s xs,Sk4s ys)186     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
187         fXStrategy.tileXPoints(&xs);
188         fYStrategy.tileYPoints(&ys);
189         fNext->pointList4(xs, ys);
190     }
191 
192     // The span you pass must not be empty.
pointSpan(Span span)193     void pointSpan(Span span) override {
194         SkASSERT(!span.isEmpty());
195         SkPoint start; SkScalar length; int count;
196         std::tie(start, length, count) = span;
197 
198         if (span.count() == 1) {
199             // DANGER:
200             // The explicit casts from float to Sk4f are not usually necessary, but are here to
201             // work around an MSVC 2015u2 c++ code generation bug. This is tracked using skia bug
202             // 5566.
203             this->pointListFew(1, Sk4f{span.startX()}, Sk4f{span.startY()});
204             return;
205         }
206 
207         SkScalar x = X(start);
208         SkScalar y = fYStrategy.tileY(Y(start));
209         Span yAdjustedSpan{{x, y}, length, count};
210 
211         if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
212             span_fallback(span, this);
213         }
214     }
215 
216 private:
217     Next* const fNext;
218     XStrategy fXStrategy;
219     YStrategy fYStrategy;
220 };
221 
222 template <typename XStrategy, typename Next>
choose_tiler_ymode(SkShader::TileMode yMode,SkFilterQuality filterQuality,SkISize dimensions,Next * next,SkLinearBitmapPipeline::TileStage * tileStage)223 void choose_tiler_ymode(
224     SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions,
225     Next* next,
226     SkLinearBitmapPipeline::TileStage* tileStage) {
227     switch (yMode) {
228         case SkShader::kClamp_TileMode: {
229             using Tiler = CombinedTileStage<XStrategy, YClampStrategy, Next>;
230             tileStage->initStage<Tiler>(next, dimensions);
231             break;
232         }
233         case SkShader::kRepeat_TileMode: {
234             using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, Next>;
235             tileStage->initStage<Tiler>(next, dimensions);
236             break;
237         }
238         case SkShader::kMirror_TileMode: {
239             using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, Next>;
240             tileStage->initStage<Tiler>(next, dimensions);
241             break;
242         }
243     }
244 };
245 
choose_tiler(SkLinearBitmapPipeline::SampleProcessorInterface * next,SkISize dimensions,SkShader::TileMode xMode,SkShader::TileMode yMode,SkFilterQuality filterQuality,SkScalar dx,SkLinearBitmapPipeline::TileStage * tileStage)246 static SkLinearBitmapPipeline::PointProcessorInterface* choose_tiler(
247     SkLinearBitmapPipeline::SampleProcessorInterface* next,
248     SkISize dimensions,
249     SkShader::TileMode xMode,
250     SkShader::TileMode yMode,
251     SkFilterQuality filterQuality,
252     SkScalar dx,
253     SkLinearBitmapPipeline::TileStage* tileStage)
254 {
255     switch (xMode) {
256         case SkShader::kClamp_TileMode:
257             choose_tiler_ymode<XClampStrategy>(yMode, filterQuality, dimensions, next, tileStage);
258             break;
259         case SkShader::kRepeat_TileMode:
260             if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
261                 choose_tiler_ymode<XRepeatUnitScaleStrategy>(
262                     yMode, kNone_SkFilterQuality, dimensions, next, tileStage);
263             } else {
264                 choose_tiler_ymode<XRepeatStrategy>(
265                     yMode, filterQuality, dimensions, next, tileStage);
266             }
267             break;
268         case SkShader::kMirror_TileMode:
269             choose_tiler_ymode<XMirrorStrategy>(yMode, filterQuality, dimensions, next, tileStage);
270             break;
271     }
272 
273     return tileStage->get();
274 }
275 
276 ////////////////////////////////////////////////////////////////////////////////////////////////////
277 // Specialized Samplers
278 
279 // RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination
280 // are the same format and do not need in transformations in pixel space. Therefore, there is no
281 // need to convert them to HiFi pixel format.
282 class RGBA8888UnitRepeatSrc final : public SkLinearBitmapPipeline::SampleProcessorInterface,
283                                     public SkLinearBitmapPipeline::DestinationInterface {
284 public:
RGBA8888UnitRepeatSrc(const uint32_t * src,int32_t width)285     RGBA8888UnitRepeatSrc(const uint32_t* src, int32_t width)
286         : fSrc{src}, fWidth{width} { }
287 
pointListFew(int n,Sk4s xs,Sk4s ys)288     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
289         SkASSERT(fDest + n <= fEnd);
290         // At this point xs and ys should be >= 0, so trunc is the same as floor.
291         Sk4i iXs = SkNx_cast<int>(xs);
292         Sk4i iYs = SkNx_cast<int>(ys);
293 
294         if (n >= 1) *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
295         if (n >= 2) *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
296         if (n >= 3) *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
297     }
298 
pointList4(Sk4s xs,Sk4s ys)299     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
300         SkASSERT(fDest + 4 <= fEnd);
301         Sk4i iXs = SkNx_cast<int>(xs);
302         Sk4i iYs = SkNx_cast<int>(ys);
303         *fDest++ = *this->pixelAddress(iXs[0], iYs[0]);
304         *fDest++ = *this->pixelAddress(iXs[1], iYs[1]);
305         *fDest++ = *this->pixelAddress(iXs[2], iYs[2]);
306         *fDest++ = *this->pixelAddress(iXs[3], iYs[3]);
307     }
308 
pointSpan(Span span)309     void pointSpan(Span span) override {
310         SkASSERT(fDest + span.count() <= fEnd);
311         if (span.length() != 0.0f) {
312             int32_t x = SkScalarTruncToInt(span.startX());
313             int32_t y = SkScalarTruncToInt(span.startY());
314             const uint32_t* src = this->pixelAddress(x, y);
315             memmove(fDest, src, span.count() * sizeof(uint32_t));
316             fDest += span.count();
317         }
318     }
319 
repeatSpan(Span span,int32_t repeatCount)320     void repeatSpan(Span span, int32_t repeatCount) override {
321         SkASSERT(fDest + span.count() * repeatCount <= fEnd);
322 
323         int32_t x = SkScalarTruncToInt(span.startX());
324         int32_t y = SkScalarTruncToInt(span.startY());
325         const uint32_t* src = this->pixelAddress(x, y);
326         uint32_t* dest = fDest;
327         while (repeatCount --> 0) {
328             memmove(dest, src, span.count() * sizeof(uint32_t));
329             dest += span.count();
330         }
331         fDest = dest;
332     }
333 
setDestination(void * dst,int count)334     void setDestination(void* dst, int count) override  {
335         fDest = static_cast<uint32_t*>(dst);
336         fEnd = fDest + count;
337     }
338 
339 private:
pixelAddress(int32_t x,int32_t y)340     const uint32_t* pixelAddress(int32_t x, int32_t y) {
341         return &fSrc[fWidth * y + x];
342     }
343     const uint32_t* const fSrc;
344     const int32_t         fWidth;
345     uint32_t*             fDest;
346     uint32_t*             fEnd;
347 };
348 
349 // RGBA8888UnitRepeatSrc - A sampler that takes advantage of the fact the the src and destination
350 // are the same format and do not need in transformations in pixel space. Therefore, there is no
351 // need to convert them to HiFi pixel format.
352 class RGBA8888UnitRepeatSrcOver final : public SkLinearBitmapPipeline::SampleProcessorInterface,
353                                         public SkLinearBitmapPipeline::DestinationInterface {
354 public:
RGBA8888UnitRepeatSrcOver(const uint32_t * src,int32_t width)355     RGBA8888UnitRepeatSrcOver(const uint32_t* src, int32_t width)
356         : fSrc{src}, fWidth{width} { }
357 
pointListFew(int n,Sk4s xs,Sk4s ys)358     void SK_VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
359         SkASSERT(fDest + n <= fEnd);
360         // At this point xs and ys should be >= 0, so trunc is the same as floor.
361         Sk4i iXs = SkNx_cast<int>(xs);
362         Sk4i iYs = SkNx_cast<int>(ys);
363 
364         if (n >= 1) blendPixelAt(iXs[0], iYs[0]);
365         if (n >= 2) blendPixelAt(iXs[1], iYs[1]);
366         if (n >= 3) blendPixelAt(iXs[2], iYs[2]);
367     }
368 
pointList4(Sk4s xs,Sk4s ys)369     void SK_VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
370         SkASSERT(fDest + 4 <= fEnd);
371         Sk4i iXs = SkNx_cast<int>(xs);
372         Sk4i iYs = SkNx_cast<int>(ys);
373         blendPixelAt(iXs[0], iYs[0]);
374         blendPixelAt(iXs[1], iYs[1]);
375         blendPixelAt(iXs[2], iYs[2]);
376         blendPixelAt(iXs[3], iYs[3]);
377     }
378 
pointSpan(Span span)379     void pointSpan(Span span) override {
380         if (span.length() != 0.0f) {
381             this->repeatSpan(span, 1);
382         }
383     }
384 
repeatSpan(Span span,int32_t repeatCount)385     void repeatSpan(Span span, int32_t repeatCount) override {
386         SkASSERT(fDest + span.count() * repeatCount <= fEnd);
387         SkASSERT(span.count() > 0);
388         SkASSERT(repeatCount > 0);
389 
390         int32_t x = (int32_t)span.startX();
391         int32_t y = (int32_t)span.startY();
392         const uint32_t* beginSpan = this->pixelAddress(x, y);
393 
394         SkOpts::srcover_srgb_srgb(fDest, beginSpan, span.count() * repeatCount, span.count());
395 
396         fDest += span.count() * repeatCount;
397 
398         SkASSERT(fDest <= fEnd);
399     }
400 
setDestination(void * dst,int count)401     void setDestination(void* dst, int count) override  {
402         SkASSERT(count > 0);
403         fDest = static_cast<uint32_t*>(dst);
404         fEnd = fDest + count;
405     }
406 
407 private:
pixelAddress(int32_t x,int32_t y)408     const uint32_t* pixelAddress(int32_t x, int32_t y) {
409         return &fSrc[fWidth * y + x];
410     }
411 
blendPixelAt(int32_t x,int32_t y)412     void blendPixelAt(int32_t x, int32_t y) {
413         const uint32_t* src = this->pixelAddress(x, y);
414         SkOpts::srcover_srgb_srgb(fDest, src, 1, 1);
415         fDest += 1;
416     }
417 
418     const uint32_t* const fSrc;
419     const int32_t         fWidth;
420     uint32_t*             fDest;
421     uint32_t*             fEnd;
422 };
423 
424 using Blender = SkLinearBitmapPipeline::BlendProcessorInterface;
425 
426 template <SkColorType colorType>
choose_specific_accessor(const SkPixmap & srcPixmap,SkLinearBitmapPipeline::Accessor * accessor)427 static SkLinearBitmapPipeline::PixelAccessorInterface* choose_specific_accessor(
428     const SkPixmap& srcPixmap, SkLinearBitmapPipeline::Accessor* accessor)
429 {
430     if (srcPixmap.info().gammaCloseToSRGB()) {
431         using PA = PixelAccessor<colorType, kSRGB_SkGammaType>;
432         accessor->init<PA>(srcPixmap);
433         return accessor->get();
434     } else {
435         using PA = PixelAccessor<colorType, kLinear_SkGammaType>;
436         accessor->init<PA>(srcPixmap);
437         return accessor->get();
438     }
439 }
440 
choose_pixel_accessor(const SkPixmap & srcPixmap,const SkColor A8TintColor,SkLinearBitmapPipeline::Accessor * accessor)441 static SkLinearBitmapPipeline::PixelAccessorInterface* choose_pixel_accessor(
442     const SkPixmap& srcPixmap,
443     const SkColor A8TintColor,
444     SkLinearBitmapPipeline::Accessor* accessor)
445 {
446     const SkImageInfo& imageInfo = srcPixmap.info();
447 
448     SkLinearBitmapPipeline::PixelAccessorInterface* pixelAccessor = nullptr;
449     switch (imageInfo.colorType()) {
450         case kAlpha_8_SkColorType: {
451                 using PA = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
452                 accessor->init<PA>(srcPixmap, A8TintColor);
453                 pixelAccessor = accessor->get();
454             }
455             break;
456         case kARGB_4444_SkColorType:
457             pixelAccessor = choose_specific_accessor<kARGB_4444_SkColorType>(srcPixmap, accessor);
458             break;
459         case kRGB_565_SkColorType:
460             pixelAccessor = choose_specific_accessor<kRGB_565_SkColorType>(srcPixmap, accessor);
461             break;
462         case kRGBA_8888_SkColorType:
463             pixelAccessor = choose_specific_accessor<kRGBA_8888_SkColorType>(srcPixmap, accessor);
464             break;
465         case kBGRA_8888_SkColorType:
466             pixelAccessor = choose_specific_accessor<kBGRA_8888_SkColorType>(srcPixmap, accessor);
467             break;
468         case kIndex_8_SkColorType:
469             pixelAccessor = choose_specific_accessor<kIndex_8_SkColorType>(srcPixmap, accessor);
470             break;
471         case kGray_8_SkColorType:
472             pixelAccessor = choose_specific_accessor<kGray_8_SkColorType>(srcPixmap, accessor);
473             break;
474         case kRGBA_F16_SkColorType: {
475                 using PA = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
476                 accessor->init<PA>(srcPixmap);
477                 pixelAccessor = accessor->get();
478             }
479             break;
480         default:
481             SkFAIL("Not implemented. Unsupported src");
482             break;
483     }
484 
485     return pixelAccessor;
486 }
487 
choose_pixel_sampler(Blender * next,SkFilterQuality filterQuality,SkShader::TileMode xTile,SkShader::TileMode yTile,const SkPixmap & srcPixmap,const SkColor A8TintColor,SkLinearBitmapPipeline::SampleStage * sampleStage,SkLinearBitmapPipeline::Accessor * accessor)488 SkLinearBitmapPipeline::SampleProcessorInterface* choose_pixel_sampler(
489     Blender* next,
490     SkFilterQuality filterQuality,
491     SkShader::TileMode xTile, SkShader::TileMode yTile,
492     const SkPixmap& srcPixmap,
493     const SkColor A8TintColor,
494     SkLinearBitmapPipeline::SampleStage* sampleStage,
495     SkLinearBitmapPipeline::Accessor* accessor) {
496     const SkImageInfo& imageInfo = srcPixmap.info();
497     SkISize dimensions = imageInfo.dimensions();
498 
499     // Special case samplers with fully expanded templates
500     if (imageInfo.gammaCloseToSRGB()) {
501         if (filterQuality == kNone_SkFilterQuality) {
502             switch (imageInfo.colorType()) {
503                 case kN32_SkColorType: {
504                     using S =
505                     NearestNeighborSampler<
506                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
507                     sampleStage->initStage<S>(next, srcPixmap);
508                     return sampleStage->get();
509                 }
510                 case kIndex_8_SkColorType: {
511                     using S =
512                     NearestNeighborSampler<
513                         PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
514                     sampleStage->initStage<S>(next, srcPixmap);
515                     return sampleStage->get();
516                 }
517                 default:
518                     break;
519             }
520         } else {
521             switch (imageInfo.colorType()) {
522                 case kN32_SkColorType: {
523                     using S =
524                     BilerpSampler<
525                         PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
526                     sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
527                     return sampleStage->get();
528                 }
529                 case kIndex_8_SkColorType: {
530                     using S =
531                     BilerpSampler<
532                         PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
533                     sampleStage->initStage<S>(next, dimensions, xTile, yTile, srcPixmap);
534                     return sampleStage->get();
535                 }
536                 default:
537                     break;
538             }
539         }
540     }
541 
542     auto pixelAccessor = choose_pixel_accessor(srcPixmap, A8TintColor, accessor);
543     // General cases.
544     if (filterQuality == kNone_SkFilterQuality) {
545         using S = NearestNeighborSampler<PixelAccessorShim, Blender>;
546         sampleStage->initStage<S>(next, pixelAccessor);
547     } else {
548         using S = BilerpSampler<PixelAccessorShim, Blender>;
549         sampleStage->initStage<S>(next, dimensions, xTile, yTile, pixelAccessor);
550     }
551     return sampleStage->get();
552 }
553 
554 ////////////////////////////////////////////////////////////////////////////////////////////////////
555 // Pixel Blender Stage
556 template <SkAlphaType alphaType>
557 class SrcFPPixel final : public SkLinearBitmapPipeline::BlendProcessorInterface {
558 public:
SrcFPPixel(float postAlpha)559     SrcFPPixel(float postAlpha) : fPostAlpha{postAlpha} { }
SrcFPPixel(const SrcFPPixel & Blender)560     SrcFPPixel(const SrcFPPixel& Blender) : fPostAlpha(Blender.fPostAlpha) {}
blendPixel(Sk4f pixel)561     void SK_VECTORCALL blendPixel(Sk4f pixel) override {
562         SkASSERT(fDst + 1 <= fEnd );
563         this->srcPixel(fDst, pixel, 0);
564         fDst += 1;
565     }
566 
blend4Pixels(Sk4f p0,Sk4f p1,Sk4f p2,Sk4f p3)567     void SK_VECTORCALL blend4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
568         SkASSERT(fDst + 4 <= fEnd);
569         SkPM4f* dst = fDst;
570         this->srcPixel(dst, p0, 0);
571         this->srcPixel(dst, p1, 1);
572         this->srcPixel(dst, p2, 2);
573         this->srcPixel(dst, p3, 3);
574         fDst += 4;
575     }
576 
setDestination(void * dst,int count)577     void setDestination(void* dst, int count) override {
578         fDst = static_cast<SkPM4f*>(dst);
579         fEnd = fDst + count;
580     }
581 
582 private:
srcPixel(SkPM4f * dst,Sk4f pixel,int index)583     void SK_VECTORCALL srcPixel(SkPM4f* dst, Sk4f pixel, int index) {
584         check_pixel(pixel);
585 
586         Sk4f newPixel = pixel;
587         if (alphaType == kUnpremul_SkAlphaType) {
588             newPixel = Premultiply(pixel);
589         }
590         newPixel = newPixel * fPostAlpha;
591         newPixel.store(dst + index);
592     }
Premultiply(Sk4f pixel)593     static Sk4f SK_VECTORCALL Premultiply(Sk4f pixel) {
594         float alpha = pixel[3];
595         return pixel * Sk4f{alpha, alpha, alpha, 1.0f};
596     }
597 
598     SkPM4f* fDst;
599     SkPM4f* fEnd;
600     Sk4f fPostAlpha;
601 };
602 
choose_blender_for_shading(SkAlphaType alphaType,float postAlpha,SkLinearBitmapPipeline::BlenderStage * blenderStage)603 static SkLinearBitmapPipeline::BlendProcessorInterface* choose_blender_for_shading(
604     SkAlphaType alphaType,
605     float postAlpha,
606     SkLinearBitmapPipeline::BlenderStage* blenderStage) {
607     if (alphaType == kUnpremul_SkAlphaType) {
608         blenderStage->initSink<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
609     } else {
610         // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
611         blenderStage->initSink<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
612     }
613     return blenderStage->get();
614 }
615 
616 }  // namespace
617 
618 ////////////////////////////////////////////////////////////////////////////////////////////////////
619 // SkLinearBitmapPipeline
~SkLinearBitmapPipeline()620 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
621 
SkLinearBitmapPipeline(const SkMatrix & inverse,SkFilterQuality filterQuality,SkShader::TileMode xTile,SkShader::TileMode yTile,SkColor paintColor,const SkPixmap & srcPixmap)622 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
623     const SkMatrix& inverse,
624     SkFilterQuality filterQuality,
625     SkShader::TileMode xTile, SkShader::TileMode yTile,
626     SkColor paintColor,
627     const SkPixmap& srcPixmap)
628 {
629     SkISize dimensions = srcPixmap.info().dimensions();
630     const SkImageInfo& srcImageInfo = srcPixmap.info();
631 
632     SkMatrix adjustedInverse = inverse;
633     if (filterQuality == kNone_SkFilterQuality) {
634         if (inverse.getScaleX() >= 0.0f) {
635             adjustedInverse.setTranslateX(
636                 nextafterf(inverse.getTranslateX(), std::floor(inverse.getTranslateX())));
637         }
638         if (inverse.getScaleY() >= 0.0f) {
639             adjustedInverse.setTranslateY(
640                 nextafterf(inverse.getTranslateY(), std::floor(inverse.getTranslateY())));
641         }
642     }
643 
644     SkScalar dx = adjustedInverse.getScaleX();
645 
646     // If it is an index 8 color type, the sampler converts to unpremul for better fidelity.
647     SkAlphaType alphaType = srcImageInfo.alphaType();
648     if (srcPixmap.colorType() == kIndex_8_SkColorType) {
649         alphaType = kUnpremul_SkAlphaType;
650     }
651 
652     float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f);
653     // As the stages are built, the chooser function may skip a stage. For example, with the
654     // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
655     auto blenderStage = choose_blender_for_shading(alphaType, postAlpha, &fBlenderStage);
656     auto samplerStage = choose_pixel_sampler(
657         blenderStage, filterQuality, xTile, yTile,
658         srcPixmap, paintColor, &fSampleStage, &fAccessor);
659     auto tilerStage   = choose_tiler(samplerStage, dimensions, xTile, yTile,
660                                      filterQuality, dx, &fTileStage);
661     fFirstStage       = choose_matrix(tilerStage, adjustedInverse, &fMatrixStage);
662     fLastStage        = blenderStage;
663 }
664 
ClonePipelineForBlitting(SkEmbeddableLinearPipeline * pipelineStorage,const SkLinearBitmapPipeline & pipeline,SkMatrix::TypeMask matrixMask,SkShader::TileMode xTileMode,SkShader::TileMode yTileMode,SkFilterQuality filterQuality,const SkPixmap & srcPixmap,float finalAlpha,SkXfermode::Mode xferMode,const SkImageInfo & dstInfo)665 bool SkLinearBitmapPipeline::ClonePipelineForBlitting(
666     SkEmbeddableLinearPipeline* pipelineStorage,
667     const SkLinearBitmapPipeline& pipeline,
668     SkMatrix::TypeMask matrixMask,
669     SkShader::TileMode xTileMode,
670     SkShader::TileMode yTileMode,
671     SkFilterQuality filterQuality,
672     const SkPixmap& srcPixmap,
673     float finalAlpha,
674     SkXfermode::Mode xferMode,
675     const SkImageInfo& dstInfo)
676 {
677     if (xferMode == SkXfermode::kSrcOver_Mode
678         && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
679         xferMode = SkXfermode::kSrc_Mode;
680     }
681 
682     if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return false; }
683     if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return false; }
684     if (finalAlpha != 1.0f) { return false; }
685     if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
686         || dstInfo.colorType() != kRGBA_8888_SkColorType) { return false; }
687 
688     if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
689         return false;
690     }
691 
692     if (xferMode != SkXfermode::kSrc_Mode && xferMode != SkXfermode::kSrcOver_Mode) {
693         return false;
694     }
695 
696     pipelineStorage->init(pipeline, srcPixmap, xferMode, dstInfo);
697 
698     return true;
699 }
700 
SkLinearBitmapPipeline(const SkLinearBitmapPipeline & pipeline,const SkPixmap & srcPixmap,SkXfermode::Mode mode,const SkImageInfo & dstInfo)701 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
702     const SkLinearBitmapPipeline& pipeline,
703     const SkPixmap& srcPixmap,
704     SkXfermode::Mode mode,
705     const SkImageInfo& dstInfo)
706 {
707     SkASSERT(mode == SkXfermode::kSrc_Mode || mode == SkXfermode::kSrcOver_Mode);
708     SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
709              && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
710 
711     if (mode == SkXfermode::kSrc_Mode) {
712         fSampleStage.initSink<RGBA8888UnitRepeatSrc>(
713             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
714         fLastStage = fSampleStage.getInterface<DestinationInterface, RGBA8888UnitRepeatSrc>();
715     } else {
716         fSampleStage.initSink<RGBA8888UnitRepeatSrcOver>(
717             srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
718         fLastStage = fSampleStage.getInterface<DestinationInterface, RGBA8888UnitRepeatSrcOver>();
719     }
720 
721     auto sampleStage = fSampleStage.get();
722     auto tilerStage = pipeline.fTileStage.cloneStageTo(sampleStage, &fTileStage);
723     tilerStage = (tilerStage != nullptr) ? tilerStage : sampleStage;
724     auto matrixStage = pipeline.fMatrixStage.cloneStageTo(tilerStage, &fMatrixStage);
725     matrixStage = (matrixStage != nullptr) ? matrixStage : tilerStage;
726     fFirstStage = matrixStage;
727 }
728 
shadeSpan4f(int x,int y,SkPM4f * dst,int count)729 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
730     SkASSERT(count > 0);
731     this->blitSpan(x, y, dst, count);
732 }
733 
blitSpan(int x,int y,void * dst,int count)734 void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) {
735     SkASSERT(count > 0);
736     fLastStage->setDestination(dst, count);
737 
738     // The count and length arguments start out in a precise relation in order to keep the
739     // math correct through the different stages. Count is the number of pixel to produce.
740     // Since the code samples at pixel centers, length is the distance from the center of the
741     // first pixel to the center of the last pixel. This implies that length is count-1.
742     fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count});
743 }
744