| 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" |
| (...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 263 } | 263 } |
| 264 | 264 |
| 265 void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { | 265 void SkRadialGradient::flatten(SkWriteBuffer& buffer) const { |
| 266 this->INHERITED::flatten(buffer); | 266 this->INHERITED::flatten(buffer); |
| 267 buffer.writePoint(fCenter); | 267 buffer.writePoint(fCenter); |
| 268 buffer.writeScalar(fRadius); | 268 buffer.writeScalar(fRadius); |
| 269 } | 269 } |
| 270 | 270 |
| 271 namespace { | 271 namespace { |
| 272 | 272 |
| 273 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 | |
| 275 bool xClamped = (fx >= SK_FixedHalf && dx >= 0) || (fx <= -SK_FixedHalf && d
x <= 0); | |
| 276 bool yClamped = (fy >= SK_FixedHalf && dy >= 0) || (fy <= -SK_FixedHalf && d
y <= 0); | |
| 277 return xClamped || yClamped; | |
| 278 } | |
| 279 | |
| 280 inline bool radial_completely_pinned(SkScalar fx, SkScalar dx, SkScalar fy, SkSc
alar dy) { | 273 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 | 274 // fast, overly-conservative test: checks unit square instead of unit circle |
| 282 bool xClamped = (fx >= 1 && dx >= 0) || (fx <= -1 && dx <= 0); | 275 bool xClamped = (fx >= 1 && dx >= 0) || (fx <= -1 && dx <= 0); |
| 283 bool yClamped = (fy >= 1 && dy >= 0) || (fy <= -1 && dy <= 0); | 276 bool yClamped = (fy >= 1 && dy >= 0) || (fy <= -1 && dy <= 0); |
| 284 return xClamped || yClamped; | 277 return xClamped || yClamped; |
| 285 } | 278 } |
| 286 | 279 |
| 287 // Return true if (fx * fy) is always inside the unit circle | |
| 288 // SkPin32 is expensive, but so are all the SkFixedMul in this test, | |
| 289 // so it shouldn't be run if count is small. | |
| 290 inline bool no_need_for_radial_pin(int fx, int dx, | |
| 291 int fy, int dy, int count) { | |
| 292 SkASSERT(count > 0); | |
| 293 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { | |
| 294 return false; | |
| 295 } | |
| 296 if (fx*fx + fy*fy > 0x7FFF*0x7FFF) { | |
| 297 return false; | |
| 298 } | |
| 299 fx += (count - 1) * dx; | |
| 300 fy += (count - 1) * dy; | |
| 301 if (SkAbs32(fx) > 0x7FFF || SkAbs32(fy) > 0x7FFF) { | |
| 302 return false; | |
| 303 } | |
| 304 return fx*fx + fy*fy <= 0x7FFF*0x7FFF; | |
| 305 } | |
| 306 | |
| 307 #define UNPINNED_RADIAL_STEP \ | |
| 308 fi = (fx * fx + fy * fy) >> (14 + 16 - kSQRT_TABLE_BITS); \ | |
| 309 *dstC++ = cache[toggle + \ | |
| 310 (sqrt_table[fi] >> SkGradientShaderBase::kSqrt32Shift)]; \ | |
| 311 toggle = next_dither_toggle(toggle); \ | |
| 312 fx += dx; \ | |
| 313 fy += dy; | |
| 314 | |
| 315 typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx, | 280 typedef void (* RadialShadeProc)(SkScalar sfx, SkScalar sdx, |
| 316 SkScalar sfy, SkScalar sdy, | 281 SkScalar sfy, SkScalar sdy, |
| 317 SkPMColor* dstC, const SkPMColor* cache, | 282 SkPMColor* dstC, const SkPMColor* cache, |
| 318 int count, int toggle); | 283 int count, int toggle); |
| 319 | 284 |
| 320 // On Linux, this is faster with SkPMColor[] params than SkPMColor* SK_RESTRICT | |
| 321 void shadeSpan_radial_clamp(SkScalar sfx, SkScalar sdx, | |
| 322 SkScalar sfy, SkScalar sdy, | |
| 323 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache, | |
| 324 int count, int toggle) { | |
| 325 // Floating point seems to be slower than fixed point, | |
| 326 // even when we have float hardware. | |
| 327 const uint8_t* SK_RESTRICT sqrt_table = gSqrt8Table; | |
| 328 SkFixed fx = SkScalarToFixed(sfx) >> 1; | |
| 329 SkFixed dx = SkScalarToFixed(sdx) >> 1; | |
| 330 SkFixed fy = SkScalarToFixed(sfy) >> 1; | |
| 331 SkFixed dy = SkScalarToFixed(sdy) >> 1; | |
| 332 if ((count > 4) && radial_completely_pinned(fx, dx, fy, dy)) { | |
| 333 unsigned fi = SkGradientShaderBase::kCache32Count - 1; | |
| 334 sk_memset32_dither(dstC, | |
| 335 cache[toggle + fi], | |
| 336 cache[next_dither_toggle(toggle) + fi], | |
| 337 count); | |
| 338 } else if ((count > 4) && | |
| 339 no_need_for_radial_pin(fx, dx, fy, dy, count)) { | |
| 340 unsigned fi; | |
| 341 // 4x unroll appears to be no faster than 2x unroll on Linux | |
| 342 while (count > 1) { | |
| 343 UNPINNED_RADIAL_STEP; | |
| 344 UNPINNED_RADIAL_STEP; | |
| 345 count -= 2; | |
| 346 } | |
| 347 if (count) { | |
| 348 UNPINNED_RADIAL_STEP; | |
| 349 } | |
| 350 } else { | |
| 351 // Specializing for dy == 0 gains us 25% on Skia benchmarks | |
| 352 if (dy == 0) { | |
| 353 unsigned yy = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); | |
| 354 yy *= yy; | |
| 355 do { | |
| 356 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); | |
| 357 unsigned fi = (xx * xx + yy) >> (14 + 16 - kSQRT_TABLE_BITS); | |
| 358 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); | |
| 359 *dstC++ = cache[toggle + (sqrt_table[fi] >> | |
| 360 SkGradientShaderBase::kSqrt32Shift)]; | |
| 361 toggle = next_dither_toggle(toggle); | |
| 362 fx += dx; | |
| 363 } while (--count != 0); | |
| 364 } else { | |
| 365 do { | |
| 366 unsigned xx = SkPin32(fx, -0xFFFF >> 1, 0xFFFF >> 1); | |
| 367 unsigned fi = SkPin32(fy, -0xFFFF >> 1, 0xFFFF >> 1); | |
| 368 fi = (xx * xx + fi * fi) >> (14 + 16 - kSQRT_TABLE_BITS); | |
| 369 fi = SkFastMin32(fi, 0xFFFF >> (16 - kSQRT_TABLE_BITS)); | |
| 370 *dstC++ = cache[toggle + (sqrt_table[fi] >> | |
| 371 SkGradientShaderBase::kSqrt32Shift)]; | |
| 372 toggle = next_dither_toggle(toggle); | |
| 373 fx += dx; | |
| 374 fy += dy; | |
| 375 } while (--count != 0); | |
| 376 } | |
| 377 } | |
| 378 } | |
| 379 | |
| 380 static inline Sk4f fast_sqrt(const Sk4f& R) { | 285 static inline Sk4f fast_sqrt(const Sk4f& R) { |
| 381 // R * R.rsqrt0() is much faster, but it's non-monotonic, which isn't so pre
tty for gradients. | 286 // R * R.rsqrt0() is much faster, but it's non-monotonic, which isn't so pre
tty for gradients. |
| 382 return R * R.rsqrt1(); | 287 return R * R.rsqrt1(); |
| 383 } | 288 } |
| 384 | 289 |
| 385 static inline Sk4f sum_squares(const Sk4f& a, const Sk4f& b) { | 290 static inline Sk4f sum_squares(const Sk4f& a, const Sk4f& b) { |
| 386 return a * a + b * b; | 291 return a * a + b * b; |
| 387 } | 292 } |
| 388 | 293 |
| 389 void shadeSpan_radial_clamp2(SkScalar sfx, SkScalar sdx, SkScalar sfy, SkScalar
sdy, | 294 void shadeSpan_radial_clamp2(SkScalar sfx, SkScalar sdx, SkScalar sfy, SkScalar
sdy, |
| (...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 467 void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, | 372 void shadeSpan_radial_repeat(SkScalar fx, SkScalar dx, SkScalar fy, SkScalar dy, |
| 468 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RE
STRICT cache, | 373 SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RE
STRICT cache, |
| 469 int count, int toggle) { | 374 int count, int toggle) { |
| 470 shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, cou
nt, toggle); | 375 shadeSpan_radial<repeat_tileproc_nonstatic>(fx, dx, fy, dy, dstC, cache, cou
nt, toggle); |
| 471 } | 376 } |
| 472 | 377 |
| 473 } // namespace | 378 } // namespace |
| 474 | 379 |
| 475 void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, | 380 void SkRadialGradient::RadialGradientContext::shadeSpan(int x, int y, |
| 476 SkPMColor* SK_RESTRICT d
stC, int count) { | 381 SkPMColor* SK_RESTRICT d
stC, int count) { |
| 477 #ifdef SK_SUPPORT_LEGACY_RADIAL_GRADIENT_SQRT | |
| 478 const bool use_new_proc = false; | |
| 479 #else | |
| 480 const bool use_new_proc = true; | |
| 481 #endif | |
| 482 SkASSERT(count > 0); | 382 SkASSERT(count > 0); |
| 483 | 383 |
| 484 const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&
>(fShader); | 384 const SkRadialGradient& radialGradient = static_cast<const SkRadialGradient&
>(fShader); |
| 485 | 385 |
| 486 SkPoint srcPt; | 386 SkPoint srcPt; |
| 487 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | 387 SkMatrix::MapXYProc dstProc = fDstToIndexProc; |
| 488 TileProc proc = radialGradient.fTileProc; | 388 TileProc proc = radialGradient.fTileProc; |
| 489 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); | 389 const SkPMColor* SK_RESTRICT cache = fCache->getCache32(); |
| 490 int toggle = init_dither_toggle(x, y); | 390 int toggle = init_dither_toggle(x, y); |
| 491 | 391 |
| 492 if (fDstToIndexClass != kPerspective_MatrixClass) { | 392 if (fDstToIndexClass != kPerspective_MatrixClass) { |
| 493 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | 393 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, |
| 494 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | 394 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); |
| 495 SkScalar sdx = fDstToIndex.getScaleX(); | 395 SkScalar sdx = fDstToIndex.getScaleX(); |
| 496 SkScalar sdy = fDstToIndex.getSkewY(); | 396 SkScalar sdy = fDstToIndex.getSkewY(); |
| 497 | 397 |
| 498 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | 398 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { |
| 499 SkFixed storage[2]; | 399 SkFixed storage[2]; |
| 500 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), | 400 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), |
| 501 &storage[0], &storage[1]); | 401 &storage[0], &storage[1]); |
| 502 sdx = SkFixedToScalar(storage[0]); | 402 sdx = SkFixedToScalar(storage[0]); |
| 503 sdy = SkFixedToScalar(storage[1]); | 403 sdy = SkFixedToScalar(storage[1]); |
| 504 } else { | 404 } else { |
| 505 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | 405 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); |
| 506 } | 406 } |
| 507 | 407 |
| 508 RadialShadeProc shadeProc = shadeSpan_radial_repeat; | 408 RadialShadeProc shadeProc = shadeSpan_radial_repeat; |
| 509 if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { | 409 if (SkShader::kClamp_TileMode == radialGradient.fTileMode) { |
| 510 shadeProc = use_new_proc ? shadeSpan_radial_clamp2 : shadeSpan_radia
l_clamp; | 410 shadeProc = shadeSpan_radial_clamp2; |
| 511 } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { | 411 } else if (SkShader::kMirror_TileMode == radialGradient.fTileMode) { |
| 512 shadeProc = shadeSpan_radial_mirror; | 412 shadeProc = shadeSpan_radial_mirror; |
| 513 } else { | 413 } else { |
| 514 SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); | 414 SkASSERT(SkShader::kRepeat_TileMode == radialGradient.fTileMode); |
| 515 } | 415 } |
| 516 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); | 416 (*shadeProc)(srcPt.fX, sdx, srcPt.fY, sdy, dstC, cache, count, toggle); |
| 517 } else { // perspective case | 417 } else { // perspective case |
| 518 SkScalar dstX = SkIntToScalar(x); | 418 SkScalar dstX = SkIntToScalar(x); |
| 519 SkScalar dstY = SkIntToScalar(y); | 419 SkScalar dstY = SkIntToScalar(y); |
| 520 do { | 420 do { |
| (...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 687 str->appendScalar(fCenter.fY); | 587 str->appendScalar(fCenter.fY); |
| 688 str->append(") radius: "); | 588 str->append(") radius: "); |
| 689 str->appendScalar(fRadius); | 589 str->appendScalar(fRadius); |
| 690 str->append(" "); | 590 str->append(" "); |
| 691 | 591 |
| 692 this->INHERITED::toString(str); | 592 this->INHERITED::toString(str); |
| 693 | 593 |
| 694 str->append(")"); | 594 str->append(")"); |
| 695 } | 595 } |
| 696 #endif | 596 #endif |
| OLD | NEW |