OLD | NEW |
---|---|
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 #include "SkPM4f.h" | 9 #include "SkPM4f.h" |
10 | 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 | 16 |
17 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. | 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 | 18 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
19 #define VECTORCALL __vectorcall | 19 #define VECTORCALL __vectorcall |
20 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) | 20 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) |
21 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) | 21 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) |
22 #else | 22 #else |
23 #define VECTORCALL | 23 #define VECTORCALL |
24 #endif | 24 #endif |
25 | 25 |
26 class SkLinearBitmapPipeline::PointProcessorInterface { | 26 class SkLinearBitmapPipeline::PointProcessorInterface { |
27 public: | 27 public: |
28 virtual ~PointProcessorInterface() { } | 28 virtual ~PointProcessorInterface() { } |
29 virtual void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) = 0; | 29 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; |
30 virtual void VECTORCALL pointList4(Sk4f xs, Sk4f ys) = 0; | 30 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; |
31 | 31 |
32 // The pointSpan method efficiently process horizontal spans of pixels. | 32 // The pointSpan method efficiently process horizontal spans of pixels. |
33 // * start - the point where to start the span. | 33 // * start - the point where to start the span. |
34 // * length - the number of pixels to traverse in source space. | 34 // * length - the number of pixels to traverse in source space. |
35 // * count - the number of pixels to produce in destination 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 | 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. | 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. | 38 // The tilers can produce spans that seem nonsensical. |
39 // * The clamp tiler can create spans with length of 0. This indicates to co py an edge pixel out | 39 // * The clamp tiler can create spans with length of 0. This indicates to co py an edge pixel out |
40 // to the edge of the destination scan. | 40 // to the edge of the destination scan. |
(...skipping 10 matching lines...) Expand all Loading... | |
51 // | | | | 51 // | | | |
52 // | px00 | px10 | | 52 // | px00 | px10 | |
53 // | 0 | 1 | | 53 // | 0 | 1 | |
54 // +--------+--------+ | 54 // +--------+--------+ |
55 // | | | | 55 // | | | |
56 // | px01 | px11 | | 56 // | px01 | px11 | |
57 // | 2 | 3 | | 57 // | 2 | 3 | |
58 // +--------+--------+ | 58 // +--------+--------+ |
59 // These pixels coordinates are arranged in the following order in xs and ys : | 59 // These pixels coordinates are arranged in the following order in xs and ys : |
60 // px00 px10 px01 px11 | 60 // px00 px10 px01 px11 |
61 virtual void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) = 0; | 61 virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0; |
62 }; | 62 }; |
63 | 63 |
64 class SkLinearBitmapPipeline::PixelPlacerInterface { | 64 class SkLinearBitmapPipeline::PixelPlacerInterface { |
65 public: | 65 public: |
66 virtual ~PixelPlacerInterface() { } | 66 virtual ~PixelPlacerInterface() { } |
67 virtual void setDestination(SkPM4f* dst) = 0; | 67 virtual void setDestination(SkPM4f* dst) = 0; |
68 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; | 68 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; |
69 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0 ; | 69 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0 ; |
70 }; | 70 }; |
71 | 71 |
72 namespace { | 72 namespace { |
73 | 73 |
74 struct X { | 74 struct X { |
75 explicit X(SkScalar val) : fVal{val} { } | 75 explicit X(SkScalar val) : fVal{val} { } |
76 explicit X(SkPoint pt) : fVal{pt.fX} { } | 76 explicit X(SkPoint pt) : fVal{pt.fX} { } |
77 explicit X(SkSize s) : fVal{s.fWidth} { } | 77 explicit X(SkSize s) : fVal{s.fWidth} { } |
78 explicit X(SkISize s) : fVal(s.fWidth) { } | 78 explicit X(SkISize s) : fVal(s.fWidth) { } |
79 operator float () const {return fVal;} | 79 operator SkScalar () const {return fVal;} |
80 private: | 80 private: |
81 float fVal; | 81 SkScalar fVal; |
82 }; | 82 }; |
83 | 83 |
84 struct Y { | 84 struct Y { |
85 explicit Y(SkScalar val) : fVal{val} { } | 85 explicit Y(SkScalar val) : fVal{val} { } |
86 explicit Y(SkPoint pt) : fVal{pt.fY} { } | 86 explicit Y(SkPoint pt) : fVal{pt.fY} { } |
87 explicit Y(SkSize s) : fVal{s.fHeight} { } | 87 explicit Y(SkSize s) : fVal{s.fHeight} { } |
88 explicit Y(SkISize s) : fVal(s.fHeight) { } | 88 explicit Y(SkISize s) : fVal(s.fHeight) { } |
89 operator float () const {return fVal;} | 89 operator SkScalar () const {return fVal;} |
90 private: | 90 private: |
91 float fVal; | 91 SkScalar fVal; |
92 }; | 92 }; |
93 | 93 |
94 template <typename Stage> | 94 template <typename Stage> |
95 void 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. | 96 Sk4f xs{X(start)}; |
97 SkASSERT(count > 1); | 97 Sk4f ys{Y(start)}; |
98 | 98 Sk4s fourDx; |
99 float dx = length / (count - 1); | 99 if (count > 1) { |
100 Sk4f Xs = Sk4f(X(start)) + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * Sk4f{dx}; | 100 SkScalar dx = length / (count - 1); |
101 Sk4f Ys{Y(start)}; | 101 xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx; |
102 Sk4f fourDx = {4.0f * dx}; | 102 // Only used if count is >= 4. |
103 fourDx = Sk4f{4.0f * dx}; | |
104 } | |
103 | 105 |
104 while (count >= 4) { | 106 while (count >= 4) { |
105 stage->pointList4(Xs, Ys); | 107 stage->pointList4(xs, ys); |
106 Xs = Xs + fourDx; | 108 xs = xs + fourDx; |
107 count -= 4; | 109 count -= 4; |
108 } | 110 } |
109 if (count > 0) { | 111 if (count > 0) { |
110 stage->pointListFew(count, Xs, Ys); | 112 stage->pointListFew(count, xs, ys); |
111 } | 113 } |
112 } | 114 } |
113 | 115 |
114 // PointProcessor uses a strategy to help complete the work of the different sta ges. The strategy | 116 // PointProcessor uses a strategy to help complete the work of the different sta ges. The strategy |
115 // must implement the following methods: | 117 // must implement the following methods: |
116 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. | 118 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. |
117 // * maybeProcessSpan(start, length, count) - This represents a horizontal serie s of pixels | 119 // * maybeProcessSpan(start, length, count) - This represents a horizontal serie s of pixels |
118 // to work over. | 120 // to work over. |
119 // start - is the starting pixel. This is in destination space before the matr ix stage, and in | 121 // start - is the starting pixel. This is in destination space before the matr ix stage, and in |
120 // source space after the matrix stage. | 122 // source space after the matrix stage. |
121 // length - is this distance between the first pixel center and the last pixel center. Like start, | 123 // 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. | 124 // 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. | 125 // count - the number of pixels in source space to produce. |
124 // next - a pointer to the next stage. | 126 // next - a pointer to the next stage. |
125 // maybeProcessSpan - returns false if it can not process the span and needs t o fallback to | 127 // maybeProcessSpan - returns false if it can not process the span and needs t o fallback to |
126 // point lists for processing. | 128 // point lists for processing. |
127 template<typename Strategy, typename Next> | 129 template<typename Strategy, typename Next> |
128 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterf ace { | 130 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterf ace { |
129 public: | 131 public: |
130 template <typename... Args> | 132 template <typename... Args> |
131 PointProcessor(Next* next, Args&&... args) | 133 PointProcessor(Next* next, Args&&... args) |
132 : fNext{next} | 134 : fNext{next} |
133 , fStrategy{std::forward<Args>(args)...}{ } | 135 , fStrategy{std::forward<Args>(args)...}{ } |
134 | 136 |
135 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 137 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
136 fStrategy.processPoints(&xs, &ys); | 138 fStrategy.processPoints(&xs, &ys); |
137 fNext->pointListFew(n, xs, ys); | 139 fNext->pointListFew(n, xs, ys); |
138 } | 140 } |
139 | 141 |
140 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 142 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
141 fStrategy.processPoints(&xs, &ys); | 143 fStrategy.processPoints(&xs, &ys); |
142 fNext->pointList4(xs, ys); | 144 fNext->pointList4(xs, ys); |
143 } | 145 } |
144 | 146 |
145 void pointSpan(SkPoint start, SkScalar length, int count) override { | 147 void pointSpan(SkPoint start, SkScalar length, int count) override { |
146 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { | 148 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { |
147 span_fallback(start, length, count, this); | 149 span_fallback(start, length, count, this); |
148 } | 150 } |
149 } | 151 } |
150 | 152 |
151 private: | 153 private: |
152 Next* const fNext; | 154 Next* const fNext; |
153 Strategy fStrategy; | 155 Strategy fStrategy; |
154 }; | 156 }; |
155 | 157 |
156 // See PointProcessor for responsibilities of Strategy. | 158 // See PointProcessor for responsibilities of Strategy. |
157 template<typename Strategy, typename Next> | 159 template<typename Strategy, typename Next> |
158 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInte rface { | 160 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInte rface { |
159 public: | 161 public: |
160 template <typename... Args> | 162 template <typename... Args> |
161 BilerpProcessor(Next* next, Args&&... args) | 163 BilerpProcessor(Next* next, Args&&... args) |
162 : fNext{next} | 164 : fNext{next} |
163 , fStrategy{std::forward<Args>(args)...}{ } | 165 , fStrategy{std::forward<Args>(args)...}{ } |
164 | 166 |
165 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 167 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
166 fStrategy.processPoints(&xs, &ys); | 168 fStrategy.processPoints(&xs, &ys); |
167 fNext->pointListFew(n, xs, ys); | 169 fNext->pointListFew(n, xs, ys); |
168 } | 170 } |
169 | 171 |
170 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 172 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
171 fStrategy.processPoints(&xs, &ys); | 173 fStrategy.processPoints(&xs, &ys); |
172 fNext->pointList4(xs, ys); | 174 fNext->pointList4(xs, ys); |
173 } | 175 } |
174 | 176 |
175 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 177 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
176 fStrategy.processPoints(&xs, &ys); | 178 fStrategy.processPoints(&xs, &ys); |
177 fNext->bilerpList(xs, ys); | 179 fNext->bilerpList(xs, ys); |
178 } | 180 } |
179 | 181 |
180 void pointSpan(SkPoint start, SkScalar length, int count) override { | 182 void pointSpan(SkPoint start, SkScalar length, int count) override { |
181 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { | 183 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { |
182 span_fallback(start, length, count, this); | 184 span_fallback(start, length, count, this); |
183 } | 185 } |
184 } | 186 } |
185 | 187 |
186 private: | 188 private: |
187 Next* const fNext; | 189 Next* const fNext; |
188 Strategy fStrategy; | 190 Strategy fStrategy; |
189 }; | 191 }; |
190 | 192 |
191 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterfa ce { | 193 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterfa ce { |
192 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 194 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
193 SkFAIL("Skipped stage."); | 195 SkFAIL("Skipped stage."); |
194 } | 196 } |
195 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 197 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
196 SkFAIL("Skipped stage."); | 198 SkFAIL("Skipped stage."); |
197 } | 199 } |
198 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 200 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
199 SkFAIL("Skipped stage."); | 201 SkFAIL("Skipped stage."); |
200 } | 202 } |
201 void pointSpan(SkPoint start, SkScalar length, int count) override { | 203 void pointSpan(SkPoint start, SkScalar length, int count) override { |
202 SkFAIL("Skipped stage."); | 204 SkFAIL("Skipped stage."); |
203 } | 205 } |
204 }; | 206 }; |
205 | 207 |
206 class TranslateMatrixStrategy { | 208 class TranslateMatrixStrategy { |
207 public: | 209 public: |
208 TranslateMatrixStrategy(SkVector offset) | 210 TranslateMatrixStrategy(SkVector offset) |
209 : fXOffset{X(offset)} | 211 : fXOffset{X(offset)} |
210 , fYOffset{Y(offset)} { } | 212 , fYOffset{Y(offset)} { } |
211 | 213 |
212 void processPoints(Sk4f* xs, Sk4f* ys) { | 214 void processPoints(Sk4s* xs, Sk4s* ys) { |
213 *xs = *xs + fXOffset; | 215 *xs = *xs + fXOffset; |
214 *ys = *ys + fYOffset; | 216 *ys = *ys + fYOffset; |
215 } | 217 } |
216 | 218 |
217 template <typename Next> | 219 template <typename Next> |
218 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 220 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
219 next->pointSpan(start + SkPoint{fXOffset[0], fYOffset[0]}, length, count ); | 221 next->pointSpan(start + SkPoint{fXOffset[0], fYOffset[0]}, length, count ); |
220 return true; | 222 return true; |
221 } | 223 } |
222 | 224 |
223 private: | 225 private: |
224 const Sk4f fXOffset, fYOffset; | 226 const Sk4s fXOffset, fYOffset; |
225 }; | 227 }; |
226 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 228 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
227 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; | 229 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; |
228 | 230 |
229 class ScaleMatrixStrategy { | 231 class ScaleMatrixStrategy { |
230 public: | 232 public: |
231 ScaleMatrixStrategy(SkVector offset, SkVector scale) | 233 ScaleMatrixStrategy(SkVector offset, SkVector scale) |
232 : fXOffset{X(offset)}, fYOffset{Y(offset)} | 234 : fXOffset{X(offset)}, fYOffset{Y(offset)} |
233 , fXScale{X(scale)}, fYScale{Y(scale)} { } | 235 , fXScale{X(scale)}, fYScale{Y(scale)} { } |
234 void processPoints(Sk4f* xs, Sk4f* ys) { | 236 void processPoints(Sk4s* xs, Sk4s* ys) { |
235 *xs = *xs * fXScale + fXOffset; | 237 *xs = *xs * fXScale + fXOffset; |
236 *ys = *ys * fYScale + fYOffset; | 238 *ys = *ys * fYScale + fYOffset; |
237 } | 239 } |
238 | 240 |
239 template <typename Next> | 241 template <typename Next> |
240 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 242 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
241 SkPoint newStart = | 243 SkPoint newStart = |
242 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]}; | 244 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] + fYOffset[0]}; |
243 SkScalar newLength = length * fXScale[0]; | 245 SkScalar newLength = length * fXScale[0]; |
244 next->pointSpan(newStart, newLength, count); | 246 next->pointSpan(newStart, newLength, count); |
245 return true; | 247 return true; |
246 } | 248 } |
247 | 249 |
248 private: | 250 private: |
249 const Sk4f fXOffset, fYOffset; | 251 const Sk4s fXOffset, fYOffset; |
250 const Sk4f fXScale, fYScale; | 252 const Sk4s fXScale, fYScale; |
251 }; | 253 }; |
252 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 254 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
253 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; | 255 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; |
254 | 256 |
255 class AffineMatrixStrategy { | 257 class AffineMatrixStrategy { |
256 public: | 258 public: |
257 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) | 259 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) |
258 : fXOffset{X(offset)}, fYOffset{Y(offset)} | 260 : fXOffset{X(offset)}, fYOffset{Y(offset)} |
259 , fXScale{X(scale)}, fYScale{Y(scale)} | 261 , fXScale{X(scale)}, fYScale{Y(scale)} |
260 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } | 262 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } |
261 void processPoints(Sk4f* xs, Sk4f* ys) { | 263 void processPoints(Sk4s* xs, Sk4s* ys) { |
262 Sk4f newXs = fXScale * *xs + fXSkew * *ys + fXOffset; | 264 Sk4s newXs = fXScale * *xs + fXSkew * *ys + fXOffset; |
263 Sk4f newYs = fYSkew * *xs + fYScale * *ys + fYOffset; | 265 Sk4s newYs = fYSkew * *xs + fYScale * *ys + fYOffset; |
264 | 266 |
265 *xs = newXs; | 267 *xs = newXs; |
266 *ys = newYs; | 268 *ys = newYs; |
267 } | 269 } |
268 | 270 |
269 template <typename Next> | 271 template <typename Next> |
270 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 272 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
271 return false; | 273 return false; |
272 } | 274 } |
273 | 275 |
274 private: | 276 private: |
275 const Sk4f fXOffset, fYOffset; | 277 const Sk4s fXOffset, fYOffset; |
276 const Sk4f fXScale, fYScale; | 278 const Sk4s fXScale, fYScale; |
277 const Sk4f fXSkew, fYSkew; | 279 const Sk4s fXSkew, fYSkew; |
278 }; | 280 }; |
279 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 281 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
280 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; | 282 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; |
281 | 283 |
282 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( | 284 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( |
283 SkLinearBitmapPipeline::PointProcessorInterface* next, | 285 SkLinearBitmapPipeline::PointProcessorInterface* next, |
284 const SkMatrix& inverse, | 286 const SkMatrix& inverse, |
285 SkLinearBitmapPipeline::MatrixStage* matrixProc) { | 287 SkLinearBitmapPipeline::MatrixStage* matrixProc) { |
286 if (inverse.hasPerspective()) { | 288 if (inverse.hasPerspective()) { |
287 SkFAIL("Not implemented."); | 289 SkFAIL("Not implemented."); |
(...skipping 17 matching lines...) Expand all Loading... | |
305 return next; | 307 return next; |
306 } | 308 } |
307 return matrixProc->get(); | 309 return matrixProc->get(); |
308 } | 310 } |
309 | 311 |
310 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 312 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
311 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac e { | 313 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac e { |
312 public: | 314 public: |
313 ExpandBilerp(Next* next) : fNext{next} { } | 315 ExpandBilerp(Next* next) : fNext{next} { } |
314 | 316 |
315 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 317 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
316 SkASSERT(0 < n && n < 4); | 318 SkASSERT(0 < n && n < 4); |
317 // px00 px10 px01 px11 | 319 // px00 px10 px01 px11 |
318 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 320 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, |
319 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | 321 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; |
320 if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYO ffsets); | 322 if (n >= 1) fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYO ffsets); |
321 if (n >= 2) fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYO ffsets); | 323 if (n >= 2) fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYO ffsets); |
322 if (n >= 3) fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYO ffsets); | 324 if (n >= 3) fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYO ffsets); |
323 } | 325 } |
324 | 326 |
325 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 327 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { |
326 // px00 px10 px01 px11 | 328 // px00 px10 px01 px11 |
327 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 329 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, |
328 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | 330 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; |
329 fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets); | 331 fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets); |
330 fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets); | 332 fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets); |
331 fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets); | 333 fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets); |
332 fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets); | 334 fNext->bilerpList(Sk4s{xs[3]} + kXOffsets, Sk4s{ys[3]} + kYOffsets); |
333 } | 335 } |
334 | 336 |
335 void pointSpan(SkPoint start, SkScalar length, int count) override { | 337 void pointSpan(SkPoint start, SkScalar length, int count) override { |
336 span_fallback(start, length, count, this); | 338 span_fallback(start, length, count, this); |
337 } | 339 } |
338 | 340 |
339 private: | 341 private: |
340 Next* const fNext; | 342 Next* const fNext; |
341 }; | 343 }; |
342 | 344 |
(...skipping 14 matching lines...) Expand all Loading... | |
357 public: | 359 public: |
358 ClampStrategy(X max) | 360 ClampStrategy(X max) |
359 : fXMin{0.0f} | 361 : fXMin{0.0f} |
360 , fXMax{max - 1.0f} { } | 362 , fXMax{max - 1.0f} { } |
361 ClampStrategy(Y max) | 363 ClampStrategy(Y max) |
362 : fYMin{0.0f} | 364 : fYMin{0.0f} |
363 , fYMax{max - 1.0f} { } | 365 , fYMax{max - 1.0f} { } |
364 ClampStrategy(SkSize max) | 366 ClampStrategy(SkSize max) |
365 : fXMin{0.0f} | 367 : fXMin{0.0f} |
366 , fYMin{0.0f} | 368 , fYMin{0.0f} |
367 , fXMax{X(max) - 1.0f} | 369 , fXMax{X(max) - 1.0f} |
mtklein
2016/02/24 19:42:52
Some of this stuff would be clearer if we stuck to
| |
368 , fYMax{Y(max) - 1.0f} { } | 370 , fYMax{Y(max) - 1.0f} { } |
369 | 371 |
370 void processPoints(Sk4f* xs, Sk4f* ys) { | 372 void processPoints(Sk4s* xs, Sk4s* ys) { |
371 *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax); | 373 *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax); |
372 *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax); | 374 *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax); |
373 } | 375 } |
374 | 376 |
375 template <typename Next> | 377 template <typename Next> |
376 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 378 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
377 return false; | 379 SkScalar xMin = fXMin[0]; |
380 SkScalar xMax = fXMax[0] + 1.0f; | |
381 SkScalar yMin = fYMin[0]; | |
382 SkScalar yMax = fYMax[0]; | |
383 SkScalar x = X(start); | |
384 SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax); | |
385 | |
386 bool under = x < xMin; | |
387 | |
388 if (!under && x + length < xMax) { | |
389 next->pointSpan(start, length, count); | |
390 return true; | |
391 } | |
392 | |
393 SkScalar dx = length / (count - 1); | |
mtklein
2016/02/24 19:42:52
Watch out for NaN?
| |
394 | |
395 if (dx > xMax) { | |
396 return false; | |
mtklein
2016/02/24 19:42:52
// TODO: left and right spans could still get some
| |
397 } | |
398 | |
399 // A B C | |
400 // +-------+-------+-------++-------+-------+-------+ +-------+----- --++------ | |
401 // | *---*|---*---|*---*--||-*---*-|---*---|*---...| |--*---*|---*- --||*---*.... | |
402 // | | | || | | | ... | | || | |
403 // | | | || | | | | | || | |
404 // +-------+-------+-------++-------+-------+-------+ +-------+----- --++------ | |
405 // ^ ^ | |
406 // | xMin xMax- 1 | xMax | |
407 // | |
408 // *---*---*---... - track of samples. * = sample | |
409 // | |
410 // +-+ || | |
411 // | | - pixels in source space. || - tile border. | |
412 // +-+ || | |
413 // | |
414 // The length from A to B is the length in source space or 4 * dx or (co unt - 1) * dx | |
415 // where dx is the distance between samples. There are 5 destination pix els | |
416 // corresponding to 5 samples specified in the A, B span. The distance f rom A to the next | |
417 // span starting at C is 5 * dx, so count * dx. | |
418 // Remember, count is the number of pixels needed for the destination an d the number of | |
419 // samples. | |
420 // Overall Strategy: | |
421 // * Under - for portions of the span < xMin, take the color at pixel {x Min, y} and use it | |
422 // to fill in the 5 pixel sampled from A to B. | |
423 // * Middle - for the portion of the span between xMin and xMax sample n ormally. | |
424 // * Over - for the portion of the span > xMax, take the color at pixel {xMax-1, y} and | |
425 // use it to fill in the rest of the destination pixels. | |
426 if (under) { | |
427 // It could be that the entire span is off the left edge of the tile . | |
428 SkScalar EdgeOrXEnd = std::min(xMin, x + length + 1.0f); | |
mtklein
2016/02/24 19:42:52
+1 ?
| |
429 int underCount = SkScalarFloorToInt((EdgeOrXEnd - x) / dx) + 1; | |
mtklein
2016/02/24 19:42:51
// There are n dx's between n+1 samples. (5 *'s a
mtklein
2016/02/24 19:42:52
Should be safe to assert (EdgeOrXEnd - x >= 0).
| |
430 if (underCount > 0) { | |
mtklein
2016/02/24 19:42:52
how can this not be at least 1?
| |
431 // Use the pixel on the edge of the bitmap as the color for the entire span. | |
432 // Using a length of 0 causes x not to move in the sampler resul ting in the same | |
433 // pixel being used for the entire span. | |
434 next->pointSpan({xMin, y}, 0.0f, underCount); | |
435 | |
436 // The length is not the distance to xMin, but to the next start ing sample. | |
437 SkScalar lengthToNextStart = dx * underCount; | |
438 count -= underCount; | |
439 length -= lengthToNextStart; | |
440 x += lengthToNextStart; | |
441 } | |
442 } | |
443 | |
444 // If there are more pixels needed, sample from the middle of the tile. | |
mtklein
2016/02/24 19:42:52
Three cases left:
- all in the tile
- some in
| |
445 if (count > 0) { | |
446 // It could be that span continues off the edge of tile; use min for the limit. | |
447 SkScalar EdgeOrXEnd = std::min(xMax, x + length); | |
448 int middleCount = SkScalarFloorToInt((EdgeOrXEnd - x) / dx) + 1; | |
449 SkScalar middleLength = (middleCount - 1) * dx; | |
mtklein
2016/02/24 19:42:52
// N samples span N-1 dx's.
| |
450 next->pointSpan({x, y}, middleLength, middleCount); | |
451 count -= middleCount; | |
452 } | |
453 | |
454 if (count > 0) { | |
455 // Use the pixel on the edge of the bitmap as the color for the enti re span. | |
456 // Using a length of 0 causes x not to move in the sampler resulting in the same | |
457 // pixel being used for the entire span. | |
458 next->pointSpan({xMax - 1.0f, y}, 0.0f, count); | |
459 } | |
460 | |
461 return true; | |
378 } | 462 } |
379 | 463 |
380 private: | 464 private: |
381 const Sk4f fXMin{SK_FloatNegativeInfinity}; | 465 const Sk4s fXMin{SK_FloatNegativeInfinity}; |
382 const Sk4f fYMin{SK_FloatNegativeInfinity}; | 466 const Sk4s fYMin{SK_FloatNegativeInfinity}; |
383 const Sk4f fXMax{SK_FloatInfinity}; | 467 const Sk4s fXMax{SK_FloatInfinity}; |
384 const Sk4f fYMax{SK_FloatInfinity}; | 468 const Sk4s fYMax{SK_FloatInfinity}; |
385 }; | 469 }; |
386 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 470 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
387 using Clamp = BilerpProcessor<ClampStrategy, Next>; | 471 using Clamp = BilerpProcessor<ClampStrategy, Next>; |
388 | 472 |
473 // It would be nice to use fmod, but it uses trunc based rounding where floor ro unding is needed. | |
mtklein
2016/02/24 19:42:52
remove comment?
| |
474 static SkScalar tile_mod(SkScalar x, SkScalar base) { | |
475 return x - std::floor(x / base) * base; | |
476 } | |
477 | |
389 class RepeatStrategy { | 478 class RepeatStrategy { |
390 public: | 479 public: |
391 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } | 480 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } |
392 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } | 481 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } |
393 RepeatStrategy(SkSize max) | 482 RepeatStrategy(SkSize max) |
394 : fXMax{X(max)} | 483 : fXMax{X(max)} |
395 , fXInvMax{1.0f / X(max)} | 484 , fXInvMax{1.0f / X(max)} |
396 , fYMax{Y(max)} | 485 , fYMax{Y(max)} |
397 , fYInvMax{1.0f / Y(max)} { } | 486 , fYInvMax{1.0f / Y(max)} { } |
398 | 487 |
399 void processPoints(Sk4f* xs, Sk4f* ys) { | 488 void processPoints(Sk4s* xs, Sk4s* ys) { |
400 Sk4f divX = (*xs * fXInvMax).floor(); | 489 Sk4s divX = (*xs * fXInvMax).floor(); |
401 Sk4f divY = (*ys * fYInvMax).floor(); | 490 Sk4s divY = (*ys * fYInvMax).floor(); |
402 Sk4f baseX = (divX * fXMax); | 491 Sk4s baseX = (divX * fXMax); |
403 Sk4f baseY = (divY * fYMax); | 492 Sk4s baseY = (divY * fYMax); |
404 *xs = *xs - baseX; | 493 *xs = *xs - baseX; |
405 *ys = *ys - baseY; | 494 *ys = *ys - baseY; |
406 } | 495 } |
407 | 496 |
408 template <typename Next> | 497 template <typename Next> |
409 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { | 498 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next) { |
410 return false; | 499 // Make x and y in range on the tile. |
500 SkScalar x = tile_mod(X(start), fXMax[0]); | |
501 SkScalar y = tile_mod(Y(start), fYMax[0]); | |
502 SkScalar xMax = fXMax[0]; | |
503 SkScalar dx = length / (count - 1); | |
mtklein
2016/02/24 19:42:52
NaN
| |
504 if (dx > xMax) { | |
505 return false; | |
mtklein
2016/02/24 19:42:52
// No point to spanning if we're not going to have
| |
506 } | |
507 | |
508 // A B C D Z | |
509 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------ | |
510 // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*| || | |
511 // | | | || | | || ... | | || | |
512 // | | | || | | || | | || | |
513 // +-------+-------+-------++-------+-------+-------++ +-------+---- ---++------ | |
514 // ^^ ^^ ^^ | |
515 // xMax || xMin xMax || xMin xM ax || xMin | |
516 // | |
517 // *---*---*---... - track of samples. * = sample | |
518 // | |
519 // +-+ || | |
520 // | | - pixels in source space. || - tile border. | |
521 // +-+ || | |
522 // | |
523 // | |
524 // The given span starts at A and continues on through several tiles to sample point Z. | |
525 // The idea is to break this into several spans one on each tile the ent ire span | |
526 // intersects. The A to B span only covers a partial tile and has a coun t of 3 and the | |
527 // distance from A to B is (count - 1) * dx or 2 * dx. The distance from A to the start of | |
528 // the next span is count * dx or 3 * dx. Span C to D covers an entire t ile has a count | |
529 // of 5 and a length of 4 * dx. Remember, count is the number of pixels needed for the | |
530 // destination and the number of samples. | |
531 // | |
532 // Overall Strategy: | |
533 // While the span hangs over the edge of the tile, draw the span coverin g the tile then | |
534 // slide the span over to the next tile. | |
535 | |
536 // The guard could have been count > 0, but then a bunch of math would b e done in the | |
537 // common case. | |
538 while (x + length > xMax) { | |
539 // The number of samples that intersect this tile. | |
540 int countForTile = SkScalarFloorToInt((xMax - x) / dx) + 1; | |
541 // The distance between the first and last sample. | |
542 SkScalar lengthForSpanOnTile = (countForTile - 1) * dx; | |
543 // Span the samples. | |
544 next->pointSpan({x, y}, lengthForSpanOnTile, countForTile); | |
545 // Add one more dx to get to the first sample on the next tile. | |
546 SkScalar lengthToNextStart = lengthForSpanOnTile + dx; | |
547 // slide over to the next tile. | |
548 length -= lengthToNextStart; | |
549 count -= countForTile; | |
550 x += lengthToNextStart - xMax; | |
mtklein
2016/02/24 19:42:51
// step forward the length we've consumed, then mo
| |
551 } | |
552 // All on a single tile. | |
553 if (count > 0) { | |
554 next->pointSpan({x, y}, length, count); | |
555 } | |
556 | |
557 return true; | |
411 } | 558 } |
412 | 559 |
413 private: | 560 private: |
414 const Sk4f fXMax{0.0f}; | 561 const Sk4s fXMax{0.0f}; |
415 const Sk4f fXInvMax{0.0f}; | 562 const Sk4s fXInvMax{0.0f}; |
416 const Sk4f fYMax{0.0f}; | 563 const Sk4s fYMax{0.0f}; |
417 const Sk4f fYInvMax{0.0f}; | 564 const Sk4s fYInvMax{0.0f}; |
418 }; | 565 }; |
419 | 566 |
420 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 567 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
421 using Repeat = BilerpProcessor<RepeatStrategy, Next>; | 568 using Repeat = BilerpProcessor<RepeatStrategy, Next>; |
422 | 569 |
423 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( | 570 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( |
424 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | 571 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
425 SkSize dimensions, | 572 SkSize dimensions, |
426 SkShader::TileMode xMode, | 573 SkShader::TileMode xMode, |
427 SkShader::TileMode yMode, | 574 SkShader::TileMode yMode, |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
462 case SkShader::kMirror_TileMode: | 609 case SkShader::kMirror_TileMode: |
463 SkFAIL("Not implemented."); | 610 SkFAIL("Not implemented."); |
464 break; | 611 break; |
465 } | 612 } |
466 } | 613 } |
467 return tileProcXOrBoth->get(); | 614 return tileProcXOrBoth->get(); |
468 } | 615 } |
469 | 616 |
470 class sRGBFast { | 617 class sRGBFast { |
471 public: | 618 public: |
472 static Sk4f VECTORCALL sRGBToLinear(Sk4f pixel) { | 619 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) { |
473 Sk4f l = pixel * pixel; | 620 Sk4s l = pixel * pixel; |
474 return Sk4f{l[0], l[1], l[2], pixel[3]}; | 621 return Sk4s{l[0], l[1], l[2], pixel[3]}; |
475 } | 622 } |
476 }; | 623 }; |
477 | 624 |
478 template <SkColorProfileType colorProfile> | 625 template <SkColorProfileType colorProfile> |
479 class Passthrough8888 { | 626 class Passthrough8888 { |
480 public: | 627 public: |
481 Passthrough8888(int width, const uint32_t* src) | 628 Passthrough8888(int width, const uint32_t* src) |
482 : fSrc{src}, fWidth{width}{ } | 629 : fSrc{src}, fWidth{width}{ } |
483 | 630 |
484 void VECTORCALL getFewPixels(int n, Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) { | 631 void VECTORCALL getFewPixels(int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2) { |
485 Sk4i XIs = SkNx_cast<int, float>(xs); | 632 Sk4i XIs = SkNx_cast<int, SkScalar>(xs); |
486 Sk4i YIs = SkNx_cast<int, float>(ys); | 633 Sk4i YIs = SkNx_cast<int, SkScalar>(ys); |
487 Sk4i bufferLoc = YIs * fWidth + XIs; | 634 Sk4i bufferLoc = YIs * fWidth + XIs; |
488 switch (n) { | 635 switch (n) { |
489 case 3: | 636 case 3: |
490 *px2 = getPixel(fSrc, bufferLoc[2]); | 637 *px2 = getPixel(fSrc, bufferLoc[2]); |
491 case 2: | 638 case 2: |
492 *px1 = getPixel(fSrc, bufferLoc[1]); | 639 *px1 = getPixel(fSrc, bufferLoc[1]); |
493 case 1: | 640 case 1: |
494 *px0 = getPixel(fSrc, bufferLoc[0]); | 641 *px0 = getPixel(fSrc, bufferLoc[0]); |
495 default: | 642 default: |
496 break; | 643 break; |
497 } | 644 } |
498 } | 645 } |
499 | 646 |
500 void VECTORCALL get4Pixels(Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2 , Sk4f* px3) { | 647 void VECTORCALL get4Pixels(Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2 , Sk4f* px3) { |
501 Sk4i XIs = SkNx_cast<int, float>(xs); | 648 Sk4i XIs = SkNx_cast<int, SkScalar>(xs); |
502 Sk4i YIs = SkNx_cast<int, float>(ys); | 649 Sk4i YIs = SkNx_cast<int, SkScalar>(ys); |
503 Sk4i bufferLoc = YIs * fWidth + XIs; | 650 Sk4i bufferLoc = YIs * fWidth + XIs; |
504 *px0 = getPixel(fSrc, bufferLoc[0]); | 651 *px0 = getPixel(fSrc, bufferLoc[0]); |
505 *px1 = getPixel(fSrc, bufferLoc[1]); | 652 *px1 = getPixel(fSrc, bufferLoc[1]); |
506 *px2 = getPixel(fSrc, bufferLoc[2]); | 653 *px2 = getPixel(fSrc, bufferLoc[2]); |
507 *px3 = getPixel(fSrc, bufferLoc[3]); | 654 *px3 = getPixel(fSrc, bufferLoc[3]); |
508 } | 655 } |
509 | 656 |
510 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } | 657 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } |
511 | 658 |
512 private: | 659 private: |
(...skipping 23 matching lines...) Expand all Loading... | |
536 // +--------+--------+ | 683 // +--------+--------+ |
537 // | 684 // |
538 // | 685 // |
539 // Given a pixelxy each is multiplied by a different factor derived from the fra ctional part of x | 686 // Given a pixelxy each is multiplied by a different factor derived from the fra ctional part of x |
540 // and y: | 687 // and y: |
541 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy | 688 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy |
542 // * px10 -> x(1 - y) = x - xy | 689 // * px10 -> x(1 - y) = x - xy |
543 // * px01 -> (1 - x)y = y - xy | 690 // * px01 -> (1 - x)y = y - xy |
544 // * px11 -> xy | 691 // * px11 -> xy |
545 // So x * y is calculated first and then used to calculate all the other factors . | 692 // So x * y is calculated first and then used to calculate all the other factors . |
546 static Sk4f VECTORCALL bilerp4(Sk4f xs, Sk4f ys, Sk4f px00, Sk4f px10, | 693 static Sk4s VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10, |
547 Sk4f px01, Sk4f px11) { | 694 Sk4f px01, Sk4f px11) { |
548 // Calculate fractional xs and ys. | 695 // Calculate fractional xs and ys. |
549 Sk4f fxs = xs - xs.floor(); | 696 Sk4s fxs = xs - xs.floor(); |
550 Sk4f fys = ys - ys.floor(); | 697 Sk4s fys = ys - ys.floor(); |
551 Sk4f fxys{fxs * fys}; | 698 Sk4s fxys{fxs * fys}; |
552 Sk4f sum = px11 * fxys; | 699 Sk4f sum = px11 * fxys; |
553 sum = sum + px01 * (fys - fxys); | 700 sum = sum + px01 * (fys - fxys); |
554 sum = sum + px10 * (fxs - fxys); | 701 sum = sum + px10 * (fxs - fxys); |
555 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); | 702 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); |
556 return sum; | 703 return sum; |
557 } | 704 } |
558 | 705 |
559 template <typename SourceStrategy> | 706 template <typename SourceStrategy> |
560 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { | 707 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { |
561 public: | 708 public: |
562 template <typename... Args> | 709 template <typename... Args> |
563 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) | 710 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) |
564 : fNext{next} | 711 : fNext{next} |
565 , fStrategy{std::forward<Args>(args)...} { } | 712 , fStrategy{std::forward<Args>(args)...} { } |
566 | 713 |
567 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 714 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
568 SkASSERT(0 < n && n < 4); | 715 SkASSERT(0 < n && n < 4); |
569 Sk4f px0, px1, px2; | 716 Sk4f px0, px1, px2; |
570 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); | 717 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); |
571 if (n >= 1) fNext->placePixel(px0); | 718 if (n >= 1) fNext->placePixel(px0); |
572 if (n >= 2) fNext->placePixel(px1); | 719 if (n >= 2) fNext->placePixel(px1); |
573 if (n >= 3) fNext->placePixel(px2); | 720 if (n >= 3) fNext->placePixel(px2); |
574 } | 721 } |
575 | 722 |
576 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 723 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
577 Sk4f px0, px1, px2, px3; | 724 Sk4f px0, px1, px2, px3; |
578 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); | 725 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); |
579 fNext->place4Pixels(px0, px1, px2, px3); | 726 fNext->place4Pixels(px0, px1, px2, px3); |
580 } | 727 } |
581 | 728 |
582 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 729 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
583 Sk4f px00, px10, px01, px11; | 730 Sk4f px00, px10, px01, px11; |
584 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); | 731 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); |
585 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); | 732 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); |
586 fNext->placePixel(pixel); | 733 fNext->placePixel(pixel); |
587 } | 734 } |
588 | 735 |
589 void pointSpan(SkPoint start, SkScalar length, int count) override { | 736 void pointSpan(SkPoint start, SkScalar length, int count) override { |
590 span_fallback(start, length, count, this); | 737 span_fallback(start, length, count, this); |
591 } | 738 } |
592 | 739 |
(...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
690 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp leStage); | 837 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp leStage); |
691 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage, | 838 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX OrBothStage, |
692 &fTileYStage); | 839 &fTileYStage); |
693 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage ); | 840 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage ); |
694 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); | 841 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); |
695 } | 842 } |
696 | 843 |
697 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { | 844 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { |
698 SkASSERT(count > 0); | 845 SkASSERT(count > 0); |
699 fPixelStage->setDestination(dst); | 846 fPixelStage->setDestination(dst); |
700 // Adjust points by 0.5, 0.5 to sample from the center of the pixels. | 847 // The count and length arguments start out in a precise relation in order t o keep the |
701 if (count == 1) { | 848 // math correct through the different stages. Count is the number of pixel t o produce. |
702 fFirstStage->pointListFew(1, Sk4f{x + 0.5f}, Sk4f{y + 0.5f}); | 849 // Since the code samples at pixel centers, length is the distance from the center of the |
703 } else { | 850 // first pixel to the center of the last pixel. This implies that length is count-1. |
704 // The count and length arguments start out in a precise relation in ord er to keep the | 851 fFirstStage->pointSpan(SkPoint{x + 0.5f, y + 0.5f}, count - 1, count); |
705 // math correct through the different stages. Count is the number of pix el 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 } | 852 } |
OLD | NEW |