Home | History | Annotate | Download | only in gradients
      1 /*
      2  * Copyright 2012 Google Inc.
      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 #ifndef SkGradientShaderPriv_DEFINED
      9 #define SkGradientShaderPriv_DEFINED
     10 
     11 #include "SkGradientBitmapCache.h"
     12 #include "SkGradientShader.h"
     13 
     14 #include "SkArenaAlloc.h"
     15 #include "SkAutoMalloc.h"
     16 #include "SkClampRange.h"
     17 #include "SkColorPriv.h"
     18 #include "SkColorSpace.h"
     19 #include "SkMallocPixelRef.h"
     20 #include "SkOnce.h"
     21 #include "SkReadBuffer.h"
     22 #include "SkShader.h"
     23 #include "SkUtils.h"
     24 #include "SkWriteBuffer.h"
     25 
     26 #if SK_SUPPORT_GPU
     27     #define GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS 1
     28 #endif
     29 
     30 static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
     31                                int count) {
     32     if (count > 0) {
     33         if (v0 == v1) {
     34             sk_memset32(dst, v0, count);
     35         } else {
     36             int pairs = count >> 1;
     37             for (int i = 0; i < pairs; i++) {
     38                 *dst++ = v0;
     39                 *dst++ = v1;
     40             }
     41             if (count & 1) {
     42                 *dst = v0;
     43             }
     44         }
     45     }
     46 }
     47 
     48 //  Clamp
     49 
     50 static inline SkFixed clamp_tileproc(SkFixed x) {
     51     return SkClampMax(x, 0xFFFF);
     52 }
     53 
     54 // Repeat
     55 
     56 static inline SkFixed repeat_tileproc(SkFixed x) {
     57     return x & 0xFFFF;
     58 }
     59 
     60 // Mirror
     61 
     62 static inline SkFixed mirror_tileproc(SkFixed x) {
     63     int s = SkLeftShift(x, 15) >> 31;
     64     return (x ^ s) & 0xFFFF;
     65 }
     66 
     67 ///////////////////////////////////////////////////////////////////////////////
     68 
     69 typedef SkFixed (*TileProc)(SkFixed);
     70 
     71 ///////////////////////////////////////////////////////////////////////////////
     72 
     73 static const TileProc gTileProcs[] = {
     74     clamp_tileproc,
     75     repeat_tileproc,
     76     mirror_tileproc
     77 };
     78 
     79 ///////////////////////////////////////////////////////////////////////////////
     80 
     81 class SkGradientShaderBase : public SkShader {
     82 public:
     83     struct Descriptor {
     84         Descriptor() {
     85             sk_bzero(this, sizeof(*this));
     86             fTileMode = SkShader::kClamp_TileMode;
     87         }
     88 
     89         const SkMatrix*     fLocalMatrix;
     90         const SkColor4f*    fColors;
     91         sk_sp<SkColorSpace> fColorSpace;
     92         const SkScalar*     fPos;
     93         int                 fCount;
     94         SkShader::TileMode  fTileMode;
     95         uint32_t            fGradFlags;
     96 
     97         void flatten(SkWriteBuffer&) const;
     98     };
     99 
    100     class DescriptorScope : public Descriptor {
    101     public:
    102         DescriptorScope() {}
    103 
    104         bool unflatten(SkReadBuffer&);
    105 
    106         // fColors and fPos always point into local memory, so they can be safely mutated
    107         //
    108         SkColor4f* mutableColors() { return const_cast<SkColor4f*>(fColors); }
    109         SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
    110 
    111     private:
    112         enum {
    113             kStorageCount = 16
    114         };
    115         SkColor4f fColorStorage[kStorageCount];
    116         SkScalar fPosStorage[kStorageCount];
    117         SkMatrix fLocalMatrixStorage;
    118         SkAutoMalloc fDynamicStorage;
    119     };
    120 
    121     SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
    122     ~SkGradientShaderBase() override;
    123 
    124     // The cache is initialized on-demand when getCache32 is called.
    125     class GradientShaderCache : public SkRefCnt {
    126     public:
    127         GradientShaderCache(U8CPU alpha, bool dither, const SkGradientShaderBase& shader);
    128         ~GradientShaderCache();
    129 
    130         const SkPMColor*    getCache32();
    131 
    132         SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; }
    133 
    134         unsigned getAlpha() const { return fCacheAlpha; }
    135         bool getDither() const { return fCacheDither; }
    136 
    137     private:
    138         // Working pointer. If it's nullptr, we need to recompute the cache values.
    139         SkPMColor*  fCache32;
    140 
    141         SkMallocPixelRef* fCache32PixelRef;
    142         const unsigned    fCacheAlpha;        // The alpha value we used when we computed the cache.
    143                                               // Larger than 8bits so we can store uninitialized
    144                                               // value.
    145         const bool        fCacheDither;       // The dither flag used when we computed the cache.
    146 
    147         const SkGradientShaderBase& fShader;
    148 
    149         // Make sure we only initialize the cache once.
    150         SkOnce fCache32InitOnce;
    151 
    152         static void initCache32(GradientShaderCache* cache);
    153 
    154         static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
    155                                     U8CPU alpha, uint32_t gradFlags, bool dither);
    156     };
    157 
    158     class GradientShaderBaseContext : public SkShader::Context {
    159     public:
    160         GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
    161 
    162         uint32_t getFlags() const override { return fFlags; }
    163 
    164         bool isValid() const;
    165 
    166     protected:
    167         SkMatrix    fDstToIndex;
    168         SkMatrix::MapXYProc fDstToIndexProc;
    169         uint8_t     fDstToIndexClass;
    170         uint8_t     fFlags;
    171         bool        fDither;
    172 
    173         sk_sp<GradientShaderCache> fCache;
    174 
    175     private:
    176         typedef SkShader::Context INHERITED;
    177     };
    178 
    179     bool isOpaque() const override;
    180 
    181     enum class GradientBitmapType : uint8_t {
    182         kLegacy,
    183         kSRGB,
    184         kHalfFloat,
    185     };
    186 
    187     void getGradientTableBitmap(SkBitmap*, GradientBitmapType bitmapType) const;
    188 
    189     enum {
    190         /// Seems like enough for visual accuracy. TODO: if pos[] deserves
    191         /// it, use a larger cache.
    192         kCache32Bits    = 8,
    193         kCache32Count   = (1 << kCache32Bits),
    194         kCache32Shift   = 16 - kCache32Bits,
    195         kSqrt32Shift    = 8 - kCache32Bits,
    196 
    197         /// This value is used to *read* the dither cache; it may be 0
    198         /// if dithering is disabled.
    199         kDitherStride32 = kCache32Count,
    200     };
    201 
    202     uint32_t getGradFlags() const { return fGradFlags; }
    203 
    204 protected:
    205     class GradientShaderBase4fContext;
    206 
    207     SkGradientShaderBase(SkReadBuffer& );
    208     void flatten(SkWriteBuffer&) const override;
    209     SK_TO_STRING_OVERRIDE()
    210 
    211     const SkMatrix fPtsToUnit;
    212     TileMode    fTileMode;
    213     TileProc    fTileProc;
    214     uint8_t     fGradFlags;
    215 
    216     struct Rec {
    217         SkFixed     fPos;   // 0...1
    218         uint32_t    fScale; // (1 << 24) / range
    219     };
    220     Rec*        fRecs;
    221 
    222     void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
    223 
    224     bool onAsLuminanceColor(SkColor*) const override;
    225 
    226 
    227     void initLinearBitmap(SkBitmap* bitmap) const;
    228 
    229     /*
    230      * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively.
    231      * Count is the number of colors in the gradient
    232      * It will then flip all the color and rec information and return in their respective Dst
    233      * pointers. It is assumed that space has already been allocated for the Dst pointers.
    234      * The rec src and dst are only assumed to be valid if count > 2
    235      */
    236     static void FlipGradientColors(SkColor* colorDst, Rec* recDst,
    237                                    SkColor* colorSrc, Rec* recSrc,
    238                                    int count);
    239 
    240     template <typename T, typename... Args>
    241     static Context* CheckedMakeContext(SkArenaAlloc* alloc, Args&&... args) {
    242         auto* ctx = alloc->make<T>(std::forward<Args>(args)...);
    243         if (!ctx->isValid()) {
    244             return nullptr;
    245         }
    246         return ctx;
    247     }
    248 
    249 private:
    250     enum {
    251         kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
    252 
    253         kStorageSize = kColorStorageCount *
    254                        (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec) + sizeof(SkColor4f))
    255     };
    256     SkColor             fStorage[(kStorageSize + 3) >> 2];
    257 public:
    258     SkColor*            fOrigColors;   // original colors, before modulation by paint in context.
    259     SkColor4f*          fOrigColors4f; // original colors, as linear floats
    260     SkScalar*           fOrigPos;      // original positions
    261     int                 fColorCount;
    262     sk_sp<SkColorSpace> fColorSpace; // color space of gradient stops
    263 
    264     bool colorsAreOpaque() const { return fColorsAreOpaque; }
    265 
    266     TileMode getTileMode() const { return fTileMode; }
    267     Rec* getRecs() const { return fRecs; }
    268 
    269 private:
    270     bool                fColorsAreOpaque;
    271 
    272     sk_sp<GradientShaderCache> refCache(U8CPU alpha, bool dither) const;
    273     mutable SkMutex                    fCacheMutex;
    274     mutable sk_sp<GradientShaderCache> fCache;
    275 
    276     void initCommon();
    277 
    278     typedef SkShader INHERITED;
    279 };
    280 
    281 static inline int init_dither_toggle(int x, int y) {
    282     x &= 1;
    283     y = (y & 1) << 1;
    284     return (x | y) * SkGradientShaderBase::kDitherStride32;
    285 }
    286 
    287 static inline int next_dither_toggle(int toggle) {
    288     return toggle ^ SkGradientShaderBase::kDitherStride32;
    289 }
    290 
    291 ///////////////////////////////////////////////////////////////////////////////
    292 
    293 #if SK_SUPPORT_GPU
    294 
    295 #include "GrColorSpaceXform.h"
    296 #include "GrCoordTransform.h"
    297 #include "GrFragmentProcessor.h"
    298 #include "glsl/GrGLSLColorSpaceXformHelper.h"
    299 #include "glsl/GrGLSLFragmentProcessor.h"
    300 #include "glsl/GrGLSLProgramDataManager.h"
    301 
    302 class GrInvariantOutput;
    303 
    304 /*
    305  * The interpretation of the texture matrix depends on the sample mode. The
    306  * texture matrix is applied both when the texture coordinates are explicit
    307  * and  when vertex positions are used as texture  coordinates. In the latter
    308  * case the texture matrix is applied to the pre-view-matrix position
    309  * values.
    310  *
    311  * Normal SampleMode
    312  *  The post-matrix texture coordinates are in normalize space with (0,0) at
    313  *  the top-left and (1,1) at the bottom right.
    314  * RadialGradient
    315  *  The matrix specifies the radial gradient parameters.
    316  *  (0,0) in the post-matrix space is center of the radial gradient.
    317  * Radial2Gradient
    318  *   Matrix transforms to space where first circle is centered at the
    319  *   origin. The second circle will be centered (x, 0) where x may be
    320  *   0 and is provided by setRadial2Params. The post-matrix space is
    321  *   normalized such that 1 is the second radius - first radius.
    322  * SweepGradient
    323  *  The angle from the origin of texture coordinates in post-matrix space
    324  *  determines the gradient value.
    325  */
    326 
    327  class GrTextureStripAtlas;
    328 
    329 // Base class for Gr gradient effects
    330 class GrGradientEffect : public GrFragmentProcessor {
    331 public:
    332     struct CreateArgs {
    333         CreateArgs(GrContext* context,
    334                    const SkGradientShaderBase* shader,
    335                    const SkMatrix* matrix,
    336                    SkShader::TileMode tileMode,
    337                    sk_sp<GrColorSpaceXform> colorSpaceXform,
    338                    bool gammaCorrect)
    339             : fContext(context)
    340             , fShader(shader)
    341             , fMatrix(matrix)
    342             , fTileMode(tileMode)
    343             , fColorSpaceXform(std::move(colorSpaceXform))
    344             , fGammaCorrect(gammaCorrect) {}
    345 
    346         GrContext*                  fContext;
    347         const SkGradientShaderBase* fShader;
    348         const SkMatrix*             fMatrix;
    349         SkShader::TileMode          fTileMode;
    350         sk_sp<GrColorSpaceXform>    fColorSpaceXform;
    351         bool                        fGammaCorrect;
    352     };
    353 
    354     class GLSLProcessor;
    355 
    356     ~GrGradientEffect() override;
    357 
    358     bool useAtlas() const { return SkToBool(-1 != fRow); }
    359     SkScalar getYCoord() const { return fYCoord; }
    360 
    361     enum ColorType {
    362         kTwo_ColorType,
    363         kThree_ColorType, // Symmetric three color
    364         kTexture_ColorType,
    365 
    366 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
    367         kSingleHardStop_ColorType,     // 0, t, t, 1
    368         kHardStopLeftEdged_ColorType,  // 0, 0, 1
    369         kHardStopRightEdged_ColorType, // 0, 1, 1
    370 #endif
    371     };
    372 
    373     ColorType getColorType() const { return fColorType; }
    374 
    375     // Determines the type of gradient, one of:
    376     //    - Two-color
    377     //    - Symmetric three-color
    378     //    - Texture
    379     //    - Centered hard stop
    380     //    - Left-edged hard stop
    381     //    - Right-edged hard stop
    382     ColorType determineColorType(const SkGradientShaderBase& shader);
    383 
    384     enum PremulType {
    385         kBeforeInterp_PremulType,
    386         kAfterInterp_PremulType,
    387     };
    388 
    389     PremulType getPremulType() const { return fPremulType; }
    390 
    391     const SkColor* getColors(int pos) const {
    392         SkASSERT(fColorType != kTexture_ColorType);
    393         SkASSERT(pos < fColors.count());
    394         return &fColors[pos];
    395     }
    396 
    397     const SkColor4f* getColors4f(int pos) const {
    398         SkASSERT(fColorType != kTexture_ColorType);
    399         SkASSERT(pos < fColors4f.count());
    400         return &fColors4f[pos];
    401     }
    402 
    403 protected:
    404     GrGradientEffect(const CreateArgs&, bool isOpaque);
    405 
    406     #if GR_TEST_UTILS
    407     /** Helper struct that stores (and populates) parameters to construct a random gradient.
    408         If fUseColors4f is true, then the SkColor4f factory should be called, with fColors4f and
    409         fColorSpace. Otherwise, the SkColor factory should be called, with fColors. fColorCount
    410         will be the number of color stops in either case, and fColors and fStops can be passed to
    411         the gradient factory. (The constructor may decide not to use stops, in which case fStops
    412         will be nullptr). */
    413     struct RandomGradientParams {
    414         static const int kMaxRandomGradientColors = 5;
    415 
    416         RandomGradientParams(SkRandom* r);
    417 
    418         bool fUseColors4f;
    419         SkColor fColors[kMaxRandomGradientColors];
    420         SkColor4f fColors4f[kMaxRandomGradientColors];
    421         sk_sp<SkColorSpace> fColorSpace;
    422         SkScalar fStopStorage[kMaxRandomGradientColors];
    423         SkShader::TileMode fTileMode;
    424         int fColorCount;
    425         SkScalar* fStops;
    426     };
    427     #endif
    428 
    429     bool onIsEqual(const GrFragmentProcessor&) const override;
    430 
    431     const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
    432 
    433 private:
    434     static OptimizationFlags OptFlags(bool isOpaque);
    435 
    436     // If we're in legacy mode, then fColors will be populated. If we're gamma-correct, then
    437     // fColors4f and fColorSpaceXform will be populated.
    438     SkTDArray<SkColor>       fColors;
    439 
    440     SkTDArray<SkColor4f>     fColors4f;
    441     sk_sp<GrColorSpaceXform> fColorSpaceXform;
    442 
    443     SkTDArray<SkScalar>      fPositions;
    444     SkShader::TileMode       fTileMode;
    445 
    446     GrCoordTransform fCoordTransform;
    447     TextureSampler fTextureSampler;
    448     SkScalar fYCoord;
    449     GrTextureStripAtlas* fAtlas;
    450     int fRow;
    451     bool fIsOpaque;
    452     ColorType fColorType;
    453     PremulType fPremulType; // This is already baked into the table for texture gradients, and
    454                             // only changes behavior for gradients that don't use a texture.
    455     typedef GrFragmentProcessor INHERITED;
    456 
    457 };
    458 
    459 ///////////////////////////////////////////////////////////////////////////////
    460 
    461 // Base class for GL gradient effects
    462 class GrGradientEffect::GLSLProcessor : public GrGLSLFragmentProcessor {
    463 public:
    464     GLSLProcessor() {
    465         fCachedYCoord = SK_ScalarMax;
    466     }
    467 
    468 protected:
    469     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
    470 
    471 protected:
    472     /**
    473      * Subclasses must call this. It will return a key for the part of the shader code controlled
    474      * by the base class. The subclasses must stick it in their key and then pass it to the below
    475      * emit* functions from their emitCode function.
    476      */
    477     static uint32_t GenBaseGradientKey(const GrProcessor&);
    478 
    479     // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
    480     // should call this method from their emitCode().
    481     void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
    482 
    483     // Emit code that gets a fragment's color from an expression for t; has branches for
    484     // several control flows inside -- 2-color gradients, 3-color symmetric gradients, 4+
    485     // color gradients that use the traditional texture lookup, as well as several varieties
    486     // of hard stop gradients
    487     void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
    488                    GrGLSLUniformHandler* uniformHandler,
    489                    const GrShaderCaps* shaderCaps,
    490                    const GrGradientEffect&,
    491                    const char* gradientTValue,
    492                    const char* outputColor,
    493                    const char* inputColor,
    494                    const TextureSamplers&);
    495 
    496 private:
    497     enum {
    498         // First bit for premul before/after interp
    499         kPremulBeforeInterpKey  =  1,
    500 
    501         // Next three bits for 2/3 color type or different special
    502         // hard stop cases (neither means using texture atlas)
    503         kTwoColorKey            =  2,
    504         kThreeColorKey          =  4,
    505 #if GR_GL_USE_ACCURATE_HARD_STOP_GRADIENTS
    506         kHardStopCenteredKey    =  6,
    507         kHardStopZeroZeroOneKey =  8,
    508         kHardStopZeroOneOneKey  = 10,
    509 
    510         // Next two bits for tile mode
    511         kClampTileMode          = 16,
    512         kRepeatTileMode         = 32,
    513         kMirrorTileMode         = 48,
    514 
    515         // Lower six bits for premul, 2/3 color type, and tile mode
    516         kReservedBits           = 6,
    517 #endif
    518     };
    519 
    520     SkScalar fCachedYCoord;
    521     GrGLSLProgramDataManager::UniformHandle fColorsUni;
    522     GrGLSLProgramDataManager::UniformHandle fHardStopT;
    523     GrGLSLProgramDataManager::UniformHandle fFSYUni;
    524     GrGLSLColorSpaceXformHelper             fColorSpaceHelper;
    525 
    526     typedef GrGLSLFragmentProcessor INHERITED;
    527 };
    528 
    529 #endif
    530 
    531 #endif
    532