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