OLD | NEW |
1 | 1 |
2 /* | 2 /* |
3 * Copyright 2012 Google Inc. | 3 * Copyright 2012 Google Inc. |
4 * | 4 * |
5 * Use of this source code is governed by a BSD-style license that can be | 5 * Use of this source code is governed by a BSD-style license that can be |
6 * found in the LICENSE file. | 6 * found in the LICENSE file. |
7 */ | 7 */ |
8 | 8 |
9 #include "SkRadialGradient.h" | 9 #include "SkRadialGradient.h" |
10 #include "SkRadialGradient_Table.h" | 10 #include "SkRadialGradient_Table.h" |
11 #include "SkNx.h" | |
12 | 11 |
13 #define kSQRT_TABLE_BITS 11 | 12 #define kSQRT_TABLE_BITS 11 |
14 #define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS) | 13 #define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS) |
15 | 14 |
16 SK_COMPILE_ASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE, SqrtTableSizesMatch); | 15 SK_COMPILE_ASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE, SqrtTableSizesMatch); |
17 | 16 |
18 #if 0 | 17 #if 0 |
19 | 18 |
20 #include <stdio.h> | 19 #include <stdio.h> |
21 | 20 |
(...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 | 263 |
265 void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { | 264 void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { |
266 this->INHERITED::flatten(buffer); | 265 this->INHERITED::flatten(buffer); |
267 buffer.writePoint(fCenter); | 266 buffer.writePoint(fCenter); |
268 buffer.writeScalar(fRadius); | 267 buffer.writeScalar(fRadius); |
269 } | 268 } |
270 | 269 |
271 namespace { | 270 namespace { |
272 | 271 |
273 inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) { | 272 inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) { |
274 // fast, overly-conservative test: checks unit square instead of unit circle | 273 // fast, overly-conservative test: checks unit square instead |
275 bool xClamped = (fx >= SK_FixedHalf && dx >= 0) || (fx <= -SK_FixedHalf && d
x <= 0); | 274 // of unit circle |
276 bool yClamped = (fy >= SK_FixedHalf && dy >= 0) || (fy <= -SK_FixedHalf && d
y <= 0); | 275 bool xClamped = (fx >= SK_FixedHalf && dx >= 0) || |
| 276 (fx <= -SK_FixedHalf && dx <= 0); |
| 277 bool yClamped = (fy >= SK_FixedHalf && dy >= 0) || |
| 278 (fy <= -SK_FixedHalf && dy <= 0); |
| 279 |
277 return xClamped || yClamped; | 280 return xClamped || yClamped; |
278 } | 281 } |
279 | 282 |
280 inline bool radial_completely_pinned(SkScalar fx, SkScalar dx, SkScalar fy, SkSc
alar dy) { | |
281 // fast, overly-conservative test: checks unit square instead of unit circle | |
282 bool xClamped = (fx >= 1 && dx >= 0) || (fx <= -1 && dx <= 0); | |
283 bool yClamped = (fy >= 1 && dy >= 0) || (fy <= -1 && dy <= 0); | |
284 return xClamped || yClamped; | |
285 } | |
286 | |
287 // Return true if (fx * fy) is always inside the unit circle | 283 // Return true if (fx * fy) is always inside the unit circle |
288 // SkPin32 is expensive, but so are all the SkFixedMul in this test, | 284 // SkPin32 is expensive, but so are all the SkFixedMul in this test, |
289 // so it shouldn't be run if count is small. | 285 // so it shouldn't be run if count is small. |
290 inline bool no_need_for_radial_pin(int fx, int dx, | 286 inline bool no_need_for_radial_pin(int fx, int dx, |
291 int fy, int dy, int count) { | 287 int fy, int dy, int count) { |
292 SkASSERT(count > 0); | 288 SkASSERT(count > 0); |
293 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { | 289 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { |
294 return false; | 290 return false; |
295 } | 291 } |
296 if (fx*fx + fy*fy > 0x7FFF*0x7FFF) { | 292 if (fx*fx + fy*fy > 0x7FFF*0x7FFF) { |
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 *dstC++ = cache[toggle + (sqrt_table[fi] >> | 366 *dstC++ = cache[toggle + (sqrt_table[fi] >> |
371 SkGradientShaderBase::kSqrt32Shift)]; | 367 SkGradientShaderBase::kSqrt32Shift)]; |
372 toggle = next_dither_toggle(toggle); | 368 toggle = next_dither_toggle(toggle); |
373 fx += dx; | 369 fx += dx; |
374 fy += dy; | 370 fy += dy; |
375 } while (--count != 0); | 371 } while (--count != 0); |
376 } | 372 } |
377 } | 373 } |
378 } | 374 } |
379 | 375 |
380 // TODO: can we get away with 0th approximatino of inverse-sqrt (i.e. faster tha
n rsqrt)? | |
381 // seems like ~10bits is more than enough for our use, since we want a byt
e-index | |
382 static inline Sk4f fast_sqrt(const Sk4f& R) { | |
383 return R * R.rsqrt(); | |
384 } | |
385 | |
386 static inline Sk4f sum_squares(const Sk4f& a, const Sk4f& b) { | |
387 return a * a + b * b; | |
388 } | |
389 | |
390 void shadeSpan_radial_clamp2(SkScalar sfx, SkScalar sdx, SkScalar sfy, SkScalar
sdy, | |
391 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RE
STRICT cache, | |
392 int count, int toggle) { | |
393 if (radial_completely_pinned(sfx, sdx, sfy, sdy)) { | |
394 unsigned fi = SkGradientShaderBase::kCache32Count - 1; | |
395 sk_memset32_dither(dstC, | |
396 cache[toggle + fi], | |
397 cache[next_dither_toggle(toggle) + fi], | |
398 count); | |
399 } else { | |
400 const Sk4f max(255); | |
401 const float scale = 255; | |
402 sfx *= scale; | |
403 sfy *= scale; | |
404 sdx *= scale; | |
405 sdy *= scale; | |
406 const Sk4f fx4(sfx, sfx + sdx, sfx + 2*sdx, sfx + 3*sdx); | |
407 const Sk4f fy4(sfy, sfy + sdy, sfy + 2*sdy, sfy + 3*sdy); | |
408 const Sk4f dx4(sdx * 4); | |
409 const Sk4f dy4(sdy * 4); | |
410 | |
411 Sk4f tmpxy = fx4 * dx4 + fy4 * dy4; | |
412 Sk4f tmpdxdy = sum_squares(dx4, dy4); | |
413 Sk4f R = sum_squares(fx4, fy4); | |
414 Sk4f dR = tmpxy + tmpxy + tmpdxdy; | |
415 const Sk4f ddR = tmpdxdy + tmpdxdy; | |
416 | |
417 for (int i = 0; i < (count >> 2); ++i) { | |
418 Sk4f dist = Sk4f::Min(fast_sqrt(R), max); | |
419 R += dR; | |
420 dR += ddR; | |
421 | |
422 int fi[4]; | |
423 dist.castTrunc().store(fi); | |
424 | |
425 for (int i = 0; i < 4; i++) { | |
426 *dstC++ = cache[toggle + fi[i]]; | |
427 toggle = next_dither_toggle(toggle); | |
428 } | |
429 } | |
430 count &= 3; | |
431 if (count) { | |
432 Sk4f dist = Sk4f::Min(fast_sqrt(R), max); | |
433 | |
434 int fi[4]; | |
435 dist.castTrunc().store(fi); | |
436 for (int i = 0; i < count; i++) { | |
437 *dstC++ = cache[toggle + fi[i]]; | |
438 toggle = next_dither_toggle(toggle); | |
439 } | |
440 } | |
441 } | |
442 } | |
443 | |
444 // Unrolling this loop doesn't seem to help (when float); we're stalling to | 376 // Unrolling this loop doesn't seem to help (when float); we're stalling to |
445 // get the results of the sqrt (?), and don't have enough extra registers to | 377 // get the results of the sqrt (?), and don't have enough extra registers to |
446 // have many in flight. | 378 // have many in flight. |
447 template <SkFixed (*TileProc)(SkFixed)> | 379 template <SkFixed (*TileProc)(SkFixed)> |
448 void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, | 380 void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, |
449 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT
cache, | 381 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT
cache, |
450 int count, int toggle) { | 382 int count, int toggle) { |
451 do { | 383 do { |
452 const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); | 384 const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); |
453 const unsigned fi = TileProc(dist); | 385 const unsigned fi = TileProc(dist); |
(...skipping 14 matching lines...) Expand all Loading... |
468 void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, | 400 void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, |
469 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RE
STRICT cache, | 401 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RE
STRICT cache, |
470 int count, int toggle) { | 402 int count, int toggle) { |
471 shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, cou
nt, toggle); | 403 shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, cou
nt, toggle); |
472 } | 404 } |
473 | 405 |
474 } // namespace | 406 } // namespace |
475 | 407 |
476 void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, | 408 void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, |
477 SkPMColor* SK_RESTRICT d
stC, int count) { | 409 SkPMColor* SK_RESTRICT d
stC, int count) { |
478 #ifdef SK_SUPPORT_LEGACY_RADIAL_GRADIENT_SQRT | |
479 const bool use_new_proc = false; | |
480 #else | |
481 const bool use_new_proc = true; | |
482 #endif | |
483 SkASSERT(count > 0); | 410 SkASSERT(count > 0); |
484 | 411 |
485 const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&
>(fShader); | 412 const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&
>(fShader); |
486 | 413 |
487 SkPoint srcPt; | 414 SkPoint srcPt; |
488 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 415 SkMatrix::MapXYProc dstProc = fDstToIndexProc; |
489 TileProc proc = radialGradient.fTileProc; | 416 TileProc proc = radialGradient.fTileProc; |
490 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); | 417 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); |
491 int toggle = init_dither_toggle(x, y); | 418 int toggle = init_dither_toggle(x, y); |
492 | 419 |
493 if (fDstToIndexClass != kPerspective_MatrixClass) { | 420 if (fDstToIndexClass != kPerspective_MatrixClass) { |
494 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | 421 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, |
495 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | 422 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
496 SkScalar sdx = fDstToIndex.getScaleX(); | 423 SkScalar sdx = fDstToIndex.getScaleX(); |
497 SkScalar sdy = fDstToIndex.getSkewY(); | 424 SkScalar sdy = fDstToIndex.getSkewY(); |
498 | 425 |
499 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | 426 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
500 SkFixed storage[2]; | 427 SkFixed storage[2]; |
501 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), | 428 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), |
502 &storage[0], &storage[1]); | 429 &storage[0], &storage[1]); |
503 sdx = SkFixedToScalar(storage[0]); | 430 sdx = SkFixedToScalar(storage[0]); |
504 sdy = SkFixedToScalar(storage[1]); | 431 sdy = SkFixedToScalar(storage[1]); |
505 } else { | 432 } else { |
506 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | 433 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
507 } | 434 } |
508 | 435 |
509 RadialShadeProc shadeProc = shadeSpan_radial_repeat; | 436 RadialShadeProc shadeProc = shadeSpan_radial_repeat; |
510 if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { | 437 if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { |
511 shadeProc = use_new_proc ? shadeSpan_radial_clamp2 : shadeSpan_radia
l_clamp; | 438 shadeProc = shadeSpan_radial_clamp; |
512 } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { | 439 } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { |
513 shadeProc = shadeSpan_radial_mirror; | 440 shadeProc = shadeSpan_radial_mirror; |
514 } else { | 441 } else { |
515 SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); | 442 SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); |
516 } | 443 } |
517 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); | 444 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); |
518 } else { // perspective case | 445 } else { // perspective case |
519 SkScalar dstX = SkIntToScalar(x); | 446 SkScalar dstX = SkIntToScalar(x); |
520 SkScalar dstY = SkIntToScalar(y); | 447 SkScalar dstY = SkIntToScalar(y); |
521 do { | 448 do { |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
688 str->appendScalar(fCenter.fY); | 615 str->appendScalar(fCenter.fY); |
689 str->append(") radius: "); | 616 str->append(") radius: "); |
690 str->appendScalar(fRadius); | 617 str->appendScalar(fRadius); |
691 str->append(" "); | 618 str->append(" "); |
692 | 619 |
693 this->INHERITED::toString(str); | 620 this->INHERITED::toString(str); |
694 | 621 |
695 str->append(")"); | 622 str->append(")"); |
696 } | 623 } |
697 #endif | 624 #endif |
OLD | NEW |