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