blob: 807bf324ada694b01a82cc900fc2292e2de7fa42 [file] [log] [blame]
rileya@google.com1c6d64b2012-07-27 15:49:05 +00001
2/*
3 * Copyright 2012 Google Inc.
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
9#ifndef SkGradientShaderPriv_DEFINED
10#define SkGradientShaderPriv_DEFINED
11
12#include "SkGradientShader.h"
13#include "SkClampRange.h"
14#include "SkColorPriv.h"
15#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
22#ifndef SK_DISABLE_DITHER_32BIT_GRADIENT
23 #define USE_DITHER_32BIT_GRADIENT
24#endif
25
26static void sk_memset32_dither(uint32_t dst[], uint32_t v0, uint32_t v1,
27 int count) {
28 if (count > 0) {
29 if (v0 == v1) {
30 sk_memset32(dst, v0, count);
31 } else {
32 int pairs = count >> 1;
33 for (int i = 0; i < pairs; i++) {
34 *dst++ = v0;
35 *dst++ = v1;
36 }
37 if (count & 1) {
38 *dst = v0;
39 }
40 }
41 }
42}
43
44// Clamp
45
46static SkFixed clamp_tileproc(SkFixed x) {
47 return SkClampMax(x, 0xFFFF);
48}
49
50// Repeat
51
52static SkFixed repeat_tileproc(SkFixed x) {
53 return x & 0xFFFF;
54}
55
56// Mirror
57
58// Visual Studio 2010 (MSC_VER=1600) optimizes bit-shift code incorrectly.
59// See http://code.google.com/p/skia/issues/detail?id=472
60#if defined(_MSC_VER) && (_MSC_VER >= 1600)
61#pragma optimize("", off)
62#endif
63
64static inline SkFixed mirror_tileproc(SkFixed x) {
65 int s = x << 15 >> 31;
66 return (x ^ s) & 0xFFFF;
67}
68
69#if defined(_MSC_VER) && (_MSC_VER >= 1600)
70#pragma optimize("", on)
71#endif
72
73///////////////////////////////////////////////////////////////////////////////
74
75typedef SkFixed (*TileProc)(SkFixed);
76
77///////////////////////////////////////////////////////////////////////////////
78
79static const TileProc gTileProcs[] = {
80 clamp_tileproc,
81 repeat_tileproc,
82 mirror_tileproc
83};
84
85///////////////////////////////////////////////////////////////////////////////
86
87class SkGradientShaderBase : public SkShader {
88public:
89 SkGradientShaderBase(const SkColor colors[], const SkScalar pos[],
90 int colorCount, SkShader::TileMode mode, SkUnitMapper* mapper);
91 virtual ~SkGradientShaderBase();
92
93 // overrides
94 virtual bool setContext(const SkBitmap&, const SkPaint&, const SkMatrix&) SK_OVERRIDE;
95 virtual uint32_t getFlags() SK_OVERRIDE { return fFlags; }
96 virtual bool isOpaque() const SK_OVERRIDE;
97
98 void getGradientTableBitmap(SkBitmap*) const;
99
100 enum {
101 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
102 /// it, use a larger cache.
103 kCache16Bits = 8,
104 kGradient16Length = (1 << kCache16Bits),
105 /// Each cache gets 1 extra entry at the end so we don't have to
106 /// test for end-of-cache in lerps. This is also the value used
107 /// to stride *writes* into the dither cache; it must not be zero.
108 /// Total space for a cache is 2x kCache16Count entries: one
109 /// regular cache, one for dithering.
110 kCache16Count = kGradient16Length + 1,
111 kCache16Shift = 16 - kCache16Bits,
112 kSqrt16Shift = 8 - kCache16Bits,
113
114 /// Seems like enough for visual accuracy. TODO: if pos[] deserves
115 /// it, use a larger cache.
116 kCache32Bits = 8,
117 kGradient32Length = (1 << kCache32Bits),
118 /// Each cache gets 1 extra entry at the end so we don't have to
119 /// test for end-of-cache in lerps. This is also the value used
120 /// to stride *writes* into the dither cache; it must not be zero.
121 /// Total space for a cache is 2x kCache32Count entries: one
122 /// regular cache, one for dithering.
123 kCache32Count = kGradient32Length + 1,
124 kCache32Shift = 16 - kCache32Bits,
125 kSqrt32Shift = 8 - kCache32Bits,
126
127 /// This value is used to *read* the dither cache; it may be 0
128 /// if dithering is disabled.
129#ifdef USE_DITHER_32BIT_GRADIENT
130 kDitherStride32 = kCache32Count,
131#else
132 kDitherStride32 = 0,
133#endif
134 kDitherStride16 = kCache16Count,
135 kLerpRemainderMask32 = (1 << (16 - kCache32Bits)) - 1
136 };
137
138
139protected:
140 SkGradientShaderBase(SkFlattenableReadBuffer& );
141 virtual void flatten(SkFlattenableWriteBuffer&) const SK_OVERRIDE;
142
143 SkUnitMapper* fMapper;
144 SkMatrix fPtsToUnit; // set by subclass
145 SkMatrix fDstToIndex;
146 SkMatrix::MapXYProc fDstToIndexProc;
147 TileMode fTileMode;
148 TileProc fTileProc;
149 int fColorCount;
150 uint8_t fDstToIndexClass;
151 uint8_t fFlags;
152
153 struct Rec {
154 SkFixed fPos; // 0...1
155 uint32_t fScale; // (1 << 24) / range
156 };
157 Rec* fRecs;
158
159 const uint16_t* getCache16() const;
160 const SkPMColor* getCache32() const;
161
162 void commonAsAGradient(GradientInfo*) const;
163
164private:
165 enum {
166 kColorStorageCount = 4, // more than this many colors, and we'll use sk_malloc for the space
167
168 kStorageSize = kColorStorageCount * (sizeof(SkColor) + sizeof(Rec))
169 };
170 SkColor fStorage[(kStorageSize + 3) >> 2];
171 SkColor* fOrigColors; // original colors, before modulation by paint in setContext
172 bool fColorsAreOpaque;
173
174 mutable uint16_t* fCache16; // working ptr. If this is NULL, we need to recompute the cache values
175 mutable SkPMColor* fCache32; // working ptr. If this is NULL, we need to recompute the cache values
176
177 mutable uint16_t* fCache16Storage; // storage for fCache16, allocated on demand
178 mutable SkMallocPixelRef* fCache32PixelRef;
179 mutable unsigned fCacheAlpha; // the alpha value we used when we computed the cache. larger than 8bits so we can store uninitialized value
180
181 static void Build16bitCache(uint16_t[], SkColor c0, SkColor c1, int count);
182 static void Build32bitCache(SkPMColor[], SkColor c0, SkColor c1, int count,
183 U8CPU alpha);
184 void setCacheAlpha(U8CPU alpha) const;
185 void initCommon();
186
187 typedef SkShader INHERITED;
188};
189
190///////////////////////////////////////////////////////////////////////////////
191
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000192#if SK_SUPPORT_GPU
193
194#include "gl/GrGLProgramStage.h"
195
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000196class GrSamplerState;
197class GrProgramStageFactory;
198
199/*
200 * The intepretation of the texture matrix depends on the sample mode. The
201 * texture matrix is applied both when the texture coordinates are explicit
202 * and when vertex positions are used as texture coordinates. In the latter
203 * case the texture matrix is applied to the pre-view-matrix position
204 * values.
205 *
206 * Normal SampleMode
207 * The post-matrix texture coordinates are in normalize space with (0,0) at
208 * the top-left and (1,1) at the bottom right.
209 * RadialGradient
210 * The matrix specifies the radial gradient parameters.
211 * (0,0) in the post-matrix space is center of the radial gradient.
212 * Radial2Gradient
213 * Matrix transforms to space where first circle is centered at the
214 * origin. The second circle will be centered (x, 0) where x may be
215 * 0 and is provided by setRadial2Params. The post-matrix space is
216 * normalized such that 1 is the second radius - first radius.
217 * SweepGradient
218 * The angle from the origin of texture coordinates in post-matrix space
219 * determines the gradient value.
220 */
221
222// Base class for Gr gradient effects
223class GrGradientEffect : public GrCustomStage {
224public:
225
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000226 GrGradientEffect(GrContext* ctx, const SkGradientShaderBase& shader,
227 GrSamplerState* sampler);
228
229 virtual ~GrGradientEffect();
230
231 unsigned int numTextures() const;
232 GrTexture* texture(unsigned int index) const;
233
234 bool useTexture() const { return fUseTexture; }
235
bsalomon@google.comd4726202012-08-03 14:34:46 +0000236protected:
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000237
bsalomon@google.comd4726202012-08-03 14:34:46 +0000238 /** Populates a pair of arrays with colors and stop info to construct a random gradient.
239 The function decides whether stop values should be used or not. The return value indicates
240 the number of colors, which will be capped by kMaxRandomGradientColors. colors should be
241 sized to be at least kMaxRandomGradientColors. stops is a pointer to an array of at least
242 size kMaxRandomGradientColors. It may be updated to NULL, indicating that NULL should be
243 passed to the gradient factory rather than the array.
244 */
245 static const int kMaxRandomGradientColors = 4;
246 static int RandomGradientParams(SkRandom* r,
247 SkColor colors[kMaxRandomGradientColors],
248 SkScalar** stops,
249 SkShader::TileMode* tm);
250
251private:
rileya@google.com1c6d64b2012-07-27 15:49:05 +0000252 GrTexture* fTexture;
253 bool fUseTexture;
254
255 typedef GrCustomStage INHERITED;
256
257};
258
259///////////////////////////////////////////////////////////////////////////////
260
261// Base class for GL gradient custom stages
262class GrGLGradientStage : public GrGLProgramStage {
263public:
264
265 GrGLGradientStage(const GrProgramStageFactory& factory);
266 virtual ~GrGLGradientStage();
267
268 // emit code that gets a fragment's color from an expression for t; for now
269 // this always uses the texture, but for simpler cases we'll be able to lerp
270 void emitColorLookup(GrGLShaderBuilder* builder, const char* t,
271 const char* outputColor, const char* samplerName);
272
273private:
274
275 typedef GrGLProgramStage INHERITED;
276};
277
278#endif
279
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000280#endif
281