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