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

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

Issue 1775963002: Bilerp + mirror + perspective (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Address comments. 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 | « src/core/SkLinearBitmapPipeline.h ('k') | 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
10 #include "SkPM4f.h" 10 #include "SkPM4f.h"
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 #include "SkLinearBitmapPipeline_core.h" 17 #include "SkLinearBitmapPipeline_core.h"
18 #include "SkLinearBitmapPipeline_matrix.h" 18 #include "SkLinearBitmapPipeline_matrix.h"
19 #include "SkLinearBitmapPipeline_tile.h" 19 #include "SkLinearBitmapPipeline_tile.h"
20 #include "SkLinearBitmapPipeline_sample.h"
20 21
21 class SkLinearBitmapPipeline::PointProcessorInterface { 22 class SkLinearBitmapPipeline::PointProcessorInterface {
22 public: 23 public:
23 virtual ~PointProcessorInterface() { } 24 virtual ~PointProcessorInterface() { }
25 // Take the first n (where 0 < n && n < 4) items from xs and ys and sample t hose points. For
26 // nearest neighbor, that means just taking the floor xs and ys. For bilerp, this means
27 // to expand the bilerp filter around the point and sample using that filter .
24 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; 28 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0;
29 // Same as pointListFew, but n = 4.
25 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; 30 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0;
31 // A span is a compact form of sample points that are obtained by mapping po ints from
32 // destination space to source space. This is used for horizontal lines only , and is mainly
33 // used to take advantage of memory coherence for horizontal spans.
26 virtual void pointSpan(Span span) = 0; 34 virtual void pointSpan(Span span) = 0;
27 }; 35 };
28 36
29 class SkLinearBitmapPipeline::BilerpProcessorInterface 37 class SkLinearBitmapPipeline::BilerpProcessorInterface
30 : public SkLinearBitmapPipeline::PointProcessorInterface { 38 : public SkLinearBitmapPipeline::PointProcessorInterface {
31 public: 39 public:
32 // The x's and y's are setup in the following order: 40 // The x's and y's are setup in the following order:
33 // +--------+--------+ 41 // +--------+--------+
34 // | | | 42 // | | |
35 // | px00 | px10 | 43 // | px00 | px10 |
36 // | 0 | 1 | 44 // | 0 | 1 |
37 // +--------+--------+ 45 // +--------+--------+
38 // | | | 46 // | | |
39 // | px01 | px11 | 47 // | px01 | px11 |
40 // | 2 | 3 | 48 // | 2 | 3 |
41 // +--------+--------+ 49 // +--------+--------+
42 // These pixels coordinates are arranged in the following order in xs and ys : 50 // These pixels coordinates are arranged in the following order in xs and ys :
43 // px00 px10 px01 px11 51 // px00 px10 px01 px11
44 virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0; 52 virtual void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) = 0;
45 virtual void bilerpSpan(BilerpSpan span) = 0; 53
54 // A span represents sample points that have been mapped from destination sp ace to source
55 // space. Each sample point is then expanded to the four bilerp points by ad d +/- 0.5. The
56 // resulting Y values my be off the tile. When y +/- 0.5 are more than 1 apa rt because of
57 // tiling, the second Y is used to denote the retiled Y value.
58 virtual void bilerpSpan(Span span, SkScalar y) = 0;
46 }; 59 };
47 60
48 class SkLinearBitmapPipeline::PixelPlacerInterface { 61 class SkLinearBitmapPipeline::PixelPlacerInterface {
49 public: 62 public:
50 virtual ~PixelPlacerInterface() { } 63 virtual ~PixelPlacerInterface() { }
51 virtual void setDestination(SkPM4f* dst) = 0; 64 virtual void setDestination(SkPM4f* dst) = 0;
52 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; 65 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0;
53 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0 ; 66 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0 ;
54 }; 67 };
55 68
56 namespace { 69 namespace {
70
71 //////////////////////////////////////////////////////////////////////////////// ////////////////////
72 // Matrix Stage
57 // PointProcessor uses a strategy to help complete the work of the different sta ges. The strategy 73 // PointProcessor uses a strategy to help complete the work of the different sta ges. The strategy
58 // must implement the following methods: 74 // must implement the following methods:
59 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. 75 // * processPoints(xs, ys) - must mutate the xs and ys for the stage.
60 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel s 76 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel s
61 // to work over. 77 // to work over.
62 // span - encapsulation of span. 78 // span - encapsulation of span.
63 // next - a pointer to the next stage. 79 // next - a pointer to the next stage.
64 // maybeProcessSpan - returns false if it can not process the span and needs t o fallback to 80 // maybeProcessSpan - returns false if it can not process the span and needs t o fallback to
65 // point lists for processing. 81 // point lists for processing.
66 template<typename Strategy, typename Next> 82 template<typename Strategy, typename Next>
67 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterf ace { 83 class MatrixStage final : public SkLinearBitmapPipeline::PointProcessorInterface {
68 public: 84 public:
69 template <typename... Args> 85 template <typename... Args>
70 PointProcessor(Next* next, Args&&... args) 86 MatrixStage(Next* next, Args&&... args)
71 : fNext{next} 87 : fNext{next}
72 , fStrategy{std::forward<Args>(args)...}{ } 88 , fStrategy{std::forward<Args>(args)...}{ }
73 89
74 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 90 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
75 fStrategy.processPoints(&xs, &ys); 91 fStrategy.processPoints(&xs, &ys);
76 fNext->pointListFew(n, xs, ys); 92 fNext->pointListFew(n, xs, ys);
77 } 93 }
78 94
79 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { 95 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
80 fStrategy.processPoints(&xs, &ys); 96 fStrategy.processPoints(&xs, &ys);
81 fNext->pointList4(xs, ys); 97 fNext->pointList4(xs, ys);
82 } 98 }
83 99
84 // The span you pass must not be empty. 100 // The span you pass must not be empty.
85 void pointSpan(Span span) override { 101 void pointSpan(Span span) override {
86 SkASSERT(!span.isEmpty()); 102 SkASSERT(!span.isEmpty());
87 if (!fStrategy.maybeProcessSpan(span, fNext)) { 103 if (!fStrategy.maybeProcessSpan(span, fNext)) {
88 span_fallback(span, this); 104 span_fallback(span, this);
89 } 105 }
90 } 106 }
91 107
92 private: 108 private:
93 Next* const fNext; 109 Next* const fNext;
94 Strategy fStrategy; 110 Strategy fStrategy;
95 }; 111 };
96 112
97 // See PointProcessor for responsibilities of Strategy.
98 template<typename Strategy, typename Next>
99 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInte rface {
100 public:
101 template <typename... Args>
102 BilerpProcessor(Next* next, Args&&... args)
103 : fNext{next}
104 , fStrategy{std::forward<Args>(args)...}{ }
105
106 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
107 fStrategy.processPoints(&xs, &ys);
108 fNext->pointListFew(n, xs, ys);
109 }
110
111 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
112 fStrategy.processPoints(&xs, &ys);
113 fNext->pointList4(xs, ys);
114 }
115
116 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override {
117 fStrategy.processPoints(&xs, &ys);
118 fNext->bilerpList(xs, ys);
119 }
120
121 void pointSpan(Span span) override {
122 SkASSERT(!span.isEmpty());
123 if (!fStrategy.maybeProcessSpan(span, fNext)) {
124 span_fallback(span, this);
125 }
126 }
127
128 void bilerpSpan(BilerpSpan bSpan) override {
129 SkASSERT(!bSpan.isEmpty());
130 if (!fStrategy.maybeProcessBilerpSpan(bSpan, fNext)) {
131 bilerp_span_fallback(bSpan, this);
132 }
133 }
134
135 private:
136 Next* const fNext;
137 Strategy fStrategy;
138 };
139
140 //////////////////////////////////////////////////////////////////////////////// ////////////////////
141 // Matrix Stage
142 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 113 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
143 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; 114 using TranslateMatrix = MatrixStage<TranslateMatrixStrategy, Next>;
144 115
145 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 116 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
146 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; 117 using ScaleMatrix = MatrixStage<ScaleMatrixStrategy, Next>;
147 118
148 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> 119 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
149 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; 120 using AffineMatrix = MatrixStage<AffineMatrixStrategy, Next>;
121
122 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface>
123 using PerspectiveMatrix = MatrixStage<PerspectiveMatrixStrategy, Next>;
124
150 125
151 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( 126 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix(
152 SkLinearBitmapPipeline::PointProcessorInterface* next, 127 SkLinearBitmapPipeline::PointProcessorInterface* next,
153 const SkMatrix& inverse, 128 const SkMatrix& inverse,
154 SkLinearBitmapPipeline::MatrixStage* matrixProc) { 129 SkLinearBitmapPipeline::MatrixStage* matrixProc) {
155 if (inverse.hasPerspective()) { 130 if (inverse.hasPerspective()) {
156 SkFAIL("Not implemented."); 131 matrixProc->Initialize<PerspectiveMatrix<>>(
132 next,
133 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
134 SkVector{inverse.getScaleX(), inverse.getScaleY()},
135 SkVector{inverse.getSkewX(), inverse.getSkewY()},
136 SkVector{inverse.getPerspX(), inverse.getPerspY()},
137 inverse.get(SkMatrix::kMPersp2));
157 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) { 138 } else if (inverse.getSkewX() != 0.0f || inverse.getSkewY() != 0.0f) {
158 matrixProc->Initialize<AffineMatrix<>>( 139 matrixProc->Initialize<AffineMatrix<>>(
159 next, 140 next,
160 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, 141 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
161 SkVector{inverse.getScaleX(), inverse.getScaleY()}, 142 SkVector{inverse.getScaleX(), inverse.getScaleY()},
162 SkVector{inverse.getSkewX(), inverse.getSkewY()}); 143 SkVector{inverse.getSkewX(), inverse.getSkewY()});
163 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) { 144 } else if (inverse.getScaleX() != 1.0f || inverse.getScaleY() != 1.0f) {
164 matrixProc->Initialize<ScaleMatrix<>>( 145 matrixProc->Initialize<ScaleMatrix<>>(
165 next, 146 next,
166 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}, 147 SkVector{inverse.getTranslateX(), inverse.getTranslateY()},
167 SkVector{inverse.getScaleX(), inverse.getScaleY()}); 148 SkVector{inverse.getScaleX(), inverse.getScaleY()});
168 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0 f) { 149 } else if (inverse.getTranslateX() != 0.0f || inverse.getTranslateY() != 0.0 f) {
169 matrixProc->Initialize<TranslateMatrix<>>( 150 matrixProc->Initialize<TranslateMatrix<>>(
170 next, 151 next,
171 SkVector{inverse.getTranslateX(), inverse.getTranslateY()}); 152 SkVector{inverse.getTranslateX(), inverse.getTranslateY()});
172 } else { 153 } else {
173 return next; 154 return next;
174 } 155 }
175 return matrixProc->get(); 156 return matrixProc->get();
176 } 157 }
177 158
178 //////////////////////////////////////////////////////////////////////////////// //////////////////// 159 //////////////////////////////////////////////////////////////////////////////// ////////////////////
179 // Bilerp Expansion Stage 160 // Tile Stage
180 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> 161
181 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac e { 162 template<typename XStrategy, typename YStrategy, typename Next>
163 class NearestTileStage final : public SkLinearBitmapPipeline::PointProcessorInte rface {
182 public: 164 public:
183 ExpandBilerp(Next* next) : fNext{next} { } 165 template <typename... Args>
166 NearestTileStage(Next* next, SkISize dimensions)
167 : fNext{next}
168 , fXStrategy{dimensions.width()}
169 , fYStrategy{dimensions.height()}{ }
184 170
185 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 171 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
186 SkASSERT(0 < n && n < 4); 172 fXStrategy.tileXPoints(&xs);
187 // px00 px10 px01 px11 173 fYStrategy.tileYPoints(&ys);
188 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, 174 fNext->pointListFew(n, xs, ys);
189 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; 175 }
190 if (n >= 1) fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYO ffsets); 176
191 if (n >= 2) fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYO ffsets); 177 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
192 if (n >= 3) fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYO ffsets); 178 fXStrategy.tileXPoints(&xs);
193 } 179 fYStrategy.tileYPoints(&ys);
194 180 fNext->pointList4(xs, ys);
195 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { 181 }
196 // px00 px10 px01 px11 182
197 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, 183 // The span you pass must not be empty.
198 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f};
199 fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets);
200 fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets);
201 fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets);
202 fNext->bilerpList(Sk4s{xs[3]} + kXOffsets, Sk4s{ys[3]} + kYOffsets);
203 }
204
205 void pointSpan(Span span) override { 184 void pointSpan(Span span) override {
206 SkASSERT(!span.isEmpty()); 185 SkASSERT(!span.isEmpty());
207 SkPoint start; SkScalar length; int count; 186 SkPoint start; SkScalar length; int count;
208 std::tie(start, length, count) = span; 187 std::tie(start, length, count) = span;
209 // Adjust the span so that it is in the correct phase with the pixel. 188 SkScalar x = X(start);
210 BilerpSpan bSpan{X(start) - 0.5f, Y(start) - 0.5f, Y(start) + 0.5f, leng th, count}; 189 SkScalar y = fYStrategy.tileY(Y(start));
211 fNext->bilerpSpan(bSpan); 190 Span yAdjustedSpan{{x, y}, length, count};
191 if (!fXStrategy.maybeProcessSpan(yAdjustedSpan, fNext)) {
192 span_fallback(span, this);
193 }
212 } 194 }
213 195
214 private: 196 private:
215 Next* const fNext; 197 Next* const fNext;
216 }; 198 XStrategy fXStrategy;
217 199 YStrategy fYStrategy;
218 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( 200 };
219 SkLinearBitmapPipeline::BilerpProcessorInterface* next, 201
220 SkFilterQuality filterQuailty, 202 template<typename XStrategy, typename YStrategy, typename Next>
221 SkLinearBitmapPipeline::FilterStage* filterProc) { 203 class BilerpTileStage final : public SkLinearBitmapPipeline::PointProcessorInter face {
222 if (SkFilterQuality::kNone_SkFilterQuality == filterQuailty) {
223 return next;
224 } else {
225 filterProc->Initialize<ExpandBilerp<>>(next);
226 return filterProc->get();
227 }
228 }
229
230 //////////////////////////////////////////////////////////////////////////////// ////////////////////
231 // Tile Stage
232 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
233 using Clamp = BilerpProcessor<ClampStrategy, Next>;
234
235 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface>
236 using Repeat = BilerpProcessor<RepeatStrategy, Next>;
237
238 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler(
239 SkLinearBitmapPipeline::BilerpProcessorInterface* next,
240 SkSize dimensions,
241 SkShader::TileMode xMode,
242 SkShader::TileMode yMode,
243 SkLinearBitmapPipeline::TileStage* tileProcXOrBoth,
244 SkLinearBitmapPipeline::TileStage* tileProcY) {
245 if (xMode == yMode) {
246 switch (xMode) {
247 case SkShader::kClamp_TileMode:
248 tileProcXOrBoth->Initialize<Clamp<>>(next, dimensions);
249 break;
250 case SkShader::kRepeat_TileMode:
251 tileProcXOrBoth->Initialize<Repeat<>>(next, dimensions);
252 break;
253 case SkShader::kMirror_TileMode:
254 SkFAIL("Not implemented.");
255 break;
256 }
257 } else {
258 switch (yMode) {
259 case SkShader::kClamp_TileMode:
260 tileProcY->Initialize<Clamp<>>(next, Y(dimensions));
261 break;
262 case SkShader::kRepeat_TileMode:
263 tileProcY->Initialize<Repeat<>>(next, Y(dimensions));
264 break;
265 case SkShader::kMirror_TileMode:
266 SkFAIL("Not implemented.");
267 break;
268 }
269 switch (xMode) {
270 case SkShader::kClamp_TileMode:
271 tileProcXOrBoth->Initialize<Clamp<>>(tileProcY->get(), X(dimensi ons));
272 break;
273 case SkShader::kRepeat_TileMode:
274 tileProcXOrBoth->Initialize<Repeat<>>(tileProcY->get(), X(dimens ions));
275 break;
276 case SkShader::kMirror_TileMode:
277 SkFAIL("Not implemented.");
278 break;
279 }
280 }
281 return tileProcXOrBoth->get();
282 }
283
284 //////////////////////////////////////////////////////////////////////////////// ////////////////////
285 // Source Sampling Stage
286 class sRGBFast {
287 public:
288 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) {
289 Sk4s l = pixel * pixel;
290 return Sk4s{l[0], l[1], l[2], pixel[3]};
291 }
292 };
293
294 enum class ColorOrder {
295 kRGBA = false,
296 kBGRA = true,
297 };
298 template <SkColorProfileType colorProfile, ColorOrder colorOrder>
299 class Pixel8888 {
300 public:
301 Pixel8888(int width, const uint32_t* src) : fSrc{src}, fWidth{width}{ }
302 Pixel8888(const SkPixmap& srcPixmap)
303 : fSrc{srcPixmap.addr32()}
304 , fWidth{static_cast<int>(srcPixmap.rowBytes() / 4)} { }
305
306 void VECTORCALL getFewPixels(int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) {
307 Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
308 Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
309 Sk4i bufferLoc = YIs * fWidth + XIs;
310 switch (n) {
311 case 3:
312 *px2 = this->getPixel(fSrc, bufferLoc[2]);
313 case 2:
314 *px1 = this->getPixel(fSrc, bufferLoc[1]);
315 case 1:
316 *px0 = this->getPixel(fSrc, bufferLoc[0]);
317 default:
318 break;
319 }
320 }
321
322 void VECTORCALL get4Pixels(Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2 , Sk4f* px3) {
323 Sk4i XIs = SkNx_cast<int, SkScalar>(xs);
324 Sk4i YIs = SkNx_cast<int, SkScalar>(ys);
325 Sk4i bufferLoc = YIs * fWidth + XIs;
326 *px0 = this->getPixel(fSrc, bufferLoc[0]);
327 *px1 = this->getPixel(fSrc, bufferLoc[1]);
328 *px2 = this->getPixel(fSrc, bufferLoc[2]);
329 *px3 = this->getPixel(fSrc, bufferLoc[3]);
330 }
331
332 void get4Pixels(const void* vsrc, int index, Sk4f* px0, Sk4f* px1, Sk4f* px2 , Sk4f* px3) {
333 const uint32_t* src = static_cast<const uint32_t*>(vsrc);
334 *px0 = this->getPixel(src, index + 0);
335 *px1 = this->getPixel(src, index + 1);
336 *px2 = this->getPixel(src, index + 2);
337 *px3 = this->getPixel(src, index + 3);
338 }
339
340 Sk4f getPixel(const void* vsrc, int index) {
341 const uint32_t* src = static_cast<const uint32_t*>(vsrc);
342 Sk4b bytePixel = Sk4b::Load((uint8_t *)(&src[index]));
343 Sk4f pixel = SkNx_cast<float, uint8_t>(bytePixel);
344 if (colorOrder == ColorOrder::kBGRA) {
345 pixel = SkNx_shuffle<2, 1, 0, 3>(pixel);
346 }
347 pixel = pixel * Sk4f{1.0f/255.0f};
348 if (colorProfile == kSRGB_SkColorProfileType) {
349 pixel = sRGBFast::sRGBToLinear(pixel);
350 }
351 return pixel;
352 }
353
354 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; }
355
356 private:
357 const uint32_t* const fSrc;
358 const Sk4i fWidth;
359 };
360
361 // Explaination of the math:
362 // 1 - x x
363 // +--------+--------+
364 // | | |
365 // 1 - y | px00 | px10 |
366 // | | |
367 // +--------+--------+
368 // | | |
369 // y | px01 | px11 |
370 // | | |
371 // +--------+--------+
372 //
373 //
374 // Given a pixelxy each is multiplied by a different factor derived from the fra ctional part of x
375 // and y:
376 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy
377 // * px10 -> x(1 - y) = x - xy
378 // * px01 -> (1 - x)y = y - xy
379 // * px11 -> xy
380 // So x * y is calculated first and then used to calculate all the other factors .
381 static Sk4s VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10,
382 Sk4f px01, Sk4f px11) {
383 // Calculate fractional xs and ys.
384 Sk4s fxs = xs - xs.floor();
385 Sk4s fys = ys - ys.floor();
386 Sk4s fxys{fxs * fys};
387 Sk4f sum = px11 * fxys;
388 sum = sum + px01 * (fys - fxys);
389 sum = sum + px10 * (fxs - fxys);
390 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys);
391 return sum;
392 }
393
394 template <typename SourceStrategy>
395 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface {
396 public: 204 public:
397 template <typename... Args> 205 template <typename... Args>
398 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) 206 BilerpTileStage(Next* next, SkISize dimensions)
399 : fNext{next} 207 : fXMax(dimensions.width())
400 , fStrategy{std::forward<Args>(args)...} { } 208 , fYMax(dimensions.height())
209 , fNext{next}
210 , fXStrategy{dimensions.width()}
211 , fYStrategy{dimensions.height()}{ }
401 212
402 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { 213 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
403 SkASSERT(0 < n && n < 4); 214 fXStrategy.tileXPoints(&xs);
404 Sk4f px0, px1, px2; 215 fYStrategy.tileYPoints(&ys);
405 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); 216 // TODO: check to see if xs and ys are in range then just call pointList Few on next.
406 if (n >= 1) fNext->placePixel(px0); 217 if (n >= 1) this->bilerpPoint(xs[0], ys[0]);
407 if (n >= 2) fNext->placePixel(px1); 218 if (n >= 2) this->bilerpPoint(xs[1], ys[1]);
408 if (n >= 3) fNext->placePixel(px2); 219 if (n >= 3) this->bilerpPoint(xs[2], ys[2]);
409 } 220 }
410 221
411 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { 222 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
412 Sk4f px0, px1, px2, px3; 223 fXStrategy.tileXPoints(&xs);
413 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); 224 fYStrategy.tileYPoints(&ys);
414 fNext->place4Pixels(px0, px1, px2, px3); 225 // TODO: check to see if xs and ys are in range then just call pointList 4 on next.
415 } 226 this->bilerpPoint(xs[0], ys[0]);
416 227 this->bilerpPoint(xs[1], ys[1]);
417 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { 228 this->bilerpPoint(xs[2], ys[2]);
418 Sk4f px00, px10, px01, px11; 229 this->bilerpPoint(xs[3], ys[3]);
419 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); 230 }
420 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); 231
421 fNext->placePixel(pixel); 232 struct Wrapper {
422 } 233 void pointSpan(Span span) {
423 234 processor->breakIntoEdges(span);
235 }
236
237 BilerpTileStage* processor;
238 };
239
240 // The span you pass must not be empty.
424 void pointSpan(Span span) override { 241 void pointSpan(Span span) override {
425 SkASSERT(!span.isEmpty()); 242 SkASSERT(!span.isEmpty());
426 SkPoint start; SkScalar length; int count; 243
427 std::tie(start, length, count) = span; 244 Wrapper wrapper = {this};
428 if (length < (count - 1)) { 245 if (!fXStrategy.maybeProcessSpan(span, &wrapper)) {
429 this->pointSpanSlowRate(span); 246 span_fallback(span, this);
430 } else if (length == (count - 1)) {
431 this->pointSpanUnitRate(span);
432 } else {
433 this->pointSpanFastRate(span);
434 } 247 }
435 } 248 }
436 249
437 private: 250 private:
438 // When moving through source space more slowly than dst space (zoomed in), 251 void bilerpPoint(SkScalar x, SkScalar y) {
439 // we'll be sampling from the same source pixel more than once. 252 Sk4f txs = Sk4f{x} + Sk4f{-0.5f, 0.5f, -0.5f, 0.5f};
440 void pointSpanSlowRate(Span span) { 253 Sk4f tys = Sk4f{y} + Sk4f{-0.5f, -0.5f, 0.5f, 0.5f};
254 fXStrategy.tileXPoints(&txs);
255 fYStrategy.tileYPoints(&tys);
256 fNext->bilerpEdge(txs, tys);
257 }
258
259 void handleEdges(Span span, SkScalar dx) {
441 SkPoint start; SkScalar length; int count; 260 SkPoint start; SkScalar length; int count;
442 std::tie(start, length, count) = span; 261 std::tie(start, length, count) = span;
443 SkScalar x = X(start); 262 SkScalar x = X(start);
444 SkFixed fx = SkScalarToFixed(x); 263 SkScalar y = Y(start);
445 SkScalar dx = length / (count - 1); 264 SkScalar tiledY = fYStrategy.tileY(y);
446 SkFixed fdx = SkScalarToFixed(dx); 265 while (count > 0) {
447 266 this->bilerpPoint(x, tiledY);
448 const void* row = fStrategy.row((int)std::floor(Y(start))); 267 x += dx;
449 SkLinearBitmapPipeline::PixelPlacerInterface* next = fNext; 268 count -= 1;
450 269 }
451 int ix = SkFixedFloorToInt(fx); 270 }
452 int prevIX = ix; 271
453 Sk4f fpixel = fStrategy.getPixel(row, ix); 272 void yProcessSpan(Span span) {
454 273 SkScalar tiledY = fYStrategy.tileY(span.startY());
455 // When dx is less than one, each pixel is used more than once. Using th e fixed point fx 274 if (0.5f <= tiledY && tiledY < fYMax - 0.5f ) {
456 // allows the code to quickly check that the same pixel is being used. T he code uses this 275 Span tiledSpan{{span.startX(), tiledY}, span.length(), span.count()} ;
457 // same pixel check to do the sRGB and normalization only once. 276 fNext->pointSpan(tiledSpan);
458 auto getNextPixel = [&]() { 277 } else {
459 if (ix != prevIX) { 278 // Convert to the Y0 bilerp sample set by shifting by -0.5f. Then ti le that new y
460 fpixel = fStrategy.getPixel(row, ix); 279 // value and shift it back resulting in the working Y0. Do the same thing with Y1 but
461 prevIX = ix; 280 // in the opposite direction.
281 SkScalar y0 = fYStrategy.tileY(span.startY() - 0.5f) + 0.5f;
282 SkScalar y1 = fYStrategy.tileY(span.startY() + 0.5f) - 0.5f;
283 Span newSpan{{span.startX(), y0}, span.length(), span.count()};
284 fNext->bilerpSpan(newSpan, y1);
285 }
286 }
287 void breakIntoEdges(Span span) {
288 if (span.length() == 0) {
289 yProcessSpan(span);
290 } else {
291 SkScalar dx = span.length() / (span.count() - 1);
292 if (span.length() > 0) {
293 Span leftBorder = span.breakAt(0.5f, dx);
294 if (!leftBorder.isEmpty()) {
295 this->handleEdges(leftBorder, dx);
296 }
297 Span center = span.breakAt(fXMax - 0.5f, dx);
298 if (!center.isEmpty()) {
299 this->yProcessSpan(center);
300 }
301
302 if (!span.isEmpty()) {
303 this->handleEdges(span, dx);
304 }
305 } else {
306 Span center = span.breakAt(fXMax + 0.5f, dx);
307 if (!span.isEmpty()) {
308 this->handleEdges(span, dx);
309 }
310 Span leftEdge = center.breakAt(0.5f, dx);
311 if (!center.isEmpty()) {
312 this->yProcessSpan(center);
313 }
314 if (!leftEdge.isEmpty()) {
315 this->handleEdges(leftEdge, dx);
316 }
317
462 } 318 }
463 fx += fdx; 319 }
464 ix = SkFixedFloorToInt(fx); 320 }
465 return fpixel; 321
466 }; 322 SkScalar fXMax;
467 323 SkScalar fYMax;
468 while (count >= 4) { 324 Next* const fNext;
469 Sk4f px0 = getNextPixel(); 325 XStrategy fXStrategy;
470 Sk4f px1 = getNextPixel(); 326 YStrategy fYStrategy;
471 Sk4f px2 = getNextPixel(); 327 };
472 Sk4f px3 = getNextPixel(); 328
473 next->place4Pixels(px0, px1, px2, px3); 329 template <typename XStrategy, typename YStrategy, typename Next>
474 count -= 4; 330 void make_tile_stage(
475 } 331 SkFilterQuality filterQuality, SkISize dimensions,
476 while (count > 0) { 332 Next* next, SkLinearBitmapPipeline::TileStage* tileStage) {
477 next->placePixel(getNextPixel()); 333 if (filterQuality == kNone_SkFilterQuality) {
478 count -= 1; 334 tileStage->Initialize<NearestTileStage<XStrategy, YStrategy, Next>>(next , dimensions);
479 } 335 } else {
480 } 336 tileStage->Initialize<BilerpTileStage<XStrategy, YStrategy, Next>>(next, dimensions);
481 337 }
482 // We're moving through source space at a rate of 1 source pixel per 1 dst p ixel. 338 }
483 // We'll never re-use pixels, but we can at least load contiguous pixels. 339 template <typename XStrategy>
484 void pointSpanUnitRate(Span span) { 340 void choose_tiler_ymode(
485 SkPoint start; SkScalar length; int count; 341 SkShader::TileMode yMode, SkFilterQuality filterQuality, SkISize dimensions,
486 std::tie(start, length, count) = span; 342 SkLinearBitmapPipeline::BilerpProcessorInterface* next,
487 int ix = SkScalarFloorToInt(X(start)); 343 SkLinearBitmapPipeline::TileStage* tileStage) {
488 const void* row = fStrategy.row((int)std::floor(Y(start))); 344 switch (yMode) {
489 SkLinearBitmapPipeline::PixelPlacerInterface* next = fNext; 345 case SkShader::kClamp_TileMode:
490 while (count >= 4) { 346 make_tile_stage<XStrategy, YClampStrategy>(filterQuality, dimensions , next, tileStage);
491 Sk4f px0, px1, px2, px3; 347 break;
492 fStrategy.get4Pixels(row, ix, &px0, &px1, &px2, &px3); 348 case SkShader::kRepeat_TileMode:
493 next->place4Pixels(px0, px1, px2, px3); 349 make_tile_stage<XStrategy, YRepeatStrategy>(filterQuality, dimension s, next, tileStage);
494 ix += 4; 350 break;
495 count -= 4; 351 case SkShader::kMirror_TileMode:
496 } 352 make_tile_stage<XStrategy, YMirrorStrategy>(filterQuality, dimension s, next, tileStage);
497 353 break;
498 while (count > 0) { 354 }
499 next->placePixel(fStrategy.getPixel(row, ix)); 355 };
500 ix += 1; 356
501 count -= 1; 357 static SkLinearBitmapPipeline::PointProcessorInterface* choose_tiler(
502 } 358 SkLinearBitmapPipeline::BilerpProcessorInterface* next,
503 } 359 SkISize dimensions,
504 360 SkShader::TileMode xMode,
505 // We're moving through source space faster than dst (zoomed out), 361 SkShader::TileMode yMode,
506 // so we'll never reuse a source pixel or be able to do contiguous loads. 362 SkFilterQuality filterQuality,
507 void pointSpanFastRate(Span span) { 363 SkLinearBitmapPipeline::TileStage* tileStage) {
508 span_fallback(span, this); 364 switch (xMode) {
509 } 365 case SkShader::kClamp_TileMode:
510 366 choose_tiler_ymode<XClampStrategy>(yMode, filterQuality, dimensions, next, tileStage);
511 void bilerpSpan(BilerpSpan span) override { 367 break;
512 bilerp_span_fallback(span, this); 368 case SkShader::kRepeat_TileMode:
369 choose_tiler_ymode<XRepeatStrategy>(yMode, filterQuality, dimensions , next, tileStage);
370 break;
371 case SkShader::kMirror_TileMode:
372 choose_tiler_ymode<XMirrorStrategy>(yMode, filterQuality, dimensions , next, tileStage);
373 break;
374 }
375
376 return tileStage->get();
377 }
378
379
380 //////////////////////////////////////////////////////////////////////////////// ////////////////////
381 // Source Sampling Stage
382 template <typename SourceStrategy, typename Next>
383 class NearestNeighborSampler final : public SkLinearBitmapPipeline::BilerpProces sorInterface {
384 public:
385 template <typename... Args>
386 NearestNeighborSampler(Next* next, Args&&... args)
387 : fSampler{next, std::forward<Args>(args)...} { }
388
389 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
390 fSampler.nearestListFew(n, xs, ys);
391 }
392 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
393 fSampler.nearestList4(xs, ys);
394 }
395 void pointSpan(Span span) override {
396 fSampler.nearestSpan(span);
397 }
398 void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override {
399 SkFAIL("Using nearest neighbor sampler, but calling a bilerpEdge.");
400 }
401
402 virtual void bilerpSpan(Span span, SkScalar y) override {
403 SkFAIL("Using nearest neighbor sampler, but calling a bilerpSpan.");
513 } 404 }
514 405
515 private: 406 private:
516 SkLinearBitmapPipeline::PixelPlacerInterface* const fNext; 407 GeneralSampler<SourceStrategy, Next> fSampler;
517 SourceStrategy fStrategy; 408 };
518 }; 409
519 410 template <typename SourceStrategy, typename Next>
520 using Pixel8888SRGB = Pixel8888<kSRGB_SkColorProfileType, ColorOrder::kRGBA>; 411 class BilerpSampler final : public SkLinearBitmapPipeline::BilerpProcessorInterf ace {
521 using Pixel8888LRGB = Pixel8888<kLinear_SkColorProfileType, ColorOrder::kRGBA>; 412 public:
522 using Pixel8888SBGR = Pixel8888<kSRGB_SkColorProfileType, ColorOrder::kBGRA>; 413 template <typename... Args>
523 using Pixel8888LBGR = Pixel8888<kLinear_SkColorProfileType, ColorOrder::kBGRA>; 414 BilerpSampler(Next* next, Args&&... args)
524 415 : fSampler{next, std::forward<Args>(args)...} { }
525 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler( 416
526 SkLinearBitmapPipeline::PixelPlacerInterface* next, 417 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override {
418 fSampler.bilerpListFew(n, xs, ys);
419 }
420 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override {
421 fSampler.bilerpList4(xs, ys);
422 }
423 void pointSpan(Span span) override {
424 fSampler.bilerpSpan(span);
425 }
426 void VECTORCALL bilerpEdge(Sk4s xs, Sk4s ys) override {
427 fSampler.bilerpEdge(xs, ys);
428 }
429
430 virtual void bilerpSpan(Span span, SkScalar y) override {
431 fSampler.bilerpSpanWithY(span, y);
432 }
433
434 private:
435 GeneralSampler<SourceStrategy, Next> fSampler;
436 };
437
438 using Placer = SkLinearBitmapPipeline::PixelPlacerInterface;
439
440 template<template <typename, typename> class Sampler>
441 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler_ba se(
442 Placer* next,
527 const SkPixmap& srcPixmap, 443 const SkPixmap& srcPixmap,
528 SkLinearBitmapPipeline::SampleStage* sampleStage) { 444 SkLinearBitmapPipeline::SampleStage* sampleStage) {
529 const SkImageInfo& imageInfo = srcPixmap.info(); 445 const SkImageInfo& imageInfo = srcPixmap.info();
530 switch (imageInfo.colorType()) { 446 switch (imageInfo.colorType()) {
531 case kRGBA_8888_SkColorType: 447 case kRGBA_8888_SkColorType:
532 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { 448 if (imageInfo.profileType() == kSRGB_SkColorProfileType) {
533 sampleStage->Initialize<Sampler<Pixel8888SRGB>>(next, srcPixmap) ; 449 sampleStage->Initialize<Sampler<Pixel8888SRGB, Placer>>(next, sr cPixmap);
534 } else { 450 } else {
535 sampleStage->Initialize<Sampler<Pixel8888LRGB>>(next, srcPixmap) ; 451 sampleStage->Initialize<Sampler<Pixel8888LRGB, Placer>>(next, sr cPixmap);
536 } 452 }
537 break; 453 break;
538 case kBGRA_8888_SkColorType: 454 case kBGRA_8888_SkColorType:
539 if (imageInfo.profileType() == kSRGB_SkColorProfileType) { 455 if (imageInfo.profileType() == kSRGB_SkColorProfileType) {
540 sampleStage->Initialize<Sampler<Pixel8888SBGR>>(next, srcPixmap) ; 456 sampleStage->Initialize<Sampler<Pixel8888SBGR, Placer>>(next, sr cPixmap);
541 } else { 457 } else {
542 sampleStage->Initialize<Sampler<Pixel8888LBGR>>(next, srcPixmap) ; 458 sampleStage->Initialize<Sampler<Pixel8888LBGR, Placer>>(next, sr cPixmap);
543 } 459 }
544 break; 460 break;
545 default: 461 default:
546 SkFAIL("Not implemented. Unsupported src"); 462 SkFAIL("Not implemented. Unsupported src");
547 break; 463 break;
548 } 464 }
549 return sampleStage->get(); 465 return sampleStage->get();
550 } 466 }
551 467
468 SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler(
469 Placer* next,
470 SkFilterQuality filterQuality,
471 const SkPixmap& srcPixmap,
472 SkLinearBitmapPipeline::SampleStage* sampleStage) {
473 if (filterQuality == kNone_SkFilterQuality) {
474 return choose_pixel_sampler_base<NearestNeighborSampler>(next, srcPixmap , sampleStage);
475 } else {
476 return choose_pixel_sampler_base<BilerpSampler>(next, srcPixmap, sampleS tage);
477 }
478 }
479
552 //////////////////////////////////////////////////////////////////////////////// //////////////////// 480 //////////////////////////////////////////////////////////////////////////////// ////////////////////
553 // Pixel Placement Stage 481 // Pixel Placement Stage
554 template <SkAlphaType alphaType> 482 template <SkAlphaType alphaType>
555 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface { 483 class PlaceFPPixel final : public SkLinearBitmapPipeline::PixelPlacerInterface {
556 public: 484 public:
485 PlaceFPPixel(float postAlpha) : fPostAlpha{postAlpha} { }
557 void VECTORCALL placePixel(Sk4f pixel) override { 486 void VECTORCALL placePixel(Sk4f pixel) override {
558 PlacePixel(fDst, pixel, 0); 487 PlacePixel(fDst, pixel, 0);
559 fDst += 1; 488 fDst += 1;
560 } 489 }
561 490
562 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override { 491 void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) override {
563 SkPM4f* dst = fDst; 492 SkPM4f* dst = fDst;
564 PlacePixel(dst, p0, 0); 493 PlacePixel(dst, p0, 0);
565 PlacePixel(dst, p1, 1); 494 PlacePixel(dst, p1, 1);
566 PlacePixel(dst, p2, 2); 495 PlacePixel(dst, p2, 2);
567 PlacePixel(dst, p3, 3); 496 PlacePixel(dst, p3, 3);
568 fDst += 4; 497 fDst += 4;
569 } 498 }
570 499
571 void setDestination(SkPM4f* dst) override { 500 void setDestination(SkPM4f* dst) override {
572 fDst = dst; 501 fDst = dst;
573 } 502 }
574 503
575 private: 504 private:
576 static void VECTORCALL PlacePixel(SkPM4f* dst, Sk4f pixel, int index) { 505 void VECTORCALL PlacePixel(SkPM4f* dst, Sk4f pixel, int index) {
577 Sk4f newPixel = pixel; 506 Sk4f newPixel = pixel;
578 if (alphaType == kUnpremul_SkAlphaType) { 507 if (alphaType == kUnpremul_SkAlphaType) {
579 newPixel = Premultiply(pixel); 508 newPixel = Premultiply(pixel);
580 } 509 }
510 newPixel = newPixel * fPostAlpha;
581 newPixel.store(dst + index); 511 newPixel.store(dst + index);
582 } 512 }
583 static Sk4f VECTORCALL Premultiply(Sk4f pixel) { 513 static Sk4f VECTORCALL Premultiply(Sk4f pixel) {
584 float alpha = pixel[3]; 514 float alpha = pixel[3];
585 return pixel * Sk4f{alpha, alpha, alpha, 1.0f}; 515 return pixel * Sk4f{alpha, alpha, alpha, 1.0f};
586 } 516 }
587 517
588 SkPM4f* fDst; 518 SkPM4f* fDst;
519 Sk4f fPostAlpha;
589 }; 520 };
590 521
591 static SkLinearBitmapPipeline::PixelPlacerInterface* choose_pixel_placer( 522 static SkLinearBitmapPipeline::PixelPlacerInterface* choose_pixel_placer(
592 SkAlphaType alphaType, 523 SkAlphaType alphaType,
524 float postAlpha,
593 SkLinearBitmapPipeline::PixelStage* placerStage) { 525 SkLinearBitmapPipeline::PixelStage* placerStage) {
594 if (alphaType == kUnpremul_SkAlphaType) { 526 if (alphaType == kUnpremul_SkAlphaType) {
595 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(); 527 placerStage->Initialize<PlaceFPPixel<kUnpremul_SkAlphaType>>(postAlpha);
596 } else { 528 } else {
597 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType 529 // kOpaque_SkAlphaType is treated the same as kPremul_SkAlphaType
598 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(); 530 placerStage->Initialize<PlaceFPPixel<kPremul_SkAlphaType>>(postAlpha);
599 } 531 }
600 return placerStage->get(); 532 return placerStage->get();
601 } 533 }
602 } // namespace 534 } // namespace
603 535
604 //////////////////////////////////////////////////////////////////////////////// //////////////////// 536 //////////////////////////////////////////////////////////////////////////////// ////////////////////
605 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {} 537 SkLinearBitmapPipeline::~SkLinearBitmapPipeline() {}
606 538
607 SkLinearBitmapPipeline::SkLinearBitmapPipeline( 539 SkLinearBitmapPipeline::SkLinearBitmapPipeline(
608 const SkMatrix& inverse, 540 const SkMatrix& inverse,
609 SkFilterQuality filterQuality, 541 SkFilterQuality filterQuality,
610 SkShader::TileMode xTile, SkShader::TileMode yTile, 542 SkShader::TileMode xTile, SkShader::TileMode yTile,
543 float postAlpha,
611 const SkPixmap& srcPixmap) { 544 const SkPixmap& srcPixmap) {
612 SkSize size = SkSize::Make(srcPixmap.width(), srcPixmap.height()); 545 SkISize dimensions = srcPixmap.info().dimensions();
613 const SkImageInfo& srcImageInfo = srcPixmap.info(); 546 const SkImageInfo& srcImageInfo = srcPixmap.info();
614 547
548 SkMatrix adjustedInverse = inverse;
549 if (filterQuality == kNone_SkFilterQuality) {
550 if (inverse.getScaleX() >= 0.0f) {
551 adjustedInverse.setTranslateX(
552 nextafterf(inverse.getTranslateX(), std::floor(inverse.getTransl ateX())));
553 }
554 if (inverse.getScaleY() >= 0.0f) {
555 adjustedInverse.setTranslateY(
556 nextafterf(inverse.getTranslateY(), std::floor(inverse.getTransl ateY())));
557 }
558 }
559
615 // As the stages are built, the chooser function may skip a stage. For examp le, with the 560 // As the stages are built, the chooser function may skip a stage. For examp le, with the
616 // identity matrix, the matrix stage is skipped, and the tilerStage is the f irst stage. 561 // identity matrix, the matrix stage is skipped, and the tilerStage is the f irst stage.
617 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), &fPixelS tage); 562 auto placementStage = choose_pixel_placer(srcImageInfo.alphaType(), postAlph a, &fPixelStage);
618 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp leStage); 563 auto samplerStage = choose_pixel_sampler(placementStage,
619 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage, 564 filterQuality, srcPixmap, &fSampl eStage);
620 &fTileYStage); 565 auto tilerStage = choose_tiler(samplerStage,
621 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage ); 566 dimensions, xTile, yTile, filterQuality, &fTiler);
622 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); 567 fFirstStage = choose_matrix(tilerStage, adjustedInverse, &fMatrixSta ge);
623 } 568 }
624 569
625 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { 570 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) {
626 SkASSERT(count > 0); 571 SkASSERT(count > 0);
627 fPixelStage->setDestination(dst); 572 fPixelStage->setDestination(dst);
628 // The count and length arguments start out in a precise relation in order t o keep the 573 // The count and length arguments start out in a precise relation in order t o keep the
629 // math correct through the different stages. Count is the number of pixel t o produce. 574 // math correct through the different stages. Count is the number of pixel t o produce.
630 // Since the code samples at pixel centers, length is the distance from the center of the 575 // Since the code samples at pixel centers, length is the distance from the center of the
631 // first pixel to the center of the last pixel. This implies that length is count-1. 576 // first pixel to the center of the last pixel. This implies that length is count-1.
632 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, count }); 577 fFirstStage->pointSpan(Span{{x + 0.5f, y + 0.5f}, count - 1.0f, count});
633 } 578 }
579
OLDNEW
« no previous file with comments | « src/core/SkLinearBitmapPipeline.h ('k') | src/core/SkLinearBitmapPipeline_core.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698