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 "SkFlattenableBuffers.h"
15#include "SkMallocPixelRef.h"
16#include "SkUnitMapper.h"
17#include "SkUtils.h"
18#include "SkTemplates.h"
19#include "SkBitmapCache.h"
20#include "SkShader.h"
21
22static 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
42static inline SkFixed clamp_tileproc(SkFixed x) {
43    return SkClampMax(x, 0xFFFF);
44}
45
46// Repeat
47
48static 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
60static inline SkFixed mirror_tileproc(SkFixed x) {
61    int s = 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
71typedef SkFixed (*TileProc)(SkFixed);
72
73///////////////////////////////////////////////////////////////////////////////
74
75static const TileProc gTileProcs[] = {
76    clamp_tileproc,
77    repeat_tileproc,
78    mirror_tileproc
79};
80
81///////////////////////////////////////////////////////////////////////////////
82
83class SkGradientShaderBase : public SkShader {
84public:
85    struct Descriptor {
86        Descriptor() {
87            sk_bzero(this, sizeof(*this));
88            fTileMode = SkShader::kClamp_TileMode;
89        }
90
91        const SkColor*      fColors;
92        const SkScalar*     fPos;
93        int                 fCount;
94        SkShader::TileMode  fTileMode;
95        SkUnitMapper*       fMapper;
96        uint32_t            fFlags;
97    };
98
99public:
100    SkGradientShaderBase(const Descriptor& desc);
101    virtual ~SkGradientShaderBase();
102
103    virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
104    virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
105    virtual bool isOpaque() const SK_OVERRIDE;
106
107    void getGradientTableBitmap(SkBitmap*) const;
108
109    enum {
110        /// Seems like enough for visual accuracy. TODO: if pos[] deserves
111        /// it, use a larger cache.
112        kCache16Bits    = 8,
113        kCache16Count = (1 << kCache16Bits),
114        kCache16Shift   = 16 - kCache16Bits,
115        kSqrt16Shift    = 8 - kCache16Bits,
116
117        /// Seems like enough for visual accuracy. TODO: if pos[] deserves
118        /// it, use a larger cache.
119        kCache32Bits    = 8,
120        kCache32Count   = (1 << kCache32Bits),
121        kCache32Shift   = 16 - kCache32Bits,
122        kSqrt32Shift    = 8 - kCache32Bits,
123
124        /// This value is used to *read* the dither cache; it may be 0
125        /// if dithering is disabled.
126        kDitherStride32 = kCache32Count,
127        kDitherStride16 = kCache16Count,
128    };
129
130
131protected:
132    SkGradientShaderBase(SkFlattenableReadBuffer& );
133    virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
134    SK_DEVELOPER_TO_STRING()
135
136    SkUnitMapper* fMapper;
137    SkMatrix    fPtsToUnit;     // set by subclass
138    SkMatrix    fDstToIndex;
139    SkMatrix::MapXYProc fDstToIndexProc;
140    TileMode    fTileMode;
141    TileProc    fTileProc;
142    int         fColorCount;
143    uint8_t     fDstToIndexClass;
144    uint8_t     fFlags;
145    uint8_t     fGradFlags;
146
147    struct Rec {
148        SkFixed     fPos;   // 0...1
149        uint32_t    fScale; // (1 << 24) / range
150    };
151    Rec*        fRecs;
152
153    const uint16_t*     getCache16() const;
154    const SkPMColor*    getCache32() const;
155
156    void commonAsAGradient(GradientInfo*) const;
157
158private:
159    enum {
160        kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
161
162        kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
163    };
164    SkColor     fStorage[(kStorageSize + 3) >> 2];
165    SkColor*    fOrigColors; // original colors, before modulation by paint in setContext
166    bool        fColorsAreOpaque;
167
168    mutable uint16_t*   fCache16;   // working ptr. If this is NULL, we need to recompute the cache values
169    mutable SkPMColor*  fCache32;   // working ptr. If this is NULL, we need to recompute the cache values
170
171    mutable uint16_t*   fCache16Storage;    // storage for fCache16, allocated on demand
172    mutable SkMallocPixelRef* fCache32PixelRef;
173    mutable unsigned    fCacheAlpha;        // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
174
175    static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
176    static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
177                                U8CPU alpha, uint32_t gradFlags);
178    void setCacheAlpha(U8CPU alpha) const;
179    void initCommon();
180
181    typedef SkShader INHERITED;
182};
183
184static inline int init_dither_toggle(int x, int y) {
185    x &= 1;
186    y = (y & 1) << 1;
187    return (x | y) * SkGradientShaderBase::kDitherStride32;
188}
189
190static inline int next_dither_toggle(int toggle) {
191    return toggle ^ SkGradientShaderBase::kDitherStride32;
192}
193
194static inline int init_dither_toggle16(int x, int y) {
195    return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride16;
196}
197
198static inline int next_dither_toggle16(int toggle) {
199    return toggle ^ SkGradientShaderBase::kDitherStride16;
200}
201
202///////////////////////////////////////////////////////////////////////////////
203
204#if SK_SUPPORT_GPU
205
206#include "GrCoordTransform.h"
207#include "gl/GrGLEffect.h"
208
209class GrEffectStage;
210class GrBackendEffectFactory;
211
212/*
213 * The interpretation of the texture matrix depends on the sample mode. The
214 * texture matrix is applied both when the texture coordinates are explicit
215 * and  when vertex positions are used as texture  coordinates. In the latter
216 * case the texture matrix is applied to the pre-view-matrix position
217 * values.
218 *
219 * Normal SampleMode
220 *  The post-matrix texture coordinates are in normalize space with (0,0) at
221 *  the top-left and (1,1) at the bottom right.
222 * RadialGradient
223 *  The matrix specifies the radial gradient parameters.
224 *  (0,0) in the post-matrix space is center of the radial gradient.
225 * Radial2Gradient
226 *   Matrix transforms to space where first circle is centered at the
227 *   origin. The second circle will be centered (x, 0) where x may be
228 *   0 and is provided by setRadial2Params. The post-matrix space is
229 *   normalized such that 1 is the second radius - first radius.
230 * SweepGradient
231 *  The angle from the origin of texture coordinates in post-matrix space
232 *  determines the gradient value.
233 */
234
235 class GrTextureStripAtlas;
236
237// Base class for Gr gradient effects
238class GrGradientEffect : public GrEffect {
239public:
240
241    GrGradientEffect(GrContext* ctx,
242                     const SkGradientShaderBase& shader,
243                     const SkMatrix& matrix,
244                     SkShader::TileMode tileMode);
245
246    virtual ~GrGradientEffect();
247
248    bool useAtlas() const { return SkToBool(-1 != fRow); }
249    SkScalar getYCoord() const { return fYCoord; };
250
251    virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
252
253    enum ColorType {
254        kTwo_ColorType,
255        kThree_ColorType,
256        kTexture_ColorType
257    };
258
259    ColorType getColorType() const { return fColorType; }
260
261    enum PremulType {
262        kBeforeInterp_PremulType,
263        kAfterInterp_PremulType,
264    };
265
266    PremulType getPremulType() const { return fPremulType; }
267
268    const SkColor* getColors(int pos) const {
269        SkASSERT(fColorType != kTexture_ColorType);
270        SkASSERT((pos-1) <= fColorType);
271        return &fColors[pos];
272    }
273
274protected:
275
276    /** Populates a pair of arrays with colors and stop info to construct a random gradient.
277        The function decides whether stop values should be used or not. The return value indicates
278        the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
279        sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
280        size kMaxRandomGradientColors. It may be updated to NULL, indicating that NULL should be
281        passed to the gradient factory rather than the array.
282    */
283    static const int kMaxRandomGradientColors = 4;
284    static int RandomGradientParams(SkRandom* r,
285                                    SkColor colors[kMaxRandomGradientColors],
286                                    SkScalar** stops,
287                                    SkShader::TileMode* tm);
288
289    virtual bool onIsEqual(const GrEffect& effect) const SK_OVERRIDE;
290
291    const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
292
293private:
294    static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
295
296    enum {
297        kMaxAnalyticColors = 3 // if more colors use texture
298    };
299
300    GrCoordTransform fCoordTransform;
301    GrTextureAccess fTextureAccess;
302    SkScalar fYCoord;
303    GrTextureStripAtlas* fAtlas;
304    int fRow;
305    bool fIsOpaque;
306    ColorType fColorType;
307    SkColor fColors[kMaxAnalyticColors];
308    PremulType fPremulType; // This only changes behavior for two and three color special cases.
309                            // It is already baked into to the table for texture gradients.
310    typedef GrEffect INHERITED;
311
312};
313
314///////////////////////////////////////////////////////////////////////////////
315
316// Base class for GL gradient effects
317class GrGLGradientEffect : public GrGLEffect {
318public:
319    GrGLGradientEffect(const GrBackendEffectFactory& factory);
320    virtual ~GrGLGradientEffect();
321
322    virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
323
324protected:
325    enum {
326        kPremulTypeKeyBitCnt = 1,
327        kPremulTypeMask = 1,
328        kPremulBeforeInterpKey = kPremulTypeMask,
329
330        kTwoColorKey = 2 << kPremulTypeKeyBitCnt,
331        kThreeColorKey = 3 << kPremulTypeKeyBitCnt,
332        kColorKeyMask = kTwoColorKey | kThreeColorKey,
333        kColorKeyBitCnt = 2,
334
335        // Subclasses must shift any key bits they produce up by this amount
336        // and combine with the result of GenBaseGradientKey.
337        kBaseKeyBitCnt = (kPremulTypeKeyBitCnt + kColorKeyBitCnt)
338    };
339
340    static GrGradientEffect::ColorType ColorTypeFromKey(EffectKey key){
341        if (kTwoColorKey == (key & kColorKeyMask)) {
342            return GrGradientEffect::kTwo_ColorType;
343        } else if (kThreeColorKey == (key & kColorKeyMask)) {
344            return GrGradientEffect::kThree_ColorType;
345        } else {return GrGradientEffect::kTexture_ColorType;}
346    }
347
348    static GrGradientEffect::PremulType PremulTypeFromKey(EffectKey key){
349        if (kPremulBeforeInterpKey == (key & kPremulTypeMask)) {
350            return GrGradientEffect::kBeforeInterp_PremulType;
351        } else {
352            return GrGradientEffect::kAfterInterp_PremulType;
353        }
354    }
355
356    /**
357     * Subclasses must call this. It will return a value restricted to the lower kBaseKeyBitCnt
358     * bits.
359     */
360    static EffectKey GenBaseGradientKey(const GrDrawEffect&);
361
362    // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
363    // should call this method from their emitCode().
364    void emitUniforms(GrGLShaderBuilder* builder, EffectKey key);
365
366
367    // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
368    // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
369    // native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
370    void emitColor(GrGLShaderBuilder* builder,
371                   const char* gradientTValue,
372                   EffectKey key,
373                   const char* outputColor,
374                   const char* inputColor,
375                   const TextureSamplerArray& samplers);
376
377private:
378    SkScalar fCachedYCoord;
379    GrGLUniformManager::UniformHandle fFSYUni;
380    GrGLUniformManager::UniformHandle fColorStartUni;
381    GrGLUniformManager::UniformHandle fColorMidUni;
382    GrGLUniformManager::UniformHandle fColorEndUni;
383
384    typedef GrGLEffect INHERITED;
385};
386
387#endif
388
389#endif
390