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"
17 #include "SkUnitMapper.h"
19 #include "SkTemplates.h"
20 #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 SkColor* fColors;
95 SkShader::TileMode fTileMode;
96 SkUnitMapper* fMapper;
101 SkGradientShaderBase(const Descriptor& desc);
102 virtual ~SkGradientShaderBase();
104 virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
105 virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
106 virtual bool isOpaque() const SK_OVERRIDE;
108 void getGradientTableBitmap(SkBitmap*) const;
111 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
112 /// it, use a larger cache.
114 kCache16Count = (1 << kCache16Bits),
115 kCache16Shift = 16 - kCache16Bits,
116 kSqrt16Shift = 8 - kCache16Bits,
118 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
119 /// it, use a larger cache.
121 kCache32Count = (1 << kCache32Bits),
122 kCache32Shift = 16 - kCache32Bits,
123 kSqrt32Shift = 8 - kCache32Bits,
125 /// This value is used to *read* the dither cache; it may be 0
126 /// if dithering is disabled.
127 kDitherStride32 = kCache32Count,
128 kDitherStride16 = kCache16Count,
133 SkGradientShaderBase(SkReadBuffer& );
134 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
135 SK_DEVELOPER_TO_STRING()
137 SkUnitMapper* fMapper;
138 SkMatrix fPtsToUnit; // set by subclass
139 SkMatrix fDstToIndex;
140 SkMatrix::MapXYProc fDstToIndexProc;
144 uint8_t fDstToIndexClass;
149 SkFixed fPos; // 0...1
150 uint32_t fScale; // (1 << 24) / range
154 const uint16_t* getCache16() const;
155 const SkPMColor* getCache32() const;
157 void commonAsAGradient(GradientInfo*) const;
161 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
163 kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
165 SkColor fStorage[(kStorageSize + 3) >> 2];
166 SkColor* fOrigColors; // original colors, before modulation by paint in setContext
167 bool fColorsAreOpaque;
169 mutable uint16_t* fCache16; // working ptr. If this is NULL, we need to recompute the cache values
170 mutable SkPMColor* fCache32; // working ptr. If this is NULL, we need to recompute the cache values
172 mutable uint16_t* fCache16Storage; // storage for fCache16, allocated on demand
173 mutable SkMallocPixelRef* fCache32PixelRef;
174 mutable unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
176 static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
177 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
178 U8CPU alpha, uint32_t gradFlags);
179 void setCacheAlpha(U8CPU alpha) const;
182 typedef SkShader INHERITED;
185 static inline int init_dither_toggle(int x, int y) {
188 return (x | y) * SkGradientShaderBase::kDitherStride32;
191 static inline int next_dither_toggle(int toggle) {
192 return toggle ^ SkGradientShaderBase::kDitherStride32;
195 static inline int init_dither_toggle16(int x, int y) {
196 return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride16;
199 static inline int next_dither_toggle16(int toggle) {
200 return toggle ^ SkGradientShaderBase::kDitherStride16;
203 ///////////////////////////////////////////////////////////////////////////////
207 #include "GrCoordTransform.h"
208 #include "gl/GrGLEffect.h"
211 class GrBackendEffectFactory;
214 * The interpretation of the texture matrix depends on the sample mode. The
215 * texture matrix is applied both when the texture coordinates are explicit
216 * and when vertex positions are used as texture coordinates. In the latter
217 * case the texture matrix is applied to the pre-view-matrix position
221 * The post-matrix texture coordinates are in normalize space with (0,0) at
222 * the top-left and (1,1) at the bottom right.
224 * The matrix specifies the radial gradient parameters.
225 * (0,0) in the post-matrix space is center of the radial gradient.
227 * Matrix transforms to space where first circle is centered at the
228 * origin. The second circle will be centered (x, 0) where x may be
229 * 0 and is provided by setRadial2Params. The post-matrix space is
230 * normalized such that 1 is the second radius - first radius.
232 * The angle from the origin of texture coordinates in post-matrix space
233 * determines the gradient value.
236 class GrTextureStripAtlas;
238 // Base class for Gr gradient effects
239 class GrGradientEffect : public GrEffect {
242 GrGradientEffect(GrContext* ctx,
243 const SkGradientShaderBase& shader,
244 const SkMatrix& matrix,
245 SkShader::TileMode tileMode);
247 virtual ~GrGradientEffect();
249 bool useAtlas() const { return SkToBool(-1 != fRow); }
250 SkScalar getYCoord() const { return fYCoord; };
252 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
260 ColorType getColorType() const { return fColorType; }
263 kBeforeInterp_PremulType,
264 kAfterInterp_PremulType,
267 PremulType getPremulType() const { return fPremulType; }
269 const SkColor* getColors(int pos) const {
270 SkASSERT(fColorType != kTexture_ColorType);
271 SkASSERT((pos-1) <= fColorType);
272 return &fColors[pos];
277 /** Populates a pair of arrays with colors and stop info to construct a random gradient.
278 The function decides whether stop values should be used or not. The return value indicates
279 the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
280 sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
281 size kMaxRandomGradientColors. It may be updated to NULL, indicating that NULL should be
282 passed to the gradient factory rather than the array.
284 static const int kMaxRandomGradientColors = 4;
285 static int RandomGradientParams(SkRandom* r,
286 SkColor colors[kMaxRandomGradientColors],
288 SkShader::TileMode* tm);
290 virtual bool onIsEqual(const GrEffect& effect) const SK_OVERRIDE;
292 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
295 static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
298 kMaxAnalyticColors = 3 // if more colors use texture
301 GrCoordTransform fCoordTransform;
302 GrTextureAccess fTextureAccess;
304 GrTextureStripAtlas* fAtlas;
307 ColorType fColorType;
308 SkColor fColors[kMaxAnalyticColors];
309 PremulType fPremulType; // This only changes behavior for two and three color special cases.
310 // It is already baked into to the table for texture gradients.
311 typedef GrEffect INHERITED;
315 ///////////////////////////////////////////////////////////////////////////////
317 // Base class for GL gradient effects
318 class GrGLGradientEffect : public GrGLEffect {
320 GrGLGradientEffect(const GrBackendEffectFactory& factory);
321 virtual ~GrGLGradientEffect();
323 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
327 kPremulTypeKeyBitCnt = 1,
329 kPremulBeforeInterpKey = kPremulTypeMask,
331 kTwoColorKey = 2 << kPremulTypeKeyBitCnt,
332 kThreeColorKey = 3 << kPremulTypeKeyBitCnt,
333 kColorKeyMask = kTwoColorKey | kThreeColorKey,
336 // Subclasses must shift any key bits they produce up by this amount
337 // and combine with the result of GenBaseGradientKey.
338 kBaseKeyBitCnt = (kPremulTypeKeyBitCnt + kColorKeyBitCnt)
341 static GrGradientEffect::ColorType ColorTypeFromKey(EffectKey key){
342 if (kTwoColorKey == (key & kColorKeyMask)) {
343 return GrGradientEffect::kTwo_ColorType;
344 } else if (kThreeColorKey == (key & kColorKeyMask)) {
345 return GrGradientEffect::kThree_ColorType;
346 } else {return GrGradientEffect::kTexture_ColorType;}
349 static GrGradientEffect::PremulType PremulTypeFromKey(EffectKey key){
350 if (kPremulBeforeInterpKey == (key & kPremulTypeMask)) {
351 return GrGradientEffect::kBeforeInterp_PremulType;
353 return GrGradientEffect::kAfterInterp_PremulType;
358 * Subclasses must call this. It will return a value restricted to the lower kBaseKeyBitCnt
361 static EffectKey GenBaseGradientKey(const GrDrawEffect&);
363 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
364 // should call this method from their emitCode().
365 void emitUniforms(GrGLShaderBuilder* builder, EffectKey key);
368 // emit code that gets a fragment's color from an expression for t; Has branches for 3 separate
369 // control flows inside -- 2 color gradients, 3 color symmetric gradients (both using
370 // native GLSL mix), and 4+ color gradients that use the traditional texture lookup.
371 void emitColor(GrGLShaderBuilder* builder,
372 const char* gradientTValue,
374 const char* outputColor,
375 const char* inputColor,
376 const TextureSamplerArray& samplers);
379 SkScalar fCachedYCoord;
380 GrGLUniformManager::UniformHandle fFSYUni;
381 GrGLUniformManager::UniformHandle fColorStartUni;
382 GrGLUniformManager::UniformHandle fColorMidUni;
383 GrGLUniformManager::UniformHandle fColorEndUni;
385 typedef GrGLEffect INHERITED;