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