gfx/skia/trunk/src/effects/gradients/SkGradientShaderPriv.h

branch
TOR_BUG_3246
changeset 6
8bccb770b82d
equal deleted inserted replaced
-1:000000000000 0:a38d9c6b7002
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 "SkReadBuffer.h"
15 #include "SkWriteBuffer.h"
16 #include "SkMallocPixelRef.h"
17 #include "SkUnitMapper.h"
18 #include "SkUtils.h"
19 #include "SkTemplates.h"
20 #include "SkBitmapCache.h"
21 #include "SkShader.h"
22
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
43 static inline SkFixed clamp_tileproc(SkFixed x) {
44 return SkClampMax(x, 0xFFFF);
45 }
46
47 // Repeat
48
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
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 {
87 Descriptor() {
88 sk_bzero(this, sizeof(*this));
89 fTileMode = SkShader::kClamp_TileMode;
90 }
91
92 const SkColor* fColors;
93 const SkScalar* fPos;
94 int fCount;
95 SkShader::TileMode fTileMode;
96 SkUnitMapper* fMapper;
97 uint32_t fFlags;
98 };
99
100 public:
101 SkGradientShaderBase(const Descriptor& desc);
102 virtual ~SkGradientShaderBase();
103
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;
107
108 void getGradientTableBitmap(SkBitmap*) const;
109
110 enum {
111 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
112 /// it, use a larger cache.
113 kCache16Bits = 8,
114 kCache16Count = (1 << kCache16Bits),
115 kCache16Shift = 16 - kCache16Bits,
116 kSqrt16Shift = 8 - kCache16Bits,
117
118 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
119 /// it, use a larger cache.
120 kCache32Bits = 8,
121 kCache32Count = (1 << kCache32Bits),
122 kCache32Shift = 16 - kCache32Bits,
123 kSqrt32Shift = 8 - kCache32Bits,
124
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,
129 };
130
131
132 protected:
133 SkGradientShaderBase(SkReadBuffer& );
134 virtual void flatten(SkWriteBuffer&) const SK_OVERRIDE;
135 SK_TO_STRING_OVERRIDE()
136
137 SkUnitMapper* fMapper;
138 SkMatrix fPtsToUnit; // set by subclass
139 SkMatrix fDstToIndex;
140 SkMatrix::MapXYProc fDstToIndexProc;
141 TileMode fTileMode;
142 TileProc fTileProc;
143 int fColorCount;
144 uint8_t fDstToIndexClass;
145 uint8_t fFlags;
146 uint8_t fGradFlags;
147
148 struct Rec {
149 SkFixed fPos; // 0...1
150 uint32_t fScale; // (1 << 24) / range
151 };
152 Rec* fRecs;
153
154 const uint16_t* getCache16() const;
155 const SkPMColor* getCache32() const;
156
157 void commonAsAGradient(GradientInfo*) const;
158
159 private:
160 enum {
161 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
162
163 kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
164 };
165 SkColor fStorage[(kStorageSize + 3) >> 2];
166 SkColor* fOrigColors; // original colors, before modulation by paint in setContext
167 bool fColorsAreOpaque;
168
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
171
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
175
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;
180 void initCommon();
181
182 typedef SkShader INHERITED;
183 };
184
185 static inline int init_dither_toggle(int x, int y) {
186 x &= 1;
187 y = (y & 1) << 1;
188 return (x | y) * SkGradientShaderBase::kDitherStride32;
189 }
190
191 static inline int next_dither_toggle(int toggle) {
192 return toggle ^ SkGradientShaderBase::kDitherStride32;
193 }
194
195 static inline int init_dither_toggle16(int x, int y) {
196 return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride16;
197 }
198
199 static inline int next_dither_toggle16(int toggle) {
200 return toggle ^ SkGradientShaderBase::kDitherStride16;
201 }
202
203 ///////////////////////////////////////////////////////////////////////////////
204
205 #if SK_SUPPORT_GPU
206
207 #include "GrCoordTransform.h"
208 #include "gl/GrGLEffect.h"
209
210 class GrEffectStage;
211 class GrBackendEffectFactory;
212
213 /*
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
218 * values.
219 *
220 * Normal SampleMode
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.
223 * RadialGradient
224 * The matrix specifies the radial gradient parameters.
225 * (0,0) in the post-matrix space is center of the radial gradient.
226 * Radial2Gradient
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.
231 * SweepGradient
232 * The angle from the origin of texture coordinates in post-matrix space
233 * determines the gradient value.
234 */
235
236 class GrTextureStripAtlas;
237
238 // Base class for Gr gradient effects
239 class GrGradientEffect : public GrEffect {
240 public:
241
242 GrGradientEffect(GrContext* ctx,
243 const SkGradientShaderBase& shader,
244 const SkMatrix& matrix,
245 SkShader::TileMode tileMode);
246
247 virtual ~GrGradientEffect();
248
249 bool useAtlas() const { return SkToBool(-1 != fRow); }
250 SkScalar getYCoord() const { return fYCoord; };
251
252 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
253
254 enum ColorType {
255 kTwo_ColorType,
256 kThree_ColorType,
257 kTexture_ColorType
258 };
259
260 ColorType getColorType() const { return fColorType; }
261
262 enum PremulType {
263 kBeforeInterp_PremulType,
264 kAfterInterp_PremulType,
265 };
266
267 PremulType getPremulType() const { return fPremulType; }
268
269 const SkColor* getColors(int pos) const {
270 SkASSERT(fColorType != kTexture_ColorType);
271 SkASSERT((pos-1) <= fColorType);
272 return &fColors[pos];
273 }
274
275 protected:
276
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.
283 */
284 static const int kMaxRandomGradientColors = 4;
285 static int RandomGradientParams(SkRandom* r,
286 SkColor colors[kMaxRandomGradientColors],
287 SkScalar** stops,
288 SkShader::TileMode* tm);
289
290 virtual bool onIsEqual(const GrEffect& effect) const SK_OVERRIDE;
291
292 const GrCoordTransform& getCoordTransform() const { return fCoordTransform; }
293
294 private:
295 static const GrCoordSet kCoordSet = kLocal_GrCoordSet;
296
297 enum {
298 kMaxAnalyticColors = 3 // if more colors use texture
299 };
300
301 GrCoordTransform fCoordTransform;
302 GrTextureAccess fTextureAccess;
303 SkScalar fYCoord;
304 GrTextureStripAtlas* fAtlas;
305 int fRow;
306 bool fIsOpaque;
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;
312
313 };
314
315 ///////////////////////////////////////////////////////////////////////////////
316
317 // Base class for GL gradient effects
318 class GrGLGradientEffect : public GrGLEffect {
319 public:
320 GrGLGradientEffect(const GrBackendEffectFactory& factory);
321 virtual ~GrGLGradientEffect();
322
323 virtual void setData(const GrGLUniformManager&, const GrDrawEffect&) SK_OVERRIDE;
324
325 protected:
326 enum {
327 kPremulTypeKeyBitCnt = 1,
328 kPremulTypeMask = 1,
329 kPremulBeforeInterpKey = kPremulTypeMask,
330
331 kTwoColorKey = 2 << kPremulTypeKeyBitCnt,
332 kThreeColorKey = 3 << kPremulTypeKeyBitCnt,
333 kColorKeyMask = kTwoColorKey | kThreeColorKey,
334 kColorKeyBitCnt = 2,
335
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)
339 };
340
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;}
347 }
348
349 static GrGradientEffect::PremulType PremulTypeFromKey(EffectKey key){
350 if (kPremulBeforeInterpKey == (key & kPremulTypeMask)) {
351 return GrGradientEffect::kBeforeInterp_PremulType;
352 } else {
353 return GrGradientEffect::kAfterInterp_PremulType;
354 }
355 }
356
357 /**
358 * Subclasses must call this. It will return a value restricted to the lower kBaseKeyBitCnt
359 * bits.
360 */
361 static EffectKey GenBaseGradientKey(const GrDrawEffect&);
362
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);
366
367
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,
373 EffectKey key,
374 const char* outputColor,
375 const char* inputColor,
376 const TextureSamplerArray& samplers);
377
378 private:
379 SkScalar fCachedYCoord;
380 GrGLUniformManager::UniformHandle fFSYUni;
381 GrGLUniformManager::UniformHandle fColorStartUni;
382 GrGLUniformManager::UniformHandle fColorMidUni;
383 GrGLUniformManager::UniformHandle fColorEndUni;
384
385 typedef GrGLEffect INHERITED;
386 };
387
388 #endif
389
390 #endif

mercurial