OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 | 7 |
8 #include "SkLinearGradient.h" | 8 #include "SkLinearGradient.h" |
9 | 9 |
10 static const float kInv255Float = 1.0f / 255; | 10 static const float kInv255Float = 1.0f / 255; |
11 | 11 |
12 static inline int repeat_bits(int x, const int bits) { | |
13 return x & ((1 << bits) - 1); | |
14 } | |
15 | |
16 static inline int repeat_8bits(int x) { | 12 static inline int repeat_8bits(int x) { |
17 return x & 0xFF; | 13 return x & 0xFF; |
18 } | 14 } |
19 | 15 |
20 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. | 16 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly. |
21 // See http://code.google.com/p/skia/issues/detail?id=472 | 17 // See http://code.google.com/p/skia/issues/detail?id=472 |
22 #if defined(_MSC_VER) && (_MSC_VER >= 1600) | 18 #if defined(_MSC_VER) && (_MSC_VER >= 1600) |
23 #pragma optimize("", off) | 19 #pragma optimize("", off) |
24 #endif | 20 #endif |
25 | 21 |
26 static inline int mirror_bits(int x, const int bits) { | |
27 if (x & (1 << bits)) { | |
28 x = ~x; | |
29 } | |
30 return x & ((1 << bits) - 1); | |
31 } | |
32 | |
33 static inline int mirror_8bits(int x) { | 22 static inline int mirror_8bits(int x) { |
34 if (x & 256) { | 23 if (x & 256) { |
35 x = ~x; | 24 x = ~x; |
36 } | 25 } |
37 return x & 255; | 26 return x & 255; |
38 } | 27 } |
39 | 28 |
40 #if defined(_MSC_VER) && (_MSC_VER >= 1600) | 29 #if defined(_MSC_VER) && (_MSC_VER >= 1600) |
41 #pragma optimize("", on) | 30 #pragma optimize("", on) |
42 #endif | 31 #endif |
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
95 // SkPMColor from the floats, without having to swizzle each time. | 84 // SkPMColor from the floats, without having to swizzle each time. |
96 // | 85 // |
97 static uint32_t SkSwizzle_Color_to_PMColor(SkColor c) { | 86 static uint32_t SkSwizzle_Color_to_PMColor(SkColor c) { |
98 return SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), S
kColorGetB(c)); | 87 return SkPackARGB32NoCheck(SkColorGetA(c), SkColorGetR(c), SkColorGetG(c), S
kColorGetB(c)); |
99 } | 88 } |
100 | 89 |
101 SkLinearGradient::LinearGradientContext::LinearGradientContext( | 90 SkLinearGradient::LinearGradientContext::LinearGradientContext( |
102 const SkLinearGradient& shader, const ContextRec& ctx) | 91 const SkLinearGradient& shader, const ContextRec& ctx) |
103 : INHERITED(shader, ctx) | 92 : INHERITED(shader, ctx) |
104 { | 93 { |
105 unsigned mask = SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask; | |
106 if ((fDstToIndex.getType() & ~mask) == 0) { | |
107 // when we dither, we are (usually) not const-in-Y | |
108 if ((fFlags & SkShader::kHasSpan16_Flag) && !ctx.fPaint->isDither()) { | |
109 // only claim this if we do have a 16bit mode (i.e. none of our | |
110 // colors have alpha), and if we are not dithering (which obviously | |
111 // is not const in Y). | |
112 fFlags |= SkShader::kConstInY16_Flag; | |
113 } | |
114 } | |
115 | |
116 // setup for Sk4f | 94 // setup for Sk4f |
117 int count = shader.fColorCount; | 95 int count = shader.fColorCount; |
118 fRecs.setCount(count); | 96 fRecs.setCount(count); |
119 Rec* rec = fRecs.begin(); | 97 Rec* rec = fRecs.begin(); |
120 if (shader.fOrigPos) { | 98 if (shader.fOrigPos) { |
121 rec[0].fPos = 0; | 99 rec[0].fPos = 0; |
122 SkDEBUGCODE(rec[0].fPosScale = SK_FloatNaN;) // should never get used | 100 SkDEBUGCODE(rec[0].fPosScale = SK_FloatNaN;) // should never get used |
123 for (int i = 1; i < count; ++i) { | 101 for (int i = 1; i < count; ++i) { |
124 rec[i].fPos = SkTPin(shader.fOrigPos[i], rec[i - 1].fPos, 1.0f); | 102 rec[i].fPos = SkTPin(shader.fOrigPos[i], rec[i - 1].fPos, 1.0f); |
125 rec[i].fPosScale = 1.0f / (rec[i].fPos - rec[i - 1].fPos); | 103 rec[i].fPosScale = 1.0f / (rec[i].fPos - rec[i - 1].fPos); |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
340 | 318 |
341 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { | 319 SkShader::GradientType SkLinearGradient::asAGradient(GradientInfo* info) const { |
342 if (info) { | 320 if (info) { |
343 commonAsAGradient(info); | 321 commonAsAGradient(info); |
344 info->fPoint[0] = fStart; | 322 info->fPoint[0] = fStart; |
345 info->fPoint[1] = fEnd; | 323 info->fPoint[1] = fEnd; |
346 } | 324 } |
347 return kLinear_GradientType; | 325 return kLinear_GradientType; |
348 } | 326 } |
349 | 327 |
350 static void dither_memset16(uint16_t dst[], uint16_t value, uint16_t other, | |
351 int count) { | |
352 if (reinterpret_cast<uintptr_t>(dst) & 2) { | |
353 *dst++ = value; | |
354 count -= 1; | |
355 SkTSwap(value, other); | |
356 } | |
357 | |
358 sk_memset32((uint32_t*)dst, (value << 16) | other, count >> 1); | |
359 | |
360 if (count & 1) { | |
361 dst[count - 1] = value; | |
362 } | |
363 } | |
364 | |
365 #define NO_CHECK_ITER_16 \ | |
366 do { \ | |
367 unsigned fi = SkGradFixedToFixed(fx) >> SkGradientShaderBase::kCache16Shift;
\ | |
368 SkASSERT(fi < SkGradientShaderBase::kCache16Count); \ | |
369 fx += dx; \ | |
370 *dstC++ = cache[toggle + fi]; \ | |
371 toggle = next_dither_toggle16(toggle); \ | |
372 } while (0) | |
373 | |
374 namespace { | |
375 | |
376 typedef void (*LinearShade16Proc)(TileProc proc, SkGradFixed dx, SkGradFixed fx, | |
377 uint16_t* dstC, const uint16_t* cache, | |
378 int toggle, int count); | |
379 | |
380 void shadeSpan16_linear_vertical(TileProc proc, SkGradFixed dx, SkGradFixed fx, | |
381 uint16_t* SK_RESTRICT dstC, | |
382 const uint16_t* SK_RESTRICT cache, | |
383 int toggle, int count) { | |
384 // we're a vertical gradient, so no change in a span | |
385 unsigned fi = proc(SkGradFixedToFixed(fx)) >> SkGradientShaderBase::kCache16
Shift; | |
386 SkASSERT(fi < SkGradientShaderBase::kCache16Count); | |
387 dither_memset16(dstC, cache[toggle + fi], | |
388 cache[next_dither_toggle16(toggle) + fi], count); | |
389 } | |
390 | |
391 void shadeSpan16_linear_clamp(TileProc proc, SkGradFixed dx, SkGradFixed fx, | |
392 uint16_t* SK_RESTRICT dstC, | |
393 const uint16_t* SK_RESTRICT cache, | |
394 int toggle, int count) { | |
395 SkClampRange range; | |
396 range.init(fx, dx, count, 0, SkGradientShaderBase::kCache32Count - 1); | |
397 range.validate(count); | |
398 | |
399 if ((count = range.fCount0) > 0) { | |
400 dither_memset16(dstC, | |
401 cache[toggle + range.fV0], | |
402 cache[next_dither_toggle16(toggle) + range.fV0], | |
403 count); | |
404 dstC += count; | |
405 } | |
406 if ((count = range.fCount1) > 0) { | |
407 int unroll = count >> 3; | |
408 fx = range.fFx1; | |
409 for (int i = 0; i < unroll; i++) { | |
410 NO_CHECK_ITER_16; NO_CHECK_ITER_16; | |
411 NO_CHECK_ITER_16; NO_CHECK_ITER_16; | |
412 NO_CHECK_ITER_16; NO_CHECK_ITER_16; | |
413 NO_CHECK_ITER_16; NO_CHECK_ITER_16; | |
414 } | |
415 if ((count &= 7) > 0) { | |
416 do { | |
417 NO_CHECK_ITER_16; | |
418 } while (--count != 0); | |
419 } | |
420 } | |
421 if ((count = range.fCount2) > 0) { | |
422 dither_memset16(dstC, | |
423 cache[toggle + range.fV1], | |
424 cache[next_dither_toggle16(toggle) + range.fV1], | |
425 count); | |
426 } | |
427 } | |
428 | |
429 void shadeSpan16_linear_mirror(TileProc proc, SkGradFixed dx, SkGradFixed fx, | |
430 uint16_t* SK_RESTRICT dstC, | |
431 const uint16_t* SK_RESTRICT cache, | |
432 int toggle, int count) { | |
433 do { | |
434 unsigned fi = mirror_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase
::kCache16Shift, | |
435 SkGradientShaderBase::kCache16Bits); | |
436 SkASSERT(fi < SkGradientShaderBase::kCache16Count); | |
437 fx += dx; | |
438 *dstC++ = cache[toggle + fi]; | |
439 toggle = next_dither_toggle16(toggle); | |
440 } while (--count != 0); | |
441 } | |
442 | |
443 void shadeSpan16_linear_repeat(TileProc proc, SkGradFixed dx, SkGradFixed fx, | |
444 uint16_t* SK_RESTRICT dstC, | |
445 const uint16_t* SK_RESTRICT cache, | |
446 int toggle, int count) { | |
447 do { | |
448 unsigned fi = repeat_bits(SkGradFixedToFixed(fx) >> SkGradientShaderBase
::kCache16Shift, | |
449 SkGradientShaderBase::kCache16Bits); | |
450 SkASSERT(fi < SkGradientShaderBase::kCache16Count); | |
451 fx += dx; | |
452 *dstC++ = cache[toggle + fi]; | |
453 toggle = next_dither_toggle16(toggle); | |
454 } while (--count != 0); | |
455 } | |
456 } | |
457 | |
458 static bool fixed_nearly_zero(SkFixed x) { | |
459 return SkAbs32(x) < (SK_Fixed1 >> 12); | |
460 } | |
461 | |
462 void SkLinearGradient::LinearGradientContext::shadeSpan16(int x, int y, | |
463 uint16_t* SK_RESTRICT
dstC, int count) { | |
464 SkASSERT(count > 0); | |
465 | |
466 const SkLinearGradient& linearGradient = static_cast<const SkLinearGradient&
>(fShader); | |
467 | |
468 SkPoint srcPt; | |
469 SkMatrix::MapXYProc dstProc = fDstToIndexProc; | |
470 TileProc proc = linearGradient.fTileProc; | |
471 const uint16_t* SK_RESTRICT cache = fCache->getCache16(); | |
472 int toggle = init_dither_toggle16(x, y); | |
473 | |
474 if (fDstToIndexClass != kPerspective_MatrixClass) { | |
475 dstProc(fDstToIndex, SkIntToScalar(x) + SK_ScalarHalf, | |
476 SkIntToScalar(y) + SK_ScalarHalf, &srcPt); | |
477 SkGradFixed dx, fx = SkScalarToGradFixed(srcPt.fX); | |
478 | |
479 if (fDstToIndexClass == kFixedStepInX_MatrixClass) { | |
480 SkFixed dxStorage[1]; | |
481 (void)fDstToIndex.fixedStepInX(SkIntToScalar(y), dxStorage, nullptr)
; | |
482 // todo: do we need a real/high-precision value for dx here? | |
483 dx = SkFixedToGradFixed(dxStorage[0]); | |
484 } else { | |
485 SkASSERT(fDstToIndexClass == kLinear_MatrixClass); | |
486 dx = SkScalarToGradFixed(fDstToIndex.getScaleX()); | |
487 } | |
488 | |
489 LinearShade16Proc shadeProc = shadeSpan16_linear_repeat; | |
490 if (fixed_nearly_zero(SkGradFixedToFixed(dx))) { | |
491 shadeProc = shadeSpan16_linear_vertical; | |
492 } else if (SkShader::kClamp_TileMode == linearGradient.fTileMode) { | |
493 shadeProc = shadeSpan16_linear_clamp; | |
494 } else if (SkShader::kMirror_TileMode == linearGradient.fTileMode) { | |
495 shadeProc = shadeSpan16_linear_mirror; | |
496 } else { | |
497 SkASSERT(SkShader::kRepeat_TileMode == linearGradient.fTileMode); | |
498 } | |
499 (*shadeProc)(proc, dx, fx, dstC, cache, toggle, count); | |
500 } else { | |
501 SkScalar dstX = SkIntToScalar(x); | |
502 SkScalar dstY = SkIntToScalar(y); | |
503 do { | |
504 dstProc(fDstToIndex, dstX, dstY, &srcPt); | |
505 unsigned fi = proc(SkScalarToFixed(srcPt.fX)); | |
506 SkASSERT(fi <= 0xFFFF); | |
507 | |
508 int index = fi >> kCache16Shift; | |
509 *dstC++ = cache[toggle + index]; | |
510 toggle = next_dither_toggle16(toggle); | |
511 | |
512 dstX += SK_Scalar1; | |
513 } while (--count != 0); | |
514 } | |
515 } | |
516 | |
517 #if SK_SUPPORT_GPU | 328 #if SK_SUPPORT_GPU |
518 | 329 |
519 #include "glsl/GrGLSLCaps.h" | 330 #include "glsl/GrGLSLCaps.h" |
520 #include "glsl/GrGLSLFragmentShaderBuilder.h" | 331 #include "glsl/GrGLSLFragmentShaderBuilder.h" |
521 #include "SkGr.h" | 332 #include "SkGr.h" |
522 | 333 |
523 ///////////////////////////////////////////////////////////////////// | 334 ///////////////////////////////////////////////////////////////////// |
524 | 335 |
525 class GrGLLinearGradient : public GrGLGradientEffect { | 336 class GrGLLinearGradient : public GrGLGradientEffect { |
526 public: | 337 public: |
(...skipping 395 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
922 } | 733 } |
923 } else { | 734 } else { |
924 if (fApplyAlphaAfterInterp) { | 735 if (fApplyAlphaAfterInterp) { |
925 this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dithe
r); | 736 this->shade4_dx_clamp<true, false>(dstC, count, fx, dx, invDx, dithe
r); |
926 } else { | 737 } else { |
927 this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dith
er); | 738 this->shade4_dx_clamp<false, false>(dstC, count, fx, dx, invDx, dith
er); |
928 } | 739 } |
929 } | 740 } |
930 } | 741 } |
931 | 742 |
OLD | NEW |