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 #include <tuple> |
16 | 17 |
17 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. | 18 // Tweak ABI of functions that pass Sk4f by value to pass them via registers. |
18 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 | 19 #if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2 |
19 #define VECTORCALL __vectorcall | 20 #define VECTORCALL __vectorcall |
20 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) | 21 #elif defined(SK_CPU_ARM32) && defined(SK_ARM_HAS_NEON) |
21 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) | 22 #define VECTORCALL __attribute__((pcs("aapcs-vfp"))) |
22 #else | 23 #else |
23 #define VECTORCALL | 24 #define VECTORCALL |
24 #endif | 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 } // namespace |
25 | 136 |
26 class SkLinearBitmapPipeline::PointProcessorInterface { | 137 class SkLinearBitmapPipeline::PointProcessorInterface { |
27 public: | 138 public: |
28 virtual ~PointProcessorInterface() { } | 139 virtual ~PointProcessorInterface() { } |
29 virtual void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) = 0; | 140 virtual void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) = 0; |
30 virtual void VECTORCALL pointList4(Sk4f xs, Sk4f ys) = 0; | 141 virtual void VECTORCALL pointList4(Sk4s xs, Sk4s ys) = 0; |
31 | 142 virtual void pointSpan(Span span) = 0; |
32 // The pointSpan method efficiently process horizontal spans of pixels. | |
33 // * start - the point where to start the span. | |
34 // * length - the number of pixels to traverse in source space. | |
35 // * count - the number of pixels to produce in destination space. | |
36 // Both start and length are mapped through the inversion matrix to produce
values in source | |
37 // space. After the matrix operation, the tilers may break the spans up into
smaller spans. | |
38 // The tilers can produce spans that seem nonsensical. | |
39 // * The clamp tiler can create spans with length of 0. This indicates to co
py an edge pixel out | |
40 // to the edge of the destination scan. | |
41 // * The mirror tiler can produce spans with negative length. This indicates
that the source | |
42 // should be traversed in the opposite direction to the destination pixels
. | |
43 virtual void pointSpan(SkPoint start, SkScalar length, int count) = 0; | |
44 }; | 143 }; |
45 | 144 |
46 class SkLinearBitmapPipeline::BilerpProcessorInterface | 145 class SkLinearBitmapPipeline::BilerpProcessorInterface |
47 : public SkLinearBitmapPipeline::PointProcessorInterface { | 146 : public SkLinearBitmapPipeline::PointProcessorInterface { |
48 public: | 147 public: |
49 // The x's and y's are setup in the following order: | 148 // The x's and y's are setup in the following order: |
50 // +--------+--------+ | 149 // +--------+--------+ |
51 // | | | | 150 // | | | |
52 // | px00 | px10 | | 151 // | px00 | px10 | |
53 // | 0 | 1 | | 152 // | 0 | 1 | |
54 // +--------+--------+ | 153 // +--------+--------+ |
55 // | | | | 154 // | | | |
56 // | px01 | px11 | | 155 // | px01 | px11 | |
57 // | 2 | 3 | | 156 // | 2 | 3 | |
58 // +--------+--------+ | 157 // +--------+--------+ |
59 // These pixels coordinates are arranged in the following order in xs and ys
: | 158 // These pixels coordinates are arranged in the following order in xs and ys
: |
60 // px00 px10 px01 px11 | 159 // px00 px10 px01 px11 |
61 virtual void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) = 0; | 160 virtual void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) = 0; |
62 }; | 161 }; |
63 | 162 |
64 class SkLinearBitmapPipeline::PixelPlacerInterface { | 163 class SkLinearBitmapPipeline::PixelPlacerInterface { |
65 public: | 164 public: |
66 virtual ~PixelPlacerInterface() { } | 165 virtual ~PixelPlacerInterface() { } |
67 virtual void setDestination(SkPM4f* dst) = 0; | 166 virtual void setDestination(SkPM4f* dst) = 0; |
68 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; | 167 virtual void VECTORCALL placePixel(Sk4f pixel0) = 0; |
69 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0
; | 168 virtual void VECTORCALL place4Pixels(Sk4f p0, Sk4f p1, Sk4f p2, Sk4f p3) = 0
; |
70 }; | 169 }; |
71 | 170 |
72 namespace { | 171 namespace { |
73 | |
74 struct X { | |
75 explicit X(SkScalar val) : fVal{val} { } | |
76 explicit X(SkPoint pt) : fVal{pt.fX} { } | |
77 explicit X(SkSize s) : fVal{s.fWidth} { } | |
78 explicit X(SkISize s) : fVal(s.fWidth) { } | |
79 operator float () const {return fVal;} | |
80 private: | |
81 float fVal; | |
82 }; | |
83 | |
84 struct Y { | |
85 explicit Y(SkScalar val) : fVal{val} { } | |
86 explicit Y(SkPoint pt) : fVal{pt.fY} { } | |
87 explicit Y(SkSize s) : fVal{s.fHeight} { } | |
88 explicit Y(SkISize s) : fVal(s.fHeight) { } | |
89 operator float () const {return fVal;} | |
90 private: | |
91 float fVal; | |
92 }; | |
93 | |
94 template <typename Stage> | 172 template <typename Stage> |
95 void span_fallback(SkPoint start, SkScalar length, int count, Stage* stage) { | 173 void span_fallback(Span span, Stage* stage) { |
96 // If count == 1 use PointListFew instead. | 174 SkPoint start; |
97 SkASSERT(count > 1); | 175 SkScalar length; |
98 | 176 int count; |
99 float dx = length / (count - 1); | 177 std::tie(start, length, count) = span; |
100 Sk4f Xs = Sk4f(X(start)) + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * Sk4f{dx}; | 178 Sk4f xs{X(start)}; |
101 Sk4f Ys{Y(start)}; | 179 Sk4f ys{Y(start)}; |
102 Sk4f fourDx = {4.0f * dx}; | 180 Sk4s fourDx; |
| 181 if (count > 1) { |
| 182 SkScalar dx = length / (count - 1); |
| 183 xs = xs + Sk4f{0.0f, 1.0f, 2.0f, 3.0f} * dx; |
| 184 // Only used if count is >= 4. |
| 185 fourDx = Sk4f{4.0f * dx}; |
| 186 } |
103 | 187 |
104 while (count >= 4) { | 188 while (count >= 4) { |
105 stage->pointList4(Xs, Ys); | 189 stage->pointList4(xs, ys); |
106 Xs = Xs + fourDx; | 190 xs = xs + fourDx; |
107 count -= 4; | 191 count -= 4; |
108 } | 192 } |
109 if (count > 0) { | 193 if (count > 0) { |
110 stage->pointListFew(count, Xs, Ys); | 194 stage->pointListFew(count, xs, ys); |
111 } | 195 } |
112 } | 196 } |
113 | 197 |
114 // PointProcessor uses a strategy to help complete the work of the different sta
ges. The strategy | 198 // PointProcessor uses a strategy to help complete the work of the different sta
ges. The strategy |
115 // must implement the following methods: | 199 // must implement the following methods: |
116 // * processPoints(xs, ys) - must mutate the xs and ys for the stage. | 200 // * 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 | 201 // * maybeProcessSpan(span, next) - This represents a horizontal series of pixel
s |
118 // to work over. | 202 // to work over. |
119 // start - is the starting pixel. This is in destination space before the matr
ix stage, and in | 203 // span - encapsulation of span. |
120 // source space after the matrix stage. | |
121 // length - is this distance between the first pixel center and the last pixel
center. Like start, | |
122 // this is in destination space before the matrix stage, and in source
space after. | |
123 // count - the number of pixels in source space to produce. | |
124 // next - a pointer to the next stage. | 204 // next - a pointer to the next stage. |
125 // maybeProcessSpan - returns false if it can not process the span and needs t
o fallback to | 205 // maybeProcessSpan - returns false if it can not process the span and needs t
o fallback to |
126 // point lists for processing. | 206 // point lists for processing. |
127 template<typename Strategy, typename Next> | 207 template<typename Strategy, typename Next> |
128 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterf
ace { | 208 class PointProcessor final : public SkLinearBitmapPipeline::PointProcessorInterf
ace { |
129 public: | 209 public: |
130 template <typename... Args> | 210 template <typename... Args> |
131 PointProcessor(Next* next, Args&&... args) | 211 PointProcessor(Next* next, Args&&... args) |
132 : fNext{next} | 212 : fNext{next} |
133 , fStrategy{std::forward<Args>(args)...}{ } | 213 , fStrategy{std::forward<Args>(args)...}{ } |
134 | 214 |
135 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 215 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
136 fStrategy.processPoints(&xs, &ys); | 216 fStrategy.processPoints(&xs, &ys); |
137 fNext->pointListFew(n, xs, ys); | 217 fNext->pointListFew(n, xs, ys); |
138 } | 218 } |
139 | 219 |
140 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 220 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
141 fStrategy.processPoints(&xs, &ys); | 221 fStrategy.processPoints(&xs, &ys); |
142 fNext->pointList4(xs, ys); | 222 fNext->pointList4(xs, ys); |
143 } | 223 } |
144 | 224 |
145 void pointSpan(SkPoint start, SkScalar length, int count) override { | 225 // The span you pass must not be empty. |
146 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { | 226 void pointSpan(Span span) override { |
147 span_fallback(start, length, count, this); | 227 SkASSERT(!span.isEmpty()); |
| 228 if (!fStrategy.maybeProcessSpan(span, fNext)) { |
| 229 span_fallback(span, this); |
148 } | 230 } |
149 } | 231 } |
150 | 232 |
151 private: | 233 private: |
152 Next* const fNext; | 234 Next* const fNext; |
153 Strategy fStrategy; | 235 Strategy fStrategy; |
154 }; | 236 }; |
155 | 237 |
156 // See PointProcessor for responsibilities of Strategy. | 238 // See PointProcessor for responsibilities of Strategy. |
157 template<typename Strategy, typename Next> | 239 template<typename Strategy, typename Next> |
158 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInte
rface { | 240 class BilerpProcessor final : public SkLinearBitmapPipeline::BilerpProcessorInte
rface { |
159 public: | 241 public: |
160 template <typename... Args> | 242 template <typename... Args> |
161 BilerpProcessor(Next* next, Args&&... args) | 243 BilerpProcessor(Next* next, Args&&... args) |
162 : fNext{next} | 244 : fNext{next} |
163 , fStrategy{std::forward<Args>(args)...}{ } | 245 , fStrategy{std::forward<Args>(args)...}{ } |
164 | 246 |
165 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 247 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
166 fStrategy.processPoints(&xs, &ys); | 248 fStrategy.processPoints(&xs, &ys); |
167 fNext->pointListFew(n, xs, ys); | 249 fNext->pointListFew(n, xs, ys); |
168 } | 250 } |
169 | 251 |
170 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 252 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
171 fStrategy.processPoints(&xs, &ys); | 253 fStrategy.processPoints(&xs, &ys); |
172 fNext->pointList4(xs, ys); | 254 fNext->pointList4(xs, ys); |
173 } | 255 } |
174 | 256 |
175 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 257 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
176 fStrategy.processPoints(&xs, &ys); | 258 fStrategy.processPoints(&xs, &ys); |
177 fNext->bilerpList(xs, ys); | 259 fNext->bilerpList(xs, ys); |
178 } | 260 } |
179 | 261 |
180 void pointSpan(SkPoint start, SkScalar length, int count) override { | 262 void pointSpan(Span span) override { |
181 if (!fStrategy.maybeProcessSpan(start, length, count, fNext)) { | 263 SkASSERT(!span.isEmpty()); |
182 span_fallback(start, length, count, this); | 264 if (!fStrategy.maybeProcessSpan(span, fNext)) { |
| 265 span_fallback(span, this); |
183 } | 266 } |
184 } | 267 } |
185 | 268 |
186 private: | 269 private: |
187 Next* const fNext; | 270 Next* const fNext; |
188 Strategy fStrategy; | 271 Strategy fStrategy; |
189 }; | 272 }; |
190 | 273 |
191 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterfa
ce { | 274 class SkippedStage final : public SkLinearBitmapPipeline::BilerpProcessorInterfa
ce { |
192 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 275 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
193 SkFAIL("Skipped stage."); | 276 SkFAIL("Skipped stage."); |
194 } | 277 } |
195 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 278 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
196 SkFAIL("Skipped stage."); | 279 SkFAIL("Skipped stage."); |
197 } | 280 } |
198 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 281 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
199 SkFAIL("Skipped stage."); | 282 SkFAIL("Skipped stage."); |
200 } | 283 } |
201 void pointSpan(SkPoint start, SkScalar length, int count) override { | 284 void pointSpan(Span span) override { |
202 SkFAIL("Skipped stage."); | 285 SkFAIL("Skipped stage."); |
203 } | 286 } |
204 }; | 287 }; |
205 | 288 |
206 class TranslateMatrixStrategy { | 289 class TranslateMatrixStrategy { |
207 public: | 290 public: |
208 TranslateMatrixStrategy(SkVector offset) | 291 TranslateMatrixStrategy(SkVector offset) |
209 : fXOffset{X(offset)} | 292 : fXOffset{X(offset)} |
210 , fYOffset{Y(offset)} { } | 293 , fYOffset{Y(offset)} { } |
211 | 294 |
212 void processPoints(Sk4f* xs, Sk4f* ys) { | 295 void processPoints(Sk4s* xs, Sk4s* ys) { |
213 *xs = *xs + fXOffset; | 296 *xs = *xs + fXOffset; |
214 *ys = *ys + fYOffset; | 297 *ys = *ys + fYOffset; |
215 } | 298 } |
216 | 299 |
217 template <typename Next> | 300 template <typename Next> |
218 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next)
{ | 301 bool maybeProcessSpan(Span span, Next* next) { |
219 next->pointSpan(start + SkPoint{fXOffset[0], fYOffset[0]}, length, count
); | 302 SkPoint start; SkScalar length; int count; |
| 303 std::tie(start, length, count) = span; |
| 304 next->pointSpan(Span{start + SkPoint{fXOffset[0], fYOffset[0]}, length,
count}); |
220 return true; | 305 return true; |
221 } | 306 } |
222 | 307 |
223 private: | 308 private: |
224 const Sk4f fXOffset, fYOffset; | 309 const Sk4s fXOffset, fYOffset; |
225 }; | 310 }; |
226 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 311 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
227 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; | 312 using TranslateMatrix = PointProcessor<TranslateMatrixStrategy, Next>; |
228 | 313 |
229 class ScaleMatrixStrategy { | 314 class ScaleMatrixStrategy { |
230 public: | 315 public: |
231 ScaleMatrixStrategy(SkVector offset, SkVector scale) | 316 ScaleMatrixStrategy(SkVector offset, SkVector scale) |
232 : fXOffset{X(offset)}, fYOffset{Y(offset)} | 317 : fXOffset{X(offset)}, fYOffset{Y(offset)} |
233 , fXScale{X(scale)}, fYScale{Y(scale)} { } | 318 , fXScale{X(scale)}, fYScale{Y(scale)} { } |
234 void processPoints(Sk4f* xs, Sk4f* ys) { | 319 void processPoints(Sk4s* xs, Sk4s* ys) { |
235 *xs = *xs * fXScale + fXOffset; | 320 *xs = *xs * fXScale + fXOffset; |
236 *ys = *ys * fYScale + fYOffset; | 321 *ys = *ys * fYScale + fYOffset; |
237 } | 322 } |
238 | 323 |
239 template <typename Next> | 324 template <typename Next> |
240 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next)
{ | 325 bool maybeProcessSpan(Span span, Next* next) { |
| 326 SkPoint start; SkScalar length; int count; |
| 327 std::tie(start, length, count) = span; |
241 SkPoint newStart = | 328 SkPoint newStart = |
242 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] +
fYOffset[0]}; | 329 SkPoint{X(start) * fXScale[0] + fXOffset[0], Y(start) * fYScale[0] +
fYOffset[0]}; |
243 SkScalar newLength = length * fXScale[0]; | 330 SkScalar newLength = length * fXScale[0]; |
244 next->pointSpan(newStart, newLength, count); | 331 next->pointSpan(Span{newStart, newLength, count}); |
245 return true; | 332 return true; |
246 } | 333 } |
247 | 334 |
248 private: | 335 private: |
249 const Sk4f fXOffset, fYOffset; | 336 const Sk4s fXOffset, fYOffset; |
250 const Sk4f fXScale, fYScale; | 337 const Sk4s fXScale, fYScale; |
251 }; | 338 }; |
252 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 339 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
253 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; | 340 using ScaleMatrix = PointProcessor<ScaleMatrixStrategy, Next>; |
254 | 341 |
255 class AffineMatrixStrategy { | 342 class AffineMatrixStrategy { |
256 public: | 343 public: |
257 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) | 344 AffineMatrixStrategy(SkVector offset, SkVector scale, SkVector skew) |
258 : fXOffset{X(offset)}, fYOffset{Y(offset)} | 345 : fXOffset{X(offset)}, fYOffset{Y(offset)} |
259 , fXScale{X(scale)}, fYScale{Y(scale)} | 346 , fXScale{X(scale)}, fYScale{Y(scale)} |
260 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } | 347 , fXSkew{X(skew)}, fYSkew{Y(skew)} { } |
261 void processPoints(Sk4f* xs, Sk4f* ys) { | 348 void processPoints(Sk4s* xs, Sk4s* ys) { |
262 Sk4f newXs = fXScale * *xs + fXSkew * *ys + fXOffset; | 349 Sk4s newXs = fXScale * *xs + fXSkew * *ys + fXOffset; |
263 Sk4f newYs = fYSkew * *xs + fYScale * *ys + fYOffset; | 350 Sk4s newYs = fYSkew * *xs + fYScale * *ys + fYOffset; |
264 | 351 |
265 *xs = newXs; | 352 *xs = newXs; |
266 *ys = newYs; | 353 *ys = newYs; |
267 } | 354 } |
268 | 355 |
269 template <typename Next> | 356 template <typename Next> |
270 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next)
{ | 357 bool maybeProcessSpan(Span span, Next* next) { |
271 return false; | 358 return false; |
272 } | 359 } |
273 | 360 |
274 private: | 361 private: |
275 const Sk4f fXOffset, fYOffset; | 362 const Sk4s fXOffset, fYOffset; |
276 const Sk4f fXScale, fYScale; | 363 const Sk4s fXScale, fYScale; |
277 const Sk4f fXSkew, fYSkew; | 364 const Sk4s fXSkew, fYSkew; |
278 }; | 365 }; |
279 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> | 366 template <typename Next = SkLinearBitmapPipeline::PointProcessorInterface> |
280 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; | 367 using AffineMatrix = PointProcessor<AffineMatrixStrategy, Next>; |
281 | 368 |
282 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( | 369 static SkLinearBitmapPipeline::PointProcessorInterface* choose_matrix( |
283 SkLinearBitmapPipeline::PointProcessorInterface* next, | 370 SkLinearBitmapPipeline::PointProcessorInterface* next, |
284 const SkMatrix& inverse, | 371 const SkMatrix& inverse, |
285 SkLinearBitmapPipeline::MatrixStage* matrixProc) { | 372 SkLinearBitmapPipeline::MatrixStage* matrixProc) { |
286 if (inverse.hasPerspective()) { | 373 if (inverse.hasPerspective()) { |
287 SkFAIL("Not implemented."); | 374 SkFAIL("Not implemented."); |
(...skipping 17 matching lines...) Expand all Loading... |
305 return next; | 392 return next; |
306 } | 393 } |
307 return matrixProc->get(); | 394 return matrixProc->get(); |
308 } | 395 } |
309 | 396 |
310 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 397 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
311 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac
e { | 398 class ExpandBilerp final : public SkLinearBitmapPipeline::PointProcessorInterfac
e { |
312 public: | 399 public: |
313 ExpandBilerp(Next* next) : fNext{next} { } | 400 ExpandBilerp(Next* next) : fNext{next} { } |
314 | 401 |
315 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 402 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
316 SkASSERT(0 < n && n < 4); | 403 SkASSERT(0 < n && n < 4); |
317 // px00 px10 px01 px11 | 404 // px00 px10 px01 px11 |
318 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 405 const Sk4s kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, |
319 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | 406 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; |
320 if (n >= 1) fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYO
ffsets); | 407 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); | 408 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); | 409 if (n >= 3) fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYO
ffsets); |
323 } | 410 } |
324 | 411 |
325 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 412 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { |
326 // px00 px10 px01 px11 | 413 // px00 px10 px01 px11 |
327 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, | 414 const Sk4f kXOffsets{-0.5f, 0.5f, -0.5f, 0.5f}, |
328 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; | 415 kYOffsets{-0.5f, -0.5f, 0.5f, 0.5f}; |
329 fNext->bilerpList(Sk4f{xs[0]} + kXOffsets, Sk4f{ys[0]} + kYOffsets); | 416 fNext->bilerpList(Sk4s{xs[0]} + kXOffsets, Sk4s{ys[0]} + kYOffsets); |
330 fNext->bilerpList(Sk4f{xs[1]} + kXOffsets, Sk4f{ys[1]} + kYOffsets); | 417 fNext->bilerpList(Sk4s{xs[1]} + kXOffsets, Sk4s{ys[1]} + kYOffsets); |
331 fNext->bilerpList(Sk4f{xs[2]} + kXOffsets, Sk4f{ys[2]} + kYOffsets); | 418 fNext->bilerpList(Sk4s{xs[2]} + kXOffsets, Sk4s{ys[2]} + kYOffsets); |
332 fNext->bilerpList(Sk4f{xs[3]} + kXOffsets, Sk4f{ys[3]} + kYOffsets); | 419 fNext->bilerpList(Sk4s{xs[3]} + kXOffsets, Sk4s{ys[3]} + kYOffsets); |
333 } | 420 } |
334 | 421 |
335 void pointSpan(SkPoint start, SkScalar length, int count) override { | 422 void pointSpan(Span span) override { |
336 span_fallback(start, length, count, this); | 423 SkASSERT(!span.isEmpty()); |
| 424 span_fallback(span, fNext); |
337 } | 425 } |
338 | 426 |
339 private: | 427 private: |
340 Next* const fNext; | 428 Next* const fNext; |
341 }; | 429 }; |
342 | 430 |
343 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( | 431 static SkLinearBitmapPipeline::PointProcessorInterface* choose_filter( |
344 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | 432 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
345 SkFilterQuality filterQuailty, | 433 SkFilterQuality filterQuailty, |
346 SkLinearBitmapPipeline::FilterStage* filterProc) { | 434 SkLinearBitmapPipeline::FilterStage* filterProc) { |
(...skipping 13 matching lines...) Expand all Loading... |
360 , fXMax{max - 1.0f} { } | 448 , fXMax{max - 1.0f} { } |
361 ClampStrategy(Y max) | 449 ClampStrategy(Y max) |
362 : fYMin{0.0f} | 450 : fYMin{0.0f} |
363 , fYMax{max - 1.0f} { } | 451 , fYMax{max - 1.0f} { } |
364 ClampStrategy(SkSize max) | 452 ClampStrategy(SkSize max) |
365 : fXMin{0.0f} | 453 : fXMin{0.0f} |
366 , fYMin{0.0f} | 454 , fYMin{0.0f} |
367 , fXMax{X(max) - 1.0f} | 455 , fXMax{X(max) - 1.0f} |
368 , fYMax{Y(max) - 1.0f} { } | 456 , fYMax{Y(max) - 1.0f} { } |
369 | 457 |
370 void processPoints(Sk4f* xs, Sk4f* ys) { | 458 void processPoints(Sk4s* xs, Sk4s* ys) { |
371 *xs = Sk4f::Min(Sk4f::Max(*xs, fXMin), fXMax); | 459 *xs = Sk4s::Min(Sk4s::Max(*xs, fXMin), fXMax); |
372 *ys = Sk4f::Min(Sk4f::Max(*ys, fYMin), fYMax); | 460 *ys = Sk4s::Min(Sk4s::Max(*ys, fYMin), fYMax); |
373 } | 461 } |
374 | 462 |
375 template <typename Next> | 463 template <typename Next> |
376 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next)
{ | 464 bool maybeProcessSpan(Span originalSpan, Next* next) { |
377 return false; | 465 SkASSERT(!originalSpan.isEmpty()); |
| 466 SkPoint start; SkScalar length; int count; |
| 467 std::tie(start, length, count) = originalSpan; |
| 468 SkScalar xMin = fXMin[0]; |
| 469 SkScalar xMax = fXMax[0] + 1.0f; |
| 470 SkScalar yMin = fYMin[0]; |
| 471 SkScalar yMax = fYMax[0]; |
| 472 SkScalar x = X(start); |
| 473 SkScalar y = std::min(std::max<SkScalar>(yMin, Y(start)), yMax); |
| 474 |
| 475 Span span{{x, y}, length, count}; |
| 476 |
| 477 if (span.completelyWithin(xMin, xMax)) { |
| 478 next->pointSpan(span); |
| 479 return true; |
| 480 } |
| 481 if (1 == count || 0.0f == length) { |
| 482 return false; |
| 483 } |
| 484 |
| 485 SkScalar dx = length / (count - 1); |
| 486 |
| 487 // A B C |
| 488 // +-------+-------+-------++-------+-------+-------+ +-------+-----
--++------ |
| 489 // | *---*|---*---|*---*--||-*---*-|---*---|*---...| |--*---*|---*-
--||*---*.... |
| 490 // | | | || | | | ... | |
|| |
| 491 // | | | || | | | | |
|| |
| 492 // +-------+-------+-------++-------+-------+-------+ +-------+-----
--++------ |
| 493 // ^
^ |
| 494 // | xMin xMax-
1 | xMax |
| 495 // |
| 496 // *---*---*---... - track of samples. * = sample |
| 497 // |
| 498 // +-+ || |
| 499 // | | - pixels in source space. || - tile border. |
| 500 // +-+ || |
| 501 // |
| 502 // The length from A to B is the length in source space or 4 * dx or (co
unt - 1) * dx |
| 503 // where dx is the distance between samples. There are 5 destination pix
els |
| 504 // corresponding to 5 samples specified in the A, B span. The distance f
rom A to the next |
| 505 // span starting at C is 5 * dx, so count * dx. |
| 506 // Remember, count is the number of pixels needed for the destination an
d the number of |
| 507 // samples. |
| 508 // Overall Strategy: |
| 509 // * Under - for portions of the span < xMin, take the color at pixel {x
Min, y} and use it |
| 510 // to fill in the 5 pixel sampled from A to B. |
| 511 // * Middle - for the portion of the span between xMin and xMax sample n
ormally. |
| 512 // * Over - for the portion of the span > xMax, take the color at pixel
{xMax-1, y} and |
| 513 // use it to fill in the rest of the destination pixels. |
| 514 if (dx >= 0) { |
| 515 Span leftClamped = span.breakAt(xMin, dx); |
| 516 if (!leftClamped.isEmpty()) { |
| 517 leftClamped.clampToSinglePixel({xMin, y}); |
| 518 next->pointSpan(leftClamped); |
| 519 } |
| 520 Span middle = span.breakAt(xMax, dx); |
| 521 if (!middle.isEmpty()) { |
| 522 next->pointSpan(middle); |
| 523 } |
| 524 if (!span.isEmpty()) { |
| 525 span.clampToSinglePixel({xMax - 1, y}); |
| 526 next->pointSpan(span); |
| 527 } |
| 528 } else { |
| 529 Span rightClamped = span.breakAt(xMax, dx); |
| 530 if (!rightClamped.isEmpty()) { |
| 531 rightClamped.clampToSinglePixel({xMax - 1, y}); |
| 532 next->pointSpan(rightClamped); |
| 533 } |
| 534 Span middle = span.breakAt(xMin, dx); |
| 535 if (!middle.isEmpty()) { |
| 536 next->pointSpan(middle); |
| 537 } |
| 538 if (!span.isEmpty()) { |
| 539 span.clampToSinglePixel({xMin, y}); |
| 540 next->pointSpan(span); |
| 541 } |
| 542 } |
| 543 return true; |
378 } | 544 } |
379 | 545 |
380 private: | 546 private: |
381 const Sk4f fXMin{SK_FloatNegativeInfinity}; | 547 const Sk4s fXMin{SK_FloatNegativeInfinity}; |
382 const Sk4f fYMin{SK_FloatNegativeInfinity}; | 548 const Sk4s fYMin{SK_FloatNegativeInfinity}; |
383 const Sk4f fXMax{SK_FloatInfinity}; | 549 const Sk4s fXMax{SK_FloatInfinity}; |
384 const Sk4f fYMax{SK_FloatInfinity}; | 550 const Sk4s fYMax{SK_FloatInfinity}; |
385 }; | 551 }; |
386 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 552 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
387 using Clamp = BilerpProcessor<ClampStrategy, Next>; | 553 using Clamp = BilerpProcessor<ClampStrategy, Next>; |
388 | 554 |
| 555 static SkScalar tile_mod(SkScalar x, SkScalar base) { |
| 556 return x - std::floor(x / base) * base; |
| 557 } |
| 558 |
389 class RepeatStrategy { | 559 class RepeatStrategy { |
390 public: | 560 public: |
391 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } | 561 RepeatStrategy(X max) : fXMax{max}, fXInvMax{1.0f/max} { } |
392 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } | 562 RepeatStrategy(Y max) : fYMax{max}, fYInvMax{1.0f/max} { } |
393 RepeatStrategy(SkSize max) | 563 RepeatStrategy(SkSize max) |
394 : fXMax{X(max)} | 564 : fXMax{X(max)} |
395 , fXInvMax{1.0f / X(max)} | 565 , fXInvMax{1.0f / X(max)} |
396 , fYMax{Y(max)} | 566 , fYMax{Y(max)} |
397 , fYInvMax{1.0f / Y(max)} { } | 567 , fYInvMax{1.0f / Y(max)} { } |
398 | 568 |
399 void processPoints(Sk4f* xs, Sk4f* ys) { | 569 void processPoints(Sk4s* xs, Sk4s* ys) { |
400 Sk4f divX = (*xs * fXInvMax).floor(); | 570 Sk4s divX = (*xs * fXInvMax).floor(); |
401 Sk4f divY = (*ys * fYInvMax).floor(); | 571 Sk4s divY = (*ys * fYInvMax).floor(); |
402 Sk4f baseX = (divX * fXMax); | 572 Sk4s baseX = (divX * fXMax); |
403 Sk4f baseY = (divY * fYMax); | 573 Sk4s baseY = (divY * fYMax); |
404 *xs = *xs - baseX; | 574 *xs = *xs - baseX; |
405 *ys = *ys - baseY; | 575 *ys = *ys - baseY; |
406 } | 576 } |
407 | 577 |
408 template <typename Next> | 578 template <typename Next> |
409 bool maybeProcessSpan(SkPoint start, SkScalar length, int count, Next* next)
{ | 579 bool maybeProcessSpan(Span originalSpan, Next* next) { |
410 return false; | 580 SkASSERT(!originalSpan.isEmpty()); |
| 581 SkPoint start; SkScalar length; int count; |
| 582 std::tie(start, length, count) = originalSpan; |
| 583 // Make x and y in range on the tile. |
| 584 SkScalar x = tile_mod(X(start), fXMax[0]); |
| 585 SkScalar y = tile_mod(Y(start), fYMax[0]); |
| 586 SkScalar xMax = fXMax[0]; |
| 587 SkScalar xMin = 0.0f; |
| 588 SkScalar dx = length / (count - 1); |
| 589 |
| 590 // No need trying to go fast because the steps are larger than a tile or
there is one point. |
| 591 if (SkScalarAbs(dx) >= xMax || count <= 1) { |
| 592 return false; |
| 593 } |
| 594 |
| 595 // A B C D Z |
| 596 // +-------+-------+-------++-------+-------+-------++ +-------+----
---++------ |
| 597 // | | *---|*---*--||-*---*-|---*---|*---*--|| |--*---*|
|| |
| 598 // | | | || | | || ... | |
|| |
| 599 // | | | || | | || | |
|| |
| 600 // +-------+-------+-------++-------+-------+-------++ +-------+----
---++------ |
| 601 // ^^ ^^
^^ |
| 602 // xMax || xMin xMax || xMin xM
ax || xMin |
| 603 // |
| 604 // *---*---*---... - track of samples. * = sample |
| 605 // |
| 606 // +-+ || |
| 607 // | | - pixels in source space. || - tile border. |
| 608 // +-+ || |
| 609 // |
| 610 // |
| 611 // The given span starts at A and continues on through several tiles to
sample point Z. |
| 612 // The idea is to break this into several spans one on each tile the ent
ire span |
| 613 // intersects. The A to B span only covers a partial tile and has a coun
t of 3 and the |
| 614 // distance from A to B is (count - 1) * dx or 2 * dx. The distance from
A to the start of |
| 615 // the next span is count * dx or 3 * dx. Span C to D covers an entire t
ile has a count |
| 616 // of 5 and a length of 4 * dx. Remember, count is the number of pixels
needed for the |
| 617 // destination and the number of samples. |
| 618 // |
| 619 // Overall Strategy: |
| 620 // While the span hangs over the edge of the tile, draw the span coverin
g the tile then |
| 621 // slide the span over to the next tile. |
| 622 |
| 623 // The guard could have been count > 0, but then a bunch of math would b
e done in the |
| 624 // common case. |
| 625 |
| 626 Span span({x,y}, length, count); |
| 627 if (dx > 0) { |
| 628 while (!span.isEmpty() && span.endX() > xMax) { |
| 629 Span toDraw = span.breakAt(xMax, dx); |
| 630 next->pointSpan(toDraw); |
| 631 span.offset(-xMax); |
| 632 } |
| 633 } else { |
| 634 while (!span.isEmpty() && span.endX() < xMin) { |
| 635 Span toDraw = span.breakAt(xMin, dx); |
| 636 next->pointSpan(toDraw); |
| 637 span.offset(xMax); |
| 638 } |
| 639 } |
| 640 |
| 641 // All on a single tile. |
| 642 if (!span.isEmpty()) { |
| 643 next->pointSpan(span); |
| 644 } |
| 645 |
| 646 return true; |
411 } | 647 } |
412 | 648 |
413 private: | 649 private: |
414 const Sk4f fXMax{0.0f}; | 650 const Sk4s fXMax{0.0f}; |
415 const Sk4f fXInvMax{0.0f}; | 651 const Sk4s fXInvMax{0.0f}; |
416 const Sk4f fYMax{0.0f}; | 652 const Sk4s fYMax{0.0f}; |
417 const Sk4f fYInvMax{0.0f}; | 653 const Sk4s fYInvMax{0.0f}; |
418 }; | 654 }; |
419 | 655 |
420 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> | 656 template <typename Next = SkLinearBitmapPipeline::BilerpProcessorInterface> |
421 using Repeat = BilerpProcessor<RepeatStrategy, Next>; | 657 using Repeat = BilerpProcessor<RepeatStrategy, Next>; |
422 | 658 |
423 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( | 659 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_tiler( |
424 SkLinearBitmapPipeline::BilerpProcessorInterface* next, | 660 SkLinearBitmapPipeline::BilerpProcessorInterface* next, |
425 SkSize dimensions, | 661 SkSize dimensions, |
426 SkShader::TileMode xMode, | 662 SkShader::TileMode xMode, |
427 SkShader::TileMode yMode, | 663 SkShader::TileMode yMode, |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
462 case SkShader::kMirror_TileMode: | 698 case SkShader::kMirror_TileMode: |
463 SkFAIL("Not implemented."); | 699 SkFAIL("Not implemented."); |
464 break; | 700 break; |
465 } | 701 } |
466 } | 702 } |
467 return tileProcXOrBoth->get(); | 703 return tileProcXOrBoth->get(); |
468 } | 704 } |
469 | 705 |
470 class sRGBFast { | 706 class sRGBFast { |
471 public: | 707 public: |
472 static Sk4f VECTORCALL sRGBToLinear(Sk4f pixel) { | 708 static Sk4s VECTORCALL sRGBToLinear(Sk4s pixel) { |
473 Sk4f l = pixel * pixel; | 709 Sk4s l = pixel * pixel; |
474 return Sk4f{l[0], l[1], l[2], pixel[3]}; | 710 return Sk4s{l[0], l[1], l[2], pixel[3]}; |
475 } | 711 } |
476 }; | 712 }; |
477 | 713 |
478 template <SkColorProfileType colorProfile> | 714 template <SkColorProfileType colorProfile> |
479 class Passthrough8888 { | 715 class Passthrough8888 { |
480 public: | 716 public: |
481 Passthrough8888(int width, const uint32_t* src) | 717 Passthrough8888(int width, const uint32_t* src) |
482 : fSrc{src}, fWidth{width}{ } | 718 : fSrc{src}, fWidth{width}{ } |
483 | 719 |
484 void VECTORCALL getFewPixels(int n, Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1,
Sk4f* px2) { | 720 void VECTORCALL getFewPixels(int n, Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1,
Sk4f* px2) { |
485 Sk4i XIs = SkNx_cast<int, float>(xs); | 721 Sk4i XIs = SkNx_cast<int, SkScalar>(xs); |
486 Sk4i YIs = SkNx_cast<int, float>(ys); | 722 Sk4i YIs = SkNx_cast<int, SkScalar>(ys); |
487 Sk4i bufferLoc = YIs * fWidth + XIs; | 723 Sk4i bufferLoc = YIs * fWidth + XIs; |
488 switch (n) { | 724 switch (n) { |
489 case 3: | 725 case 3: |
490 *px2 = getPixel(fSrc, bufferLoc[2]); | 726 *px2 = getPixel(fSrc, bufferLoc[2]); |
491 case 2: | 727 case 2: |
492 *px1 = getPixel(fSrc, bufferLoc[1]); | 728 *px1 = getPixel(fSrc, bufferLoc[1]); |
493 case 1: | 729 case 1: |
494 *px0 = getPixel(fSrc, bufferLoc[0]); | 730 *px0 = getPixel(fSrc, bufferLoc[0]); |
495 default: | 731 default: |
496 break; | 732 break; |
497 } | 733 } |
498 } | 734 } |
499 | 735 |
500 void VECTORCALL get4Pixels(Sk4f xs, Sk4f ys, Sk4f* px0, Sk4f* px1, Sk4f* px2
, Sk4f* px3) { | 736 void VECTORCALL get4Pixels(Sk4s xs, Sk4s ys, Sk4f* px0, Sk4f* px1, Sk4f* px2
, Sk4f* px3) { |
501 Sk4i XIs = SkNx_cast<int, float>(xs); | 737 Sk4i XIs = SkNx_cast<int, SkScalar>(xs); |
502 Sk4i YIs = SkNx_cast<int, float>(ys); | 738 Sk4i YIs = SkNx_cast<int, SkScalar>(ys); |
503 Sk4i bufferLoc = YIs * fWidth + XIs; | 739 Sk4i bufferLoc = YIs * fWidth + XIs; |
504 *px0 = getPixel(fSrc, bufferLoc[0]); | 740 *px0 = getPixel(fSrc, bufferLoc[0]); |
505 *px1 = getPixel(fSrc, bufferLoc[1]); | 741 *px1 = getPixel(fSrc, bufferLoc[1]); |
506 *px2 = getPixel(fSrc, bufferLoc[2]); | 742 *px2 = getPixel(fSrc, bufferLoc[2]); |
507 *px3 = getPixel(fSrc, bufferLoc[3]); | 743 *px3 = getPixel(fSrc, bufferLoc[3]); |
508 } | 744 } |
509 | 745 |
510 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } | 746 const uint32_t* row(int y) { return fSrc + y * fWidth[0]; } |
511 | 747 |
512 private: | 748 private: |
(...skipping 23 matching lines...) Expand all Loading... |
536 // +--------+--------+ | 772 // +--------+--------+ |
537 // | 773 // |
538 // | 774 // |
539 // Given a pixelxy each is multiplied by a different factor derived from the fra
ctional part of x | 775 // Given a pixelxy each is multiplied by a different factor derived from the fra
ctional part of x |
540 // and y: | 776 // and y: |
541 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy | 777 // * px00 -> (1 - x)(1 - y) = 1 - x - y + xy |
542 // * px10 -> x(1 - y) = x - xy | 778 // * px10 -> x(1 - y) = x - xy |
543 // * px01 -> (1 - x)y = y - xy | 779 // * px01 -> (1 - x)y = y - xy |
544 // * px11 -> xy | 780 // * px11 -> xy |
545 // So x * y is calculated first and then used to calculate all the other factors
. | 781 // 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, | 782 static Sk4s VECTORCALL bilerp4(Sk4s xs, Sk4s ys, Sk4f px00, Sk4f px10, |
547 Sk4f px01, Sk4f px11) { | 783 Sk4f px01, Sk4f px11) { |
548 // Calculate fractional xs and ys. | 784 // Calculate fractional xs and ys. |
549 Sk4f fxs = xs - xs.floor(); | 785 Sk4s fxs = xs - xs.floor(); |
550 Sk4f fys = ys - ys.floor(); | 786 Sk4s fys = ys - ys.floor(); |
551 Sk4f fxys{fxs * fys}; | 787 Sk4s fxys{fxs * fys}; |
552 Sk4f sum = px11 * fxys; | 788 Sk4f sum = px11 * fxys; |
553 sum = sum + px01 * (fys - fxys); | 789 sum = sum + px01 * (fys - fxys); |
554 sum = sum + px10 * (fxs - fxys); | 790 sum = sum + px10 * (fxs - fxys); |
555 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); | 791 sum = sum + px00 * (Sk4f{1.0f} - fxs - fys + fxys); |
556 return sum; | 792 return sum; |
557 } | 793 } |
558 | 794 |
559 template <typename SourceStrategy> | 795 template <typename SourceStrategy> |
560 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { | 796 class Sampler final : public SkLinearBitmapPipeline::BilerpProcessorInterface { |
561 public: | 797 public: |
562 template <typename... Args> | 798 template <typename... Args> |
563 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) | 799 Sampler(SkLinearBitmapPipeline::PixelPlacerInterface* next, Args&&... args) |
564 : fNext{next} | 800 : fNext{next} |
565 , fStrategy{std::forward<Args>(args)...} { } | 801 , fStrategy{std::forward<Args>(args)...} { } |
566 | 802 |
567 void VECTORCALL pointListFew(int n, Sk4f xs, Sk4f ys) override { | 803 void VECTORCALL pointListFew(int n, Sk4s xs, Sk4s ys) override { |
568 SkASSERT(0 < n && n < 4); | 804 SkASSERT(0 < n && n < 4); |
569 Sk4f px0, px1, px2; | 805 Sk4f px0, px1, px2; |
570 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); | 806 fStrategy.getFewPixels(n, xs, ys, &px0, &px1, &px2); |
571 if (n >= 1) fNext->placePixel(px0); | 807 if (n >= 1) fNext->placePixel(px0); |
572 if (n >= 2) fNext->placePixel(px1); | 808 if (n >= 2) fNext->placePixel(px1); |
573 if (n >= 3) fNext->placePixel(px2); | 809 if (n >= 3) fNext->placePixel(px2); |
574 } | 810 } |
575 | 811 |
576 void VECTORCALL pointList4(Sk4f xs, Sk4f ys) override { | 812 void VECTORCALL pointList4(Sk4s xs, Sk4s ys) override { |
577 Sk4f px0, px1, px2, px3; | 813 Sk4f px0, px1, px2, px3; |
578 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); | 814 fStrategy.get4Pixels(xs, ys, &px0, &px1, &px2, &px3); |
579 fNext->place4Pixels(px0, px1, px2, px3); | 815 fNext->place4Pixels(px0, px1, px2, px3); |
580 } | 816 } |
581 | 817 |
582 void VECTORCALL bilerpList(Sk4f xs, Sk4f ys) override { | 818 void VECTORCALL bilerpList(Sk4s xs, Sk4s ys) override { |
583 Sk4f px00, px10, px01, px11; | 819 Sk4f px00, px10, px01, px11; |
584 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); | 820 fStrategy.get4Pixels(xs, ys, &px00, &px10, &px01, &px11); |
585 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); | 821 Sk4f pixel = bilerp4(xs, ys, px00, px10, px01, px11); |
586 fNext->placePixel(pixel); | 822 fNext->placePixel(pixel); |
587 } | 823 } |
588 | 824 |
589 void pointSpan(SkPoint start, SkScalar length, int count) override { | 825 void pointSpan(Span span) override { |
590 span_fallback(start, length, count, this); | 826 span_fallback(span, this); |
591 } | 827 } |
592 | 828 |
593 private: | 829 private: |
594 SkLinearBitmapPipeline::PixelPlacerInterface* const fNext; | 830 SkLinearBitmapPipeline::PixelPlacerInterface* const fNext; |
595 SourceStrategy fStrategy; | 831 SourceStrategy fStrategy; |
596 }; | 832 }; |
597 | 833 |
598 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler( | 834 static SkLinearBitmapPipeline::BilerpProcessorInterface* choose_pixel_sampler( |
599 SkLinearBitmapPipeline::PixelPlacerInterface* next, | 835 SkLinearBitmapPipeline::PixelPlacerInterface* next, |
600 const SkPixmap& srcPixmap, | 836 const SkPixmap& srcPixmap, |
(...skipping 89 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
690 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp
leStage); | 926 auto samplerStage = choose_pixel_sampler(placementStage, srcPixmap, &fSamp
leStage); |
691 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX
OrBothStage, | 927 auto tilerStage = choose_tiler(samplerStage, size, xTile, yTile, &fTileX
OrBothStage, |
692 &fTileYStage); | 928 &fTileYStage); |
693 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage
); | 929 auto filterStage = choose_filter(tilerStage, filterQuality, &fFilterStage
); |
694 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); | 930 fFirstStage = choose_matrix(filterStage, inverse, &fMatrixStage); |
695 } | 931 } |
696 | 932 |
697 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { | 933 void SkLinearBitmapPipeline::shadeSpan4f(int x, int y, SkPM4f* dst, int count) { |
698 SkASSERT(count > 0); | 934 SkASSERT(count > 0); |
699 fPixelStage->setDestination(dst); | 935 fPixelStage->setDestination(dst); |
700 // Adjust points by 0.5, 0.5 to sample from the center of the pixels. | 936 // The count and length arguments start out in a precise relation in order t
o keep the |
701 if (count == 1) { | 937 // 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}); | 938 // Since the code samples at pixel centers, length is the distance from the
center of the |
703 } else { | 939 // 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 | 940 fFirstStage->pointSpan(Span{SkPoint{x + 0.5f, y + 0.5f}, count - 1.0f, 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 } | 941 } |
OLD | NEW |