| 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" |
| 11 | 12 |
| 12 #define kSQRT_TABLE_BITS 11 | 13 #define kSQRT_TABLE_BITS 11 |
| 13 #define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS) | 14 #define kSQRT_TABLE_SIZE (1 << kSQRT_TABLE_BITS) |
| 14 | 15 |
| 15 SK_COMPILE_ASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE, SqrtTableSizesMatch); | 16 SK_COMPILE_ASSERT(sizeof(gSqrt8Table) == kSQRT_TABLE_SIZE, SqrtTableSizesMatch); |
| 16 | 17 |
| 17 #if 0 | 18 #if 0 |
| 18 | 19 |
| 19 #include <stdio.h> | 20 #include <stdio.h> |
| 20 | 21 |
| (...skipping 242 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 | 264 |
| 264 void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { | 265 void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { |
| 265 this->INHERITED::flatten(buffer); | 266 this->INHERITED::flatten(buffer); |
| 266 buffer.writePoint(fCenter); | 267 buffer.writePoint(fCenter); |
| 267 buffer.writeScalar(fRadius); | 268 buffer.writeScalar(fRadius); |
| 268 } | 269 } |
| 269 | 270 |
| 270 namespace { | 271 namespace { |
| 271 | 272 |
| 272 inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) { | 273 inline bool radial_completely_pinned(int fx, int dx, int fy, int dy) { |
| 273 // fast, overly-conservative test: checks unit square instead | 274 // fast, overly-conservative test: checks unit square instead of unit circle |
| 274 // of unit circle | 275 bool xClamped = (fx >= SK_FixedHalf && dx >= 0) || (fx <= -SK_FixedHalf && d
x <= 0); |
| 275 bool xClamped = (fx >= SK_FixedHalf && dx >= 0) || | 276 bool yClamped = (fy >= SK_FixedHalf && dy >= 0) || (fy <= -SK_FixedHalf && d
y <= 0); |
| 276 (fx <= -SK_FixedHalf && dx <= 0); | |
| 277 bool yClamped = (fy >= SK_FixedHalf && dy >= 0) || | |
| 278 (fy <= -SK_FixedHalf && dy <= 0); | |
| 279 | |
| 280 return xClamped || yClamped; | 277 return xClamped || yClamped; |
| 281 } | 278 } |
| 282 | 279 |
| 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 |
| 283 // Return true if (fx * fy) is always inside the unit circle | 287 // Return true if (fx * fy) is always inside the unit circle |
| 284 // SkPin32 is expensive, but so are all the SkFixedMul in this test, | 288 // SkPin32 is expensive, but so are all the SkFixedMul in this test, |
| 285 // so it shouldn't be run if count is small. | 289 // so it shouldn't be run if count is small. |
| 286 inline bool no_need_for_radial_pin(int fx, int dx, | 290 inline bool no_need_for_radial_pin(int fx, int dx, |
| 287 int fy, int dy, int count) { | 291 int fy, int dy, int count) { |
| 288 SkASSERT(count > 0); | 292 SkASSERT(count > 0); |
| 289 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { | 293 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { |
| 290 return false; | 294 return false; |
| 291 } | 295 } |
| 292 if (fx*fx + fy*fy > 0x7FFF*0x7FFF) { | 296 if (fx*fx + fy*fy > 0x7FFF*0x7FFF) { |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 366 *dstC++ = cache[toggle + (sqrt_table[fi] >> | 370 *dstC++ = cache[toggle + (sqrt_table[fi] >> |
| 367 SkGradientShaderBase::kSqrt32Shift)]; | 371 SkGradientShaderBase::kSqrt32Shift)]; |
| 368 toggle = next_dither_toggle(toggle); | 372 toggle = next_dither_toggle(toggle); |
| 369 fx += dx; | 373 fx += dx; |
| 370 fy += dy; | 374 fy += dy; |
| 371 } while (--count != 0); | 375 } while (--count != 0); |
| 372 } | 376 } |
| 373 } | 377 } |
| 374 } | 378 } |
| 375 | 379 |
| 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 unsigned fi0 = (unsigned)dist.kth<0>(); SkASSERT(fi0 < 256); |
| 423 unsigned fi1 = (unsigned)dist.kth<1>(); SkASSERT(fi1 < 256); |
| 424 unsigned fi2 = (unsigned)dist.kth<2>(); SkASSERT(fi2 < 256); |
| 425 unsigned fi3 = (unsigned)dist.kth<3>(); SkASSERT(fi3 < 256); |
| 426 *dstC++ = cache[toggle + fi0]; toggle = next_dither_toggle(toggle); |
| 427 *dstC++ = cache[toggle + fi1]; toggle = next_dither_toggle(toggle); |
| 428 *dstC++ = cache[toggle + fi2]; toggle = next_dither_toggle(toggle); |
| 429 *dstC++ = cache[toggle + fi3]; toggle = next_dither_toggle(toggle); |
| 430 } |
| 431 count &= 3; |
| 432 if (count) { |
| 433 Sk4f dist = Sk4f::Min(fast_sqrt(R), max); |
| 434 unsigned fi[3]; |
| 435 fi[0] = (unsigned)dist.kth<0>(); |
| 436 fi[1] = (unsigned)dist.kth<1>(); |
| 437 fi[2] = (unsigned)dist.kth<2>(); |
| 438 SkASSERT(count <= 3); |
| 439 for (int i = 0; i < count; ++i) { |
| 440 SkASSERT(fi[i] < 256); |
| 441 *dstC++ = cache[toggle + fi[i]]; toggle = next_dither_toggle(tog
gle); |
| 442 } |
| 443 } |
| 444 } |
| 445 } |
| 446 |
| 376 // Unrolling this loop doesn't seem to help (when float); we're stalling to | 447 // Unrolling this loop doesn't seem to help (when float); we're stalling to |
| 377 // get the results of the sqrt (?), and don't have enough extra registers to | 448 // get the results of the sqrt (?), and don't have enough extra registers to |
| 378 // have many in flight. | 449 // have many in flight. |
| 379 template <SkFixed (*TileProc)(SkFixed)> | 450 template <SkFixed (*TileProc)(SkFixed)> |
| 380 void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, | 451 void shadeSpan_radial(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, |
| 381 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT
cache, | 452 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT
cache, |
| 382 int count, int toggle) { | 453 int count, int toggle) { |
| 383 do { | 454 do { |
| 384 const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); | 455 const SkFixed dist = SkFloatToFixed(sk_float_sqrt(fx*fx + fy*fy)); |
| 385 const unsigned fi = TileProc(dist); | 456 const unsigned fi = TileProc(dist); |
| (...skipping 14 matching lines...) Expand all Loading... |
| 400 void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, | 471 void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, |
| 401 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RE
STRICT cache, | 472 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RE
STRICT cache, |
| 402 int count, int toggle) { | 473 int count, int toggle) { |
| 403 shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, cou
nt, toggle); | 474 shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, cou
nt, toggle); |
| 404 } | 475 } |
| 405 | 476 |
| 406 } // namespace | 477 } // namespace |
| 407 | 478 |
| 408 void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, | 479 void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, |
| 409 SkPMColor* SK_RESTRICT d
stC, int count) { | 480 SkPMColor* SK_RESTRICT d
stC, int count) { |
| 481 #ifdef SK_SUPPORT_LEGACY_RADIAL_GRADIENT_SQRT |
| 482 const bool use_new_proc = false; |
| 483 #else |
| 484 const bool use_new_proc = true; |
| 485 #endif |
| 410 SkASSERT(count > 0); | 486 SkASSERT(count > 0); |
| 411 | 487 |
| 412 const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&
>(fShader); | 488 const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&
>(fShader); |
| 413 | 489 |
| 414 SkPoint srcPt; | 490 SkPoint srcPt; |
| 415 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 491 SkMatrix::MapXYProc dstProc = fDstToIndexProc; |
| 416 TileProc proc = radialGradient.fTileProc; | 492 TileProc proc = radialGradient.fTileProc; |
| 417 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); | 493 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); |
| 418 int toggle = init_dither_toggle(x, y); | 494 int toggle = init_dither_toggle(x, y); |
| 419 | 495 |
| 420 if (fDstToIndexClass != kPerspective_MatrixClass) { | 496 if (fDstToIndexClass != kPerspective_MatrixClass) { |
| 421 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | 497 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, |
| 422 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | 498 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
| 423 SkScalar sdx = fDstToIndex.getScaleX(); | 499 SkScalar sdx = fDstToIndex.getScaleX(); |
| 424 SkScalar sdy = fDstToIndex.getSkewY(); | 500 SkScalar sdy = fDstToIndex.getSkewY(); |
| 425 | 501 |
| 426 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | 502 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
| 427 SkFixed storage[2]; | 503 SkFixed storage[2]; |
| 428 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), | 504 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), |
| 429 &storage[0], &storage[1]); | 505 &storage[0], &storage[1]); |
| 430 sdx = SkFixedToScalar(storage[0]); | 506 sdx = SkFixedToScalar(storage[0]); |
| 431 sdy = SkFixedToScalar(storage[1]); | 507 sdy = SkFixedToScalar(storage[1]); |
| 432 } else { | 508 } else { |
| 433 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | 509 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
| 434 } | 510 } |
| 435 | 511 |
| 436 RadialShadeProc shadeProc = shadeSpan_radial_repeat; | 512 RadialShadeProc shadeProc = shadeSpan_radial_repeat; |
| 437 if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { | 513 if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { |
| 438 shadeProc = shadeSpan_radial_clamp; | 514 shadeProc = use_new_proc ? shadeSpan_radial_clamp2 : shadeSpan_radia
l_clamp; |
| 439 } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { | 515 } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { |
| 440 shadeProc = shadeSpan_radial_mirror; | 516 shadeProc = shadeSpan_radial_mirror; |
| 441 } else { | 517 } else { |
| 442 SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); | 518 SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); |
| 443 } | 519 } |
| 444 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); | 520 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); |
| 445 } else { // perspective case | 521 } else { // perspective case |
| 446 SkScalar dstX = SkIntToScalar(x); | 522 SkScalar dstX = SkIntToScalar(x); |
| 447 SkScalar dstY = SkIntToScalar(y); | 523 SkScalar dstY = SkIntToScalar(y); |
| 448 do { | 524 do { |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 615 str->appendScalar(fCenter.fY); | 691 str->appendScalar(fCenter.fY); |
| 616 str->append(") radius: "); | 692 str->append(") radius: "); |
| 617 str->appendScalar(fRadius); | 693 str->appendScalar(fRadius); |
| 618 str->append(" "); | 694 str->append(" "); |
| 619 | 695 |
| 620 this->INHERITED::toString(str); | 696 this->INHERITED::toString(str); |
| 621 | 697 |
| 622 str->append(")"); | 698 str->append(")"); |
| 623 } | 699 } |
| 624 #endif | 700 #endif |
| OLD | NEW |