Home | History | Annotate | Download | only in gradients
      1 /*
      2  * Copyright 2006 The Android Open Source Project
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include <algorithm>
      9 #include "Sk4fLinearGradient.h"
     10 #include "SkColorSpace_XYZ.h"
     11 #include "SkColorSpaceXformer.h"
     12 #include "SkFloatBits.h"
     13 #include "SkGradientBitmapCache.h"
     14 #include "SkGradientShaderPriv.h"
     15 #include "SkHalf.h"
     16 #include "SkLinearGradient.h"
     17 #include "SkMallocPixelRef.h"
     18 #include "SkRadialGradient.h"
     19 #include "SkReadBuffer.h"
     20 #include "SkSweepGradient.h"
     21 #include "SkTwoPointConicalGradient.h"
     22 #include "SkWriteBuffer.h"
     23 #include "../../jumper/SkJumper.h"
     24 
     25 
     26 enum GradientSerializationFlags {
     27     // Bits 29:31 used for various boolean flags
     28     kHasPosition_GSF    = 0x80000000,
     29     kHasLocalMatrix_GSF = 0x40000000,
     30     kHasColorSpace_GSF  = 0x20000000,
     31 
     32     // Bits 12:28 unused
     33 
     34     // Bits 8:11 for fTileMode
     35     kTileModeShift_GSF  = 8,
     36     kTileModeMask_GSF   = 0xF,
     37 
     38     // Bits 0:7 for fGradFlags (note that kForce4fContext_PrivateFlag is 0x80)
     39     kGradFlagsShift_GSF = 0,
     40     kGradFlagsMask_GSF  = 0xFF,
     41 };
     42 
     43 void SkGradientShaderBase::Descriptor::flatten(SkWriteBuffer& buffer) const {
     44     uint32_t flags = 0;
     45     if (fPos) {
     46         flags |= kHasPosition_GSF;
     47     }
     48     if (fLocalMatrix) {
     49         flags |= kHasLocalMatrix_GSF;
     50     }
     51     sk_sp<SkData> colorSpaceData = fColorSpace ? fColorSpace->serialize() : nullptr;
     52     if (colorSpaceData) {
     53         flags |= kHasColorSpace_GSF;
     54     }
     55     SkASSERT(static_cast<uint32_t>(fTileMode) <= kTileModeMask_GSF);
     56     flags |= (fTileMode << kTileModeShift_GSF);
     57     SkASSERT(fGradFlags <= kGradFlagsMask_GSF);
     58     flags |= (fGradFlags << kGradFlagsShift_GSF);
     59 
     60     buffer.writeUInt(flags);
     61 
     62     buffer.writeColor4fArray(fColors, fCount);
     63     if (colorSpaceData) {
     64         buffer.writeDataAsByteArray(colorSpaceData.get());
     65     }
     66     if (fPos) {
     67         buffer.writeScalarArray(fPos, fCount);
     68     }
     69     if (fLocalMatrix) {
     70         buffer.writeMatrix(*fLocalMatrix);
     71     }
     72 }
     73 
     74 bool SkGradientShaderBase::DescriptorScope::unflatten(SkReadBuffer& buffer) {
     75     // New gradient format. Includes floating point color, color space, densely packed flags
     76     uint32_t flags = buffer.readUInt();
     77 
     78     fTileMode = (SkShader::TileMode)((flags >> kTileModeShift_GSF) & kTileModeMask_GSF);
     79     fGradFlags = (flags >> kGradFlagsShift_GSF) & kGradFlagsMask_GSF;
     80 
     81     fCount = buffer.getArrayCount();
     82     if (fCount > kStorageCount) {
     83         size_t allocSize = (sizeof(SkColor4f) + sizeof(SkScalar)) * fCount;
     84         fDynamicStorage.reset(allocSize);
     85         fColors = (SkColor4f*)fDynamicStorage.get();
     86         fPos = (SkScalar*)(fColors + fCount);
     87     } else {
     88         fColors = fColorStorage;
     89         fPos = fPosStorage;
     90     }
     91     if (!buffer.readColor4fArray(mutableColors(), fCount)) {
     92         return false;
     93     }
     94     if (SkToBool(flags & kHasColorSpace_GSF)) {
     95         sk_sp<SkData> data = buffer.readByteArrayAsData();
     96         fColorSpace = SkColorSpace::Deserialize(data->data(), data->size());
     97     } else {
     98         fColorSpace = nullptr;
     99     }
    100     if (SkToBool(flags & kHasPosition_GSF)) {
    101         if (!buffer.readScalarArray(mutablePos(), fCount)) {
    102             return false;
    103         }
    104     } else {
    105         fPos = nullptr;
    106     }
    107     if (SkToBool(flags & kHasLocalMatrix_GSF)) {
    108         fLocalMatrix = &fLocalMatrixStorage;
    109         buffer.readMatrix(&fLocalMatrixStorage);
    110     } else {
    111         fLocalMatrix = nullptr;
    112     }
    113     return buffer.isValid();
    114 }
    115 
    116 ////////////////////////////////////////////////////////////////////////////////////////////
    117 
    118 SkGradientShaderBase::SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit)
    119     : INHERITED(desc.fLocalMatrix)
    120     , fPtsToUnit(ptsToUnit)
    121     , fColorsAreOpaque(true)
    122 {
    123     fPtsToUnit.getType();  // Precache so reads are threadsafe.
    124     SkASSERT(desc.fCount > 1);
    125 
    126     fGradFlags = static_cast<uint8_t>(desc.fGradFlags);
    127 
    128     SkASSERT((unsigned)desc.fTileMode < SkShader::kTileModeCount);
    129     fTileMode = desc.fTileMode;
    130 
    131     /*  Note: we let the caller skip the first and/or last position.
    132         i.e. pos[0] = 0.3, pos[1] = 0.7
    133         In these cases, we insert dummy entries to ensure that the final data
    134         will be bracketed by [0, 1].
    135         i.e. our_pos[0] = 0, our_pos[1] = 0.3, our_pos[2] = 0.7, our_pos[3] = 1
    136 
    137         Thus colorCount (the caller's value, and fColorCount (our value) may
    138         differ by up to 2. In the above example:
    139             colorCount = 2
    140             fColorCount = 4
    141      */
    142     fColorCount = desc.fCount;
    143     // check if we need to add in dummy start and/or end position/colors
    144     bool dummyFirst = false;
    145     bool dummyLast = false;
    146     if (desc.fPos) {
    147         dummyFirst = desc.fPos[0] != 0;
    148         dummyLast = desc.fPos[desc.fCount - 1] != SK_Scalar1;
    149         fColorCount += dummyFirst + dummyLast;
    150     }
    151 
    152     size_t storageSize = fColorCount * (sizeof(SkColor4f) + (desc.fPos ? sizeof(SkScalar) : 0));
    153     fOrigColors4f      = reinterpret_cast<SkColor4f*>(fStorage.reset(storageSize));
    154     fOrigPos           = desc.fPos ? reinterpret_cast<SkScalar*>(fOrigColors4f + fColorCount)
    155                                    : nullptr;
    156 
    157     // Now copy over the colors, adding the dummies as needed
    158     SkColor4f* origColors = fOrigColors4f;
    159     if (dummyFirst) {
    160         *origColors++ = desc.fColors[0];
    161     }
    162     for (int i = 0; i < desc.fCount; ++i) {
    163         origColors[i] = desc.fColors[i];
    164         fColorsAreOpaque = fColorsAreOpaque && (desc.fColors[i].fA == 1);
    165     }
    166     if (dummyLast) {
    167         origColors += desc.fCount;
    168         *origColors = desc.fColors[desc.fCount - 1];
    169     }
    170 
    171     if (!desc.fColorSpace) {
    172         // This happens if we were constructed from SkColors, so our colors are really sRGB
    173         fColorSpace = SkColorSpace::MakeSRGBLinear();
    174     } else {
    175         // The color space refers to the float colors, so it must be linear gamma
    176         // TODO: GPU code no longer requires this (see GrGradientEffect). Remove this restriction?
    177         SkASSERT(desc.fColorSpace->gammaIsLinear());
    178         fColorSpace = desc.fColorSpace;
    179     }
    180 
    181     if (desc.fPos) {
    182         SkScalar prev = 0;
    183         SkScalar* origPosPtr = fOrigPos;
    184         *origPosPtr++ = prev; // force the first pos to 0
    185 
    186         int startIndex = dummyFirst ? 0 : 1;
    187         int count = desc.fCount + dummyLast;
    188 
    189         bool uniformStops = true;
    190         const SkScalar uniformStep = desc.fPos[startIndex] - prev;
    191         for (int i = startIndex; i < count; i++) {
    192             // Pin the last value to 1.0, and make sure pos is monotonic.
    193             auto curr = (i == desc.fCount) ? 1 : SkScalarPin(desc.fPos[i], prev, 1);
    194             uniformStops &= SkScalarNearlyEqual(uniformStep, curr - prev);
    195 
    196             *origPosPtr++ = prev = curr;
    197         }
    198 
    199         // If the stops are uniform, treat them as implicit.
    200         if (uniformStops) {
    201             fOrigPos = nullptr;
    202         }
    203     }
    204 }
    205 
    206 SkGradientShaderBase::~SkGradientShaderBase() {}
    207 
    208 void SkGradientShaderBase::flatten(SkWriteBuffer& buffer) const {
    209     Descriptor desc;
    210     desc.fColors = fOrigColors4f;
    211     desc.fColorSpace = fColorSpace;
    212     desc.fPos = fOrigPos;
    213     desc.fCount = fColorCount;
    214     desc.fTileMode = fTileMode;
    215     desc.fGradFlags = fGradFlags;
    216 
    217     const SkMatrix& m = this->getLocalMatrix();
    218     desc.fLocalMatrix = m.isIdentity() ? nullptr : &m;
    219     desc.flatten(buffer);
    220 }
    221 
    222 static void add_stop_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f Fs, SkPM4f Bs) {
    223     (ctx->fs[0])[stop] = Fs.r();
    224     (ctx->fs[1])[stop] = Fs.g();
    225     (ctx->fs[2])[stop] = Fs.b();
    226     (ctx->fs[3])[stop] = Fs.a();
    227     (ctx->bs[0])[stop] = Bs.r();
    228     (ctx->bs[1])[stop] = Bs.g();
    229     (ctx->bs[2])[stop] = Bs.b();
    230     (ctx->bs[3])[stop] = Bs.a();
    231 }
    232 
    233 static void add_const_color(SkJumper_GradientCtx* ctx, size_t stop, SkPM4f color) {
    234     add_stop_color(ctx, stop, SkPM4f::FromPremulRGBA(0,0,0,0), color);
    235 }
    236 
    237 // Calculate a factor F and a bias B so that color = F*t + B when t is in range of
    238 // the stop. Assume that the distance between stops is 1/gapCount.
    239 static void init_stop_evenly(
    240     SkJumper_GradientCtx* ctx, float gapCount, size_t stop, SkPM4f c_l, SkPM4f c_r) {
    241     // Clankium's GCC 4.9 targeting ARMv7 is barfing when we use Sk4f math here, so go scalar...
    242     SkPM4f Fs = {{
    243         (c_r.r() - c_l.r()) * gapCount,
    244         (c_r.g() - c_l.g()) * gapCount,
    245         (c_r.b() - c_l.b()) * gapCount,
    246         (c_r.a() - c_l.a()) * gapCount,
    247     }};
    248     SkPM4f Bs = {{
    249         c_l.r() - Fs.r()*(stop/gapCount),
    250         c_l.g() - Fs.g()*(stop/gapCount),
    251         c_l.b() - Fs.b()*(stop/gapCount),
    252         c_l.a() - Fs.a()*(stop/gapCount),
    253     }};
    254     add_stop_color(ctx, stop, Fs, Bs);
    255 }
    256 
    257 // For each stop we calculate a bias B and a scale factor F, such that
    258 // for any t between stops n and n+1, the color we want is B[n] + F[n]*t.
    259 static void init_stop_pos(
    260     SkJumper_GradientCtx* ctx, size_t stop, float t_l, float t_r, SkPM4f c_l, SkPM4f c_r) {
    261     // See note about Clankium's old compiler in init_stop_evenly().
    262     SkPM4f Fs = {{
    263         (c_r.r() - c_l.r()) / (t_r - t_l),
    264         (c_r.g() - c_l.g()) / (t_r - t_l),
    265         (c_r.b() - c_l.b()) / (t_r - t_l),
    266         (c_r.a() - c_l.a()) / (t_r - t_l),
    267     }};
    268     SkPM4f Bs = {{
    269         c_l.r() - Fs.r()*t_l,
    270         c_l.g() - Fs.g()*t_l,
    271         c_l.b() - Fs.b()*t_l,
    272         c_l.a() - Fs.a()*t_l,
    273     }};
    274     ctx->ts[stop] = t_l;
    275     add_stop_color(ctx, stop, Fs, Bs);
    276 }
    277 
    278 bool SkGradientShaderBase::onAppendStages(const StageRec& rec) const {
    279     SkRasterPipeline* p = rec.fPipeline;
    280     SkArenaAlloc* alloc = rec.fAlloc;
    281     SkColorSpace* dstCS = rec.fDstCS;
    282 
    283     SkMatrix matrix;
    284     if (!this->computeTotalInverse(rec.fCTM, rec.fLocalM, &matrix)) {
    285         return false;
    286     }
    287     matrix.postConcat(fPtsToUnit);
    288 
    289     SkRasterPipeline_<256> postPipeline;
    290 
    291     p->append_seed_shader();
    292     p->append_matrix(alloc, matrix);
    293     this->appendGradientStages(alloc, p, &postPipeline);
    294 
    295     switch(fTileMode) {
    296         case kMirror_TileMode: p->append(SkRasterPipeline::mirror_x_1); break;
    297         case kRepeat_TileMode: p->append(SkRasterPipeline::repeat_x_1); break;
    298         case kClamp_TileMode:
    299             if (!fOrigPos) {
    300                 // We clamp only when the stops are evenly spaced.
    301                 // If not, there may be hard stops, and clamping ruins hard stops at 0 and/or 1.
    302                 // In that case, we must make sure we're using the general "gradient" stage,
    303                 // which is the only stage that will correctly handle unclamped t.
    304                 p->append(SkRasterPipeline::clamp_x_1);
    305             }
    306     }
    307 
    308     const bool premulGrad = fGradFlags & SkGradientShader::kInterpolateColorsInPremul_Flag;
    309     auto prepareColor = [premulGrad, dstCS, this](int i) {
    310         SkColor4f c = this->getXformedColor(i, dstCS);
    311         return premulGrad ? c.premul()
    312                           : SkPM4f::From4f(Sk4f::Load(&c));
    313     };
    314 
    315     // The two-stop case with stops at 0 and 1.
    316     if (fColorCount == 2 && fOrigPos == nullptr) {
    317         const SkPM4f c_l = prepareColor(0),
    318                      c_r = prepareColor(1);
    319 
    320         // See F and B below.
    321         auto* f_and_b = alloc->makeArrayDefault<SkPM4f>(2);
    322         f_and_b[0] = SkPM4f::From4f(c_r.to4f() - c_l.to4f());
    323         f_and_b[1] = c_l;
    324 
    325         p->append(SkRasterPipeline::evenly_spaced_2_stop_gradient, f_and_b);
    326     } else {
    327         auto* ctx = alloc->make<SkJumper_GradientCtx>();
    328 
    329         // Note: In order to handle clamps in search, the search assumes a stop conceptully placed
    330         // at -inf. Therefore, the max number of stops is fColorCount+1.
    331         for (int i = 0; i < 4; i++) {
    332             // Allocate at least at for the AVX2 gather from a YMM register.
    333             ctx->fs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
    334             ctx->bs[i] = alloc->makeArray<float>(std::max(fColorCount+1, 8));
    335         }
    336 
    337         if (fOrigPos == nullptr) {
    338             // Handle evenly distributed stops.
    339 
    340             size_t stopCount = fColorCount;
    341             float gapCount = stopCount - 1;
    342 
    343             SkPM4f c_l = prepareColor(0);
    344             for (size_t i = 0; i < stopCount - 1; i++) {
    345                 SkPM4f c_r = prepareColor(i + 1);
    346                 init_stop_evenly(ctx, gapCount, i, c_l, c_r);
    347                 c_l = c_r;
    348             }
    349             add_const_color(ctx, stopCount - 1, c_l);
    350 
    351             ctx->stopCount = stopCount;
    352             p->append(SkRasterPipeline::evenly_spaced_gradient, ctx);
    353         } else {
    354             // Handle arbitrary stops.
    355 
    356             ctx->ts = alloc->makeArray<float>(fColorCount+1);
    357 
    358             // Remove the dummy stops inserted by SkGradientShaderBase::SkGradientShaderBase
    359             // because they are naturally handled by the search method.
    360             int firstStop;
    361             int lastStop;
    362             if (fColorCount > 2) {
    363                 firstStop = fOrigColors4f[0] != fOrigColors4f[1] ? 0 : 1;
    364                 lastStop = fOrigColors4f[fColorCount - 2] != fOrigColors4f[fColorCount - 1]
    365                            ? fColorCount - 1 : fColorCount - 2;
    366             } else {
    367                 firstStop = 0;
    368                 lastStop = 1;
    369             }
    370 
    371             size_t stopCount = 0;
    372             float  t_l = fOrigPos[firstStop];
    373             SkPM4f c_l = prepareColor(firstStop);
    374             add_const_color(ctx, stopCount++, c_l);
    375             // N.B. lastStop is the index of the last stop, not one after.
    376             for (int i = firstStop; i < lastStop; i++) {
    377                 float  t_r = fOrigPos[i + 1];
    378                 SkPM4f c_r = prepareColor(i + 1);
    379                 SkASSERT(t_l <= t_r);
    380                 if (t_l < t_r) {
    381                     init_stop_pos(ctx, stopCount, t_l, t_r, c_l, c_r);
    382                     stopCount += 1;
    383                 }
    384                 t_l = t_r;
    385                 c_l = c_r;
    386             }
    387 
    388             ctx->ts[stopCount] = t_l;
    389             add_const_color(ctx, stopCount++, c_l);
    390 
    391             ctx->stopCount = stopCount;
    392             p->append(SkRasterPipeline::gradient, ctx);
    393         }
    394     }
    395 
    396     if (!premulGrad && !this->colorsAreOpaque()) {
    397         p->append(SkRasterPipeline::premul);
    398     }
    399 
    400     p->extend(postPipeline);
    401 
    402     return true;
    403 }
    404 
    405 
    406 bool SkGradientShaderBase::isOpaque() const {
    407     return fColorsAreOpaque;
    408 }
    409 
    410 static unsigned rounded_divide(unsigned numer, unsigned denom) {
    411     return (numer + (denom >> 1)) / denom;
    412 }
    413 
    414 bool SkGradientShaderBase::onAsLuminanceColor(SkColor* lum) const {
    415     // we just compute an average color.
    416     // possibly we could weight this based on the proportional width for each color
    417     //   assuming they are not evenly distributed in the fPos array.
    418     int r = 0;
    419     int g = 0;
    420     int b = 0;
    421     const int n = fColorCount;
    422     // TODO: use linear colors?
    423     for (int i = 0; i < n; ++i) {
    424         SkColor c = this->getLegacyColor(i);
    425         r += SkColorGetR(c);
    426         g += SkColorGetG(c);
    427         b += SkColorGetB(c);
    428     }
    429     *lum = SkColorSetRGB(rounded_divide(r, n), rounded_divide(g, n), rounded_divide(b, n));
    430     return true;
    431 }
    432 
    433 SkGradientShaderBase::AutoXformColors::AutoXformColors(const SkGradientShaderBase& grad,
    434                                                        SkColorSpaceXformer* xformer)
    435     : fColors(grad.fColorCount) {
    436     // TODO: stay in 4f to preserve precision?
    437 
    438     SkAutoSTMalloc<8, SkColor> origColors(grad.fColorCount);
    439     for (int i = 0; i < grad.fColorCount; ++i) {
    440         origColors[i] = grad.getLegacyColor(i);
    441     }
    442 
    443     xformer->apply(fColors.get(), origColors.get(), grad.fColorCount);
    444 }
    445 
    446 static constexpr int kGradientTextureSize = 256;
    447 
    448 void SkGradientShaderBase::initLinearBitmap(SkBitmap* bitmap, GradientBitmapType bitmapType) const {
    449     const bool interpInPremul = SkToBool(fGradFlags &
    450                                          SkGradientShader::kInterpolateColorsInPremul_Flag);
    451     SkHalf* pixelsF16 = reinterpret_cast<SkHalf*>(bitmap->getPixels());
    452     uint32_t* pixels32 = reinterpret_cast<uint32_t*>(bitmap->getPixels());
    453 
    454     typedef std::function<void(const Sk4f&, int)> pixelWriteFn_t;
    455 
    456     pixelWriteFn_t writeF16Pixel = [&](const Sk4f& x, int index) {
    457         Sk4h c = SkFloatToHalf_finite_ftz(x);
    458         pixelsF16[4*index+0] = c[0];
    459         pixelsF16[4*index+1] = c[1];
    460         pixelsF16[4*index+2] = c[2];
    461         pixelsF16[4*index+3] = c[3];
    462     };
    463     pixelWriteFn_t writeS32Pixel = [&](const Sk4f& c, int index) {
    464         pixels32[index] = Sk4f_toS32(c);
    465     };
    466     pixelWriteFn_t writeL32Pixel = [&](const Sk4f& c, int index) {
    467         pixels32[index] = Sk4f_toL32(c);
    468     };
    469 
    470     pixelWriteFn_t writeSizedPixel =
    471         (bitmapType == GradientBitmapType::kHalfFloat) ? writeF16Pixel :
    472         (bitmapType == GradientBitmapType::kSRGB     ) ? writeS32Pixel : writeL32Pixel;
    473     pixelWriteFn_t writeUnpremulPixel = [&](const Sk4f& c, int index) {
    474         writeSizedPixel(c * Sk4f(c[3], c[3], c[3], 1.0f), index);
    475     };
    476 
    477     pixelWriteFn_t writePixel = interpInPremul ? writeSizedPixel : writeUnpremulPixel;
    478 
    479     // When not in legacy mode, we just want the original 4f colors - so we pass in
    480     // our own CS for identity/no transform.
    481     auto* cs = bitmapType != GradientBitmapType::kLegacy ? fColorSpace.get() : nullptr;
    482 
    483     int prevIndex = 0;
    484     for (int i = 1; i < fColorCount; i++) {
    485         // Historically, stops have been mapped to [0, 256], with 256 then nudged to the
    486         // next smaller value, then truncate for the texture index. This seems to produce
    487         // the best results for some common distributions, so we preserve the behavior.
    488         int nextIndex = SkTMin(this->getPos(i) * kGradientTextureSize,
    489                                SkIntToScalar(kGradientTextureSize - 1));
    490 
    491         if (nextIndex > prevIndex) {
    492             SkColor4f color0 = this->getXformedColor(i - 1, cs),
    493                       color1 = this->getXformedColor(i    , cs);
    494             Sk4f          c0 = Sk4f::Load(color0.vec()),
    495                           c1 = Sk4f::Load(color1.vec());
    496 
    497             if (interpInPremul) {
    498                 c0 = c0 * Sk4f(c0[3], c0[3], c0[3], 1.0f);
    499                 c1 = c1 * Sk4f(c1[3], c1[3], c1[3], 1.0f);
    500             }
    501 
    502             Sk4f step = Sk4f(1.0f / static_cast<float>(nextIndex - prevIndex));
    503             Sk4f delta = (c1 - c0) * step;
    504 
    505             for (int curIndex = prevIndex; curIndex <= nextIndex; ++curIndex) {
    506                 writePixel(c0, curIndex);
    507                 c0 += delta;
    508             }
    509         }
    510         prevIndex = nextIndex;
    511     }
    512     SkASSERT(prevIndex == kGradientTextureSize - 1);
    513 }
    514 
    515 SkColor4f SkGradientShaderBase::getXformedColor(size_t i, SkColorSpace* dstCS) const {
    516     if (dstCS) {
    517         return to_colorspace(fOrigColors4f[i], fColorSpace.get(), dstCS);
    518     }
    519 
    520     // Legacy/srgb color.
    521     // We quantize upfront to ensure stable SkColor round-trips.
    522     auto rgb255 = sk_linear_to_srgb(Sk4f::Load(fOrigColors4f[i].vec()));
    523     auto rgb    = SkNx_cast<float>(rgb255) * (1/255.0f);
    524     return { rgb[0], rgb[1], rgb[2], fOrigColors4f[i].fA };
    525 }
    526 
    527 SK_DECLARE_STATIC_MUTEX(gGradientCacheMutex);
    528 /*
    529  *  Because our caller might rebuild the same (logically the same) gradient
    530  *  over and over, we'd like to return exactly the same "bitmap" if possible,
    531  *  allowing the client to utilize a cache of our bitmap (e.g. with a GPU).
    532  *  To do that, we maintain a private cache of built-bitmaps, based on our
    533  *  colors and positions.
    534  */
    535 void SkGradientShaderBase::getGradientTableBitmap(SkBitmap* bitmap,
    536                                                   GradientBitmapType bitmapType) const {
    537     // build our key: [numColors + colors[] + {positions[]} + flags + colorType ]
    538     static_assert(sizeof(SkColor4f) % sizeof(int32_t) == 0, "");
    539     const int colorsAsIntCount = fColorCount * sizeof(SkColor4f) / sizeof(int32_t);
    540     int count = 1 + colorsAsIntCount + 1 + 1;
    541     if (fColorCount > 2) {
    542         count += fColorCount - 1;
    543     }
    544 
    545     SkAutoSTMalloc<64, int32_t> storage(count);
    546     int32_t* buffer = storage.get();
    547 
    548     *buffer++ = fColorCount;
    549     memcpy(buffer, fOrigColors4f, fColorCount * sizeof(SkColor4f));
    550     buffer += colorsAsIntCount;
    551     if (fColorCount > 2) {
    552         for (int i = 1; i < fColorCount; i++) {
    553             *buffer++ = SkFloat2Bits(this->getPos(i));
    554         }
    555     }
    556     *buffer++ = fGradFlags;
    557     *buffer++ = static_cast<int32_t>(bitmapType);
    558     SkASSERT(buffer - storage.get() == count);
    559 
    560     ///////////////////////////////////
    561 
    562     static SkGradientBitmapCache* gCache;
    563     // each cache cost 1K or 2K of RAM, since each bitmap will be 1x256 at either 32bpp or 64bpp
    564     static const int MAX_NUM_CACHED_GRADIENT_BITMAPS = 32;
    565     SkAutoMutexAcquire ama(gGradientCacheMutex);
    566 
    567     if (nullptr == gCache) {
    568         gCache = new SkGradientBitmapCache(MAX_NUM_CACHED_GRADIENT_BITMAPS);
    569     }
    570     size_t size = count * sizeof(int32_t);
    571 
    572     if (!gCache->find(storage.get(), size, bitmap)) {
    573         // For these cases we use the bitmap cache, but not the GradientShaderCache. So just
    574         // allocate and populate the bitmap's data directly.
    575 
    576         SkImageInfo info;
    577         switch (bitmapType) {
    578         case GradientBitmapType::kLegacy:
    579             info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_8888_SkColorType,
    580                                      kPremul_SkAlphaType);
    581             break;
    582         case GradientBitmapType::kSRGB:
    583             info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_8888_SkColorType,
    584                                      kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
    585             break;
    586         case GradientBitmapType::kHalfFloat:
    587             info = SkImageInfo::Make(kGradientTextureSize, 1, kRGBA_F16_SkColorType,
    588                                      kPremul_SkAlphaType, SkColorSpace::MakeSRGBLinear());
    589             break;
    590         }
    591 
    592         bitmap->allocPixels(info);
    593         this->initLinearBitmap(bitmap, bitmapType);
    594         gCache->add(storage.get(), size, *bitmap);
    595     }
    596 }
    597 
    598 void SkGradientShaderBase::commonAsAGradient(GradientInfo* info) const {
    599     if (info) {
    600         if (info->fColorCount >= fColorCount) {
    601             if (info->fColors) {
    602                 for (int i = 0; i < fColorCount; ++i) {
    603                     info->fColors[i] = this->getLegacyColor(i);
    604                 }
    605             }
    606             if (info->fColorOffsets) {
    607                 for (int i = 0; i < fColorCount; ++i) {
    608                     info->fColorOffsets[i] = this->getPos(i);
    609                 }
    610             }
    611         }
    612         info->fColorCount = fColorCount;
    613         info->fTileMode = fTileMode;
    614         info->fGradientFlags = fGradFlags;
    615     }
    616 }
    617 
    618 #ifndef SK_IGNORE_TO_STRING
    619 void SkGradientShaderBase::toString(SkString* str) const {
    620 
    621     str->appendf("%d colors: ", fColorCount);
    622 
    623     for (int i = 0; i < fColorCount; ++i) {
    624         str->appendHex(this->getLegacyColor(i), 8);
    625         if (i < fColorCount-1) {
    626             str->append(", ");
    627         }
    628     }
    629 
    630     if (fColorCount > 2) {
    631         str->append(" points: (");
    632         for (int i = 0; i < fColorCount; ++i) {
    633             str->appendScalar(this->getPos(i));
    634             if (i < fColorCount-1) {
    635                 str->append(", ");
    636             }
    637         }
    638         str->append(")");
    639     }
    640 
    641     static const char* gTileModeName[SkShader::kTileModeCount] = {
    642         "clamp", "repeat", "mirror"
    643     };
    644 
    645     str->append(" ");
    646     str->append(gTileModeName[fTileMode]);
    647 
    648     this->INHERITED::toString(str);
    649 }
    650 #endif
    651 
    652 ///////////////////////////////////////////////////////////////////////////////
    653 ///////////////////////////////////////////////////////////////////////////////
    654 
    655 // Return true if these parameters are valid/legal/safe to construct a gradient
    656 //
    657 static bool valid_grad(const SkColor4f colors[], const SkScalar pos[], int count,
    658                        unsigned tileMode) {
    659     return nullptr != colors && count >= 1 && tileMode < (unsigned)SkShader::kTileModeCount;
    660 }
    661 
    662 static void desc_init(SkGradientShaderBase::Descriptor* desc,
    663                       const SkColor4f colors[], sk_sp<SkColorSpace> colorSpace,
    664                       const SkScalar pos[], int colorCount,
    665                       SkShader::TileMode mode, uint32_t flags, const SkMatrix* localMatrix) {
    666     SkASSERT(colorCount > 1);
    667 
    668     desc->fColors       = colors;
    669     desc->fColorSpace   = std::move(colorSpace);
    670     desc->fPos          = pos;
    671     desc->fCount        = colorCount;
    672     desc->fTileMode     = mode;
    673     desc->fGradFlags    = flags;
    674     desc->fLocalMatrix  = localMatrix;
    675 }
    676 
    677 // assumes colors is SkColor4f* and pos is SkScalar*
    678 #define EXPAND_1_COLOR(count)                \
    679      SkColor4f tmp[2];                       \
    680      do {                                    \
    681          if (1 == count) {                   \
    682              tmp[0] = tmp[1] = colors[0];    \
    683              colors = tmp;                   \
    684              pos = nullptr;                  \
    685              count = 2;                      \
    686          }                                   \
    687      } while (0)
    688 
    689 struct ColorStopOptimizer {
    690     ColorStopOptimizer(const SkColor4f* colors, const SkScalar* pos,
    691                        int count, SkShader::TileMode mode)
    692         : fColors(colors)
    693         , fPos(pos)
    694         , fCount(count) {
    695 
    696             if (!pos || count != 3) {
    697                 return;
    698             }
    699 
    700             if (SkScalarNearlyEqual(pos[0], 0.0f) &&
    701                 SkScalarNearlyEqual(pos[1], 0.0f) &&
    702                 SkScalarNearlyEqual(pos[2], 1.0f)) {
    703 
    704                 if (SkShader::kRepeat_TileMode == mode ||
    705                     SkShader::kMirror_TileMode == mode ||
    706                     colors[0] == colors[1]) {
    707 
    708                     // Ignore the leftmost color/pos.
    709                     fColors += 1;
    710                     fPos    += 1;
    711                     fCount   = 2;
    712                 }
    713             } else if (SkScalarNearlyEqual(pos[0], 0.0f) &&
    714                        SkScalarNearlyEqual(pos[1], 1.0f) &&
    715                        SkScalarNearlyEqual(pos[2], 1.0f)) {
    716 
    717                 if (SkShader::kRepeat_TileMode == mode ||
    718                     SkShader::kMirror_TileMode == mode ||
    719                     colors[1] == colors[2]) {
    720 
    721                     // Ignore the rightmost color/pos.
    722                     fCount  = 2;
    723                 }
    724             }
    725     }
    726 
    727     const SkColor4f* fColors;
    728     const SkScalar*  fPos;
    729     int              fCount;
    730 };
    731 
    732 struct ColorConverter {
    733     ColorConverter(const SkColor* colors, int count) {
    734         for (int i = 0; i < count; ++i) {
    735             fColors4f.push_back(SkColor4f::FromColor(colors[i]));
    736         }
    737     }
    738 
    739     SkSTArray<2, SkColor4f, true> fColors4f;
    740 };
    741 
    742 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
    743                                              const SkColor colors[],
    744                                              const SkScalar pos[], int colorCount,
    745                                              SkShader::TileMode mode,
    746                                              uint32_t flags,
    747                                              const SkMatrix* localMatrix) {
    748     ColorConverter converter(colors, colorCount);
    749     return MakeLinear(pts, converter.fColors4f.begin(), nullptr, pos, colorCount, mode, flags,
    750                       localMatrix);
    751 }
    752 
    753 sk_sp<SkShader> SkGradientShader::MakeLinear(const SkPoint pts[2],
    754                                              const SkColor4f colors[],
    755                                              sk_sp<SkColorSpace> colorSpace,
    756                                              const SkScalar pos[], int colorCount,
    757                                              SkShader::TileMode mode,
    758                                              uint32_t flags,
    759                                              const SkMatrix* localMatrix) {
    760     if (!pts || !SkScalarIsFinite((pts[1] - pts[0]).length())) {
    761         return nullptr;
    762     }
    763     if (!valid_grad(colors, pos, colorCount, mode)) {
    764         return nullptr;
    765     }
    766     if (1 == colorCount) {
    767         return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
    768     }
    769     if (localMatrix && !localMatrix->invert(nullptr)) {
    770         return nullptr;
    771     }
    772 
    773     ColorStopOptimizer opt(colors, pos, colorCount, mode);
    774 
    775     SkGradientShaderBase::Descriptor desc;
    776     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
    777               localMatrix);
    778     return sk_make_sp<SkLinearGradient>(pts, desc);
    779 }
    780 
    781 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
    782                                              const SkColor colors[],
    783                                              const SkScalar pos[], int colorCount,
    784                                              SkShader::TileMode mode,
    785                                              uint32_t flags,
    786                                              const SkMatrix* localMatrix) {
    787     ColorConverter converter(colors, colorCount);
    788     return MakeRadial(center, radius, converter.fColors4f.begin(), nullptr, pos, colorCount, mode,
    789                       flags, localMatrix);
    790 }
    791 
    792 sk_sp<SkShader> SkGradientShader::MakeRadial(const SkPoint& center, SkScalar radius,
    793                                              const SkColor4f colors[],
    794                                              sk_sp<SkColorSpace> colorSpace,
    795                                              const SkScalar pos[], int colorCount,
    796                                              SkShader::TileMode mode,
    797                                              uint32_t flags,
    798                                              const SkMatrix* localMatrix) {
    799     if (radius <= 0) {
    800         return nullptr;
    801     }
    802     if (!valid_grad(colors, pos, colorCount, mode)) {
    803         return nullptr;
    804     }
    805     if (1 == colorCount) {
    806         return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
    807     }
    808     if (localMatrix && !localMatrix->invert(nullptr)) {
    809         return nullptr;
    810     }
    811 
    812     ColorStopOptimizer opt(colors, pos, colorCount, mode);
    813 
    814     SkGradientShaderBase::Descriptor desc;
    815     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
    816               localMatrix);
    817     return sk_make_sp<SkRadialGradient>(center, radius, desc);
    818 }
    819 
    820 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
    821                                                       SkScalar startRadius,
    822                                                       const SkPoint& end,
    823                                                       SkScalar endRadius,
    824                                                       const SkColor colors[],
    825                                                       const SkScalar pos[],
    826                                                       int colorCount,
    827                                                       SkShader::TileMode mode,
    828                                                       uint32_t flags,
    829                                                       const SkMatrix* localMatrix) {
    830     ColorConverter converter(colors, colorCount);
    831     return MakeTwoPointConical(start, startRadius, end, endRadius, converter.fColors4f.begin(),
    832                                nullptr, pos, colorCount, mode, flags, localMatrix);
    833 }
    834 
    835 sk_sp<SkShader> SkGradientShader::MakeTwoPointConical(const SkPoint& start,
    836                                                       SkScalar startRadius,
    837                                                       const SkPoint& end,
    838                                                       SkScalar endRadius,
    839                                                       const SkColor4f colors[],
    840                                                       sk_sp<SkColorSpace> colorSpace,
    841                                                       const SkScalar pos[],
    842                                                       int colorCount,
    843                                                       SkShader::TileMode mode,
    844                                                       uint32_t flags,
    845                                                       const SkMatrix* localMatrix) {
    846     if (startRadius < 0 || endRadius < 0) {
    847         return nullptr;
    848     }
    849     if (SkScalarNearlyZero((start - end).length()) && SkScalarNearlyZero(startRadius)) {
    850         // We can treat this gradient as radial, which is faster.
    851         return MakeRadial(start, endRadius, colors, std::move(colorSpace), pos, colorCount,
    852                           mode, flags, localMatrix);
    853     }
    854     if (!valid_grad(colors, pos, colorCount, mode)) {
    855         return nullptr;
    856     }
    857     if (startRadius == endRadius) {
    858         if (start == end || startRadius == 0) {
    859             return SkShader::MakeEmptyShader();
    860         }
    861     }
    862     if (localMatrix && !localMatrix->invert(nullptr)) {
    863         return nullptr;
    864     }
    865     EXPAND_1_COLOR(colorCount);
    866 
    867     ColorStopOptimizer opt(colors, pos, colorCount, mode);
    868 
    869     SkGradientShaderBase::Descriptor desc;
    870     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
    871               localMatrix);
    872     return SkTwoPointConicalGradient::Create(start, startRadius, end, endRadius, desc);
    873 }
    874 
    875 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
    876                                             const SkColor colors[],
    877                                             const SkScalar pos[],
    878                                             int colorCount,
    879                                             SkShader::TileMode mode,
    880                                             SkScalar startAngle,
    881                                             SkScalar endAngle,
    882                                             uint32_t flags,
    883                                             const SkMatrix* localMatrix) {
    884     ColorConverter converter(colors, colorCount);
    885     return MakeSweep(cx, cy, converter.fColors4f.begin(), nullptr, pos, colorCount,
    886                      mode, startAngle, endAngle, flags, localMatrix);
    887 }
    888 
    889 sk_sp<SkShader> SkGradientShader::MakeSweep(SkScalar cx, SkScalar cy,
    890                                             const SkColor4f colors[],
    891                                             sk_sp<SkColorSpace> colorSpace,
    892                                             const SkScalar pos[],
    893                                             int colorCount,
    894                                             SkShader::TileMode mode,
    895                                             SkScalar startAngle,
    896                                             SkScalar endAngle,
    897                                             uint32_t flags,
    898                                             const SkMatrix* localMatrix) {
    899     if (!valid_grad(colors, pos, colorCount, mode)) {
    900         return nullptr;
    901     }
    902     if (1 == colorCount) {
    903         return SkShader::MakeColorShader(colors[0], std::move(colorSpace));
    904     }
    905     if (startAngle >= endAngle) {
    906         return nullptr;
    907     }
    908     if (localMatrix && !localMatrix->invert(nullptr)) {
    909         return nullptr;
    910     }
    911 
    912     if (startAngle <= 0 && endAngle >= 360) {
    913         // If the t-range includes [0,1], then we can always use clamping (presumably faster).
    914         mode = SkShader::kClamp_TileMode;
    915     }
    916 
    917     ColorStopOptimizer opt(colors, pos, colorCount, mode);
    918 
    919     SkGradientShaderBase::Descriptor desc;
    920     desc_init(&desc, opt.fColors, std::move(colorSpace), opt.fPos, opt.fCount, mode, flags,
    921               localMatrix);
    922 
    923     const SkScalar t0 = startAngle / 360,
    924                    t1 =   endAngle / 360;
    925 
    926     return sk_make_sp<SkSweepGradient>(SkPoint::Make(cx, cy), t0, t1, desc);
    927 }
    928 
    929 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_START(SkGradientShader)
    930     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkLinearGradient)
    931     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkRadialGradient)
    932     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkSweepGradient)
    933     SK_DEFINE_FLATTENABLE_REGISTRAR_ENTRY(SkTwoPointConicalGradient)
    934 SK_DEFINE_FLATTENABLE_REGISTRAR_GROUP_END
    935 
    936 ///////////////////////////////////////////////////////////////////////////////
    937 
    938 #if SK_SUPPORT_GPU
    939 
    940 #include "GrColorSpaceXform.h"
    941 #include "GrContext.h"
    942 #include "GrContextPriv.h"
    943 #include "GrShaderCaps.h"
    944 #include "GrTextureStripAtlas.h"
    945 #include "gl/GrGLContext.h"
    946 #include "glsl/GrGLSLFragmentShaderBuilder.h"
    947 #include "glsl/GrGLSLProgramDataManager.h"
    948 #include "glsl/GrGLSLUniformHandler.h"
    949 #include "SkGr.h"
    950 
    951 void GrGradientEffect::GLSLProcessor::emitUniforms(GrGLSLUniformHandler* uniformHandler,
    952                                                    const GrGradientEffect& ge) {
    953     switch (ge.fStrategy) {
    954         case GrGradientEffect::InterpolationStrategy::kThreshold:
    955         case GrGradientEffect::InterpolationStrategy::kThresholdClamp0:
    956         case GrGradientEffect::InterpolationStrategy::kThresholdClamp1:
    957             fThresholdUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
    958                                                        kFloat_GrSLType,
    959                                                        kHigh_GrSLPrecision,
    960                                                        "Threshold");
    961             // fall through
    962         case GrGradientEffect::InterpolationStrategy::kSingle:
    963             fIntervalsUni = uniformHandler->addUniformArray(kFragment_GrShaderFlag,
    964                                                             kHalf4_GrSLType,
    965                                                             "Intervals",
    966                                                             ge.fIntervals.count());
    967             break;
    968         case GrGradientEffect::InterpolationStrategy::kTexture:
    969             fFSYUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
    970                                                  "GradientYCoordFS");
    971             break;
    972     }
    973 }
    974 
    975 void GrGradientEffect::GLSLProcessor::onSetData(const GrGLSLProgramDataManager& pdman,
    976                                                 const GrFragmentProcessor& processor) {
    977     const GrGradientEffect& e = processor.cast<GrGradientEffect>();
    978 
    979     switch (e.fStrategy) {
    980         case GrGradientEffect::InterpolationStrategy::kThreshold:
    981         case GrGradientEffect::InterpolationStrategy::kThresholdClamp0:
    982         case GrGradientEffect::InterpolationStrategy::kThresholdClamp1:
    983             pdman.set1f(fThresholdUni, e.fThreshold);
    984             // fall through
    985         case GrGradientEffect::InterpolationStrategy::kSingle:
    986             pdman.set4fv(fIntervalsUni, e.fIntervals.count(),
    987                          reinterpret_cast<const float*>(e.fIntervals.begin()));
    988             break;
    989         case GrGradientEffect::InterpolationStrategy::kTexture:
    990             if (e.fYCoord != fCachedYCoord) {
    991                 pdman.set1f(fFSYUni, e.fYCoord);
    992                 fCachedYCoord = e.fYCoord;
    993             }
    994             break;
    995     }
    996 }
    997 
    998 void GrGradientEffect::onGetGLSLProcessorKey(const GrShaderCaps&, GrProcessorKeyBuilder* b) const {
    999     b->add32(GLSLProcessor::GenBaseGradientKey(*this));
   1000 }
   1001 
   1002 uint32_t GrGradientEffect::GLSLProcessor::GenBaseGradientKey(const GrProcessor& processor) {
   1003     const GrGradientEffect& e = processor.cast<GrGradientEffect>();
   1004 
   1005     // Build a key using the following bit allocation:
   1006                 static constexpr uint32_t kStrategyBits = 3;
   1007                 static constexpr uint32_t kPremulBits   = 1;
   1008     SkDEBUGCODE(static constexpr uint32_t kWrapModeBits = 2;)
   1009 
   1010     uint32_t key = static_cast<uint32_t>(e.fStrategy);
   1011     SkASSERT(key < (1 << kStrategyBits));
   1012 
   1013     // This is already baked into the table for texture gradients,
   1014     // and only changes behavior for analytical gradients.
   1015     if (e.fStrategy != InterpolationStrategy::kTexture &&
   1016         e.fPremulType == GrGradientEffect::kBeforeInterp_PremulType) {
   1017         key |= 1 << kStrategyBits;
   1018         SkASSERT(key < (1 << (kStrategyBits + kPremulBits)));
   1019     }
   1020 
   1021     key |= static_cast<uint32_t>(e.fWrapMode) << (kStrategyBits + kPremulBits);
   1022     SkASSERT(key < (1 << (kStrategyBits + kPremulBits + kWrapModeBits)));
   1023 
   1024     return key;
   1025 }
   1026 
   1027 void GrGradientEffect::GLSLProcessor::emitAnalyticalColor(GrGLSLFPFragmentBuilder* fragBuilder,
   1028                                                           GrGLSLUniformHandler* uniformHandler,
   1029                                                           const GrShaderCaps* shaderCaps,
   1030                                                           const GrGradientEffect& ge,
   1031                                                           const char* t,
   1032                                                           const char* outputColor,
   1033                                                           const char* inputColor) {
   1034     // First, apply tiling rules.
   1035     switch (ge.fWrapMode) {
   1036         case GrSamplerState::WrapMode::kClamp:
   1037             switch (ge.fStrategy) {
   1038                 case GrGradientEffect::InterpolationStrategy::kThresholdClamp0:
   1039                     // allow t > 1, in order to hit the clamp interval (1, inf)
   1040                     fragBuilder->codeAppendf("half tiled_t = max(%s, 0.0);", t);
   1041                     break;
   1042                 case GrGradientEffect::InterpolationStrategy::kThresholdClamp1:
   1043                     // allow t < 0, in order to hit the clamp interval (-inf, 0)
   1044                     fragBuilder->codeAppendf("half tiled_t = min(%s, 1.0);", t);
   1045                     break;
   1046                 default:
   1047                     // regular [0, 1] clamping
   1048                     fragBuilder->codeAppendf("half tiled_t = clamp(%s, 0.0, 1.0);", t);
   1049             }
   1050             break;
   1051         case GrSamplerState::WrapMode::kRepeat:
   1052             fragBuilder->codeAppendf("half tiled_t = fract(%s);", t);
   1053             break;
   1054         case GrSamplerState::WrapMode::kMirrorRepeat:
   1055             fragBuilder->codeAppendf("half t_1 = %s - 1.0;", t);
   1056             fragBuilder->codeAppendf("half tiled_t = t_1 - 2.0 * floor(t_1 * 0.5) - 1.0;");
   1057             if (shaderCaps->mustDoOpBetweenFloorAndAbs()) {
   1058                 // At this point the expected value of tiled_t should between -1 and 1, so this
   1059                 // clamp has no effect other than to break up the floor and abs calls and make sure
   1060                 // the compiler doesn't merge them back together.
   1061                 fragBuilder->codeAppendf("tiled_t = clamp(tiled_t, -1.0, 1.0);");
   1062             }
   1063             fragBuilder->codeAppendf("tiled_t = abs(tiled_t);");
   1064             break;
   1065     }
   1066 
   1067     // Calculate the color.
   1068     const char* intervals = uniformHandler->getUniformCStr(fIntervalsUni);
   1069 
   1070     switch (ge.fStrategy) {
   1071         case GrGradientEffect::InterpolationStrategy::kSingle:
   1072             SkASSERT(ge.fIntervals.count() == 2);
   1073             fragBuilder->codeAppendf(
   1074                 "half4 color_scale = %s[0],"
   1075                 "      color_bias  = %s[1];"
   1076                 , intervals, intervals
   1077             );
   1078             break;
   1079         case GrGradientEffect::InterpolationStrategy::kThreshold:
   1080         case GrGradientEffect::InterpolationStrategy::kThresholdClamp0:
   1081         case GrGradientEffect::InterpolationStrategy::kThresholdClamp1:
   1082         {
   1083             SkASSERT(ge.fIntervals.count() == 4);
   1084             const char* threshold = uniformHandler->getUniformCStr(fThresholdUni);
   1085             fragBuilder->codeAppendf(
   1086                 "half4 color_scale, color_bias;"
   1087                 "if (tiled_t < %s) {"
   1088                 "    color_scale = %s[0];"
   1089                 "    color_bias  = %s[1];"
   1090                 "} else {"
   1091                 "    color_scale = %s[2];"
   1092                 "    color_bias  = %s[3];"
   1093                 "}"
   1094                 , threshold, intervals, intervals, intervals, intervals
   1095             );
   1096         }   break;
   1097         default:
   1098             SkASSERT(false);
   1099             break;
   1100     }
   1101 
   1102     fragBuilder->codeAppend("half4 colorTemp = tiled_t * color_scale + color_bias;");
   1103 
   1104     // We could skip this step if all colors are known to be opaque. Two considerations:
   1105     // The gradient SkShader reporting opaque is more restrictive than necessary in the two
   1106     // pt case. Make sure the key reflects this optimization (and note that it can use the
   1107     // same shader as the kBeforeInterp case).
   1108     if (ge.fPremulType == GrGradientEffect::kAfterInterp_PremulType) {
   1109         fragBuilder->codeAppend("colorTemp.rgb *= colorTemp.a;");
   1110     }
   1111 
   1112     // If the input colors were floats, or there was a color space xform, we may end up out of
   1113     // range. The simplest solution is to always clamp our (premul) value here. We only need to
   1114     // clamp RGB, but that causes hangs on the Tegra3 Nexus7. Clamping RGBA avoids the problem.
   1115     fragBuilder->codeAppend("colorTemp = clamp(colorTemp, 0, colorTemp.a);");
   1116 
   1117     fragBuilder->codeAppendf("%s = %s * colorTemp;", outputColor, inputColor);
   1118 }
   1119 
   1120 void GrGradientEffect::GLSLProcessor::emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
   1121                                                 GrGLSLUniformHandler* uniformHandler,
   1122                                                 const GrShaderCaps* shaderCaps,
   1123                                                 const GrGradientEffect& ge,
   1124                                                 const char* gradientTValue,
   1125                                                 const char* outputColor,
   1126                                                 const char* inputColor,
   1127                                                 const TextureSamplers& texSamplers) {
   1128     if (ge.fStrategy != InterpolationStrategy::kTexture) {
   1129         this->emitAnalyticalColor(fragBuilder, uniformHandler, shaderCaps, ge, gradientTValue,
   1130                                   outputColor, inputColor);
   1131         return;
   1132     }
   1133 
   1134     const char* fsyuni = uniformHandler->getUniformCStr(fFSYUni);
   1135 
   1136     fragBuilder->codeAppendf("half2 coord = half2(%s, %s);", gradientTValue, fsyuni);
   1137     fragBuilder->codeAppendf("%s = ", outputColor);
   1138     fragBuilder->appendTextureLookupAndModulate(inputColor, texSamplers[0], "coord",
   1139                                                 kFloat2_GrSLType);
   1140     fragBuilder->codeAppend(";");
   1141 }
   1142 
   1143 /////////////////////////////////////////////////////////////////////
   1144 
   1145 inline GrFragmentProcessor::OptimizationFlags GrGradientEffect::OptFlags(bool isOpaque) {
   1146     return isOpaque
   1147                    ? kPreservesOpaqueInput_OptimizationFlag |
   1148                              kCompatibleWithCoverageAsAlpha_OptimizationFlag
   1149                    : kCompatibleWithCoverageAsAlpha_OptimizationFlag;
   1150 }
   1151 
   1152 void GrGradientEffect::addInterval(const SkGradientShaderBase& shader, size_t idx0, size_t idx1,
   1153                                    SkColorSpace* dstCS) {
   1154     SkASSERT(idx0 <= idx1);
   1155     const auto  c4f0 = shader.getXformedColor(idx0, dstCS),
   1156                 c4f1 = shader.getXformedColor(idx1, dstCS);
   1157     const auto    c0 = (fPremulType == kBeforeInterp_PremulType)
   1158                      ? c4f0.premul().to4f() :  Sk4f::Load(c4f0.vec()),
   1159                   c1 = (fPremulType == kBeforeInterp_PremulType)
   1160                      ? c4f1.premul().to4f() :  Sk4f::Load(c4f1.vec());
   1161     const auto    t0 = shader.getPos(idx0),
   1162                   t1 = shader.getPos(idx1),
   1163                   dt = t1 - t0;
   1164     SkASSERT(dt >= 0);
   1165     // dt can be 0 for clamp intervals => in this case we want a scale == 0
   1166     const auto scale = SkScalarNearlyZero(dt) ? 0 : (c1 - c0) / dt,
   1167                 bias = c0 - t0 * scale;
   1168 
   1169     // Intervals are stored as (scale, bias) tuples.
   1170     SkASSERT(!(fIntervals.count() & 1));
   1171     fIntervals.emplace_back(scale[0], scale[1], scale[2], scale[3]);
   1172     fIntervals.emplace_back( bias[0],  bias[1],  bias[2],  bias[3]);
   1173 }
   1174 
   1175 GrGradientEffect::GrGradientEffect(ClassID classID, const CreateArgs& args, bool isOpaque)
   1176     : INHERITED(classID, OptFlags(isOpaque))
   1177     , fWrapMode(args.fWrapMode)
   1178     , fRow(-1)
   1179     , fIsOpaque(args.fShader->isOpaque())
   1180     , fStrategy(InterpolationStrategy::kTexture)
   1181     , fThreshold(0) {
   1182 
   1183     const SkGradientShaderBase& shader(*args.fShader);
   1184 
   1185     fPremulType = (args.fShader->getGradFlags() & SkGradientShader::kInterpolateColorsInPremul_Flag)
   1186                 ? kBeforeInterp_PremulType : kAfterInterp_PremulType;
   1187 
   1188     // First, determine the interpolation strategy and params.
   1189     switch (shader.fColorCount) {
   1190         case 2:
   1191             SkASSERT(!shader.fOrigPos);
   1192             fStrategy = InterpolationStrategy::kSingle;
   1193             this->addInterval(shader, 0, 1, args.fDstColorSpace);
   1194             break;
   1195         case 3:
   1196             fThreshold = shader.getPos(1);
   1197 
   1198             if (shader.fOrigPos) {
   1199                 SkASSERT(SkScalarNearlyEqual(shader.fOrigPos[0], 0));
   1200                 SkASSERT(SkScalarNearlyEqual(shader.fOrigPos[2], 1));
   1201                 if (SkScalarNearlyEqual(shader.fOrigPos[1], 0)) {
   1202                     // hard stop on the left edge.
   1203                     if (fWrapMode == GrSamplerState::WrapMode::kClamp) {
   1204                         fStrategy = InterpolationStrategy::kThresholdClamp1;
   1205                         // Clamp interval (scale == 0, bias == colors[0]).
   1206                         this->addInterval(shader, 0, 0, args.fDstColorSpace);
   1207                     } else {
   1208                         // We can ignore the hard stop when not clamping.
   1209                         fStrategy = InterpolationStrategy::kSingle;
   1210                     }
   1211                     this->addInterval(shader, 1, 2, args.fDstColorSpace);
   1212                     break;
   1213                 }
   1214 
   1215                 if (SkScalarNearlyEqual(shader.fOrigPos[1], 1)) {
   1216                     // hard stop on the right edge.
   1217                     this->addInterval(shader, 0, 1, args.fDstColorSpace);
   1218                     if (fWrapMode == GrSamplerState::WrapMode::kClamp) {
   1219                         fStrategy = InterpolationStrategy::kThresholdClamp0;
   1220                         // Clamp interval (scale == 0, bias == colors[2]).
   1221                         this->addInterval(shader, 2, 2, args.fDstColorSpace);
   1222                     } else {
   1223                         // We can ignore the hard stop when not clamping.
   1224                         fStrategy = InterpolationStrategy::kSingle;
   1225                     }
   1226                     break;
   1227                 }
   1228             }
   1229 
   1230             // Two arbitrary interpolation intervals.
   1231             fStrategy = InterpolationStrategy::kThreshold;
   1232             this->addInterval(shader, 0, 1, args.fDstColorSpace);
   1233             this->addInterval(shader, 1, 2, args.fDstColorSpace);
   1234             break;
   1235         case 4:
   1236             if (shader.fOrigPos && SkScalarNearlyEqual(shader.fOrigPos[1], shader.fOrigPos[2])) {
   1237                 SkASSERT(SkScalarNearlyEqual(shader.fOrigPos[0], 0));
   1238                 SkASSERT(SkScalarNearlyEqual(shader.fOrigPos[3], 1));
   1239 
   1240                 // Single hard stop => two arbitrary interpolation intervals.
   1241                 fStrategy = InterpolationStrategy::kThreshold;
   1242                 fThreshold = shader.getPos(1);
   1243                 this->addInterval(shader, 0, 1, args.fDstColorSpace);
   1244                 this->addInterval(shader, 2, 3, args.fDstColorSpace);
   1245             }
   1246             break;
   1247         default:
   1248             break;
   1249     }
   1250 
   1251     // Now that we've locked down a strategy, adjust any dependent params.
   1252     if (fStrategy != InterpolationStrategy::kTexture) {
   1253         // Analytical cases.
   1254         fCoordTransform.reset(*args.fMatrix);
   1255     } else {
   1256         SkGradientShaderBase::GradientBitmapType bitmapType =
   1257             SkGradientShaderBase::GradientBitmapType::kLegacy;
   1258         if (args.fDstColorSpace) {
   1259             // Try to use F16 if we can
   1260             if (args.fContext->caps()->isConfigTexturable(kRGBA_half_GrPixelConfig)) {
   1261                 bitmapType = SkGradientShaderBase::GradientBitmapType::kHalfFloat;
   1262             } else if (args.fContext->caps()->isConfigTexturable(kSRGBA_8888_GrPixelConfig)) {
   1263                 bitmapType = SkGradientShaderBase::GradientBitmapType::kSRGB;
   1264             } else {
   1265                 // This can happen, but only if someone explicitly creates an unsupported
   1266                 // (eg sRGB) surface. Just fall back to legacy behavior.
   1267             }
   1268         }
   1269 
   1270         SkBitmap bitmap;
   1271         shader.getGradientTableBitmap(&bitmap, bitmapType);
   1272         SkASSERT(1 == bitmap.height() && SkIsPow2(bitmap.width()));
   1273 
   1274 
   1275         GrTextureStripAtlas::Desc desc;
   1276         desc.fWidth  = bitmap.width();
   1277         desc.fHeight = 32;
   1278         desc.fRowHeight = bitmap.height();
   1279         desc.fContext = args.fContext;
   1280         desc.fConfig = SkImageInfo2GrPixelConfig(bitmap.info(), *args.fContext->caps());
   1281         fAtlas = GrTextureStripAtlas::GetAtlas(desc);
   1282         SkASSERT(fAtlas);
   1283 
   1284         // We always filter the gradient table. Each table is one row of a texture, always
   1285         // y-clamp.
   1286         GrSamplerState samplerState(args.fWrapMode, GrSamplerState::Filter::kBilerp);
   1287 
   1288         fRow = fAtlas->lockRow(bitmap);
   1289         if (-1 != fRow) {
   1290             fYCoord = fAtlas->getYOffset(fRow)+SK_ScalarHalf*fAtlas->getNormalizedTexelHeight();
   1291             // This is 1/2 places where auto-normalization is disabled
   1292             fCoordTransform.reset(*args.fMatrix, fAtlas->asTextureProxyRef().get(), false);
   1293             fTextureSampler.reset(fAtlas->asTextureProxyRef(), samplerState);
   1294         } else {
   1295             // In this instance we know the samplerState state is:
   1296             //   clampY, bilerp
   1297             // and the proxy is:
   1298             //   exact fit, power of two in both dimensions
   1299             // Only the x-tileMode is unknown. However, given all the other knowns we know
   1300             // that GrMakeCachedBitmapProxy is sufficient (i.e., it won't need to be
   1301             // extracted to a subset or mipmapped).
   1302             sk_sp<GrTextureProxy> proxy = GrMakeCachedBitmapProxy(
   1303                                                      args.fContext->contextPriv().proxyProvider(),
   1304                                                      bitmap);
   1305             if (!proxy) {
   1306                 SkDebugf("Gradient won't draw. Could not create texture.");
   1307                 return;
   1308             }
   1309             // This is 2/2 places where auto-normalization is disabled
   1310             fCoordTransform.reset(*args.fMatrix, proxy.get(), false);
   1311             fTextureSampler.reset(std::move(proxy), samplerState);
   1312             fYCoord = SK_ScalarHalf;
   1313         }
   1314 
   1315         this->addTextureSampler(&fTextureSampler);
   1316     }
   1317 
   1318     this->addCoordTransform(&fCoordTransform);
   1319 }
   1320 
   1321 GrGradientEffect::GrGradientEffect(const GrGradientEffect& that)
   1322         : INHERITED(that.classID(), OptFlags(that.fIsOpaque))
   1323         , fIntervals(that.fIntervals)
   1324         , fWrapMode(that.fWrapMode)
   1325         , fCoordTransform(that.fCoordTransform)
   1326         , fTextureSampler(that.fTextureSampler)
   1327         , fYCoord(that.fYCoord)
   1328         , fAtlas(that.fAtlas)
   1329         , fRow(that.fRow)
   1330         , fIsOpaque(that.fIsOpaque)
   1331         , fStrategy(that.fStrategy)
   1332         , fThreshold(that.fThreshold)
   1333         , fPremulType(that.fPremulType) {
   1334     this->addCoordTransform(&fCoordTransform);
   1335     if (fStrategy == InterpolationStrategy::kTexture) {
   1336         this->addTextureSampler(&fTextureSampler);
   1337     }
   1338     if (this->useAtlas()) {
   1339         fAtlas->lockRow(fRow);
   1340     }
   1341 }
   1342 
   1343 GrGradientEffect::~GrGradientEffect() {
   1344     if (this->useAtlas()) {
   1345         fAtlas->unlockRow(fRow);
   1346     }
   1347 }
   1348 
   1349 bool GrGradientEffect::onIsEqual(const GrFragmentProcessor& processor) const {
   1350     const GrGradientEffect& ge = processor.cast<GrGradientEffect>();
   1351 
   1352     if (fWrapMode != ge.fWrapMode || fStrategy != ge.fStrategy) {
   1353         return false;
   1354     }
   1355 
   1356     SkASSERT(this->useAtlas() == ge.useAtlas());
   1357     if (fStrategy == InterpolationStrategy::kTexture) {
   1358         if (fYCoord != ge.fYCoord) {
   1359             return false;
   1360         }
   1361     } else {
   1362         if (fThreshold != ge.fThreshold ||
   1363             fIntervals != ge.fIntervals ||
   1364             fPremulType != ge.fPremulType) {
   1365             return false;
   1366         }
   1367     }
   1368     return true;
   1369 }
   1370 
   1371 #if GR_TEST_UTILS
   1372 GrGradientEffect::RandomGradientParams::RandomGradientParams(SkRandom* random) {
   1373     // Set color count to min of 2 so that we don't trigger the const color optimization and make
   1374     // a non-gradient processor.
   1375     fColorCount = random->nextRangeU(2, kMaxRandomGradientColors);
   1376     fUseColors4f = random->nextBool();
   1377 
   1378     // if one color, omit stops, otherwise randomly decide whether or not to
   1379     if (fColorCount == 1 || (fColorCount >= 2 && random->nextBool())) {
   1380         fStops = nullptr;
   1381     } else {
   1382         fStops = fStopStorage;
   1383     }
   1384 
   1385     // if using SkColor4f, attach a random (possibly null) color space (with linear gamma)
   1386     if (fUseColors4f) {
   1387         fColorSpace = GrTest::TestColorSpace(random);
   1388         if (fColorSpace) {
   1389             fColorSpace = fColorSpace->makeLinearGamma();
   1390         }
   1391     }
   1392 
   1393     SkScalar stop = 0.f;
   1394     for (int i = 0; i < fColorCount; ++i) {
   1395         if (fUseColors4f) {
   1396             fColors4f[i].fR = random->nextUScalar1();
   1397             fColors4f[i].fG = random->nextUScalar1();
   1398             fColors4f[i].fB = random->nextUScalar1();
   1399             fColors4f[i].fA = random->nextUScalar1();
   1400         } else {
   1401             fColors[i] = random->nextU();
   1402         }
   1403         if (fStops) {
   1404             fStops[i] = stop;
   1405             stop = i < fColorCount - 1 ? stop + random->nextUScalar1() * (1.f - stop) : 1.f;
   1406         }
   1407     }
   1408     fTileMode = static_cast<SkShader::TileMode>(random->nextULessThan(SkShader::kTileModeCount));
   1409 }
   1410 #endif
   1411 
   1412 #endif
   1413