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 "Sk4fLinearGradient.h" | 8 #include "Sk4fLinearGradient.h" |
9 #include "SkUtils.h" | |
10 #include "SkXfermode.h" | 9 #include "SkXfermode.h" |
11 | 10 |
12 namespace { | 11 namespace { |
13 | 12 |
14 template<typename DstType, SkColorProfileType, ApplyPremul> | 13 template<DstType dstType, ApplyPremul premul> |
15 void fill(const Sk4f& c, DstType* dst, int n); | 14 void ramp(const Sk4f& c, const Sk4f& dc, typename DstTraits<dstType, premul>::Ty
pe dst[], int n) { |
16 | |
17 template<> | |
18 void fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::False> | |
19 (const Sk4f& c, SkPM4f* dst, int n) { | |
20 while (n > 0) { | |
21 c.store(dst++); | |
22 n--; | |
23 } | |
24 } | |
25 | |
26 template<> | |
27 void fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::True> | |
28 (const Sk4f& c, SkPM4f* dst, int n) { | |
29 fill<SkPM4f, kLinear_SkColorProfileType, ApplyPremul::False>(premul_4f(c), d
st, n); | |
30 } | |
31 | |
32 template<> | |
33 void fill<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::False> | |
34 (const Sk4f& c, SkPMColor* dst, int n) { | |
35 sk_memset32(dst, trunc_from_4f_255<ApplyPremul::False>(c), n); | |
36 } | |
37 | |
38 template<> | |
39 void fill<SkPMColor, kLinear_SkColorProfileType, ApplyPremul::True> | |
40 (const Sk4f& c, SkPMColor* dst, int n) { | |
41 sk_memset32(dst, trunc_from_4f_255<ApplyPremul::True>(c), n); | |
42 } | |
43 | |
44 template<> | |
45 void fill<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::False> | |
46 (const Sk4f& c, SkPMColor* dst, int n) { | |
47 // FIXME: this assumes opaque colors. Handle unpremultiplication. | |
48 sk_memset32(dst, Sk4f_toS32(c), n); | |
49 } | |
50 | |
51 template<> | |
52 void fill<SkPMColor, kSRGB_SkColorProfileType, ApplyPremul::True> | |
53 (const Sk4f& c, SkPMColor* dst, int n) { | |
54 sk_memset32(dst, Sk4f_toS32(premul_4f(c)), n); | |
55 } | |
56 | |
57 template<> | |
58 void fill<uint64_t, kLinear_SkColorProfileType, ApplyPremul::False> | |
59 (const Sk4f& c, uint64_t* dst, int n) { | |
60 sk_memset64(dst, SkFloatToHalf_01(c), n); | |
61 } | |
62 | |
63 template<> | |
64 void fill<uint64_t, kLinear_SkColorProfileType, ApplyPremul::True> | |
65 (const Sk4f& c, uint64_t* dst, int n) { | |
66 sk_memset64(dst, SkFloatToHalf_01(premul_4f(c)), n); | |
67 } | |
68 | |
69 template<typename DstType, SkColorProfileType profile, ApplyPremul premul> | |
70 void ramp(const Sk4f& c, const Sk4f& dc, DstType* dst, int n) { | |
71 SkASSERT(n > 0); | 15 SkASSERT(n > 0); |
72 | 16 |
73 const Sk4f dc2 = dc + dc; | 17 const Sk4f dc2 = dc + dc; |
74 const Sk4f dc4 = dc2 + dc2; | 18 const Sk4f dc4 = dc2 + dc2; |
75 | 19 |
76 Sk4f c0 = c ; | 20 Sk4f c0 = c ; |
77 Sk4f c1 = c + dc; | 21 Sk4f c1 = c + dc; |
78 Sk4f c2 = c0 + dc2; | 22 Sk4f c2 = c0 + dc2; |
79 Sk4f c3 = c1 + dc2; | 23 Sk4f c3 = c1 + dc2; |
80 | 24 |
81 while (n >= 4) { | 25 while (n >= 4) { |
82 store4x<DstType, profile, premul>(c0, c1, c2, c3, dst); | 26 DstTraits<dstType, premul>::store4x(c0, c1, c2, c3, dst); |
83 dst += 4; | 27 dst += 4; |
84 | 28 |
85 c0 = c0 + dc4; | 29 c0 = c0 + dc4; |
86 c1 = c1 + dc4; | 30 c1 = c1 + dc4; |
87 c2 = c2 + dc4; | 31 c2 = c2 + dc4; |
88 c3 = c3 + dc4; | 32 c3 = c3 + dc4; |
89 n -= 4; | 33 n -= 4; |
90 } | 34 } |
91 if (n & 2) { | 35 if (n & 2) { |
92 store<DstType, profile, premul>(c0, dst++); | 36 DstTraits<dstType, premul>::store(c0, dst++); |
93 store<DstType, profile, premul>(c1, dst++); | 37 DstTraits<dstType, premul>::store(c1, dst++); |
94 c0 = c0 + dc2; | 38 c0 = c0 + dc2; |
95 } | 39 } |
96 if (n & 1) { | 40 if (n & 1) { |
97 store<DstType, profile, premul>(c0, dst); | 41 DstTraits<dstType, premul>::store(c0, dst); |
98 } | 42 } |
99 } | 43 } |
100 | 44 |
101 template<SkShader::TileMode> | 45 template<SkShader::TileMode> |
102 SkScalar pinFx(SkScalar); | 46 SkScalar pinFx(SkScalar); |
103 | 47 |
104 template<> | 48 template<> |
105 SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) { | 49 SkScalar pinFx<SkShader::kClamp_TileMode>(SkScalar fx) { |
106 return fx; | 50 return fx; |
107 } | 51 } |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 void SkLinearGradient:: | 130 void SkLinearGradient:: |
187 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { | 131 LinearGradient4fContext::shadeSpan(int x, int y, SkPMColor dst[], int count) { |
188 if (!this->isFast()) { | 132 if (!this->isFast()) { |
189 this->INHERITED::shadeSpan(x, y, dst, count); | 133 this->INHERITED::shadeSpan(x, y, dst, count); |
190 return; | 134 return; |
191 } | 135 } |
192 | 136 |
193 // TODO: plumb dithering | 137 // TODO: plumb dithering |
194 SkASSERT(count > 0); | 138 SkASSERT(count > 0); |
195 if (fColorsArePremul) { | 139 if (fColorsArePremul) { |
196 this->shadePremulSpan<SkPMColor, | 140 this->shadePremulSpan<DstType::L32, |
197 kLinear_SkColorProfileType, | |
198 ApplyPremul::False>(x, y, dst, count); | 141 ApplyPremul::False>(x, y, dst, count); |
199 } else { | 142 } else { |
200 this->shadePremulSpan<SkPMColor, | 143 this->shadePremulSpan<DstType::L32, |
201 kLinear_SkColorProfileType, | |
202 ApplyPremul::True>(x, y, dst, count); | 144 ApplyPremul::True>(x, y, dst, count); |
203 } | 145 } |
204 } | 146 } |
205 | 147 |
206 void SkLinearGradient:: | 148 void SkLinearGradient:: |
207 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { | 149 LinearGradient4fContext::shadeSpan4f(int x, int y, SkPM4f dst[], int count) { |
208 if (!this->isFast()) { | 150 if (!this->isFast()) { |
209 this->INHERITED::shadeSpan4f(x, y, dst, count); | 151 this->INHERITED::shadeSpan4f(x, y, dst, count); |
210 return; | 152 return; |
211 } | 153 } |
212 | 154 |
213 // TONOTDO: plumb dithering | 155 // TONOTDO: plumb dithering |
214 SkASSERT(count > 0); | 156 SkASSERT(count > 0); |
215 if (fColorsArePremul) { | 157 if (fColorsArePremul) { |
216 this->shadePremulSpan<SkPM4f, | 158 this->shadePremulSpan<DstType::F32, |
217 kLinear_SkColorProfileType, | |
218 ApplyPremul::False>(x, y, dst, count); | 159 ApplyPremul::False>(x, y, dst, count); |
219 } else { | 160 } else { |
220 this->shadePremulSpan<SkPM4f, | 161 this->shadePremulSpan<DstType::F32, |
221 kLinear_SkColorProfileType, | |
222 ApplyPremul::True>(x, y, dst, count); | 162 ApplyPremul::True>(x, y, dst, count); |
223 } | 163 } |
224 } | 164 } |
225 | 165 |
226 template<typename DstType, SkColorProfileType profile, ApplyPremul premul> | 166 template<DstType dstType, ApplyPremul premul> |
227 void SkLinearGradient:: | 167 void SkLinearGradient:: |
228 LinearGradient4fContext::shadePremulSpan(int x, int y, | 168 LinearGradient4fContext::shadePremulSpan(int x, int y, |
229 DstType dst[], | 169 typename DstTraits<dstType, premul>::Ty
pe dst[], |
230 int count) const { | 170 int count) const { |
231 const SkLinearGradient& shader = | 171 const SkLinearGradient& shader = |
232 static_cast<const SkLinearGradient&>(fShader); | 172 static_cast<const SkLinearGradient&>(fShader); |
233 switch (shader.fTileMode) { | 173 switch (shader.fTileMode) { |
234 case kClamp_TileMode: | 174 case kClamp_TileMode: |
235 this->shadeSpanInternal<DstType, | 175 this->shadeSpanInternal<dstType, |
236 profile, | |
237 premul, | 176 premul, |
238 kClamp_TileMode>(x, y, dst, count); | 177 kClamp_TileMode>(x, y, dst, count); |
239 break; | 178 break; |
240 case kRepeat_TileMode: | 179 case kRepeat_TileMode: |
241 this->shadeSpanInternal<DstType, | 180 this->shadeSpanInternal<dstType, |
242 profile, | |
243 premul, | 181 premul, |
244 kRepeat_TileMode>(x, y, dst, count); | 182 kRepeat_TileMode>(x, y, dst, count); |
245 break; | 183 break; |
246 case kMirror_TileMode: | 184 case kMirror_TileMode: |
247 this->shadeSpanInternal<DstType, | 185 this->shadeSpanInternal<dstType, |
248 profile, | |
249 premul, | 186 premul, |
250 kMirror_TileMode>(x, y, dst, count); | 187 kMirror_TileMode>(x, y, dst, count); |
251 break; | 188 break; |
252 } | 189 } |
253 } | 190 } |
254 | 191 |
255 template<typename DstType, SkColorProfileType profile, ApplyPremul premul, | 192 template<DstType dstType, ApplyPremul premul, SkShader::TileMode tileMode> |
256 SkShader::TileMode tileMode> | |
257 void SkLinearGradient:: | 193 void SkLinearGradient:: |
258 LinearGradient4fContext::shadeSpanInternal(int x, int y, | 194 LinearGradient4fContext::shadeSpanInternal(int x, int y, |
259 DstType dst[], | 195 typename DstTraits<dstType, premul>::
Type dst[], |
260 int count) const { | 196 int count) const { |
261 SkPoint pt; | 197 SkPoint pt; |
262 fDstToPosProc(fDstToPos, | 198 fDstToPosProc(fDstToPos, |
263 x + SK_ScalarHalf, | 199 x + SK_ScalarHalf, |
264 y + SK_ScalarHalf, | 200 y + SK_ScalarHalf, |
265 &pt); | 201 &pt); |
266 const SkScalar fx = pinFx<tileMode>(pt.x()); | 202 const SkScalar fx = pinFx<tileMode>(pt.x()); |
267 const SkScalar dx = fDstToPos.getScaleX(); | 203 const SkScalar dx = fDstToPos.getScaleX(); |
268 LinearIntervalProcessor<DstType, profile, tileMode> proc(fIntervals.begin(), | 204 LinearIntervalProcessor<dstType, tileMode> proc(fIntervals.begin(), |
269 fIntervals.end() -
1, | 205 fIntervals.end() - 1, |
270 this->findInterval(
fx), | 206 this->findInterval(fx), |
271 fx, | 207 fx, |
272 dx, | 208 dx, |
273 SkScalarNearlyZero(
dx * count)); | 209 SkScalarNearlyZero(dx * coun
t)); |
274 while (count > 0) { | 210 while (count > 0) { |
275 // What we really want here is SkTPin(advance, 1, count) | 211 // What we really want here is SkTPin(advance, 1, count) |
276 // but that's a significant perf hit for >> stops; investigate. | 212 // but that's a significant perf hit for >> stops; investigate. |
277 const int n = SkScalarTruncToInt( | 213 const int n = SkScalarTruncToInt( |
278 SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count))); | 214 SkTMin<SkScalar>(proc.currentAdvance() + 1, SkIntToScalar(count))); |
279 | 215 |
280 // The current interval advance can be +inf (e.g. when reaching | 216 // The current interval advance can be +inf (e.g. when reaching |
281 // the clamp mode end intervals) - when that happens, we expect to | 217 // the clamp mode end intervals) - when that happens, we expect to |
282 // a) consume all remaining count in one swoop | 218 // a) consume all remaining count in one swoop |
283 // b) return a zero color gradient | 219 // b) return a zero color gradient |
284 SkASSERT(SkScalarIsFinite(proc.currentAdvance()) | 220 SkASSERT(SkScalarIsFinite(proc.currentAdvance()) |
285 || (n == count && proc.currentRampIsZero())); | 221 || (n == count && proc.currentRampIsZero())); |
286 | 222 |
287 if (proc.currentRampIsZero()) { | 223 if (proc.currentRampIsZero()) { |
288 fill<DstType, profile, premul>(proc.currentColor(), | 224 DstTraits<dstType, premul>::store(proc.currentColor(), |
289 dst, n); | 225 dst, n); |
290 } else { | 226 } else { |
291 ramp<DstType, profile, premul>(proc.currentColor(), | 227 ramp<dstType, premul>(proc.currentColor(), |
292 proc.currentColorGrad(), | 228 proc.currentColorGrad(), |
293 dst, n); | 229 dst, n); |
294 } | 230 } |
295 | 231 |
296 proc.advance(SkIntToScalar(n)); | 232 proc.advance(SkIntToScalar(n)); |
297 count -= n; | 233 count -= n; |
298 dst += n; | 234 dst += n; |
299 } | 235 } |
300 } | 236 } |
301 | 237 |
302 template<typename DstType, SkColorProfileType profile, SkShader::TileMode tileMo
de> | 238 template<DstType dstType, SkShader::TileMode tileMode> |
303 class SkLinearGradient:: | 239 class SkLinearGradient:: |
304 LinearGradient4fContext::LinearIntervalProcessor { | 240 LinearGradient4fContext::LinearIntervalProcessor { |
305 public: | 241 public: |
306 LinearIntervalProcessor(const Interval* firstInterval, | 242 LinearIntervalProcessor(const Interval* firstInterval, |
307 const Interval* lastInterval, | 243 const Interval* lastInterval, |
308 const Interval* i, | 244 const Interval* i, |
309 SkScalar fx, | 245 SkScalar fx, |
310 SkScalar dx, | 246 SkScalar dx, |
311 bool is_vertical) | 247 bool is_vertical) |
312 : fAdvX((i->fP1 - fx) / dx) | 248 : fAdvX((i->fP1 - fx) / dx) |
(...skipping 26 matching lines...) Expand all Loading... |
339 advX = this->advance_interval(advX); | 275 advX = this->advance_interval(advX); |
340 } | 276 } |
341 SkASSERT(advX < fAdvX); | 277 SkASSERT(advX < fAdvX); |
342 | 278 |
343 fCc = fCc + fDcDx * Sk4f(advX); | 279 fCc = fCc + fDcDx * Sk4f(advX); |
344 fAdvX -= advX; | 280 fAdvX -= advX; |
345 } | 281 } |
346 | 282 |
347 private: | 283 private: |
348 void compute_interval_props(SkScalar t) { | 284 void compute_interval_props(SkScalar t) { |
349 fDc = dst_swizzle<DstType>(fInterval->fDc); | 285 const Sk4f dC = DstTraits<dstType>::load(fInterval->fDc); |
350 fCc = dst_swizzle<DstType>(fInterval->fC0); | 286 fCc = DstTraits<dstType>::load(fInterval->fC0); |
351 fCc = fCc + fDc * Sk4f(t); | 287 fCc = fCc + dC * Sk4f(t); |
352 fCc = scale_for_dest<DstType, profile>(fCc); | 288 fDcDx = dC * fDx; |
353 fDcDx = scale_for_dest<DstType, profile>(fDc * Sk4f(fDx)); | 289 fZeroRamp = fIsVertical || fInterval->isZeroRamp(); |
354 fZeroRamp = fIsVertical || fInterval->isZeroRamp(); | |
355 } | 290 } |
356 | 291 |
357 const Interval* next_interval(const Interval* i) const { | 292 const Interval* next_interval(const Interval* i) const { |
358 SkASSERT(i >= fFirstInterval); | 293 SkASSERT(i >= fFirstInterval); |
359 SkASSERT(i <= fLastInterval); | 294 SkASSERT(i <= fLastInterval); |
360 i++; | 295 i++; |
361 | 296 |
362 if (tileMode == kClamp_TileMode) { | 297 if (tileMode == kClamp_TileMode) { |
363 SkASSERT(i <= fLastInterval); | 298 SkASSERT(i <= fLastInterval); |
364 return i; | 299 return i; |
(...skipping 12 matching lines...) Expand all Loading... |
377 SkASSERT(fAdvX > 0); | 312 SkASSERT(fAdvX > 0); |
378 } while (advX >= fAdvX); | 313 } while (advX >= fAdvX); |
379 | 314 |
380 compute_interval_props(0); | 315 compute_interval_props(0); |
381 | 316 |
382 SkASSERT(advX >= 0); | 317 SkASSERT(advX >= 0); |
383 return advX; | 318 return advX; |
384 } | 319 } |
385 | 320 |
386 // Current interval properties. | 321 // Current interval properties. |
387 Sk4f fDc; // local color gradient (dc/dt) | |
388 Sk4f fDcDx; // dst color gradient (dc/dx) | 322 Sk4f fDcDx; // dst color gradient (dc/dx) |
389 Sk4f fCc; // current color, interpolated in dst | 323 Sk4f fCc; // current color, interpolated in dst |
390 SkScalar fAdvX; // remaining interval advance in dst | 324 SkScalar fAdvX; // remaining interval advance in dst |
391 bool fZeroRamp; // current interval color grad is 0 | 325 bool fZeroRamp; // current interval color grad is 0 |
392 | 326 |
393 const Interval* fFirstInterval; | 327 const Interval* fFirstInterval; |
394 const Interval* fLastInterval; | 328 const Interval* fLastInterval; |
395 const Interval* fInterval; // current interval | 329 const Interval* fInterval; // current interval |
396 const SkScalar fDx; // 'dx' for consistency with other impls; actual
ly dt/dx | 330 const SkScalar fDx; // 'dx' for consistency with other impls; actual
ly dt/dx |
397 const bool fIsVertical; | 331 const bool fIsVertical; |
(...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
469 | 403 |
470 void SkLinearGradient:: | 404 void SkLinearGradient:: |
471 LinearGradient4fContext::D32_BlitBW(BlitState* state, int x, int y, const SkPixm
ap& dst, | 405 LinearGradient4fContext::D32_BlitBW(BlitState* state, int x, int y, const SkPixm
ap& dst, |
472 int count) { | 406 int count) { |
473 // FIXME: ignoring coverage for now | 407 // FIXME: ignoring coverage for now |
474 const LinearGradient4fContext* ctx = | 408 const LinearGradient4fContext* ctx = |
475 static_cast<const LinearGradient4fContext*>(state->fCtx); | 409 static_cast<const LinearGradient4fContext*>(state->fCtx); |
476 | 410 |
477 if (dst.info().isLinear()) { | 411 if (dst.info().isLinear()) { |
478 if (ctx->fColorsArePremul) { | 412 if (ctx->fColorsArePremul) { |
479 ctx->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, ApplyPre
mul::False>( | 413 ctx->shadePremulSpan<DstType::L32, ApplyPremul::False>( |
480 x, y, dst.writable_addr32(x, y), count); | 414 x, y, dst.writable_addr32(x, y), count); |
481 } else { | 415 } else { |
482 ctx->shadePremulSpan<SkPMColor, kLinear_SkColorProfileType, ApplyPre
mul::True>( | 416 ctx->shadePremulSpan<DstType::L32, ApplyPremul::True>( |
483 x, y, dst.writable_addr32(x, y), count); | 417 x, y, dst.writable_addr32(x, y), count); |
484 } | 418 } |
485 } else { | 419 } else { |
486 if (ctx->fColorsArePremul) { | 420 if (ctx->fColorsArePremul) { |
487 ctx->shadePremulSpan<SkPMColor, kSRGB_SkColorProfileType, ApplyPremu
l::False>( | 421 ctx->shadePremulSpan<DstType::S32, ApplyPremul::False>( |
488 x, y, dst.writable_addr32(x, y), count); | 422 x, y, dst.writable_addr32(x, y), count); |
489 } else { | 423 } else { |
490 ctx->shadePremulSpan<SkPMColor, kSRGB_SkColorProfileType, ApplyPremu
l::True>( | 424 ctx->shadePremulSpan<DstType::S32, ApplyPremul::True>( |
491 x, y, dst.writable_addr32(x, y), count); | 425 x, y, dst.writable_addr32(x, y), count); |
492 } | 426 } |
493 } | 427 } |
494 } | 428 } |
495 | 429 |
496 void SkLinearGradient:: | 430 void SkLinearGradient:: |
497 LinearGradient4fContext::D64_BlitBW(BlitState* state, int x, int y, const SkPixm
ap& dst, | 431 LinearGradient4fContext::D64_BlitBW(BlitState* state, int x, int y, const SkPixm
ap& dst, |
498 int count) { | 432 int count) { |
499 // FIXME: ignoring coverage for now | 433 // FIXME: ignoring coverage for now |
500 const LinearGradient4fContext* ctx = | 434 const LinearGradient4fContext* ctx = |
501 static_cast<const LinearGradient4fContext*>(state->fCtx); | 435 static_cast<const LinearGradient4fContext*>(state->fCtx); |
502 | 436 |
503 if (ctx->fColorsArePremul) { | 437 if (ctx->fColorsArePremul) { |
504 ctx->shadePremulSpan<uint64_t, kLinear_SkColorProfileType, ApplyPremul::
False>( | 438 ctx->shadePremulSpan<DstType::F16, ApplyPremul::False>( |
505 x, y, dst.writable_addr64(x, y), count); | 439 x, y, dst.writable_addr64(x, y), count); |
506 } else { | 440 } else { |
507 ctx->shadePremulSpan<uint64_t, kLinear_SkColorProfileType, ApplyPremul::
True>( | 441 ctx->shadePremulSpan<DstType::F16, ApplyPremul::True>( |
508 x, y, dst.writable_addr64(x, y), count); | 442 x, y, dst.writable_addr64(x, y), count); |
509 } | 443 } |
510 } | 444 } |
OLD | NEW |