Bug 777614 - Re-apply bug 687188 - Expand the gradient cache by 2 to store 0/1 colour stop values for clamping. r=nrc
authorGeorge Wright <gw@gwright.org.uk>
Wed, 12 Sep 2012 12:30:29 -0400
changeset 107522 6ab27e89e7e8e463a060b6cf2e2eee8afcb2b26d
parent 107521 3ddbacc47f234a5e665d8380aaadf0b8cbf35fbc
child 107523 73adb13034a8494c0cff7ac391221f460654fb8d
push id82
push usershu@rfrn.org
push dateFri, 05 Oct 2012 13:20:22 +0000
reviewersnrc
bugs777614, 687188
milestone18.0a1
Bug 777614 - Re-apply bug 687188 - Expand the gradient cache by 2 to store 0/1 colour stop values for clamping. r=nrc
gfx/skia/src/effects/gradients/SkGradientShader.cpp
gfx/skia/src/effects/gradients/SkGradientShaderPriv.h
gfx/skia/src/effects/gradients/SkLinearGradient.cpp
gfx/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp
gfx/skia/src/effects/gradients/SkTwoPointRadialGradient.cpp
--- a/gfx/skia/src/effects/gradients/SkGradientShader.cpp
+++ b/gfx/skia/src/effects/gradients/SkGradientShader.cpp
@@ -421,25 +421,25 @@ const uint16_t* SkGradientShaderBase::ge
 */
 static void complete_32bit_cache(SkPMColor* cache, int stride) {
     cache[stride - 1] = cache[stride - 2];
     cache[2 * stride - 1] = cache[2 * stride - 2];
 }
 
 const SkPMColor* SkGradientShaderBase::getCache32() const {
     if (fCache32 == NULL) {
-        // double the count for dither entries
-        const int entryCount = kCache32Count * 2;
+        // double the count for dither entries, and have an extra two entries for clamp values
+        const int entryCount = kCache32Count * 2 + 2;
         const size_t allocSize = sizeof(SkPMColor) * entryCount;
 
         if (NULL == fCache32PixelRef) {
             fCache32PixelRef = SkNEW_ARGS(SkMallocPixelRef,
                                           (NULL, allocSize, NULL));
         }
-        fCache32 = (SkPMColor*)fCache32PixelRef->getAddr();
+        fCache32 = (SkPMColor*)fCache32PixelRef->getAddr() + 1;
         if (fColorCount == 2) {
             Build32bitCache(fCache32, fOrigColors[0], fOrigColors[1],
                             kGradient32Length, fCacheAlpha);
         } else {
             Rec* rec = fRecs;
             int prevIndex = 0;
             for (int i = 1; i < fColorCount; i++) {
                 int nextIndex = SkFixedToFFFF(rec[i].fPos) >> kCache32Shift;
@@ -453,29 +453,41 @@ const SkPMColor* SkGradientShaderBase::g
             }
             SkASSERT(prevIndex == kGradient32Length - 1);
         }
 
         if (fMapper) {
             SkMallocPixelRef* newPR = SkNEW_ARGS(SkMallocPixelRef,
                                                  (NULL, allocSize, NULL));
             SkPMColor* linear = fCache32;           // just computed linear data
-            SkPMColor* mapped = (SkPMColor*)newPR->getAddr();    // storage for mapped data
+            SkPMColor* mapped = (SkPMColor*)newPR->getAddr() + 1;    // storage for mapped data
             SkUnitMapper* map = fMapper;
             for (int i = 0; i < kGradient32Length; i++) {
                 int index = map->mapUnit16((i << 8) | i) >> 8;
                 mapped[i] = linear[index];
                 mapped[i + kCache32Count] = linear[index + kCache32Count];
             }
             fCache32PixelRef->unref();
             fCache32PixelRef = newPR;
-            fCache32 = (SkPMColor*)newPR->getAddr();
+            fCache32 = (SkPMColor*)newPR->getAddr() + 1;
         }
         complete_32bit_cache(fCache32, kCache32Count);
     }
+
+    // Write the clamp colours into the first and last entries of fCache32
+    fCache32[kCache32ClampLower] = SkPackARGB32(fCacheAlpha,
+                                                SkColorGetR(fOrigColors[0]),
+                                                SkColorGetG(fOrigColors[0]),
+                                                SkColorGetB(fOrigColors[0]));
+
+    fCache32[kCache32ClampUpper] = SkPackARGB32(fCacheAlpha,
+                                                SkColorGetR(fOrigColors[fColorCount - 1]),
+                                                SkColorGetG(fOrigColors[fColorCount - 1]),
+                                                SkColorGetB(fOrigColors[fColorCount - 1]));
+
     return fCache32;
 }
 
 /*
  *  Because our caller might rebuild the same (logically the same) gradient
  *  over and over, we'd like to return exactly the same "bitmap" if possible,
  *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
  *  To do that, we maintain a private cache of built-bitmaps, based on our
--- a/gfx/skia/src/effects/gradients/SkGradientShaderPriv.h
+++ b/gfx/skia/src/effects/gradients/SkGradientShaderPriv.h
@@ -128,17 +128,20 @@ public:
         /// This value is used to *read* the dither cache; it may be 0
         /// if dithering is disabled.
 #ifdef USE_DITHER_32BIT_GRADIENT
         kDitherStride32 = kCache32Count,
 #else
         kDitherStride32 = 0,
 #endif
         kDitherStride16 = kCache16Count,
-        kLerpRemainderMask32 = (1 << (16 - kCache32Bits)) - 1
+        kLerpRemainderMask32 = (1 << (16 - kCache32Bits)) - 1,
+
+        kCache32ClampLower = -1,
+        kCache32ClampUpper = kCache32Count * 2
     };
 
 
 protected:
     SkGradientShaderBase(SkFlattenableReadBuffer& );
     virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
 
     SkUnitMapper* fMapper;
--- a/gfx/skia/src/effects/gradients/SkLinearGradient.cpp
+++ b/gfx/skia/src/effects/gradients/SkLinearGradient.cpp
@@ -121,16 +121,27 @@ typedef void (*LinearShadeProc)(TileProc
                                 int toggle, int count);
 
 // This function is deprecated, and will be replaced by
 // shadeSpan_linear_vertical_lerp() once Chrome has been weaned off of it.
 void shadeSpan_linear_vertical(TileProc proc, SkFixed dx, SkFixed fx,
                                SkPMColor* SK_RESTRICT dstC,
                                const SkPMColor* SK_RESTRICT cache,
                                int toggle, int count) {
+    if (proc == clamp_tileproc) {
+        // No need to lerp or dither for clamp values
+        if (fx < 0) {
+            sk_memset32(dstC, cache[SkGradientShaderBase::kCache32ClampLower], count);
+            return;
+        } else if (fx > 0xffff) {
+            sk_memset32(dstC, cache[SkGradientShaderBase::kCache32ClampUpper], count);
+            return;
+        }
+    }
+
     // We're a vertical gradient, so no change in a span.
     // If colors change sharply across the gradient, dithering is
     // insufficient (it subsamples the color space) and we need to lerp.
     unsigned fullIndex = proc(fx);
     unsigned fi = fullIndex >> (16 - SkGradientShaderBase::kCache32Bits);
     sk_memset32_dither(dstC,
             cache[toggle + fi],
             cache[(toggle ^ SkGradientShaderBase::kDitherStride32) + fi],
@@ -139,16 +150,27 @@ void shadeSpan_linear_vertical(TileProc 
 
 // Linear interpolation (lerp) is unnecessary if there are no sharp
 // discontinuities in the gradient - which must be true if there are
 // only 2 colors - but it's cheap.
 void shadeSpan_linear_vertical_lerp(TileProc proc, SkFixed dx, SkFixed fx,
                                     SkPMColor* SK_RESTRICT dstC,
                                     const SkPMColor* SK_RESTRICT cache,
                                     int toggle, int count) {
+    if (proc == clamp_tileproc) {
+        // No need to lerp or dither for clamp values
+        if (fx < 0) {
+            sk_memset32(dstC, cache[SkGradientShaderBase::kCache32ClampLower], count);
+            return;
+        } else if (fx > 0xffff) {
+            sk_memset32(dstC, cache[SkGradientShaderBase::kCache32ClampUpper], count);
+            return;
+        }
+    }
+
     // We're a vertical gradient, so no change in a span.
     // If colors change sharply across the gradient, dithering is
     // insufficient (it subsamples the color space) and we need to lerp.
     unsigned fullIndex = proc(fx);
     unsigned fi = fullIndex >> (16 - SkGradientShaderBase::kCache32Bits);
     unsigned remainder = fullIndex & SkGradientShaderBase::kLerpRemainderMask32;
     SkPMColor lerp =
         SkFastFourByteInterp(
@@ -164,20 +186,17 @@ void shadeSpan_linear_vertical_lerp(Tile
 void shadeSpan_linear_clamp(TileProc proc, SkFixed dx, SkFixed fx,
                             SkPMColor* SK_RESTRICT dstC,
                             const SkPMColor* SK_RESTRICT cache,
                             int toggle, int count) {
     SkClampRange range;
     range.init(fx, dx, count, 0, SkGradientShaderBase::kGradient32Length);
 
     if ((count = range.fCount0) > 0) {
-        sk_memset32_dither(dstC,
-            cache[toggle + range.fV0],
-            cache[(toggle ^ SkGradientShaderBase::kDitherStride32) + range.fV0],
-            count);
+        sk_memset32(dstC, cache[SkGradientShaderBase::kCache32ClampLower], count);
         dstC += count;
     }
     if ((count = range.fCount1) > 0) {
         int unroll = count >> 3;
         fx = range.fFx1;
         for (int i = 0; i < unroll; i++) {
             NO_CHECK_ITER;  NO_CHECK_ITER;
             NO_CHECK_ITER;  NO_CHECK_ITER;
@@ -186,20 +205,17 @@ void shadeSpan_linear_clamp(TileProc pro
         }
         if ((count &= 7) > 0) {
             do {
                 NO_CHECK_ITER;
             } while (--count != 0);
         }
     }
     if ((count = range.fCount2) > 0) {
-        sk_memset32_dither(dstC,
-            cache[toggle + range.fV1],
-            cache[(toggle ^ SkGradientShaderBase::kDitherStride32) + range.fV1],
-            count);
+        sk_memset32(dstC, cache[SkGradientShaderBase::kCache32ClampUpper], count);
     }
 }
 
 void shadeSpan_linear_mirror(TileProc proc, SkFixed dx, SkFixed fx,
                              SkPMColor* SK_RESTRICT dstC,
                              const SkPMColor* SK_RESTRICT cache,
                              int toggle, int count) {
     do {
--- a/gfx/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp
+++ b/gfx/skia/src/effects/gradients/SkTwoPointConicalGradient.cpp
@@ -118,19 +118,24 @@ typedef void (*TwoPointRadialProc)(TwoPt
 
 static void twopoint_clamp(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
                            const SkPMColor* SK_RESTRICT cache, int count) {
     for (; count > 0; --count) {
         SkFixed t = rec->nextT();
         if (TwoPtRadial::DontDrawT(t)) {
             *dstC++ = 0;
         } else {
-            SkFixed index = SkClampMax(t, 0xFFFF);
-            SkASSERT(index <= 0xFFFF);
-            *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
+            if (t < 0) {
+                *dstC++ = cache[SkGradientShaderBase::kCache32ClampLower];
+            } else if (t > 0xFFFF) {
+                *dstC++ = cache[SkGradientShaderBase::kCache32ClampUpper];
+            } else {
+                SkASSERT(t <= 0xFFFF);
+                *dstC++ = cache[t >> SkGradientShaderBase::kCache32Shift];
+            }
         }
     }
 }
 
 static void twopoint_repeat(TwoPtRadial* rec, SkPMColor* SK_RESTRICT dstC,
                             const SkPMColor* SK_RESTRICT cache, int count) {
     for (; count > 0; --count) {
         SkFixed t = rec->nextT();
--- a/gfx/skia/src/effects/gradients/SkTwoPointRadialGradient.cpp
+++ b/gfx/skia/src/effects/gradients/SkTwoPointRadialGradient.cpp
@@ -115,19 +115,24 @@ void shadeSpan_twopoint_clamp(SkScalar f
         SkScalar fy, SkScalar dy,
         SkScalar b, SkScalar db,
         SkScalar fSr2D2, SkScalar foura, SkScalar fOneOverTwoA, bool posRoot,
         SkPMColor* SK_RESTRICT dstC, const SkPMColor* SK_RESTRICT cache,
         int count) {
     for (; count > 0; --count) {
         SkFixed t = two_point_radial(b, fx, fy, fSr2D2, foura,
                                      fOneOverTwoA, posRoot);
-        SkFixed index = SkClampMax(t, 0xFFFF);
-        SkASSERT(index <= 0xFFFF);
-        *dstC++ = cache[index >> SkGradientShaderBase::kCache32Shift];
+        if (t < 0) {
+            *dstC++ = cache[SkGradientShaderBase::kCache32ClampLower];
+        } else if (t > 0xFFFF) {
+            *dstC++ = cache[SkGradientShaderBase::kCache32ClampUpper];
+        } else {
+            SkASSERT(t <= 0xFFFF);
+            *dstC++ = cache[t >> SkGradientShaderBase::kCache32Shift];
+        }
         fx += dx;
         fy += dy;
         b += db;
     }
 }
 void shadeSpan_twopoint_mirror(SkScalar fx, SkScalar dx,
         SkScalar fy, SkScalar dy,
         SkScalar b, SkScalar db,