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