Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(378)

Side by Side Diff: src/core/SkLinearBitmapPipeline.cpp

Issue 1765953002: break out the tile and matrix strategies (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | src/core/SkLinearBitmapPipeline_core.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright 2016 Google Inc. 2 * Copyright 2016 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkLinearBitmapPipeline.h" 8 #include "SkLinearBitmapPipeline.h"
9
9 #include "SkPM4f.h" 10 #include "SkPM4f.h"
10
11 #include <algorithm> 11 #include <algorithm>
12 #include <cmath> 12 #include <cmath>
13 #include <limits> 13 #include <limits>
14 #include "SkColor.h" 14 #include "SkColor.h"
15 #include "SkSize.h" 15 #include "SkSize.h"
16 #include <tuple> 16 #include <tuple>
17 17 #include "SkLinearBitmapPipeline_core.h"
18 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. 18 #include "SkLinearBitmapPipeline_matrix.h"
19 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 19 #include "SkLinearBitmapPipeline_tile.h"
20 #define VECTORCALL __vectorcall
21 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON)
22 #define VECTORCALL __attribute__((pcs("aapcs-vfp")))
23 #else
24 #define VECTORCALL
25 #endif
26
27 namespace {
28 struct X {
29 explicit X(SkScalar val) : fVal{val} { }
30 explicit X(SkPoint pt) : fVal{pt.fX} { }
31 explicit X(SkSize s) : fVal{s.fWidth} { }
32 explicit X(SkISize s) : fVal(s.fWidth) { }
33 operator SkScalar () const {return fVal;}
34 private:
35 SkScalar fVal;
36 };
37
38 struct Y {
39 explicit Y(SkScalar val) : fVal{val} { }
40 explicit Y(SkPoint pt) : fVal{pt.fY} { }
41 explicit Y(SkSize s) : fVal{s.fHeight} { }
42 explicit Y(SkISize s) : fVal(s.fHeight) { }
43 operator SkScalar () const {return fVal;}
44 private:
45 SkScalar fVal;
46 };
47
48 // The Span class enables efficient processing horizontal spans of pixels.
49 // * start - the point where to start the span.
50 // * length - the number of pixels to traverse in source space.
51 // * count - the number of pixels to produce in destination space.
52 // Both start and length are mapped through the inversion matrix to produce valu es in source
53 // space. After the matrix operation, the tilers may break the spans up into sma ller spans.
54 // The tilers can produce spans that seem nonsensical.
55 // * The clamp tiler can create spans with length of 0. This indicates to copy a n edge pixel out
56 // to the edge of the destination scan.
57 // * The mirror tiler can produce spans with negative length. This indicates tha t the source
58 // should be traversed in the opposite direction to the destination pixels.
59 class Span {
60 public:
61 Span(SkPoint start, SkScalar length, int count)
62 : fStart(start)
63 , fLength(length)
64 , fCount{count} {
65 SkASSERT(std::isfinite(length));
66 }
67
68 operator std::tuple<SkPoint&, SkScalar&, int&>() {
69 return std::tie(fStart, fLength, fCount);
70 }
71
72 bool isEmpty() const { return 0 == fCount; }
73 SkScalar length() const { return fLength; }
74 SkScalar startX() const { return X(fStart); }
75 SkScalar endX() const { return startX() + length(); }
76 void clear() {
77 fCount = 0;
78 }
79
80 bool completelyWithin(SkScalar xMin, SkScalar xMax) const {
81 SkScalar sMin, sMax;
82 std::tie(sMin, sMax) = std::minmax(startX(), endX());
83 return xMin <= sMin && sMax <= xMax;
84 }
85
86 void offset(SkScalar offsetX) {
87 fStart.offset(offsetX, 0.0f);
88 }
89
90 Span breakAt(SkScalar breakX, SkScalar dx) {
91 SkASSERT(std::isfinite(breakX));
92 SkASSERT(std::isfinite(dx));
93 SkASSERT(dx != 0.0f);
94
95 if (this->isEmpty()) {
96 return Span{{0.0, 0.0}, 0.0f, 0};
97 }
98
99 int dxSteps = SkScalarFloorToInt((breakX - this->startX()) / dx);
100 if (dxSteps < 0) {
101 // The span is wholly after breakX.
102 return Span{{0.0, 0.0}, 0.0f, 0};
103 } else if (dxSteps > fCount) {
104 // The span is wholly before breakX.
105 Span answer = *this;
106 this->clear();
107 return answer;
108 }
109
110 // Calculate the values for the span to cleave off.
111 SkPoint newStart = fStart;
112 SkScalar newLength = dxSteps * dx;
113 int newCount = dxSteps + 1;
114 SkASSERT(newCount > 0);
115
116 // Update this span to reflect the break.
117 SkScalar lengthToStart = newLength + dx;
118 fLength -= lengthToStart;
119 fCount -= newCount;
120 fStart = {this->startX() + lengthToStart, Y(fStart)};
121
122 return Span{newStart, newLength, newCount};
123 }
124
125 void clampToSinglePixel(SkPoint pixel) {
126 fStart = pixel;
127 fLength = 0.0f;
128 }
129
130 private:
131 SkPoint fStart;
132 SkScalar fLength;
133 int fCount;
134 };
135
136 // BilerpSpans are similar to Spans, but they represent four source samples conv erting to single
137 // destination pixel per count. The pixels for the four samples are collect alon g two horizontal
138 // lines; one starting at {x, y0} and the other starting at {x, y1}. There are t wo distinct lines
139 // to deal with the edge case of the tile mode. For example, y0 may be at the la st y position in
140 // a tile while y1 would be at the first.
141 // The step of a Bilerp (dx) is still length / (count - 1) and the start to the next sample is
142 // still dx * count, but the bounds are complicated by the sampling kernel so th at the pixels
143 // touched are from x to x + length + 1.
144 class BilerpSpan {
145 public:
146 BilerpSpan(SkScalar x, SkScalar y0, SkScalar y1, SkScalar length, int count)
147 : fX{x}, fY0{y0}, fY1{y1}, fLength{length}, fCount{count} {
148 SkASSERT(count >= 0);
149 SkASSERT(std::isfinite(length));
150 SkASSERT(std::isfinite(x));
151 SkASSERT(std::isfinite(y0));
152 SkASSERT(std::isfinite(y1));
153 }
154
155 operator std::tuple<SkScalar&, SkScalar&, SkScalar&, SkScalar&, int&>() {
156 return std::tie(fX, fY0, fY1, fLength, fCount);
157 }
158
159 bool isEmpty() const { return 0 == fCount; }
160
161 private:
162 SkScalar fX;
163 SkScalar fY0;
164 SkScalar fY1;
165 SkScalar fLength;
166 int fCount;
167 };
168 } // namespace
169 20
170 class SkLinearBitmapPipeline::PointProcessorInterface { 21 class SkLinearBitmapPipeline::PointProcessorInterface {
171 public: 22 public:
172 virtual ~PointProcessorInterface() { } 23 virtual ~PointProcessorInterface() { }
173 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; 24 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0;
174 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; 25 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0;
175 virtual void pointSpan(Span span) = 0; 26 virtual void pointSpan(Span span) = 0;
176 }; 27 };
177 28
178 class SkLinearBitmapPipeline::BilerpProcessorInterface 29 class SkLinearBitmapPipeline::BilerpProcessorInterface
(...skipping 17 matching lines...) Expand all
196 47
197 class SkLinearBitmapPipeline::PixelPlacerInterface { 48 class SkLinearBitmapPipeline::PixelPlacerInterface {
198 public: 49 public:
199 virtual ~PixelPlacerInterface() { } 50 virtual ~PixelPlacerInterface() { }
200 virtual void setDestination(SkPM4f* dst) = 0; 51 virtual void setDestination(SkPM4f* dst) = 0;
201 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; 52 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0;
202 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0 ; 53 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0 ;
203 }; 54 };
204 55
205 namespace { 56 namespace {
206 template <typename Stage>
207 void span_fallback(Span span, Stage* stage) {
208 SkPoint start;
209 SkScalar length;
210 int count;
211 std::tie(start, length, count) = span;
212 Sk4f xs{X(start)};
213 Sk4f ys{Y(start)};
214
215 // Initializing this is not needed, but some compilers can't figure this out .
216 Sk4s fourDx{0.0f};
217 if (count > 1) {
218 SkScalar dx = length / (count - 1);
219 xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx;
220 // Only used if count is >= 4.
221 fourDx = Sk4f{4.0f * dx};
222 }
223
224 while (count >= 4) {
225 stage->pointList4(xs, ys);
226 xs = xs + fourDx;
227 count -= 4;
228 }
229 if (count > 0) {
230 stage->pointListFew(count, xs, ys);
231 }
232 }
233
234 template <typename Next>
235 void bilerp_span_fallback(BilerpSpan span, Next* next) {
236 SkScalar x, y0, y1; SkScalar length; int count;
237 std::tie(x, y0, y1, length, count) = span;
238
239 SkASSERT(!span.isEmpty());
240 float dx = length / (count - 1);
241
242 Sk4f xs = Sk4f{x} + Sk4f{0.0f, 1.0f, 0.0f, 1.0f};
243 Sk4f ys = Sk4f{y0, y0, y1, y1};
244
245 // If count == 1 then dx will be inf or NaN, but that is ok because the resu lting addition is
246 // never used.
247 while (count > 0) {
248 next->bilerpList(xs, ys);
249 xs = xs + dx;
250 count -= 1;
251 }
252 }
253 57
254 // PointProcessor uses a strategy to help complete the work of the different sta ges. The strategy 58 // PointProcessor uses a strategy to help complete the work of the different sta ges. The strategy
255 // must implement the following methods: 59 // must implement the following methods:
256 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. 60 // * processPoints(xs, ys) - must mutate the xs and ys for the stage.
257 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel s 61 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel s
258 // to work over. 62 // to work over.
259 // span - encapsulation of span. 63 // span - encapsulation of span.
260 // next - a pointer to the next stage. 64 // next - a pointer to the next stage.
261 // maybeProcessSpan - returns false if it can not process the span and needs t o fallback to 65 // maybeProcessSpan - returns false if it can not process the span and needs t o fallback to
262 // point lists for processing. 66 // point lists for processing.
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
327 if (!fStrategy.maybeProcessBilerpSpan(bSpan, fNext)) { 131 if (!fStrategy.maybeProcessBilerpSpan(bSpan, fNext)) {
328 bilerp_span_fallback(bSpan, this); 132 bilerp_span_fallback(bSpan, this);
329 } 133 }
330 } 134 }
331 135
332 private: 136 private:
333 Next* const fNext; 137 Next* const fNext;
334 Strategy fStrategy; 138 Strategy fStrategy;
335 }; 139 };
336 140
337 class TranslateMatrixStrategy { 141 //////////////////////////////////////////////////////////////////////////////// ////////////////////
338 public: 142 // Matrix Stage
339 TranslateMatrixStrategy(SkVector offset)
340 : fXOffset{X(offset)}
341 , fYOffset{Y(offset)} { }
342
343 void processPoints(Sk4s* xs, Sk4s* ys) {
344 *xs = *xs + fXOffset;
345 *ys = *ys + fYOffset;
346 }
347
348 template <typename Next>
349 bool maybeProcessSpan(Span span, Next* next) {
350 SkPoint start; SkScalar length; int count;
351 std::tie(start, length, count) = span;
352 next->pointSpan(Span{start + SkPoint{fXOffset[0], fYOffset[0]}, length, count});
353 return true;
354 }
355
356 private:
357 const Sk4s fXOffset, fYOffset;
358 };
359 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 143 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
360 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; 144 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>;
361 145
362 class ScaleMatrixStrategy {
363 public:
364 ScaleMatrixStrategy(SkVector offset, SkVector scale)
365 : fXOffset{X(offset)}, fYOffset{Y(offset)}
366 , fXScale{X(scale)}, fYScale{Y(scale)} { }
367 void processPoints(Sk4s* xs, Sk4s* ys) {
368 *xs = *xs * fXScale + fXOffset;
369 *ys = *ys * fYScale + fYOffset;
370 }
371
372 template <typename Next>
373 bool maybeProcessSpan(Span span, Next* next) {
374 SkPoint start; SkScalar length; int count;
375 std::tie(start, length, count) = span;
376 SkPoint newStart =
377 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]};
378 SkScalar newLength = length * fXScale[0];
379 next->pointSpan(Span{newStart, newLength, count});
380 return true;
381 }
382
383 private:
384 const Sk4s fXOffset, fYOffset;
385 const Sk4s fXScale, fYScale;
386 };
387 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 146 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
388 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; 147 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>;
389 148
390 class AffineMatrixStrategy {
391 public:
392 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew)
393 : fXOffset{X(offset)}, fYOffset{Y(offset)}
394 , fXScale{X(scale)}, fYScale{Y(scale)}
395 , fXSkew{X(skew)}, fYSkew{Y(skew)} { }
396 void processPoints(Sk4s* xs, Sk4s* ys) {
397 Sk4s newXs = fXScale * *xs + fXSkew * *ys + fXOffset;
398 Sk4s newYs = fYSkew * *xs + fYScale * *ys + fYOffset;
399
400 *xs = newXs;
401 *ys = newYs;
402 }
403
404 template <typename Next>
405 bool maybeProcessSpan(Span span, Next* next) {
406 return false;
407 }
408
409 private:
410 const Sk4s fXOffset, fYOffset;
411 const Sk4s fXScale, fYScale;
412 const Sk4s fXSkew, fYSkew;
413 };
414 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 149 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
415 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; 150 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>;
416 151
417 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( 152 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix(
418 SkLinearBitmapPipeline::PointProcessorInterface* next, 153 SkLinearBitmapPipeline::PointProcessorInterface* next,
419 const SkMatrix& inverse, 154 const SkMatrix& inverse,
420 SkLinearBitmapPipeline::MatrixStage* matrixProc) { 155 SkLinearBitmapPipeline::MatrixStage* matrixProc) {
421 if (inverse.hasPerspective()) { 156 if (inverse.hasPerspective()) {
422 SkFAIL("Not implemented."); 157 SkFAIL("Not implemented.");
423 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { 158 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
(...skipping 10 matching lines...) Expand all
434 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0 f) { 169 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0 f) {
435 matrixProc->Initialize<TranslateMatrix<>>( 170 matrixProc->Initialize<TranslateMatrix<>>(
436 next, 171 next,
437 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); 172 SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
438 } else { 173 } else {
439 return next; 174 return next;
440 } 175 }
441 return matrixProc->get(); 176 return matrixProc->get();
442 } 177 }
443 178
179 //////////////////////////////////////////////////////////////////////////////// ////////////////////
180 // Bilerp Expansion Stage
444 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> 181 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
445 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac e { 182 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac e {
446 public: 183 public:
447 ExpandBilerp(Next* next) : fNext{next} { } 184 ExpandBilerp(Next* next) : fNext{next} { }
448 185
449 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 186 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
450 SkASSERT(0 < n && n < 4); 187 SkASSERT(0 < n && n < 4);
451 // px00 px10 px01 px11 188 // px00 px10 px01 px11
452 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, 189 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f},
453 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; 190 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f};
(...skipping 30 matching lines...) Expand all
484 SkFilterQuality filterQuailty, 221 SkFilterQuality filterQuailty,
485 SkLinearBitmapPipeline::FilterStage* filterProc) { 222 SkLinearBitmapPipeline::FilterStage* filterProc) {
486 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) { 223 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) {
487 return next; 224 return next;
488 } else { 225 } else {
489 filterProc->Initialize<ExpandBilerp<>>(next); 226 filterProc->Initialize<ExpandBilerp<>>(next);
490 return filterProc->get(); 227 return filterProc->get();
491 } 228 }
492 } 229 }
493 230
494 class ClampStrategy { 231 //////////////////////////////////////////////////////////////////////////////// ////////////////////
495 public: 232 // Tile Stage
496 ClampStrategy(X max)
497 : fXMin{0.0f}
498 , fXMax{max - 1.0f} { }
499 ClampStrategy(Y max)
500 : fYMin{0.0f}
501 , fYMax{max - 1.0f} { }
502 ClampStrategy(SkSize max)
503 : fXMin{0.0f}
504 , fYMin{0.0f}
505 , fXMax{X(max) - 1.0f}
506 , fYMax{Y(max) - 1.0f} { }
507
508 void processPoints(Sk4s* xs, Sk4s* ys) {
509 *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax);
510 *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax);
511 }
512
513 template <typename Next>
514 bool maybeProcessSpan(Span originalSpan, Next* next) {
515 SkASSERT(!originalSpan.isEmpty());
516 SkPoint start; SkScalar length; int count;
517 std::tie(start, length, count) = originalSpan;
518 SkScalar xMin = fXMin[0];
519 SkScalar xMax = fXMax[0] + 1.0f;
520 SkScalar yMin = fYMin[0];
521 SkScalar yMax = fYMax[0];
522 SkScalar x = X(start);
523 SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax);
524
525 Span span{{x, y}, length, count};
526
527 if (span.completelyWithin(xMin, xMax)) {
528 next->pointSpan(span);
529 return true;
530 }
531 if (1 == count || 0.0f == length) {
532 return false;
533 }
534
535 SkScalar dx = length / (count - 1);
536
537 // A B C
538 // +-------+-------+-------++-------+-------+-------+ +-------+----- --++------
539 // | *---*|---*---|*---*--||-*---*-|---*---|*---...| |--*---*|---*- --||*---*....
540 // | | | || | | | ... | | ||
541 // | | | || | | | | | ||
542 // +-------+-------+-------++-------+-------+-------+ +-------+----- --++------
543 // ^ ^
544 // | xMin xMax- 1 | xMax
545 //
546 // *---*---*---... - track of samples. * = sample
547 //
548 // +-+ ||
549 // | | - pixels in source space. || - tile border.
550 // +-+ ||
551 //
552 // The length from A to B is the length in source space or 4 * dx or (co unt - 1) * dx
553 // where dx is the distance between samples. There are 5 destination pix els
554 // corresponding to 5 samples specified in the A, B span. The distance f rom A to the next
555 // span starting at C is 5 * dx, so count * dx.
556 // Remember, count is the number of pixels needed for the destination an d the number of
557 // samples.
558 // Overall Strategy:
559 // * Under - for portions of the span < xMin, take the color at pixel {x Min, y} and use it
560 // to fill in the 5 pixel sampled from A to B.
561 // * Middle - for the portion of the span between xMin and xMax sample n ormally.
562 // * Over - for the portion of the span > xMax, take the color at pixel {xMax-1, y} and
563 // use it to fill in the rest of the destination pixels.
564 if (dx >= 0) {
565 Span leftClamped = span.breakAt(xMin, dx);
566 if (!leftClamped.isEmpty()) {
567 leftClamped.clampToSinglePixel({xMin, y});
568 next->pointSpan(leftClamped);
569 }
570 Span middle = span.breakAt(xMax, dx);
571 if (!middle.isEmpty()) {
572 next->pointSpan(middle);
573 }
574 if (!span.isEmpty()) {
575 span.clampToSinglePixel({xMax - 1, y});
576 next->pointSpan(span);
577 }
578 } else {
579 Span rightClamped = span.breakAt(xMax, dx);
580 if (!rightClamped.isEmpty()) {
581 rightClamped.clampToSinglePixel({xMax - 1, y});
582 next->pointSpan(rightClamped);
583 }
584 Span middle = span.breakAt(xMin, dx);
585 if (!middle.isEmpty()) {
586 next->pointSpan(middle);
587 }
588 if (!span.isEmpty()) {
589 span.clampToSinglePixel({xMin, y});
590 next->pointSpan(span);
591 }
592 }
593 return true;
594 }
595
596 template <typename Next>
597 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) {
598 return false;
599 }
600
601 private:
602 const Sk4s fXMin{SK_FloatNegativeInfinity};
603 const Sk4s fYMin{SK_FloatNegativeInfinity};
604 const Sk4s fXMax{SK_FloatInfinity};
605 const Sk4s fYMax{SK_FloatInfinity};
606 };
607 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> 233 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
608 using Clamp = BilerpProcessor<ClampStrategy, Next>; 234 using Clamp = BilerpProcessor<ClampStrategy, Next>;
609 235
610 static SkScalar tile_mod(SkScalar x, SkScalar base) {
611 return x - std::floor(x / base) * base;
612 }
613
614 class RepeatStrategy {
615 public:
616 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { }
617 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { }
618 RepeatStrategy(SkSize max)
619 : fXMax{X(max)}
620 , fXInvMax{1.0f / X(max)}
621 , fYMax{Y(max)}
622 , fYInvMax{1.0f / Y(max)} { }
623
624 void processPoints(Sk4s* xs, Sk4s* ys) {
625 Sk4s divX = (*xs * fXInvMax).floor();
626 Sk4s divY = (*ys * fYInvMax).floor();
627 Sk4s baseX = (divX * fXMax);
628 Sk4s baseY = (divY * fYMax);
629 *xs = *xs - baseX;
630 *ys = *ys - baseY;
631 }
632
633 template <typename Next>
634 bool maybeProcessSpan(Span originalSpan, Next* next) {
635 SkASSERT(!originalSpan.isEmpty());
636 SkPoint start; SkScalar length; int count;
637 std::tie(start, length, count) = originalSpan;
638 // Make x and y in range on the tile.
639 SkScalar x = tile_mod(X(start), fXMax[0]);
640 SkScalar y = tile_mod(Y(start), fYMax[0]);
641 SkScalar xMax = fXMax[0];
642 SkScalar xMin = 0.0f;
643 SkScalar dx = length / (count - 1);
644
645 // No need trying to go fast because the steps are larger than a tile or there is one point.
646 if (SkScalarAbs(dx) >= xMax || count <= 1) {
647 return false;
648 }
649
650 // A B C D Z
651 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------
652 // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*| ||
653 // | | | || | | || ... | | ||
654 // | | | || | | || | | ||
655 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------
656 // ^^ ^^ ^^
657 // xMax || xMin xMax || xMin xM ax || xMin
658 //
659 // *---*---*---... - track of samples. * = sample
660 //
661 // +-+ ||
662 // | | - pixels in source space. || - tile border.
663 // +-+ ||
664 //
665 //
666 // The given span starts at A and continues on through several tiles to sample point Z.
667 // The idea is to break this into several spans one on each tile the ent ire span
668 // intersects. The A to B span only covers a partial tile and has a coun t of 3 and the
669 // distance from A to B is (count - 1) * dx or 2 * dx. The distance from A to the start of
670 // the next span is count * dx or 3 * dx. Span C to D covers an entire t ile has a count
671 // of 5 and a length of 4 * dx. Remember, count is the number of pixels needed for the
672 // destination and the number of samples.
673 //
674 // Overall Strategy:
675 // While the span hangs over the edge of the tile, draw the span coverin g the tile then
676 // slide the span over to the next tile.
677
678 // The guard could have been count > 0, but then a bunch of math would b e done in the
679 // common case.
680
681 Span span({x,y}, length, count);
682 if (dx > 0) {
683 while (!span.isEmpty() && span.endX() > xMax) {
684 Span toDraw = span.breakAt(xMax, dx);
685 next->pointSpan(toDraw);
686 span.offset(-xMax);
687 }
688 } else {
689 while (!span.isEmpty() && span.endX() < xMin) {
690 Span toDraw = span.breakAt(xMin, dx);
691 next->pointSpan(toDraw);
692 span.offset(xMax);
693 }
694 }
695
696 // All on a single tile.
697 if (!span.isEmpty()) {
698 next->pointSpan(span);
699 }
700
701 return true;
702 }
703
704 template <typename Next>
705 bool maybeProcessBilerpSpan(BilerpSpan bSpan, Next* next) {
706 return false;
707 }
708
709 private:
710 const Sk4s fXMax{0.0f};
711 const Sk4s fXInvMax{0.0f};
712 const Sk4s fYMax{0.0f};
713 const Sk4s fYInvMax{0.0f};
714 };
715
716 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> 236 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
717 using Repeat = BilerpProcessor<RepeatStrategy, Next>; 237 using Repeat = BilerpProcessor<RepeatStrategy, Next>;
718 238
719 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( 239 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler(
720 SkLinearBitmapPipeline::BilerpProcessorInterface* next, 240 SkLinearBitmapPipeline::BilerpProcessorInterface* next,
721 SkSize dimensions, 241 SkSize dimensions,
722 SkShader::TileMode xMode, 242 SkShader::TileMode xMode,
723 SkShader::TileMode yMode, 243 SkShader::TileMode yMode,
724 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth, 244 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth,
725 SkLinearBitmapPipeline::TileStage* tileProcY) { 245 SkLinearBitmapPipeline::TileStage* tileProcY) {
(...skipping 29 matching lines...) Expand all
755 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimens ions)); 275 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimens ions));
756 break; 276 break;
757 case SkShader::kMirror_TileMode: 277 case SkShader::kMirror_TileMode:
758 SkFAIL("Not implemented."); 278 SkFAIL("Not implemented.");
759 break; 279 break;
760 } 280 }
761 } 281 }
762 return tileProcXOrBoth->get(); 282 return tileProcXOrBoth->get();
763 } 283 }
764 284
285 //////////////////////////////////////////////////////////////////////////////// ////////////////////
286 // Source Sampling Stage
765 class sRGBFast { 287 class sRGBFast {
766 public: 288 public:
767 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) { 289 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) {
768 Sk4s l = pixel * pixel; 290 Sk4s l = pixel * pixel;
769 return Sk4s{l[0], l[1], l[2], pixel[3]}; 291 return Sk4s{l[0], l[1], l[2], pixel[3]};
770 } 292 }
771 }; 293 };
772 294
773 enum class ColorOrder { 295 enum class ColorOrder {
774 kRGBA = false, 296 kRGBA = false,
(...skipping 246 matching lines...) Expand 10 before | Expand all | Expand 10 after
1021 sampleStage->Initialize<Sampler<Pixel8888LBGR>>(next, srcPixmap) ; 543 sampleStage->Initialize<Sampler<Pixel8888LBGR>>(next, srcPixmap) ;
1022 } 544 }
1023 break; 545 break;
1024 default: 546 default:
1025 SkFAIL("Not implemented. Unsupported src"); 547 SkFAIL("Not implemented. Unsupported src");
1026 break; 548 break;
1027 } 549 }
1028 return sampleStage->get(); 550 return sampleStage->get();
1029 } 551 }
1030 552
553 //////////////////////////////////////////////////////////////////////////////// ////////////////////
554 // Pixel Placement Stage
1031 template <SkAlphaType alphaType> 555 template <SkAlphaType alphaType>
1032 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { 556 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface {
1033 public: 557 public:
1034 void VECTORCALL placePixel(Sk4f pixel) override { 558 void VECTORCALL placePixel(Sk4f pixel) override {
1035 PlacePixel(fDst, pixel, 0); 559 PlacePixel(fDst, pixel, 0);
1036 fDst += 1; 560 fDst += 1;
1037 } 561 }
1038 562
1039 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { 563 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
1040 SkPM4f* dst = fDst; 564 SkPM4f* dst = fDst;
(...skipping 30 matching lines...) Expand all
1071 if (alphaType == kUnpremul_SkAlphaType) { 595 if (alphaType == kUnpremul_SkAlphaType) {
1072 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(); 596 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>();
1073 } else { 597 } else {
1074 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType 598 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
1075 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(); 599 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>();
1076 } 600 }
1077 return placerStage->get(); 601 return placerStage->get();
1078 } 602 }
1079 } // namespace 603 } // namespace
1080 604
605 //////////////////////////////////////////////////////////////////////////////// ////////////////////
1081 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} 606 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
1082 607
1083 SkLinearBitmapPipeline::SkLinearBitmapPipeline( 608 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
1084 const SkMatrix& inverse, 609 const SkMatrix& inverse,
1085 SkFilterQuality filterQuality, 610 SkFilterQuality filterQuality,
1086 SkShader::TileMode xTile, SkShader::TileMode yTile, 611 SkShader::TileMode xTile, SkShader::TileMode yTile,
1087 const SkPixmap& srcPixmap) { 612 const SkPixmap& srcPixmap) {
1088 SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height()); 613 SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height());
1089 const SkImageInfo& srcImageInfo = srcPixmap.info(); 614 const SkImageInfo& srcImageInfo = srcPixmap.info();
1090 615
1091 // As the stages are built, the chooser function may skip a stage. For examp le, with the 616 // As the stages are built, the chooser function may skip a stage. For examp le, with the
1092 // identity matrix, the matrix stage is skipped, and the tilerStage is the f irst stage. 617 // identity matrix, the matrix stage is skipped, and the tilerStage is the f irst stage.
1093 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS tage); 618 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS tage);
1094 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp leStage); 619 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp leStage);
1095 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage, 620 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage,
1096 &fTileYStage); 621 &fTileYStage);
1097 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage ); 622 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage );
1098 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); 623 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage);
1099 } 624 }
1100 625
1101 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { 626 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
1102 SkASSERT(count > 0); 627 SkASSERT(count > 0);
1103 fPixelStage->setDestination(dst); 628 fPixelStage->setDestination(dst);
1104 // The count and length arguments start out in a precise relation in order t o keep the 629 // The count and length arguments start out in a precise relation in order t o keep the
1105 // math correct through the different stages. Count is the number of pixel t o produce. 630 // math correct through the different stages. Count is the number of pixel t o produce.
1106 // Since the code samples at pixel centers, length is the distance from the center of the 631 // Since the code samples at pixel centers, length is the distance from the center of the
1107 // first pixel to the center of the last pixel. This implies that length is count-1. 632 // first pixel to the center of the last pixel. This implies that length is count-1.
1108 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, count }); 633 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, count });
1109 } 634 }
OLDNEW
« no previous file with comments | « no previous file | src/core/SkLinearBitmapPipeline_core.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698