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 |