Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(308)

Side by Side Diff: src/effects/gradients/SkRadialGradient.cpp

Issue 1072303005: use Sk4f to increase radial gradient precision but same or better speed Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « gm/gradients.cpp ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « gm/gradients.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698