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