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 #include "SkClampRange.h"
     14 #include "SkColorPriv.h"
     15 #include "SkReadBuffer.h"
     16 #include "SkWriteBuffer.h"
     17 #include "SkMallocPixelRef.h"
     18 #include "SkUtils.h"
     19 #include "SkShader.h"
     20 #include "SkOnce.h"
     21 
     22 static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
     23                                int count) {
     24     if (count > 0) {
     25         if (v0 == v1) {
     26             sk_memset32(dst, v0, count);
     27         } else {
     28             int pairs = count >> 1;
     29             for (int i = 0; i < pairs; i++) {
     30                 *dst++ = v0;
     31                 *dst++ = v1;
     32             }
     33             if (count & 1) {
     34                 *dst = v0;
     35             }
     36         }
     37     }
     38 }
     39 
     40 //  Clamp
     41 
     42 static inline SkFixed clamp_tileproc(SkFixed x) {
     43     return SkClampMax(x, 0xFFFF);
     44 }
     45 
     46 // Repeat
     47 
     48 static inline SkFixed repeat_tileproc(SkFixed x) {
     49     return x & 0xFFFF;
     50 }
     51 
     52 // Mirror
     53 
     54 // Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
     55 // See http://code.google.com/p/skia/issues/detail?id=472
     56 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
     57 #pragma optimize("", off)
     58 #endif
     59 
     60 static inline SkFixed mirror_tileproc(SkFixed x) {
     61     int s = SkLeftShift(x, 15) >> 31;
     62     return (x ^ s) & 0xFFFF;
     63 }
     64 
     65 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
     66 #pragma optimize("", on)
     67 #endif
     68 
     69 ///////////////////////////////////////////////////////////////////////////////
     70 
     71 typedef SkFixed (*TileProc)(SkFixed);
     72 
     73 ///////////////////////////////////////////////////////////////////////////////
     74 
     75 static const TileProc gTileProcs[] = {
     76     clamp_tileproc,
     77     repeat_tileproc,
     78     mirror_tileproc
     79 };
     80 
     81 ///////////////////////////////////////////////////////////////////////////////
     82 
     83 class SkGradientShaderBase : public SkShader {
     84 public:
     85     struct Descriptor {
     86         Descriptor() {
     87             sk_bzero(this, sizeof(*this));
     88             fTileMode = SkShader::kClamp_TileMode;
     89         }
     90 
     91         const SkMatrix*     fLocalMatrix;
     92         const SkColor*      fColors;
     93         const SkScalar*     fPos;
     94         int                 fCount;
     95         SkShader::TileMode  fTileMode;
     96         uint32_t            fGradFlags;
     97 
     98         void flatten(SkWriteBuffer&) const;
     99     };
    100 
    101     class DescriptorScope : public Descriptor {
    102     public:
    103         DescriptorScope() {}
    104 
    105         bool unflatten(SkReadBuffer&);
    106 
    107         // fColors and fPos always point into local memory, so they can be safely mutated
    108         //
    109         SkColor* mutableColors() { return const_cast<SkColor*>(fColors); }
    110         SkScalar* mutablePos() { return const_cast<SkScalar*>(fPos); }
    111 
    112     private:
    113         enum {
    114             kStorageCount = 16
    115         };
    116         SkColor fColorStorage[kStorageCount];
    117         SkScalar fPosStorage[kStorageCount];
    118         SkMatrix fLocalMatrixStorage;
    119         SkAutoMalloc fDynamicStorage;
    120     };
    121 
    122 public:
    123     SkGradientShaderBase(const Descriptor& desc, const SkMatrix& ptsToUnit);
    124     virtual ~SkGradientShaderBase();
    125 
    126     // The cache is initialized on-demand when getCache16/32 is called.
    127     class GradientShaderCache : public SkRefCnt {
    128     public:
    129         GradientShaderCache(U8CPU alpha, bool dither, const SkGradientShaderBase& shader);
    130         ~GradientShaderCache();
    131 
    132         const uint16_t*     getCache16();
    133         const SkPMColor*    getCache32();
    134 
    135         SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; }
    136 
    137         unsigned getAlpha() const { return fCacheAlpha; }
    138         bool getDither() const { return fCacheDither; }
    139 
    140     private:
    141         // Working pointers. If either is nullptr, we need to recompute the corresponding cache values.
    142         uint16_t*   fCache16;
    143         SkPMColor*  fCache32;
    144 
    145         uint16_t*         fCache16Storage;    // Storage for fCache16, allocated on demand.
    146         SkMallocPixelRef* fCache32PixelRef;
    147         const unsigned    fCacheAlpha;        // The alpha value we used when we computed the cache.
    148                                               // Larger than 8bits so we can store uninitialized
    149                                               // value.
    150         const bool        fCacheDither;       // The dither flag used when we computed the cache.
    151 
    152         const SkGradientShaderBase& fShader;
    153 
    154         // Make sure we only initialize the caches once.
    155         bool    fCache16Inited, fCache32Inited;
    156         SkMutex fCache16Mutex, fCache32Mutex;
    157 
    158         static void initCache16(GradientShaderCache* cache);
    159         static void initCache32(GradientShaderCache* cache);
    160 
    161         static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count, bool dither);
    162         static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
    163                                     U8CPU alpha, uint32_t gradFlags, bool dither);
    164     };
    165 
    166     class GradientShaderBaseContext : public SkShader::Context {
    167     public:
    168         GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
    169 
    170         uint32_t getFlags() const override { return fFlags; }
    171 
    172     protected:
    173         SkMatrix    fDstToIndex;
    174         SkMatrix::MapXYProc fDstToIndexProc;
    175         uint8_t     fDstToIndexClass;
    176         uint8_t     fFlags;
    177         bool        fDither;
    178 
    179         SkAutoTUnref<GradientShaderCache> fCache;
    180 
    181     private:
    182         typedef SkShader::Context INHERITED;
    183     };
    184 
    185     bool isOpaque() const override;
    186 
    187     void getGradientTableBitmap(SkBitmap*) const;
    188 
    189     enum {
    190         /// Seems like enough for visual accuracy. TODO: if pos[] deserves
    191         /// it, use a larger cache.
    192         kCache16Bits    = 8,
    193         kCache16Count = (1 << kCache16Bits),
    194         kCache16Shift   = 16 - kCache16Bits,
    195         kSqrt16Shift    = 8 - kCache16Bits,
    196 
    197         /// Seems like enough for visual accuracy. TODO: if pos[] deserves
    198         /// it, use a larger cache.
    199         kCache32Bits    = 8,
    200         kCache32Count   = (1 << kCache32Bits),
    201         kCache32Shift   = 16 - kCache32Bits,
    202         kSqrt32Shift    = 8 - kCache32Bits,
    203 
    204         /// This value is used to *read* the dither cache; it may be 0
    205         /// if dithering is disabled.
    206         kDitherStride32 = kCache32Count,
    207         kDitherStride16 = kCache16Count,
    208     };
    209 
    210     enum GpuColorType {
    211         kTwo_GpuColorType,
    212         kThree_GpuColorType, // Symmetric three color
    213         kTexture_GpuColorType
    214     };
    215 
    216     // Determines and returns the gradient is a two color gradient, symmetric three color gradient
    217     // or other (texture gradient). If it is two or symmetric three color, the colors array will
    218     // also be filled with the gradient colors
    219     GpuColorType getGpuColorType(SkColor colors[3]) const;
    220 
    221     uint32_t getGradFlags() const { return fGradFlags; }
    222 
    223 protected:
    224     class GradientShaderBase4fContext;
    225 
    226     SkGradientShaderBase(SkReadBuffer& );
    227     void flatten(SkWriteBuffer&) const override;
    228     SK_TO_STRING_OVERRIDE()
    229 
    230     const SkMatrix fPtsToUnit;
    231     TileMode    fTileMode;
    232     TileProc    fTileProc;
    233     int         fColorCount;
    234     uint8_t     fGradFlags;
    235 
    236     struct Rec {
    237         SkFixed     fPos;   // 0...1
    238         uint32_t    fScale; // (1 << 24) / range
    239     };
    240     Rec*        fRecs;
    241 
    242     void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
    243 
    244     bool onAsLuminanceColor(SkColor*) const override;
    245 
    246     /*
    247      * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively.
    248      * Count is the number of colors in the gradient
    249      * It will then flip all the color and rec information and return in their respective Dst
    250      * pointers. It is assumed that space has already been allocated for the Dst pointers.
    251      * The rec src and dst are only assumed to be valid if count > 2
    252      */
    253     static void FlipGradientColors(SkColor* colorDst, Rec* recDst,
    254                                    SkColor* colorSrc, Rec* recSrc,
    255                                    int count);
    256 
    257 private:
    258     enum {
    259         kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
    260 
    261         kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(SkScalar) + sizeof(Rec))
    262     };
    263     SkColor     fStorage[(kStorageSize + 3) >> 2];
    264 public:
    265     SkColor*    fOrigColors; // original colors, before modulation by paint in context.
    266     SkScalar*   fOrigPos;   // original positions
    267 
    268     bool colorsAreOpaque() const { return fColorsAreOpaque; }
    269 
    270 private:
    271     bool        fColorsAreOpaque;
    272 
    273     GradientShaderCache* refCache(U8CPU alpha, bool dither) const;
    274     mutable SkMutex                           fCacheMutex;
    275     mutable SkAutoTUnref<GradientShaderCache> fCache;
    276 
    277     void initCommon();
    278 
    279     typedef SkShader INHERITED;
    280 };
    281 
    282 static inline int init_dither_toggle(int x, int y) {
    283     x &= 1;
    284     y = (y & 1) << 1;
    285     return (x | y) * SkGradientShaderBase::kDitherStride32;
    286 }
    287 
    288 static inline int next_dither_toggle(int toggle) {
    289     return toggle ^ SkGradientShaderBase::kDitherStride32;
    290 }
    291 
    292 static inline int init_dither_toggle16(int x, int y) {
    293     return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride16;
    294 }
    295 
    296 static inline int next_dither_toggle16(int toggle) {
    297     return toggle ^ SkGradientShaderBase::kDitherStride16;
    298 }
    299 
    300 ///////////////////////////////////////////////////////////////////////////////
    301 
    302 #if SK_SUPPORT_GPU
    303 
    304 #include "GrCoordTransform.h"
    305 #include "GrFragmentProcessor.h"
    306 #include "glsl/GrGLSLFragmentProcessor.h"
    307 #include "glsl/GrGLSLProgramDataManager.h"
    308 
    309 class GrInvariantOutput;
    310 
    311 /*
    312  * The interpretation of the texture matrix depends on the sample mode. The
    313  * texture matrix is applied both when the texture coordinates are explicit
    314  * and  when vertex positions are used as texture  coordinates. In the latter
    315  * case the texture matrix is applied to the pre-view-matrix position
    316  * values.
    317  *
    318  * Normal SampleMode
    319  *  The post-matrix texture coordinates are in normalize space with (0,0) at
    320  *  the top-left and (1,1) at the bottom right.
    321  * RadialGradient
    322  *  The matrix specifies the radial gradient parameters.
    323  *  (0,0) in the post-matrix space is center of the radial gradient.
    324  * Radial2Gradient
    325  *   Matrix transforms to space where first circle is centered at the
    326  *   origin. The second circle will be centered (x, 0) where x may be
    327  *   0 and is provided by setRadial2Params. The post-matrix space is
    328  *   normalized such that 1 is the second radius - first radius.
    329  * SweepGradient
    330  *  The angle from the origin of texture coordinates in post-matrix space
    331  *  determines the gradient value.
    332  */
    333 
    334  class GrTextureStripAtlas;
    335 
    336 // Base class for Gr gradient effects
    337 class GrGradientEffect : public GrFragmentProcessor {
    338 public:
    339 
    340     GrGradientEffect(GrContext* ctx,
    341                      const SkGradientShaderBase& shader,
    342                      const SkMatrix& matrix,
    343                      SkShader::TileMode tileMode);
    344 
    345     virtual ~GrGradientEffect();
    346 
    347     bool useAtlas() const { return SkToBool(-1 != fRow); }
    348     SkScalar getYCoord() const { return fYCoord; };
    349 
    350     SkGradientShaderBase::GpuColorType getColorType() const { return fColorType; }
    351 
    352     enum PremulType {
    353         kBeforeInterp_PremulType,
    354         kAfterInterp_PremulType,
    355     };
    356 
    357     PremulType getPremulType() const { return fPremulType; }
    358 
    359     const SkColor* getColors(int pos) const {
    360         SkASSERT(fColorType != SkGradientShaderBase::kTexture_GpuColorType);
    361         SkASSERT((pos-1) <= fColorType);
    362         return &fColors[pos];
    363     }
    364 
    365 protected:
    366 
    367     /** Populates a pair of arrays with colors and stop info to construct a random gradient.
    368         The function decides whether stop values should be used or not. The return value indicates
    369         the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
    370         sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
    371         size kMaxRandomGradientColors. It may be updated to nullptr, indicating that nullptr should be
    372         passed to the gradient factory rather than the array.
    373     */
    374     static const int kMaxRandomGradientColors = 4;
    375     static int RandomGradientParams(SkRandom* r,
    376                                     SkColor colors[kMaxRandomGradientColors],
    377                                     SkScalar** stops,
    378                                     SkShader::TileMode* tm);
    379 
    380     bool onIsEqual(const GrFragmentProcessor&) const override;
    381 
    382     void onComputeInvariantOutput(GrInvariantOutput* inout) const override;
    383 
    384     const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
    385 
    386 private:
    387     static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
    388 
    389     GrCoordTransform fCoordTransform;
    390     GrTextureAccess fTextureAccess;
    391     SkScalar fYCoord;
    392     GrTextureStripAtlas* fAtlas;
    393     int fRow;
    394     bool fIsOpaque;
    395     SkGradientShaderBase::GpuColorType fColorType;
    396     SkColor fColors[3]; // More than 3 colors we use texture
    397     PremulType fPremulType; // This only changes behavior for two and three color special cases.
    398                             // It is already baked into to the table for texture gradients.
    399     typedef GrFragmentProcessor INHERITED;
    400 
    401 };
    402 
    403 ///////////////////////////////////////////////////////////////////////////////
    404 
    405 // Base class for GL gradient effects
    406 class GrGLGradientEffect : public GrGLSLFragmentProcessor {
    407 public:
    408     GrGLGradientEffect();
    409 
    410 protected:
    411     void onSetData(const GrGLSLProgramDataManager&, const GrProcessor&) override;
    412 
    413 protected:
    414     /**
    415      * Subclasses must call this. It will return a key for the part of the shader code controlled
    416      * by the base class. The subclasses must stick it in their key and then pass it to the below
    417      * emit* functions from their emitCode function.
    418      */
    419     static uint32_t GenBaseGradientKey(const GrProcessor&);
    420 
    421     // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
    422     // should call this method from their emitCode().
    423     void emitUniforms(GrGLSLUniformHandler*, const GrGradientEffect&);
    424 
    425 
    426     // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
    427     // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
    428     // native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
    429     void emitColor(GrGLSLFPFragmentBuilder* fragBuilder,
    430                    GrGLSLUniformHandler* uniformHandler,
    431                    const GrGLSLCaps* caps,
    432                    const GrGradientEffect&,
    433                    const char* gradientTValue,
    434                    const char* outputColor,
    435                    const char* inputColor,
    436                    const TextureSamplerArray& samplers);
    437 
    438 private:
    439     enum {
    440         kPremulTypeKeyBitCnt = 1,
    441         kPremulTypeMask = 1,
    442         kPremulBeforeInterpKey = kPremulTypeMask,
    443 
    444         kTwoColorKey = 2 << kPremulTypeKeyBitCnt,
    445         kThreeColorKey = 3 << kPremulTypeKeyBitCnt,
    446         kColorKeyMask = kTwoColorKey | kThreeColorKey,
    447         kColorKeyBitCnt = 2,
    448 
    449         // Subclasses must shift any key bits they produce up by this amount
    450         // and combine with the result of GenBaseGradientKey.
    451         kBaseKeyBitCnt = (kPremulTypeKeyBitCnt + kColorKeyBitCnt)
    452     };
    453     GR_STATIC_ASSERT(kBaseKeyBitCnt <= 32);
    454 
    455     SkScalar fCachedYCoord;
    456     GrGLSLProgramDataManager::UniformHandle fFSYUni;
    457     GrGLSLProgramDataManager::UniformHandle fColorStartUni;
    458     GrGLSLProgramDataManager::UniformHandle fColorMidUni;
    459     GrGLSLProgramDataManager::UniformHandle fColorEndUni;
    460 
    461     typedef GrGLSLFragmentProcessor INHERITED;
    462 };
    463 
    464 #endif
    465 
    466 #endif
    467