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

Side by Side Diff: src/effects/gradients/Sk4fLinearGradient.cpp

Issue 1783823002: Generic 4f gradient T sampler fallback (Closed) Base URL: https://chromium.googlesource.com/skia.git@master
Patch Set: review 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
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 "Sk4fGradientPriv.h"
8 #include "Sk4fLinearGradient.h" 9 #include "Sk4fLinearGradient.h"
9 10
10 namespace { 11 namespace {
11 12
12 Sk4f premul_4f(const Sk4f& c) {
13 const float alpha = c[SkPM4f::A];
14 // FIXME: portable swizzle?
15 return c * Sk4f(alpha, alpha, alpha, 1);
16 }
17
18 template <bool do_premul>
19 SkPMColor trunc_from_255(const Sk4f& c) {
20 SkPMColor pmc;
21 SkNx_cast<uint8_t>(c).store(&pmc);
22 if (do_premul) {
23 pmc = SkPreMultiplyARGB(SkGetPackedA32(pmc), SkGetPackedR32(pmc),
24 SkGetPackedG32(pmc), SkGetPackedB32(pmc));
25 }
26 return pmc;
27 }
28
29 template<typename DstType, bool do_premul> 13 template<typename DstType, bool do_premul>
30 void fill(const Sk4f& c, DstType* dst, int n); 14 void fill(const Sk4f& c, DstType* dst, int n);
31 15
32 template<> 16 template<>
33 void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) { 17 void fill<SkPM4f, false>(const Sk4f& c, SkPM4f* dst, int n) {
34 while (n > 0) { 18 while (n > 0) {
35 c.store(dst++); 19 c.store(dst++);
36 n--; 20 n--;
37 } 21 }
38 } 22 }
39 23
40 template<> 24 template<>
41 void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) { 25 void fill<SkPM4f, true>(const Sk4f& c, SkPM4f* dst, int n) {
42 fill<SkPM4f, false>(premul_4f(c), dst, n); 26 fill<SkPM4f, false>(premul_4f(c), dst, n);
43 } 27 }
44 28
45 template<> 29 template<>
46 void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) { 30 void fill<SkPMColor, false>(const Sk4f& c, SkPMColor* dst, int n) {
47 sk_memset32(dst, trunc_from_255<false>(c), n); 31 sk_memset32(dst, trunc_from_255<false>(c), n);
48 } 32 }
49 33
50 template<> 34 template<>
51 void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) { 35 void fill<SkPMColor, true>(const Sk4f& c, SkPMColor* dst, int n) {
52 sk_memset32(dst, trunc_from_255<true>(c), n); 36 sk_memset32(dst, trunc_from_255<true>(c), n);
53 } 37 }
54 38
55 template<typename DstType, bool do_premul> 39 template<typename DstType, bool do_premul>
56 void store(const Sk4f& color, DstType* dst);
57
58 template<>
59 void store<SkPM4f, false>(const Sk4f& c, SkPM4f* dst) {
60 c.store(dst);
61 }
62
63 template<>
64 void store<SkPM4f, true>(const Sk4f& c, SkPM4f* dst) {
65 store<SkPM4f, false>(premul_4f(c), dst);
66 }
67
68 template<>
69 void store<SkPMColor, false>(const Sk4f& c, SkPMColor* dst) {
70 *dst = trunc_from_255<false>(c);
71 }
72
73 template<>
74 void store<SkPMColor, true>(const Sk4f& c, SkPMColor* dst) {
75 *dst = trunc_from_255<true>(c);
76 }
77
78 template<typename DstType, bool do_premul>
79 void store4x(const Sk4f& c0,
80 const Sk4f& c1,
81 const Sk4f& c2,
82 const Sk4f& c3,
83 DstType* dst) {
84 store<DstType, do_premul>(c0, dst++);
85 store<DstType, do_premul>(c1, dst++);
86 store<DstType, do_premul>(c2, dst++);
87 store<DstType, do_premul>(c3, dst++);
88 }
89
90 template<>
91 void store4x<SkPMColor, false>(const Sk4f& c0,
92 const Sk4f& c1,
93 const Sk4f& c2,
94 const Sk4f& c3,
95 SkPMColor* dst) {
96 Sk4f_ToBytes((uint8_t*)dst, c0, c1, c2, c3);
97 }
98
99 template<typename DstType, bool do_premul>
100 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { 40 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) {
101 SkASSERT(n > 0); 41 SkASSERT(n > 0);
102 42
103 const Sk4f dc2 = dc + dc; 43 const Sk4f dc2 = dc + dc;
104 const Sk4f dc4 = dc2 + dc2; 44 const Sk4f dc4 = dc2 + dc2;
105 45
106 Sk4f c0 = c ; 46 Sk4f c0 = c ;
107 Sk4f c1 = c + dc; 47 Sk4f c1 = c + dc;
108 Sk4f c2 = c0 + dc2; 48 Sk4f c2 = c0 + dc2;
109 Sk4f c3 = c1 + dc2; 49 Sk4f c3 = c1 + dc2;
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
141 const SkScalar f = SkScalarFraction(fx); 81 const SkScalar f = SkScalarFraction(fx);
142 return f < 0 ? f + 1 : f; 82 return f < 0 ? f + 1 : f;
143 } 83 }
144 84
145 template<> 85 template<>
146 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) { 86 SkScalar pinFx<SkShader::kMirror_TileMode>(SkScalar fx) {
147 const SkScalar f = SkScalarMod(fx, 2.0f); 87 const SkScalar f = SkScalarMod(fx, 2.0f);
148 return f < 0 ? f + 2 : f; 88 return f < 0 ? f + 2 : f;
149 } 89 }
150 90
151 template<typename DstType>
152 float dst_component_scale();
153
154 template<>
155 float dst_component_scale<SkPM4f>() {
156 return 1;
157 }
158
159 template<>
160 float dst_component_scale<SkPMColor>() {
161 return 255;
162 }
163
164 template<typename DstType>
165 Sk4f dst_swizzle(const SkPM4f&);
166
167 template<>
168 Sk4f dst_swizzle<SkPM4f>(const SkPM4f& c) {
169 return c.to4f();
170 }
171
172 template<>
173 Sk4f dst_swizzle<SkPMColor>(const SkPM4f& c) {
174 return c.to4f_pmorder();
175 }
176
177 SkPMColor pack_color(SkColor c, bool premul) {
178 return premul
179 ? SkPreMultiplyColor(c)
180 : SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), Sk ColorGetB(c));
181 }
182
183 // true when x is in [k1,k2) 91 // true when x is in [k1,k2)
184 bool in_range(SkScalar x, SkScalar k1, SkScalar k2) { 92 bool in_range(SkScalar x, SkScalar k1, SkScalar k2) {
185 SkASSERT(k1 != k2); 93 SkASSERT(k1 != k2);
186 return (k1 < k2) 94 return (k1 < k2)
187 ? (x >= k1 && x < k2) 95 ? (x >= k1 && x < k2)
188 : (x >= k2 && x < k1); 96 : (x >= k2 && x < k1);
189 } 97 }
190 98
191 class IntervalBuilder {
192 public:
193 IntervalBuilder(const SkColor* colors, const SkScalar* pos, int count, bool reverse)
194 : fColors(colors)
195 , fPos(pos)
196 , fCount(count)
197 , fFirstPos(reverse ? SK_Scalar1 : 0)
198 , fBegin(reverse ? count - 1 : 0)
199 , fAdvance(reverse ? -1 : 1) {
200 SkASSERT(colors);
201 SkASSERT(count > 1);
202 }
203
204 template<typename F>
205 void build(F func) const {
206 if (!fPos) {
207 this->buildImplicitPos(func);
208 return;
209 }
210
211 const int end = fBegin + fAdvance * (fCount - 1);
212 const SkScalar lastPos = 1 - fFirstPos;
213 int prev = fBegin;
214 SkScalar prevPos = fFirstPos;
215
216 do {
217 const int curr = prev + fAdvance;
218 SkASSERT(curr >= 0 && curr < fCount);
219
220 // TODO: this sanitization should be done in SkGradientShaderBase
221 const SkScalar currPos = (fAdvance > 0)
222 ? SkTPin(fPos[curr], prevPos, lastPos)
223 : SkTPin(fPos[curr], lastPos, prevPos);
224
225 if (currPos != prevPos) {
226 SkASSERT((currPos - prevPos > 0) == (fAdvance > 0));
227 func(fColors[prev], fColors[curr], prevPos, currPos);
228 }
229
230 prev = curr;
231 prevPos = currPos;
232 } while (prev != end);
233 }
234
235 private:
236 template<typename F>
237 void buildImplicitPos(F func) const {
238 // When clients don't provide explicit color stop positions (fPos == nul lptr),
239 // the color stops are distributed evenly across the unit interval
240 // (implicit positioning).
241 const SkScalar dt = fAdvance * SK_Scalar1 / (fCount - 1);
242 const int end = fBegin + fAdvance * (fCount - 2);
243 int prev = fBegin;
244 SkScalar prevPos = fFirstPos;
245
246 while (prev != end) {
247 const int curr = prev + fAdvance;
248 SkASSERT(curr >= 0 && curr < fCount);
249
250 const SkScalar currPos = prevPos + dt;
251 func(fColors[prev], fColors[curr], prevPos, currPos);
252 prev = curr;
253 prevPos = currPos;
254 }
255
256 // emit the last interval with a pinned end position, to avoid precision issues
257 func(fColors[prev], fColors[prev + fAdvance], prevPos, 1 - fFirstPos);
258 }
259
260 const SkColor* fColors;
261 const SkScalar* fPos;
262 const int fCount;
263 const SkScalar fFirstPos;
264 const int fBegin;
265 const int fAdvance;
266 };
267
268 } // anonymous namespace 99 } // anonymous namespace
269 100
270 SkLinearGradient:: 101 SkLinearGradient::
271 LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader, 102 LinearGradient4fContext::LinearGradient4fContext(const SkLinearGradient& shader,
272 const ContextRec& rec) 103 const ContextRec& rec)
273 : INHERITED(shader, rec) { 104 : INHERITED(shader, rec) {
274 // The main job here is to build a specialized interval list: a different
275 // representation of the color stops data, optimized for efficient scan line
276 // access during shading.
277 //
278 // [{P0,C0} , {P1,C1}) [{P1,C2} , {P2,c3}) ... [{Pn,C2n} , {Pn+1,C2n+1})
279 //
280 // The list is sorted in increasing dst order, i.e. X(Pk) < X(Pk+1). This
281 // allows us to always traverse left->right when iterating over a scan line.
282 // It also means that the interval order matches the color stops when dx >= 0,
283 // and is the inverse (pos, colors, order are flipped) when dx < 0.
284 //
285 // Note: the current representation duplicates pos data; we could refactor t o
286 // avoid this if interval storage size becomes a concern.
287 //
288 // Aside from reordering, we also perform two more pre-processing steps at
289 // this stage:
290 //
291 // 1) scale the color components depending on paint alpha and the requeste d
292 // interpolation space (note: the interval color storage is SkPM4f, but
293 // that doesn't necessarily mean the colors are premultiplied; that
294 // property is tracked in fColorsArePremul)
295 //
296 // 2) inject synthetic intervals to support tiling.
297 //
298 // * for kRepeat, no extra intervals are needed - the iterator just
299 // wraps around at the end:
300 //
301 // ->[P0,P1)->..[Pn-1,Pn)->
302 //
303 // * for kClamp, we add two "infinite" intervals before/after:
304 //
305 // [-/+inf , P0)->[P0 , P1)->..[Pn-1 , Pn)->[Pn , +/-inf)
306 //
307 // (the iterator should never run off the end in this mode)
308 //
309 // * for kMirror, we extend the range to [0..2] and add a flipped
310 // interval series - then the iterator operates just as in the
311 // kRepeat case:
312 //
313 // ->[P0,P1)->..[Pn-1,Pn)->[2 - Pn,2 - Pn-1)->..[2 - P1,2 - P0)->
314 //
315 // TODO: investigate collapsing intervals << 1px.
316 105
317 SkASSERT(shader.fColorCount > 1); 106 // Our fast path expects interval points to be monotonically increasing in x .
318 SkASSERT(shader.fOrigColors); 107 const bool reverseIntervals = this->isFast() && fDstToPos.getScaleX() < 0;
319 108 this->buildIntervals(shader, rec, reverseIntervals);
320 const float paintAlpha = rec.fPaint->getAlpha() * (1.0f / 255);
321 const Sk4f componentScale = fColorsArePremul
322 ? Sk4f(paintAlpha)
323 : Sk4f(1.0f, 1.0f, 1.0f, paintAlpha);
324 const bool dx_is_pos = fDstToPos.getScaleX() >= 0;
325 const int first_index = dx_is_pos ? 0 : shader.fColorCount - 1;
326 const int last_index = shader.fColorCount - 1 - first_index;
327 const SkScalar first_pos = dx_is_pos ? 0 : SK_Scalar1;
328 const SkScalar last_pos = 1 - first_pos;
329
330 if (shader.fTileMode == SkShader::kClamp_TileMode) {
331 // synthetic edge interval: -/+inf .. P0
332 const SkPMColor clamp_color = pack_color(shader.fOrigColors[first_index] ,
333 fColorsArePremul);
334 const SkScalar clamp_pos = dx_is_pos ? SK_ScalarMin : SK_ScalarMax;
335 fIntervals.emplace_back(clamp_color, clamp_pos,
336 clamp_color, first_pos,
337 componentScale);
338 } else if (shader.fTileMode == SkShader::kMirror_TileMode && !dx_is_pos) {
339 // synthetic mirror intervals injected before main intervals: (2 .. 1]
340 addMirrorIntervals(shader, componentScale, dx_is_pos);
341 }
342
343 const IntervalBuilder builder(shader.fOrigColors,
344 shader.fOrigPos,
345 shader.fColorCount,
346 !dx_is_pos);
347 builder.build([this, &componentScale] (SkColor c0, SkColor c1, SkScalar p0, SkScalar p1) {
348 SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == p0);
349
350 fIntervals.emplace_back(pack_color(c0, fColorsArePremul),
351 p0,
352 pack_color(c1, fColorsArePremul),
353 p1,
354 componentScale);
355 });
356
357 if (shader.fTileMode == SkShader::kClamp_TileMode) {
358 // synthetic edge interval: Pn .. +/-inf
359 const SkPMColor clamp_color =
360 pack_color(shader.fOrigColors[last_index], fColorsArePremul);
361 const SkScalar clamp_pos = dx_is_pos ? SK_ScalarMax : SK_ScalarMin;
362 fIntervals.emplace_back(clamp_color, last_pos,
363 clamp_color, clamp_pos,
364 componentScale);
365 } else if (shader.fTileMode == SkShader::kMirror_TileMode && dx_is_pos) {
366 // synthetic mirror intervals injected after main intervals: [1 .. 2)
367 addMirrorIntervals(shader, componentScale, dx_is_pos);
368 }
369 109
370 SkASSERT(fIntervals.count() > 0); 110 SkASSERT(fIntervals.count() > 0);
371 fCachedInterval = fIntervals.begin(); 111 fCachedInterval = fIntervals.begin();
372 } 112 }
373 113
374 void SkLinearGradient::
375 LinearGradient4fContext::addMirrorIntervals(const SkLinearGradient& shader,
376 const Sk4f& componentScale, bool dx_ is_pos) {
377 // Iterates in reverse order (vs main interval builder) and adds intervals r eflected in 2.
378 const IntervalBuilder builder(shader.fOrigColors,
379 shader.fOrigPos,
380 shader.fColorCount,
381 dx_is_pos);
382 builder.build([this, &componentScale] (SkColor c0, SkColor c1, SkScalar p0, SkScalar p1) {
383 SkASSERT(fIntervals.empty() || fIntervals.back().fP1 == 2 - p0);
384
385 fIntervals.emplace_back(pack_color(c0, fColorsArePremul),
386 2 - p0,
387 pack_color(c1, fColorsArePremul),
388 2 - p1,
389 componentScale);
390 });
391 }
392
393 const SkGradientShaderBase::GradientShaderBase4fContext::Interval* 114 const SkGradientShaderBase::GradientShaderBase4fContext::Interval*
394 SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const { 115 SkLinearGradient::LinearGradient4fContext::findInterval(SkScalar fx) const {
395 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1)); 116 SkASSERT(in_range(fx, fIntervals.front().fP0, fIntervals.back().fP1));
396 117
397 if (1) { 118 if (1) {
398 // Linear search, using the last scanline interval as a starting point. 119 // Linear search, using the last scanline interval as a starting point.
399 SkASSERT(fCachedInterval >= fIntervals.begin()); 120 SkASSERT(fCachedInterval >= fIntervals.begin());
400 SkASSERT(fCachedInterval < fIntervals.end()); 121 SkASSERT(fCachedInterval < fIntervals.end());
401 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1; 122 const int search_dir = fDstToPos.getScaleX() >= 0 ? 1 : -1;
402 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) { 123 while (!in_range(fx, fCachedInterval->fP0, fCachedInterval->fP1)) {
(...skipping 24 matching lines...) Expand all
427 } 148 }
428 } 149 }
429 150
430 SkASSERT(in_range(fx, i0->fP0, i0->fP1)); 151 SkASSERT(in_range(fx, i0->fP0, i0->fP1));
431 return i0; 152 return i0;
432 } 153 }
433 } 154 }
434 155
435 void SkLinearGradient:: 156 void SkLinearGradient::
436 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { 157 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) {
158 if (!this->isFast()) {
159 this->INHERITED::shadeSpan(x, y, dst, count);
160 return;
161 }
162
437 // TODO: plumb dithering 163 // TODO: plumb dithering
438 SkASSERT(count > 0); 164 SkASSERT(count > 0);
439 if (fColorsArePremul) { 165 if (fColorsArePremul) {
440 this->shadePremulSpan<SkPMColor, false>(x, y, dst, count); 166 this->shadePremulSpan<SkPMColor, false>(x, y, dst, count);
441 } else { 167 } else {
442 this->shadePremulSpan<SkPMColor, true>(x, y, dst, count); 168 this->shadePremulSpan<SkPMColor, true>(x, y, dst, count);
443 } 169 }
444 } 170 }
445 171
446 void SkLinearGradient:: 172 void SkLinearGradient::
447 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { 173 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) {
174 if (!this->isFast()) {
175 this->INHERITED::shadeSpan4f(x, y, dst, count);
176 return;
177 }
178
448 // TONOTDO: plumb dithering 179 // TONOTDO: plumb dithering
449 SkASSERT(count > 0); 180 SkASSERT(count > 0);
450 if (fColorsArePremul) { 181 if (fColorsArePremul) {
451 this->shadePremulSpan<SkPM4f, false>(x, y, dst, count); 182 this->shadePremulSpan<SkPM4f, false>(x, y, dst, count);
452 } else { 183 } else {
453 this->shadePremulSpan<SkPM4f, true>(x, y, dst, count); 184 this->shadePremulSpan<SkPM4f, true>(x, y, dst, count);
454 } 185 }
455 } 186 }
456 187
457 template<typename DstType, bool do_premul> 188 template<typename DstType, bool do_premul>
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
538 bool is_vertical) 269 bool is_vertical)
539 : fDstComponentScale(dst_component_scale<DstType>()) 270 : fDstComponentScale(dst_component_scale<DstType>())
540 , fAdvX((i->fP1 - fx) / dx) 271 , fAdvX((i->fP1 - fx) / dx)
541 , fFirstInterval(firstInterval) 272 , fFirstInterval(firstInterval)
542 , fLastInterval(lastInterval) 273 , fLastInterval(lastInterval)
543 , fInterval(i) 274 , fInterval(i)
544 , fDx(dx) 275 , fDx(dx)
545 , fIsVertical(is_vertical) 276 , fIsVertical(is_vertical)
546 { 277 {
547 SkASSERT(firstInterval <= lastInterval); 278 SkASSERT(firstInterval <= lastInterval);
548 SkASSERT(i->contains(fx)); 279 SkASSERT(in_range(fx, i->fP0, i->fP1));
549 this->compute_interval_props(fx - i->fP0); 280 this->compute_interval_props(fx - i->fP0);
550 } 281 }
551 282
552 SkScalar currentAdvance() const { 283 SkScalar currentAdvance() const {
553 SkASSERT(fAdvX >= 0); 284 SkASSERT(fAdvX >= 0);
554 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx); 285 SkASSERT(fAdvX <= (fInterval->fP1 - fInterval->fP0) / fDx);
555 return fAdvX; 286 return fAdvX;
556 } 287 }
557 288
558 bool currentRampIsZero() const { return fZeroRamp; } 289 bool currentRampIsZero() const { return fZeroRamp; }
(...skipping 60 matching lines...) Expand 10 before | Expand all | Expand 10 after
619 Sk4f fCc; // current color, interpolated in dst 350 Sk4f fCc; // current color, interpolated in dst
620 SkScalar fAdvX; // remaining interval advance in dst 351 SkScalar fAdvX; // remaining interval advance in dst
621 bool fZeroRamp; // current interval color grad is 0 352 bool fZeroRamp; // current interval color grad is 0
622 353
623 const Interval* fFirstInterval; 354 const Interval* fFirstInterval;
624 const Interval* fLastInterval; 355 const Interval* fLastInterval;
625 const Interval* fInterval; // current interval 356 const Interval* fInterval; // current interval
626 const SkScalar fDx; // 'dx' for consistency with other impls; actual ly dt/dx 357 const SkScalar fDx; // 'dx' for consistency with other impls; actual ly dt/dx
627 const bool fIsVertical; 358 const bool fIsVertical;
628 }; 359 };
360
361 void SkLinearGradient::
362 LinearGradient4fContext::mapTs(int x, int y, SkScalar ts[], int count) const {
363 SkASSERT(count > 0);
364 SkASSERT(fDstToPosClass != kLinear_MatrixClass);
365
366 SkScalar sx = x + SK_ScalarHalf;
367 const SkScalar sy = y + SK_ScalarHalf;
368 SkPoint pt;
369
370 if (fDstToPosClass != kPerspective_MatrixClass) {
371 // kLinear_MatrixClass, kFixedStepInX_MatrixClass => fixed dt per scanli ne
372 const SkScalar dtdx = fDstToPos.fixedStepInX(sy).x();
373 fDstToPosProc(fDstToPos, sx, sy, &pt);
374
375 const Sk4f dtdx4 = Sk4f(4 * dtdx);
376 Sk4f t4 = Sk4f(pt.x() + 0 * dtdx,
377 pt.x() + 1 * dtdx,
378 pt.x() + 2 * dtdx,
379 pt.x() + 3 * dtdx);
380
381 while (count >= 4) {
382 t4.store(ts);
383 t4 = t4 + dtdx4;
384 ts += 4;
385 count -= 4;
386 }
387
388 if (count & 2) {
389 *ts++ = t4[0];
390 *ts++ = t4[1];
391 t4 = SkNx_shuffle<2, 0, 1, 3>(t4);
392 }
393
394 if (count & 1) {
395 *ts++ = t4[0];
396 }
397 } else {
398 for (int i = 0; i < count; ++i) {
399 fDstToPosProc(fDstToPos, sx, sy, &pt);
400 ts[i] = pt.x();
401 sx += SK_Scalar1;
402 }
403 }
404 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698