| 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 |