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