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