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 if (srcPixmap.colorType() == kIndex_8_SkColorType) {
376 alphaType = kUnpremul_SkAlphaType;
377 }
378
379 float postAlpha = SkColorGetA(paintColor) * (1.0f / 255.0f);
380 // As the stages are built, the chooser function may skip a stage. For example, with the
381 // identity matrix, the matrix stage is skipped, and the tilerStage is the first stage.
382 auto blenderStage = this->chooseBlenderForShading(alphaType, postAlpha, allocator);
383 auto samplerStage = this->chooseSampler(
384 blenderStage, filterQuality, xTile, yTile, srcPixmap, paintColor, allocator);
385 auto tilerStage = this->chooseTiler(
386 samplerStage, dimensions, xTile, yTile, filterQuality, dx, allocator);
387 fFirstStage = this->chooseMatrix(tilerStage, adjustedInverse, allocator);
388 fLastStage = blenderStage;
389 }
390
SkLinearBitmapPipeline(const SkLinearBitmapPipeline & pipeline,const SkPixmap & srcPixmap,SkBlendMode mode,const SkImageInfo & dstInfo,SkArenaAlloc * allocator)391 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
392 const SkLinearBitmapPipeline& pipeline,
393 const SkPixmap& srcPixmap,
394 SkBlendMode mode,
395 const SkImageInfo& dstInfo,
396 SkArenaAlloc* allocator)
397 {
398 SkASSERT(mode == SkBlendMode::kSrc || mode == SkBlendMode::kSrcOver);
399 SkASSERT(srcPixmap.info().colorType() == dstInfo.colorType()
400 && srcPixmap.info().colorType() == kRGBA_8888_SkColorType);
401
402 SampleProcessorInterface* sampleStage;
403 if (mode == SkBlendMode::kSrc) {
404 auto sampler = allocator->make<RGBA8888UnitRepeatSrc>(
405 srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
406 sampleStage = sampler;
407 fLastStage = sampler;
408 } else {
409 auto sampler = allocator->make<RGBA8888UnitRepeatSrcOver>(
410 srcPixmap.writable_addr32(0, 0), srcPixmap.rowBytes() / 4);
411 sampleStage = sampler;
412 fLastStage = sampler;
413 }
414
415 auto tilerStage = pipeline.fTileStageCloner(sampleStage, allocator);
416 auto matrixStage = pipeline.fMatrixStageCloner(tilerStage, allocator);
417 fFirstStage = matrixStage;
418 }
419
ClonePipelineForBlitting(const SkLinearBitmapPipeline & pipeline,SkMatrix::TypeMask matrixMask,SkFilterQuality filterQuality,const SkPixmap & srcPixmap,float finalAlpha,SkBlendMode blendMode,const SkImageInfo & dstInfo,SkArenaAlloc * allocator)420 SkLinearBitmapPipeline* SkLinearBitmapPipeline::ClonePipelineForBlitting(
421 const SkLinearBitmapPipeline& pipeline,
422 SkMatrix::TypeMask matrixMask,
423 SkFilterQuality filterQuality,
424 const SkPixmap& srcPixmap,
425 float finalAlpha,
426 SkBlendMode blendMode,
427 const SkImageInfo& dstInfo,
428 SkArenaAlloc* allocator)
429 {
430 if (blendMode == SkBlendMode::kSrcOver && srcPixmap.info().alphaType() == kOpaque_SkAlphaType) {
431 blendMode = SkBlendMode::kSrc;
432 }
433
434 if (matrixMask & ~SkMatrix::kTranslate_Mask ) { return nullptr; }
435 if (filterQuality != SkFilterQuality::kNone_SkFilterQuality) { return nullptr; }
436 if (finalAlpha != 1.0f) { return nullptr; }
437 if (srcPixmap.info().colorType() != kRGBA_8888_SkColorType
438 || dstInfo.colorType() != kRGBA_8888_SkColorType) { return nullptr; }
439
440 if (!srcPixmap.info().gammaCloseToSRGB() || !dstInfo.gammaCloseToSRGB()) {
441 return nullptr;
442 }
443
444 if (blendMode != SkBlendMode::kSrc && blendMode != SkBlendMode::kSrcOver) {
445 return nullptr;
446 }
447
448 return allocator->make<SkLinearBitmapPipeline>(
449 pipeline, srcPixmap, blendMode, dstInfo, allocator);
450 }
451
shadeSpan4f(int x,int y,SkPM4f * dst,int count)452 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
453 SkASSERT(count > 0);
454 this->blitSpan(x, y, dst, count);
455 }
456
blitSpan(int x,int y,void * dst,int count)457 void SkLinearBitmapPipeline::blitSpan(int x, int y, void* dst, int count) {
458 SkASSERT(count > 0);
459 fLastStage->setDestination(dst, count);
460
461 // The count and length arguments start out in a precise relation in order to keep the
462 // math correct through the different stages. Count is the number of pixel to produce.
463 // Since the code samples at pixel centers, length is the distance from the center of the
464 // first pixel to the center of the last pixel. This implies that length is count-1.
465 fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count});
466 }
467
468 SkLinearBitmapPipeline::PointProcessorInterface*
chooseMatrix(PointProcessorInterface * next,const SkMatrix & inverse,SkArenaAlloc * allocator)469 SkLinearBitmapPipeline::chooseMatrix(
470 PointProcessorInterface* next,
471 const SkMatrix& inverse,
472 SkArenaAlloc* allocator)
473 {
474 if (inverse.hasPerspective()) {
475 auto matrixStage = allocator->make<PerspectiveMatrix<>>(
476 next,
477 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
478 SkVector{inverse.getScaleX(), inverse.getScaleY()},
479 SkVector{inverse.getSkewX(), inverse.getSkewY()},
480 SkVector{inverse.getPerspX(), inverse.getPerspY()},
481 inverse.get(SkMatrix::kMPersp2));
482 fMatrixStageCloner =
483 [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
484 return memory->make<PerspectiveMatrix<>>(cloneNext, matrixStage);
485 };
486 return matrixStage;
487 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
488 auto matrixStage = allocator->make<AffineMatrix<>>(
489 next,
490 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
491 SkVector{inverse.getScaleX(), inverse.getScaleY()},
492 SkVector{inverse.getSkewX(), inverse.getSkewY()});
493 fMatrixStageCloner =
494 [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
495 return memory->make<AffineMatrix<>>(cloneNext, matrixStage);
496 };
497 return matrixStage;
498 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
499 auto matrixStage = allocator->make<ScaleMatrix<>>(
500 next,
501 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
502 SkVector{inverse.getScaleX(), inverse.getScaleY()});
503 fMatrixStageCloner =
504 [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
505 return memory->make<ScaleMatrix<>>(cloneNext, matrixStage);
506 };
507 return matrixStage;
508 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0f) {
509 auto matrixStage = allocator->make<TranslateMatrix<>>(
510 next,
511 SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
512 fMatrixStageCloner =
513 [matrixStage](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
514 return memory->make<TranslateMatrix<>>(cloneNext, matrixStage);
515 };
516 return matrixStage;
517 } else {
518 fMatrixStageCloner = [](PointProcessorInterface* cloneNext, SkArenaAlloc* memory) {
519 return cloneNext;
520 };
521 return next;
522 }
523 }
524
525 template <typename Tiler>
createTiler(SampleProcessorInterface * next,SkISize dimensions,SkArenaAlloc * allocator)526 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::createTiler(
527 SampleProcessorInterface* next,
528 SkISize dimensions,
529 SkArenaAlloc* allocator)
530 {
531 auto tilerStage = allocator->make<Tiler>(next, dimensions);
532 fTileStageCloner =
533 [tilerStage](SampleProcessorInterface* cloneNext,
534 SkArenaAlloc* memory) -> PointProcessorInterface* {
535 return memory->make<Tiler>(cloneNext, tilerStage);
536 };
537 return tilerStage;
538 }
539
540 template <typename XStrategy>
chooseTilerYMode(SampleProcessorInterface * next,SkShader::TileMode yMode,SkISize dimensions,SkArenaAlloc * allocator)541 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTilerYMode(
542 SampleProcessorInterface* next,
543 SkShader::TileMode yMode,
544 SkISize dimensions,
545 SkArenaAlloc* allocator)
546 {
547 switch (yMode) {
548 case SkShader::kClamp_TileMode: {
549 using Tiler = CombinedTileStage<XStrategy, YClampStrategy, SampleProcessorInterface>;
550 return this->createTiler<Tiler>(next, dimensions, allocator);
551 }
552 case SkShader::kRepeat_TileMode: {
553 using Tiler = CombinedTileStage<XStrategy, YRepeatStrategy, SampleProcessorInterface>;
554 return this->createTiler<Tiler>(next, dimensions, allocator);
555 }
556 case SkShader::kMirror_TileMode: {
557 using Tiler = CombinedTileStage<XStrategy, YMirrorStrategy, SampleProcessorInterface>;
558 return this->createTiler<Tiler>(next, dimensions, allocator);
559 }
560 }
561
562 // Should never get here.
563 SkFAIL("Not all Y tile cases covered.");
564 return nullptr;
565 }
566
chooseTiler(SampleProcessorInterface * next,SkISize dimensions,SkShader::TileMode xMode,SkShader::TileMode yMode,SkFilterQuality filterQuality,SkScalar dx,SkArenaAlloc * allocator)567 SkLinearBitmapPipeline::PointProcessorInterface* SkLinearBitmapPipeline::chooseTiler(
568 SampleProcessorInterface* next,
569 SkISize dimensions,
570 SkShader::TileMode xMode,
571 SkShader::TileMode yMode,
572 SkFilterQuality filterQuality,
573 SkScalar dx,
574 SkArenaAlloc* allocator)
575 {
576 switch (xMode) {
577 case SkShader::kClamp_TileMode:
578 return this->chooseTilerYMode<XClampStrategy>(next, yMode, dimensions, allocator);
579 case SkShader::kRepeat_TileMode:
580 if (dx == 1.0f && filterQuality == kNone_SkFilterQuality) {
581 return this->chooseTilerYMode<XRepeatUnitScaleStrategy>(
582 next, yMode, dimensions, allocator);
583 } else {
584 return this->chooseTilerYMode<XRepeatStrategy>(
585 next, yMode, dimensions, allocator);
586 }
587 case SkShader::kMirror_TileMode:
588 return this->chooseTilerYMode<XMirrorStrategy>(next, yMode, dimensions, allocator);
589 }
590
591 // Should never get here.
592 SkFAIL("Not all X tile cases covered.");
593 return nullptr;
594 }
595
596 template <SkColorType colorType>
597 SkLinearBitmapPipeline::PixelAccessorInterface*
chooseSpecificAccessor(const SkPixmap & srcPixmap,SkArenaAlloc * allocator)598 SkLinearBitmapPipeline::chooseSpecificAccessor(
599 const SkPixmap& srcPixmap,
600 SkArenaAlloc* allocator)
601 {
602 if (srcPixmap.info().gammaCloseToSRGB()) {
603 using Accessor = PixelAccessor<colorType, kSRGB_SkGammaType>;
604 return allocator->make<Accessor>(srcPixmap);
605 } else {
606 using Accessor = PixelAccessor<colorType, kLinear_SkGammaType>;
607 return allocator->make<Accessor>(srcPixmap);
608 }
609 }
610
choosePixelAccessor(const SkPixmap & srcPixmap,const SkColor A8TintColor,SkArenaAlloc * allocator)611 SkLinearBitmapPipeline::PixelAccessorInterface* SkLinearBitmapPipeline::choosePixelAccessor(
612 const SkPixmap& srcPixmap,
613 const SkColor A8TintColor,
614 SkArenaAlloc* allocator)
615 {
616 const SkImageInfo& imageInfo = srcPixmap.info();
617
618 switch (imageInfo.colorType()) {
619 case kAlpha_8_SkColorType: {
620 using Accessor = PixelAccessor<kAlpha_8_SkColorType, kLinear_SkGammaType>;
621 return allocator->make<Accessor>(srcPixmap, A8TintColor);
622 }
623 case kARGB_4444_SkColorType:
624 return this->chooseSpecificAccessor<kARGB_4444_SkColorType>(srcPixmap, allocator);
625 case kRGB_565_SkColorType:
626 return this->chooseSpecificAccessor<kRGB_565_SkColorType>(srcPixmap, allocator);
627 case kRGBA_8888_SkColorType:
628 return this->chooseSpecificAccessor<kRGBA_8888_SkColorType>(srcPixmap, allocator);
629 case kBGRA_8888_SkColorType:
630 return this->chooseSpecificAccessor<kBGRA_8888_SkColorType>(srcPixmap, allocator);
631 case kIndex_8_SkColorType:
632 return this->chooseSpecificAccessor<kIndex_8_SkColorType>(srcPixmap, allocator);
633 case kGray_8_SkColorType:
634 return this->chooseSpecificAccessor<kGray_8_SkColorType>(srcPixmap, allocator);
635 case kRGBA_F16_SkColorType: {
636 using Accessor = PixelAccessor<kRGBA_F16_SkColorType, kLinear_SkGammaType>;
637 return allocator->make<Accessor>(srcPixmap);
638 }
639 default:
640 // Should never get here.
641 SkFAIL("Pixel source not supported.");
642 return nullptr;
643 }
644 }
645
chooseSampler(Blender * next,SkFilterQuality filterQuality,SkShader::TileMode xTile,SkShader::TileMode yTile,const SkPixmap & srcPixmap,const SkColor A8TintColor,SkArenaAlloc * allocator)646 SkLinearBitmapPipeline::SampleProcessorInterface* SkLinearBitmapPipeline::chooseSampler(
647 Blender* next,
648 SkFilterQuality filterQuality,
649 SkShader::TileMode xTile, SkShader::TileMode yTile,
650 const SkPixmap& srcPixmap,
651 const SkColor A8TintColor,
652 SkArenaAlloc* allocator)
653 {
654 const SkImageInfo& imageInfo = srcPixmap.info();
655 SkISize dimensions = imageInfo.dimensions();
656
657 // Special case samplers with fully expanded templates
658 if (imageInfo.gammaCloseToSRGB()) {
659 if (filterQuality == kNone_SkFilterQuality) {
660 switch (imageInfo.colorType()) {
661 case kN32_SkColorType: {
662 using Sampler =
663 NearestNeighborSampler<
664 PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
665 return allocator->make<Sampler>(next, srcPixmap);
666 }
667 case kIndex_8_SkColorType: {
668 using Sampler =
669 NearestNeighborSampler<
670 PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
671 return allocator->make<Sampler>(next, srcPixmap);
672 }
673 default:
674 break;
675 }
676 } else {
677 switch (imageInfo.colorType()) {
678 case kN32_SkColorType: {
679 using Sampler =
680 BilerpSampler<
681 PixelAccessor<kN32_SkColorType, kSRGB_SkGammaType>, Blender>;
682 return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
683 }
684 case kIndex_8_SkColorType: {
685 using Sampler =
686 BilerpSampler<
687 PixelAccessor<kIndex_8_SkColorType, kSRGB_SkGammaType>, Blender>;
688 return allocator->make<Sampler>(next, dimensions, xTile, yTile, srcPixmap);
689 }
690 default:
691 break;
692 }
693 }
694 }
695
696 auto pixelAccessor = this->choosePixelAccessor(srcPixmap, A8TintColor, allocator);
697 // General cases.
698 if (filterQuality == kNone_SkFilterQuality) {
699 using Sampler = NearestNeighborSampler<PixelAccessorShim, Blender>;
700 return allocator->make<Sampler>(next, pixelAccessor);
701 } else {
702 using Sampler = BilerpSampler<PixelAccessorShim, Blender>;
703 return allocator->make<Sampler>(next, dimensions, xTile, yTile, pixelAccessor);
704 }
705 }
706
chooseBlenderForShading(SkAlphaType alphaType,float postAlpha,SkArenaAlloc * allocator)707 Blender* SkLinearBitmapPipeline::chooseBlenderForShading(
708 SkAlphaType alphaType,
709 float postAlpha,
710 SkArenaAlloc* allocator)
711 {
712 if (alphaType == kUnpremul_SkAlphaType) {
713 return allocator->make<SrcFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
714 } else {
715 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
716 return allocator->make<SrcFPPixel<kPremul_SkAlphaType>>(postAlpha);
717 }
718 }
719