LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/effects/gradients - SkGradientShaderPriv.h (source / functions) Hit Total Coverage
Test: output.info Lines: 24 70 34.3 %
Date: 2017-07-14 16:53:18 Functions: 10 40 25.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13