blob: 9e80fd34672d6540bcbabc7b09578794c5e29a79 [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
236private:
237
238 GrTexture* fTexture;
239 bool fUseTexture;
240
241 typedef GrCustomStage INHERITED;
242
243};
244
245///////////////////////////////////////////////////////////////////////////////
246
247// Base class for GL gradient custom stages
248class GrGLGradientStage : public GrGLProgramStage {
249public:
250
251 GrGLGradientStage(const GrProgramStageFactory& factory);
252 virtual ~GrGLGradientStage();
253
254 // emit code that gets a fragment's color from an expression for t; for now
255 // this always uses the texture, but for simpler cases we'll be able to lerp
256 void emitColorLookup(GrGLShaderBuilder* builder, const char* t,
257 const char* outputColor, const char* samplerName);
258
259private:
260
261 typedef GrGLProgramStage INHERITED;
262};
263
264#endif
265
bsalomon@google.comcf8fb1f2012-08-02 14:03:32 +0000266#endif
267