2 * Copyright 2012 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #ifndef SkGradientShaderPriv_DEFINED
9 #define SkGradientShaderPriv_DEFINED
11 #include "SkGradientShader.h"
12 #include "SkClampRange.h"
13 #include "SkColorPriv.h"
14 #include "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16 #include "SkMallocPixelRef.h"
18 #include "SkTemplates.h"
19 #include "SkBitmapCache.h"
23 static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
27 sk_memset32(dst, v0, count);
29 int pairs = count >> 1;
30 for (int i = 0; i < pairs; i++) {
43 static inline SkFixed clamp_tileproc(SkFixed x) {
44 return SkClampMax(x, 0xFFFF);
49 static inline SkFixed repeat_tileproc(SkFixed x) {
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)
61 static inline SkFixed mirror_tileproc(SkFixed x) {
62 int s = x << 15 >> 31;
63 return (x ^ s) & 0xFFFF;
66 #if defined(_MSC_VER) && (_MSC_VER >= 1600)
67 #pragma optimize("", on)
70 ///////////////////////////////////////////////////////////////////////////////
72 typedef SkFixed (*TileProc)(SkFixed);
74 ///////////////////////////////////////////////////////////////////////////////
76 static const TileProc gTileProcs[] = {
82 ///////////////////////////////////////////////////////////////////////////////
84 class SkGradientShaderBase : public SkShader {
88 sk_bzero(this, sizeof(*this));
89 fTileMode = SkShader::kClamp_TileMode;
92 const SkMatrix* fLocalMatrix;
93 const SkColor* fColors;
96 SkShader::TileMode fTileMode;
101 SkGradientShaderBase(const Descriptor& desc);
102 virtual ~SkGradientShaderBase();
104 // The cache is initialized on-demand when getCache16/32 is called.
105 class GradientShaderCache : public SkRefCnt {
107 GradientShaderCache(U8CPU alpha, const SkGradientShaderBase& shader);
108 ~GradientShaderCache();
110 const uint16_t* getCache16();
111 const SkPMColor* getCache32();
113 SkMallocPixelRef* getCache32PixelRef() const { return fCache32PixelRef; }
115 unsigned getAlpha() const { return fCacheAlpha; }
118 // Working pointers. If either is NULL, we need to recompute the corresponding cache values.
122 uint16_t* fCache16Storage; // Storage for fCache16, allocated on demand.
123 SkMallocPixelRef* fCache32PixelRef;
124 const unsigned fCacheAlpha; // The alpha value we used when we computed the cache.
125 // Larger than 8bits so we can store uninitialized
128 const SkGradientShaderBase& fShader;
130 // Make sure we only initialize the caches once.
131 bool fCache16Inited, fCache32Inited;
132 SkMutex fCache16Mutex, fCache32Mutex;
134 static void initCache16(GradientShaderCache* cache);
135 static void initCache32(GradientShaderCache* cache);
137 static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
138 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
139 U8CPU alpha, uint32_t gradFlags);
142 class GradientShaderBaseContext : public SkShader::Context {
144 GradientShaderBaseContext(const SkGradientShaderBase& shader, const ContextRec&);
146 virtual uint32_t getFlags() const SK_OVERRIDE { return fFlags; }
149 SkMatrix fDstToIndex;
150 SkMatrix::MapXYProc fDstToIndexProc;
151 uint8_t fDstToIndexClass;
154 SkAutoTUnref<GradientShaderCache> fCache;
157 typedef SkShader::Context INHERITED;
160 virtual bool isOpaque() const SK_OVERRIDE;
162 void getGradientTableBitmap(SkBitmap*) const;
165 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
166 /// it, use a larger cache.
168 kCache16Count = (1 << kCache16Bits),
169 kCache16Shift = 16 - kCache16Bits,
170 kSqrt16Shift = 8 - kCache16Bits,
172 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
173 /// it, use a larger cache.
175 kCache32Count = (1 << kCache32Bits),
176 kCache32Shift = 16 - kCache32Bits,
177 kSqrt32Shift = 8 - kCache32Bits,
179 /// This value is used to *read* the dither cache; it may be 0
180 /// if dithering is disabled.
181 kDitherStride32 = kCache32Count,
182 kDitherStride16 = kCache16Count,
187 kThree_GpuColorType, // Symmetric three color
188 kTexture_GpuColorType
191 // Determines and returns the gradient is a two color gradient, symmetric three color gradient
192 // or other (texture gradient). If it is two or symmetric three color, the colors array will
193 // also be filled with the gradient colors
194 GpuColorType getGpuColorType(SkColor colors[3]) const;
196 uint32_t getGradFlags() const { return fGradFlags; }
199 SkGradientShaderBase(SkReadBuffer& );
200 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
201 SK_TO_STRING_OVERRIDE()
203 SkMatrix fPtsToUnit; // set by subclass
210 SkFixed fPos; // 0...1
211 uint32_t fScale; // (1 << 24) / range
215 void commonAsAGradient(GradientInfo*, bool flipGrad = false) const;
218 * Takes in pointers to gradient color and Rec info as colorSrc and recSrc respectively.
219 * Count is the number of colors in the gradient
220 * It will then flip all the color and rec information and return in their respective Dst
221 * pointers. It is assumed that space has already been allocated for the Dst pointers.
222 * The rec src and dst are only assumed to be valid if count > 2
224 static void FlipGradientColors(SkColor* colorDst, Rec* recDst,
225 SkColor* colorSrc, Rec* recSrc,
228 // V23_COMPATIBILITY_CODE
229 // Used for 2-pt conical gradients since we sort start/end cirlces by radius
230 // Assumes space has already been allocated for fOrigColors
231 void flipGradientColors();
235 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
237 kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
239 SkColor fStorage[(kStorageSize + 3) >> 2];
240 SkColor* fOrigColors; // original colors, before modulation by paint in context.
241 bool fColorsAreOpaque;
243 GradientShaderCache* refCache(U8CPU alpha) const;
244 mutable SkMutex fCacheMutex;
245 mutable SkAutoTUnref<GradientShaderCache> fCache;
249 typedef SkShader INHERITED;
252 static inline int init_dither_toggle(int x, int y) {
255 return (x | y) * SkGradientShaderBase::kDitherStride32;
258 static inline int next_dither_toggle(int toggle) {
259 return toggle ^ SkGradientShaderBase::kDitherStride32;
262 static inline int init_dither_toggle16(int x, int y) {
263 return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride16;
266 static inline int next_dither_toggle16(int toggle) {
267 return toggle ^ SkGradientShaderBase::kDitherStride16;
270 ///////////////////////////////////////////////////////////////////////////////
274 #include "GrCoordTransform.h"
275 #include "gl/GrGLEffect.h"
278 class GrBackendEffectFactory;
281 * The interpretation of the texture matrix depends on the sample mode. The
282 * texture matrix is applied both when the texture coordinates are explicit
283 * and when vertex positions are used as texture coordinates. In the latter
284 * case the texture matrix is applied to the pre-view-matrix position
288 * The post-matrix texture coordinates are in normalize space with (0,0) at
289 * the top-left and (1,1) at the bottom right.
291 * The matrix specifies the radial gradient parameters.
292 * (0,0) in the post-matrix space is center of the radial gradient.
294 * Matrix transforms to space where first circle is centered at the
295 * origin. The second circle will be centered (x, 0) where x may be
296 * 0 and is provided by setRadial2Params. The post-matrix space is
297 * normalized such that 1 is the second radius - first radius.
299 * The angle from the origin of texture coordinates in post-matrix space
300 * determines the gradient value.
303 class GrTextureStripAtlas;
305 // Base class for Gr gradient effects
306 class GrGradientEffect : public GrEffect {
309 GrGradientEffect(GrContext* ctx,
310 const SkGradientShaderBase& shader,
311 const SkMatrix& matrix,
312 SkShader::TileMode tileMode);
314 virtual ~GrGradientEffect();
316 bool useAtlas() const { return SkToBool(-1 != fRow); }
317 SkScalar getYCoord() const { return fYCoord; };
319 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
321 SkGradientShaderBase::GpuColorType getColorType() const { return fColorType; }
324 kBeforeInterp_PremulType,
325 kAfterInterp_PremulType,
328 PremulType getPremulType() const { return fPremulType; }
330 const SkColor* getColors(int pos) const {
331 SkASSERT(fColorType != SkGradientShaderBase::kTexture_GpuColorType);
332 SkASSERT((pos-1) <= fColorType);
333 return &fColors[pos];
338 /** Populates a pair of arrays with colors and stop info to construct a random gradient.
339 The function decides whether stop values should be used or not. The return value indicates
340 the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
341 sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
342 size kMaxRandomGradientColors. It may be updated to NULL, indicating that NULL should be
343 passed to the gradient factory rather than the array.
345 static const int kMaxRandomGradientColors = 4;
346 static int RandomGradientParams(SkRandom* r,
347 SkColor colors[kMaxRandomGradientColors],
349 SkShader::TileMode* tm);
351 virtual bool onIsEqual(const GrEffect& effect) const SK_OVERRIDE;
353 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
356 static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
358 GrCoordTransform fCoordTransform;
359 GrTextureAccess fTextureAccess;
361 GrTextureStripAtlas* fAtlas;
364 SkGradientShaderBase::GpuColorType fColorType;
365 SkColor fColors[3]; // More than 3 colors we use texture
366 PremulType fPremulType; // This only changes behavior for two and three color special cases.
367 // It is already baked into to the table for texture gradients.
368 typedef GrEffect INHERITED;
372 ///////////////////////////////////////////////////////////////////////////////
374 // Base class for GL gradient effects
375 class GrGLGradientEffect : public GrGLEffect {
377 GrGLGradientEffect(const GrBackendEffectFactory& factory);
378 virtual ~GrGLGradientEffect();
380 virtual void setData(const GrGLProgramDataManager&, const GrDrawEffect&) SK_OVERRIDE;
384 * Subclasses must call this. It will return a key for the part of the shader code controlled
385 * by the base class. The subclasses must stick it in their key and then pass it to the below
386 * emit* functions from their emitCode function.
388 static uint32_t GenBaseGradientKey(const GrDrawEffect&);
390 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
391 // should call this method from their emitCode().
392 void emitUniforms(GrGLShaderBuilder* builder, uint32_t baseKey);
395 // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
396 // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
397 // native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
398 void emitColor(GrGLShaderBuilder* builder,
399 const char* gradientTValue,
401 const char* outputColor,
402 const char* inputColor,
403 const TextureSamplerArray& samplers);
407 kPremulTypeKeyBitCnt = 1,
409 kPremulBeforeInterpKey = kPremulTypeMask,
411 kTwoColorKey = 2 << kPremulTypeKeyBitCnt,
412 kThreeColorKey = 3 << kPremulTypeKeyBitCnt,
413 kColorKeyMask = kTwoColorKey | kThreeColorKey,
416 // Subclasses must shift any key bits they produce up by this amount
417 // and combine with the result of GenBaseGradientKey.
418 kBaseKeyBitCnt = (kPremulTypeKeyBitCnt + kColorKeyBitCnt)
420 GR_STATIC_ASSERT(kBaseKeyBitCnt <= 32);
422 static SkGradientShaderBase::GpuColorType ColorTypeFromKey(uint32_t baseKey){
423 if (kTwoColorKey == (baseKey & kColorKeyMask)) {
424 return SkGradientShaderBase::kTwo_GpuColorType;
425 } else if (kThreeColorKey == (baseKey & kColorKeyMask)) {
426 return SkGradientShaderBase::kThree_GpuColorType;
427 } else {return SkGradientShaderBase::kTexture_GpuColorType;}
430 static GrGradientEffect::PremulType PremulTypeFromKey(uint32_t baseKey){
431 if (kPremulBeforeInterpKey == (baseKey & kPremulTypeMask)) {
432 return GrGradientEffect::kBeforeInterp_PremulType;
434 return GrGradientEffect::kAfterInterp_PremulType;
438 SkScalar fCachedYCoord;
439 GrGLProgramDataManager::UniformHandle fFSYUni;
440 GrGLProgramDataManager::UniformHandle fColorStartUni;
441 GrGLProgramDataManager::UniformHandle fColorMidUni;
442 GrGLProgramDataManager::UniformHandle fColorEndUni;
444 typedef GrGLEffect INHERITED;