blob: 82535de5d372061083b87079980675ff4a3bfaae [file] [log] [blame]
rileya@google.com1c6d64b2012-07-27 15:49:05 +00001/*
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"
djsollen@google.comc73dd5c2012-08-07 15:54:32 +000014#include "SkFlattenableBuffers.h"
rileya@google.com1c6d64b2012-07-27 15:49:05 +000015#include "SkMallocPixelRef.h"
16#include "SkUnitMapper.h"
17#include "SkUtils.h"
18#include "SkTemplates.h"
19#include "SkBitmapCache.h"
20#include "SkShader.h"
rileya@google.com1c6d64b2012-07-27 15:49:05 +000021
reed@google.com60040292013-02-04 18:21:23 +000022#define SK_IGNORE_GRADIENT_DITHER_FIX
23
rileya@google.com1c6d64b2012-07-27 15:49:05 +000024#ifndef SK_DISABLE_DITHER_32BIT_GRADIENT
25 #define USE_DITHER_32BIT_GRADIENT
26#endif
27
humper@google.com05af1af2013-01-07 16:47:43 +000028static inline void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
rileya@google.com1c6d64b2012-07-27 15:49:05 +000029 int count) {
30 if (count > 0) {
31 if (v0 == v1) {
32 sk_memset32(dst, v0, count);
33 } else {
34 int pairs = count >> 1;
35 for (int i = 0; i < pairs; i++) {
36 *dst++ = v0;
37 *dst++ = v1;
38 }
39 if (count & 1) {
40 *dst = v0;
41 }
42 }
43 }
44}
45
46// Clamp
47
humper@google.com05af1af2013-01-07 16:47:43 +000048static inline SkFixed clamp_tileproc(SkFixed x) {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000049 return SkClampMax(x, 0xFFFF);
50}
51
52// Repeat
53
humper@google.com05af1af2013-01-07 16:47:43 +000054static inline SkFixed repeat_tileproc(SkFixed x) {
rileya@google.com1c6d64b2012-07-27 15:49:05 +000055 return x & 0xFFFF;
56}
57
58// Mirror
59
60// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
61// See http://code.google.com/p/skia/issues/detail?id=472
62#if defined(_MSC_VER) && (_MSC_VER >= 1600)
63#pragma optimize("", off)
64#endif
65
66static inline SkFixed mirror_tileproc(SkFixed x) {
67 int s = x << 15 >> 31;
68 return (x ^ s) & 0xFFFF;
69}
70
71#if defined(_MSC_VER) && (_MSC_VER >= 1600)
72#pragma optimize("", on)
73#endif
74
75///////////////////////////////////////////////////////////////////////////////
76
77typedef SkFixed (*TileProc)(SkFixed);
78
79///////////////////////////////////////////////////////////////////////////////
80
81static const TileProc gTileProcs[] = {
82 clamp_tileproc,
83 repeat_tileproc,
84 mirror_tileproc
85};
86
87///////////////////////////////////////////////////////////////////////////////
88
89class SkGradientShaderBase : public SkShader {
90public:
91 SkGradientShaderBase(const SkColor colors[], const SkScalar pos[],
92 int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
93 virtual ~SkGradientShaderBase();
94
rileya@google.com1c6d64b2012-07-27 15:49:05 +000095 virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
96 virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
97 virtual bool isOpaque() const SK_OVERRIDE;
98
99 void getGradientTableBitmap(SkBitmap*) const;
100
101 enum {
102 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
103 /// it, use a larger cache.
104 kCache16Bits = 8,
reed@google.com3c2102c2013-02-01 12:59:40 +0000105 kCache16Count = (1 << kCache16Bits),
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000106 kCache16Shift = 16 - kCache16Bits,
107 kSqrt16Shift = 8 - kCache16Bits,
108
109 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
110 /// it, use a larger cache.
111 kCache32Bits = 8,
reed@google.com60040292013-02-04 18:21:23 +0000112 kCache32Count = (1 << kCache32Bits),
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000113 kCache32Shift = 16 - kCache32Bits,
114 kSqrt32Shift = 8 - kCache32Bits,
115
116 /// This value is used to *read* the dither cache; it may be 0
117 /// if dithering is disabled.
118#ifdef USE_DITHER_32BIT_GRADIENT
119 kDitherStride32 = kCache32Count,
120#else
121 kDitherStride32 = 0,
122#endif
123 kDitherStride16 = kCache16Count,
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000124 };
125
126
127protected:
128 SkGradientShaderBase(SkFlattenableReadBuffer& );
129 virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
robertphillips@google.com76f9e932013-01-15 20:17:47 +0000130 SK_DEVELOPER_TO_STRING()
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000131
132 SkUnitMapper* fMapper;
133 SkMatrix fPtsToUnit; // set by subclass
134 SkMatrix fDstToIndex;
135 SkMatrix::MapXYProc fDstToIndexProc;
136 TileMode fTileMode;
137 TileProc fTileProc;
138 int fColorCount;
139 uint8_t fDstToIndexClass;
140 uint8_t fFlags;
141
142 struct Rec {
143 SkFixed fPos; // 0...1
144 uint32_t fScale; // (1 << 24) / range
145 };
146 Rec* fRecs;
147
148 const uint16_t* getCache16() const;
149 const SkPMColor* getCache32() const;
150
151 void commonAsAGradient(GradientInfo*) const;
152
153private:
154 enum {
155 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
156
157 kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
158 };
159 SkColor fStorage[(kStorageSize + 3) >> 2];
160 SkColor* fOrigColors; // original colors, before modulation by paint in setContext
161 bool fColorsAreOpaque;
162
163 mutable uint16_t* fCache16; // working ptr. If this is NULL, we need to recompute the cache values
164 mutable SkPMColor* fCache32; // working ptr. If this is NULL, we need to recompute the cache values
165
166 mutable uint16_t* fCache16Storage; // storage for fCache16, allocated on demand
167 mutable SkMallocPixelRef* fCache32PixelRef;
168 mutable unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
169
170 static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
171 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
172 U8CPU alpha);
173 void setCacheAlpha(U8CPU alpha) const;
174 void initCommon();
175
176 typedef SkShader INHERITED;
177};
178
reed@google.com55853db2013-02-01 19:34:59 +0000179static inline int init_dither_toggle(int x, int y) {
reed@google.com60040292013-02-04 18:21:23 +0000180#ifdef SK_IGNORE_GRADIENT_DITHER_FIX
reed@google.com55853db2013-02-01 19:34:59 +0000181 return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride32;
reed@google.com60040292013-02-04 18:21:23 +0000182#else
183 x &= 1;
184 y = (y & 1) << 1;
185 return (x | y) * SkGradientShaderBase::kDitherStride32;
186#endif
reed@google.com55853db2013-02-01 19:34:59 +0000187}
188
189static inline int next_dither_toggle(int toggle) {
190 return toggle ^ SkGradientShaderBase::kDitherStride32;
191}
192
193static inline int init_dither_toggle16(int x, int y) {
194 return ((x ^ y) & 1) * SkGradientShaderBase::kDitherStride16;
195}
196
197static inline int next_dither_toggle16(int toggle) {
198 return toggle ^ SkGradientShaderBase::kDitherStride16;
199}
200
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000201///////////////////////////////////////////////////////////////////////////////
202
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000203#if SK_SUPPORT_GPU
204
bsalomon@google.comd698f772012-10-25 13:22:00 +0000205#include "gl/GrGLEffect.h"
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000206#include "gl/GrGLEffectMatrix.h"
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000207
bsalomon@google.com08283af2012-10-26 13:01:20 +0000208class GrEffectStage;
bsalomon@google.com396e61f2012-10-25 19:00:29 +0000209class GrBackendEffectFactory;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000210
211/*
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000212 * The interpretation of the texture matrix depends on the sample mode. The
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000213 * texture matrix is applied both when the texture coordinates are explicit
214 * and when vertex positions are used as texture coordinates. In the latter
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000215 * case the texture matrix is applied to the pre-view-matrix position
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000216 * values.
217 *
218 * Normal SampleMode
219 * The post-matrix texture coordinates are in normalize space with (0,0) at
220 * the top-left and (1,1) at the bottom right.
221 * RadialGradient
222 * The matrix specifies the radial gradient parameters.
223 * (0,0) in the post-matrix space is center of the radial gradient.
224 * Radial2Gradient
225 * Matrix transforms to space where first circle is centered at the
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000226 * origin. The second circle will be centered (x, 0) where x may be
227 * 0 and is provided by setRadial2Params. The post-matrix space is
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000228 * normalized such that 1 is the second radius - first radius.
229 * SweepGradient
230 * The angle from the origin of texture coordinates in post-matrix space
231 * determines the gradient value.
232 */
233
rileya@google.comb3e50f22012-08-20 17:43:08 +0000234 class GrTextureStripAtlas;
235
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000236// Base class for Gr gradient effects
bsalomon@google.coma469c282012-10-24 18:28:34 +0000237class GrGradientEffect : public GrEffect {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000238public:
239
bsalomon@google.com1ce49fc2012-09-18 14:14:49 +0000240 GrGradientEffect(GrContext* ctx,
241 const SkGradientShaderBase& shader,
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000242 const SkMatrix& matrix,
bsalomon@google.com1ce49fc2012-09-18 14:14:49 +0000243 SkShader::TileMode tileMode);
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000244
245 virtual ~GrGradientEffect();
246
rileya@google.comb3e50f22012-08-20 17:43:08 +0000247 bool useAtlas() const { return SkToBool(-1 != fRow); }
bsalomon@google.com81712882012-11-01 17:12:34 +0000248 SkScalar getYCoord() const { return fYCoord; };
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000249 const SkMatrix& getMatrix() const { return fMatrix;}
rileya@google.comb3e50f22012-08-20 17:43:08 +0000250
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000251 virtual void getConstantColorComponents(GrColor* color, uint32_t* validFlags) const SK_OVERRIDE;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000252
bsalomon@google.comd4726202012-08-03 14:34:46 +0000253protected:
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000254
bsalomon@google.comd4726202012-08-03 14:34:46 +0000255 /** Populates a pair of arrays with colors and stop info to construct a random gradient.
256 The function decides whether stop values should be used or not. The return value indicates
257 the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
258 sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
259 size kMaxRandomGradientColors. It may be updated to NULL, indicating that NULL should be
260 passed to the gradient factory rather than the array.
261 */
262 static const int kMaxRandomGradientColors = 4;
263 static int RandomGradientParams(SkRandom* r,
264 SkColor colors[kMaxRandomGradientColors],
265 SkScalar** stops,
266 SkShader::TileMode* tm);
267
bsalomon@google.com8a252f72013-01-22 20:35:13 +0000268 virtual bool onIsEqual(const GrEffect& effect) const SK_OVERRIDE;
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000269
bsalomon@google.comd4726202012-08-03 14:34:46 +0000270private:
bsalomon@google.com68b58c92013-01-17 16:50:08 +0000271
bsalomon@google.com6d003d12012-09-11 15:45:20 +0000272 GrTextureAccess fTextureAccess;
bsalomon@google.com81712882012-11-01 17:12:34 +0000273 SkScalar fYCoord;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000274 GrTextureStripAtlas* fAtlas;
275 int fRow;
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000276 SkMatrix fMatrix;
bsalomon@google.com371e1052013-01-11 21:08:55 +0000277 bool fIsOpaque;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000278
bsalomon@google.coma469c282012-10-24 18:28:34 +0000279 typedef GrEffect INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000280
281};
282
283///////////////////////////////////////////////////////////////////////////////
284
bsalomon@google.com8ea78d82012-10-24 20:11:30 +0000285// Base class for GL gradient effects
bsalomon@google.comf78df332012-10-29 12:43:38 +0000286class GrGLGradientEffect : public GrGLEffect {
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000287public:
bsalomon@google.com0707c292012-10-25 21:45:42 +0000288 GrGLGradientEffect(const GrBackendEffectFactory& factory);
289 virtual ~GrGLGradientEffect();
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000290
bsalomon@google.com28a15fb2012-10-26 17:53:18 +0000291 virtual void setData(const GrGLUniformManager&, const GrEffectStage&) SK_OVERRIDE;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000292
bsalomon@google.comf78df332012-10-29 12:43:38 +0000293protected:
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000294 /**
295 * Subclasses must reserve the lower kMatrixKeyBitCnt of their key for use by
296 * GrGLGradientEffect.
297 */
298 enum {
299 kMatrixKeyBitCnt = GrGLEffectMatrix::kKeyBits,
300 kMatrixKeyMask = (1 << kMatrixKeyBitCnt) - 1,
301 };
302
303 /**
304 * Subclasses must call this. It will return a value restricted to the lower kMatrixKeyBitCnt
305 * bits.
306 */
307 static EffectKey GenMatrixKey(const GrEffectStage& s);
308
309 /**
310 * Inserts code to implement the GrGradientEffect's matrix. This should be called before a
311 * subclass emits its own code. The name of the 2D coords is output via fsCoordName and already
312 * incorporates any perspective division. The caller can also optionally retrieve the name of
313 * the varying inserted in the VS and its type, which may be either vec2f or vec3f depending
314 * upon whether the matrix has perspective or not. It is not necessary to mask the key before
315 * calling.
316 */
317 void setupMatrix(GrGLShaderBuilder* builder,
318 EffectKey key,
319 const char* vertexCoords,
320 const char** fsCoordName,
321 const char** vsVaryingName = NULL,
322 GrSLType* vsVaryingType = NULL);
323
bsalomon@google.comf78df332012-10-29 12:43:38 +0000324 // Emits the uniform used as the y-coord to texture samples in derived classes. Subclasses
325 // should call this method from their emitCode().
326 void emitYCoordUniform(GrGLShaderBuilder* builder);
327
328 // emit code that gets a fragment's color from an expression for t; for now this always uses the
329 // texture, but for simpler cases we'll be able to lerp. Subclasses should call this method from
330 // their emitCode().
bsalomon@google.com868a8e72012-08-30 19:11:34 +0000331 void emitColorLookup(GrGLShaderBuilder* builder,
332 const char* gradientTValue,
333 const char* outputColor,
334 const char* inputColor,
bsalomon@google.comf06df1b2012-09-06 20:22:31 +0000335 const GrGLShaderBuilder::TextureSampler&);
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000336
337private:
bsalomon@google.com81712882012-11-01 17:12:34 +0000338 SkScalar fCachedYCoord;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000339 GrGLUniformManager::UniformHandle fFSYUni;
bsalomon@google.comd8b5fac2012-11-01 17:02:46 +0000340 GrGLEffectMatrix fEffectMatrix;
rileya@google.comb3e50f22012-08-20 17:43:08 +0000341
bsalomon@google.comf78df332012-10-29 12:43:38 +0000342 typedef GrGLEffect INHERITED;
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000343};
344
345#endif
346
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000347#endif