blob: 2faeec02a16a0f2b4cfabf34c4eb6245d6436e6d [file] [log] [blame]
tomhudson@google.com7fab52d2012-05-31 19:40:13 +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#include "GrGradientEffects.h"
9#include "gl/GrGLProgramStage.h"
10#include "GrProgramStageFactory.h"
rileya@google.com03c1c352012-07-20 20:02:43 +000011#include "SkGr.h"
tomhudson@google.com7fab52d2012-05-31 19:40:13 +000012
rileya@google.com22e57f92012-07-19 15:16:19 +000013// Base class for GL gradient custom stages
14class GrGLGradientStage : public GrGLProgramStage {
15public:
16
17 GrGLGradientStage(const GrProgramStageFactory& factory);
18 virtual ~GrGLGradientStage();
19
20 // emit code that gets a fragment's color from an expression for t; for now
21 // this always uses the texture, but for simpler cases we'll be able to lerp
22 void emitColorLookup(GrGLShaderBuilder* builder, const char* t,
23 const char* outputColor, const char* samplerName);
24
25private:
26
27 typedef GrGLProgramStage INHERITED;
28};
29
30GrGLGradientStage::GrGLGradientStage(const GrProgramStageFactory& factory)
31 : INHERITED(factory) { }
32
33GrGLGradientStage::~GrGLGradientStage() { }
34
35void GrGLGradientStage::emitColorLookup(GrGLShaderBuilder* builder,
36 const char* tName,
37 const char* outputColor,
38 const char* samplerName) {
39 // Texture is effectively 1D so the y coordinate is 0.5, if we pack multiple
40 // gradients into a texture, we could instead pick the appropriate row here
41 builder->fSampleCoords.printf("vec2(%s, 0.5)", tName);
42 builder->fComplexCoord = true;
43 builder->emitDefaultFetch(outputColor, samplerName);
44}
45
tomhudson@google.com7fab52d2012-05-31 19:40:13 +000046/////////////////////////////////////////////////////////////////////
47
rileya@google.com22e57f92012-07-19 15:16:19 +000048GrGradientEffect::GrGradientEffect(GrTexture* texture)
49 : fTexture (texture)
50 , fUseTexture(true) {
51 SkSafeRef(fTexture);
52}
53
rileya@google.com03c1c352012-07-20 20:02:43 +000054GrGradientEffect::GrGradientEffect(GrContext* ctx, const SkShader& shader)
55 : fTexture (NULL)
56 , fUseTexture (false) {
57 // TODO: check for simple cases where we don't need a texture:
58 //GradientInfo info;
59 //shader.asAGradient(&info);
60 //if (info.fColorCount == 2) { ...
61
62 SkBitmap bitmap;
63 shader.asABitmap(&bitmap, NULL, NULL, NULL);
64
65 // Note: we just construct a default sampler state here, which isn't great,
66 // however, as long as the bitmap has power-of-two dimensions, which should
67 // be the case for gradient bitmaps, it should be fine
68 GrAssert(SkIsPow2(bitmap.width()) && SkIsPow2(bitmap.height()));
69 GrSamplerState sampler;
70
71 GrContext::TextureCacheEntry entry = GrLockCachedBitmapTexture(ctx, bitmap,
72 &sampler);
73 fTexture = entry.texture();
74 SkSafeRef(fTexture);
75 fUseTexture = true;
76
77 // Unlock immediately, this is not great, but we don't have a way of
78 // knowing when else to unlock it currently, so it may get purged from
79 // the cache, but it'll still be ref'd until it's no longer being used.
80 GrUnlockCachedBitmapTexture(ctx, entry);
81}
82
rileya@google.com22e57f92012-07-19 15:16:19 +000083GrGradientEffect::~GrGradientEffect() {
rileya@google.com03c1c352012-07-20 20:02:43 +000084 SkSafeUnref(fTexture);
rileya@google.com22e57f92012-07-19 15:16:19 +000085}
86
87unsigned int GrGradientEffect::numTextures() const {
88 return fUseTexture ? 1 : 0;
89}
90
91GrTexture* GrGradientEffect::texture(unsigned int index)
92 const {
93 GrAssert(fUseTexture && 0 == index);
94 return fTexture;
95}
96
97/////////////////////////////////////////////////////////////////////
98
99class GrGLLinearGradient : public GrGLGradientStage {
100public:
101
102 GrGLLinearGradient(const GrProgramStageFactory& factory,
103 const GrCustomStage&)
104 : INHERITED (factory) { }
105
106 virtual ~GrGLLinearGradient() { }
107
108 virtual void emitVS(GrGLShaderBuilder* builder,
109 const char* vertexCoords) SK_OVERRIDE { }
110 virtual void emitFS(GrGLShaderBuilder* builder,
111 const char* outputColor,
112 const char* inputColor,
113 const char* samplerName) SK_OVERRIDE;
114 static StageKey GenKey(const GrCustomStage& s) { return 0; }
115
116private:
117
118 typedef GrGLGradientStage INHERITED;
119};
120
121void GrGLLinearGradient::emitFS(GrGLShaderBuilder* builder,
122 const char* outputColor,
123 const char* inputColor,
124 const char* samplerName) {
125 SkString t;
126 t.printf("%s.x", builder->fSampleCoords.c_str());
127 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
128}
129
130/////////////////////////////////////////////////////////////////////
131
132GrLinearGradient::GrLinearGradient(GrTexture* texture)
133 : INHERITED(texture) {
134}
135
rileya@google.com03c1c352012-07-20 20:02:43 +0000136GrLinearGradient::GrLinearGradient(GrContext* ctx, const SkShader& shader)
137 : INHERITED(ctx, shader) {
138}
139
rileya@google.com22e57f92012-07-19 15:16:19 +0000140GrLinearGradient::~GrLinearGradient() {
141
142}
143
144const GrProgramStageFactory& GrLinearGradient::getFactory() const {
145 return GrTProgramStageFactory<GrLinearGradient>::getInstance();
146}
147
rileya@google.com22e57f92012-07-19 15:16:19 +0000148/////////////////////////////////////////////////////////////////////
149
150class GrGLRadialGradient : public GrGLGradientStage {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000151
152public:
153
154 GrGLRadialGradient(const GrProgramStageFactory& factory,
155 const GrCustomStage&) : INHERITED (factory) { }
156 virtual ~GrGLRadialGradient() { }
157
bsalomon@google.com032b2212012-07-16 13:36:18 +0000158 virtual void emitVS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000159 const char* vertexCoords) SK_OVERRIDE { }
bsalomon@google.com032b2212012-07-16 13:36:18 +0000160 virtual void emitFS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000161 const char* outputColor,
162 const char* inputColor,
163 const char* samplerName) SK_OVERRIDE;
164
165 static StageKey GenKey(const GrCustomStage& s) { return 0; }
166
167private:
168
rileya@google.com22e57f92012-07-19 15:16:19 +0000169 typedef GrGLGradientStage INHERITED;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000170
171};
172
bsalomon@google.com032b2212012-07-16 13:36:18 +0000173void GrGLRadialGradient::emitFS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000174 const char* outputColor,
175 const char* inputColor,
176 const char* samplerName) {
rileya@google.com22e57f92012-07-19 15:16:19 +0000177 SkString t;
178 t.printf("length(%s.xy)", builder->fSampleCoords.c_str());
179 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000180}
181
182
183/////////////////////////////////////////////////////////////////////
184
185
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000186GrRadialGradient::GrRadialGradient(GrTexture* texture)
rileya@google.com22e57f92012-07-19 15:16:19 +0000187 : INHERITED(texture) {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000188
189}
190
rileya@google.com03c1c352012-07-20 20:02:43 +0000191GrRadialGradient::GrRadialGradient(GrContext* ctx, const SkShader& shader)
192 : INHERITED(ctx, shader) {
193}
194
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000195GrRadialGradient::~GrRadialGradient() {
196
197}
198
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000199const GrProgramStageFactory& GrRadialGradient::getFactory() const {
200 return GrTProgramStageFactory<GrRadialGradient>::getInstance();
201}
202
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000203/////////////////////////////////////////////////////////////////////
204
bsalomon@google.com032b2212012-07-16 13:36:18 +0000205// For brevity, and these definitions are likely to move to a different class soon.
206typedef GrGLShaderBuilder::UniformHandle UniformHandle;
207static const UniformHandle kInvalidUniformHandle = GrGLShaderBuilder::kInvalidUniformHandle;
208
rileya@google.com22e57f92012-07-19 15:16:19 +0000209class GrGLRadial2Gradient : public GrGLGradientStage {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000210
211public:
212
213 GrGLRadial2Gradient(const GrProgramStageFactory& factory,
214 const GrCustomStage&);
215 virtual ~GrGLRadial2Gradient() { }
216
bsalomon@google.com032b2212012-07-16 13:36:18 +0000217 virtual void setupVariables(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000218 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000219 virtual void emitVS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000220 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000221 virtual void emitFS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000222 const char* outputColor,
223 const char* inputColor,
224 const char* samplerName) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000225 virtual void initUniforms(const GrGLShaderBuilder* builder,
226 const GrGLInterface*,
227 int programID) SK_OVERRIDE;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000228 virtual void setData(const GrGLInterface*,
tomhudson@google.comdcdc1fc2012-05-31 19:53:37 +0000229 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000230 const GrRenderTarget*,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000231 int stageNum) SK_OVERRIDE;
232
233 static StageKey GenKey(const GrCustomStage& s) {
234 return (static_cast<const GrRadial2Gradient&>(s).isDegenerate());
235 }
236
237protected:
238
bsalomon@google.com032b2212012-07-16 13:36:18 +0000239 UniformHandle fVSParamUni;
240 GrGLint fVSParamLocation;
241 UniformHandle fFSParamUni;
242 GrGLint fFSParamLocation;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000243
244 const char* fVSVaryingName;
245 const char* fFSVaryingName;
246
247 bool fIsDegenerate;
248
249 // @{
250 /// Values last uploaded as uniforms
251
252 GrScalar fCachedCenter;
253 GrScalar fCachedRadius;
bsalomon@google.com0b323312012-06-01 18:50:01 +0000254 bool fCachedPosRoot;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000255
256 // @}
257
258private:
259
rileya@google.com22e57f92012-07-19 15:16:19 +0000260 typedef GrGLGradientStage INHERITED;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000261
262};
263
264GrGLRadial2Gradient::GrGLRadial2Gradient(
265 const GrProgramStageFactory& factory,
266 const GrCustomStage& baseData)
267 : INHERITED(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000268 , fVSParamUni(kInvalidUniformHandle)
269 , fFSParamUni(kInvalidUniformHandle)
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000270 , fVSVaryingName(NULL)
271 , fFSVaryingName(NULL)
272 , fCachedCenter(GR_ScalarMax)
273 , fCachedRadius(-GR_ScalarMax)
274 , fCachedPosRoot(0) {
275
276 const GrRadial2Gradient& data =
277 static_cast<const GrRadial2Gradient&>(baseData);
278 fIsDegenerate = data.isDegenerate();
279}
280
bsalomon@google.com032b2212012-07-16 13:36:18 +0000281void GrGLRadial2Gradient::setupVariables(GrGLShaderBuilder* builder, int stage) {
tomhudson@google.com761b37c2012-06-13 15:22:18 +0000282 // 2 copies of uniform array, 1 for each of vertex & fragment shader,
283 // to work around Xoom bug. Doesn't seem to cause performance decrease
284 // in test apps, but need to keep an eye on it.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000285 fVSParamUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
286 kFloat_GrSLType, "uRadial2VSParams", stage, 6);
287 fFSParamUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
288 kFloat_GrSLType, "uRadial2FSParams", stage, 6);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000289
tomhudson@google.com761b37c2012-06-13 15:22:18 +0000290 fVSParamLocation = GrGLProgramStage::kUseUniform;
291 fFSParamLocation = GrGLProgramStage::kUseUniform;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000292
293 // For radial gradients without perspective we can pass the linear
294 // part of the quadratic as a varying.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000295 if (builder->fVaryingDims == builder->fCoordDims) {
296 builder->addVarying(kFloat_GrSLType, "Radial2BCoeff", stage,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000297 &fVSVaryingName, &fFSVaryingName);
298 }
299}
300
bsalomon@google.com032b2212012-07-16 13:36:18 +0000301void GrGLRadial2Gradient::emitVS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000302 const char* vertexCoords) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000303 SkString* code = &builder->fVSCode;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000304 SkString p2;
305 SkString p3;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000306 builder->getUniformVariable(fVSParamUni).appendArrayAccess(2, &p2);
307 builder->getUniformVariable(fVSParamUni).appendArrayAccess(3, &p3);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000308
309 // For radial gradients without perspective we can pass the linear
310 // part of the quadratic as a varying.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000311 if (builder->fVaryingDims == builder->fCoordDims) {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000312 // r2Var = 2 * (r2Parm[2] * varCoord.x - r2Param[3])
313 code->appendf("\t%s = 2.0 *(%s * %s.x - %s);\n",
314 fVSVaryingName, p2.c_str(),
315 vertexCoords, p3.c_str());
316 }
317}
318
bsalomon@google.com032b2212012-07-16 13:36:18 +0000319void GrGLRadial2Gradient::emitFS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000320 const char* outputColor,
321 const char* inputColor,
322 const char* samplerName) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000323 SkString* code = &builder->fFSCode;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000324 SkString cName("c");
325 SkString ac4Name("ac4");
326 SkString rootName("root");
rileya@google.com22e57f92012-07-19 15:16:19 +0000327 SkString t;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000328 SkString p0;
329 SkString p1;
330 SkString p2;
331 SkString p3;
332 SkString p4;
333 SkString p5;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000334 builder->getUniformVariable(fFSParamUni).appendArrayAccess(0, &p0);
335 builder->getUniformVariable(fFSParamUni).appendArrayAccess(1, &p1);
336 builder->getUniformVariable(fFSParamUni).appendArrayAccess(2, &p2);
337 builder->getUniformVariable(fFSParamUni).appendArrayAccess(3, &p3);
338 builder->getUniformVariable(fFSParamUni).appendArrayAccess(4, &p4);
339 builder->getUniformVariable(fFSParamUni).appendArrayAccess(5, &p5);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000340
341 // If we we're able to interpolate the linear component,
342 // bVar is the varying; otherwise compute it
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000343 SkString bVar;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000344 if (builder->fCoordDims == builder->fVaryingDims) {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000345 bVar = fFSVaryingName;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000346 GrAssert(2 == builder->fVaryingDims);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000347 } else {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000348 GrAssert(3 == builder->fVaryingDims);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000349 bVar = "b";
350 //bVar.appendS32(stageNum);
351 code->appendf("\tfloat %s = 2.0 * (%s * %s.x - %s);\n",
352 bVar.c_str(), p2.c_str(),
bsalomon@google.com032b2212012-07-16 13:36:18 +0000353 builder->fSampleCoords.c_str(), p3.c_str());
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000354 }
355
356 // c = (x^2)+(y^2) - params[4]
357 code->appendf("\tfloat %s = dot(%s, %s) - %s;\n",
bsalomon@google.com032b2212012-07-16 13:36:18 +0000358 cName.c_str(), builder->fSampleCoords.c_str(),
359 builder->fSampleCoords.c_str(),
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000360 p4.c_str());
361
362 // If we aren't degenerate, emit some extra code, and accept a slightly
363 // more complex coord.
tomhudson@google.com898e7b52012-06-01 20:42:15 +0000364 if (!fIsDegenerate) {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000365
366 // ac4 = 4.0 * params[0] * c
367 code->appendf("\tfloat %s = %s * 4.0 * %s;\n",
368 ac4Name.c_str(), p0.c_str(),
369 cName.c_str());
370
371 // root = sqrt(b^2-4ac)
372 // (abs to avoid exception due to fp precision)
373 code->appendf("\tfloat %s = sqrt(abs(%s*%s - %s));\n",
374 rootName.c_str(), bVar.c_str(), bVar.c_str(),
375 ac4Name.c_str());
376
rileya@google.com22e57f92012-07-19 15:16:19 +0000377 // t is: (-b + params[5] * sqrt(b^2-4ac)) * params[1]
378 t.printf("(-%s + %s * %s) * %s", bVar.c_str(), p5.c_str(),
379 rootName.c_str(), p1.c_str());
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000380 } else {
rileya@google.com22e57f92012-07-19 15:16:19 +0000381 // t is: -c/b
382 t.printf("-%s / %s", cName.c_str(), bVar.c_str());
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000383 }
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000384
rileya@google.com22e57f92012-07-19 15:16:19 +0000385 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000386}
387
bsalomon@google.com032b2212012-07-16 13:36:18 +0000388void GrGLRadial2Gradient::initUniforms(const GrGLShaderBuilder* builder,
389 const GrGLInterface* gl,
390 int programID) {
391 const char* vsParam = builder->getUniformCStr(fVSParamUni);
392 const char* fsParam = builder->getUniformCStr(fFSParamUni);
393 GR_GL_CALL_RET(gl, fVSParamLocation, GetUniformLocation(programID, vsParam));
394 GR_GL_CALL_RET(gl, fFSParamLocation, GetUniformLocation(programID, fsParam));
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000395}
396
397void GrGLRadial2Gradient::setData(const GrGLInterface* gl,
rileya@google.com3e332582012-07-03 13:43:35 +0000398 const GrCustomStage& baseData,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000399 const GrRenderTarget*,
rileya@google.com3e332582012-07-03 13:43:35 +0000400 int stageNum) {
tomhudson@google.comdcdc1fc2012-05-31 19:53:37 +0000401 const GrRadial2Gradient& data =
402 static_cast<const GrRadial2Gradient&>(baseData);
403 GrAssert(data.isDegenerate() == fIsDegenerate);
404 GrScalar centerX1 = data.center();
405 GrScalar radius0 = data.radius();
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000406 if (fCachedCenter != centerX1 ||
407 fCachedRadius != radius0 ||
tomhudson@google.comdcdc1fc2012-05-31 19:53:37 +0000408 fCachedPosRoot != data.isPosRoot()) {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000409
410 GrScalar a = GrMul(centerX1, centerX1) - GR_Scalar1;
411
412 // When we're in the degenerate (linear) case, the second
413 // value will be INF but the program doesn't read it. (We
414 // use the same 6 uniforms even though we don't need them
415 // all in the linear case just to keep the code complexity
416 // down).
417 float values[6] = {
418 GrScalarToFloat(a),
419 1 / (2.f * GrScalarToFloat(a)),
420 GrScalarToFloat(centerX1),
421 GrScalarToFloat(radius0),
422 GrScalarToFloat(GrMul(radius0, radius0)),
tomhudson@google.comdcdc1fc2012-05-31 19:53:37 +0000423 data.isPosRoot() ? 1.f : -1.f
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000424 };
425
tomhudson@google.com761b37c2012-06-13 15:22:18 +0000426 GR_GL_CALL(gl, Uniform1fv(fVSParamLocation, 6, values));
427 GR_GL_CALL(gl, Uniform1fv(fFSParamLocation, 6, values));
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000428 fCachedCenter = centerX1;
429 fCachedRadius = radius0;
tomhudson@google.comdcdc1fc2012-05-31 19:53:37 +0000430 fCachedPosRoot = data.isPosRoot();
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000431 }
432}
433
434
435/////////////////////////////////////////////////////////////////////
436
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000437GrRadial2Gradient::GrRadial2Gradient(GrTexture* texture,
438 GrScalar center,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000439 GrScalar radius,
440 bool posRoot)
rileya@google.com22e57f92012-07-19 15:16:19 +0000441 : INHERITED(texture)
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000442 , fCenterX1 (center)
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000443 , fRadius0 (radius)
444 , fPosRoot (posRoot) {
445
446}
447
rileya@google.com03c1c352012-07-20 20:02:43 +0000448GrRadial2Gradient::GrRadial2Gradient(GrContext* ctx, const SkShader& shader)
449 : INHERITED(ctx, shader) {
450 SkShader::GradientInfo info;
451 info.fColorCount = 0;
452 shader.asAGradient(&info);
453 fCenterX1 = SkPoint::Distance(info.fPoint[0], info.fPoint[1]);
454 SkScalar diffRadius = info.fRadius[1] - info.fRadius[0];
455 fPosRoot = diffRadius < 0;
456 SkScalar inv = 0 == diffRadius ? 0 : SkScalarInvert(diffRadius);
457 fRadius0 = SkScalarMul(info.fRadius[0], inv);
458 fCenterX1 = SkScalarMul(fCenterX1, inv);
459}
460
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000461GrRadial2Gradient::~GrRadial2Gradient() {
462
463}
464
465
466const GrProgramStageFactory& GrRadial2Gradient::getFactory() const {
467 return GrTProgramStageFactory<GrRadial2Gradient>::getInstance();
468}
469
470bool GrRadial2Gradient::isEqual(const GrCustomStage& sBase) const {
471 const GrRadial2Gradient& s = static_cast<const GrRadial2Gradient&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000472 return (INHERITED::isEqual(sBase) &&
473 this->fCenterX1 == s.fCenterX1 &&
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000474 this->fRadius0 == s.fRadius0 &&
475 this->fPosRoot == s.fPosRoot);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000476}
477
478/////////////////////////////////////////////////////////////////////
479
rileya@google.com22e57f92012-07-19 15:16:19 +0000480class GrGLConical2Gradient : public GrGLGradientStage {
rileya@google.com3e332582012-07-03 13:43:35 +0000481
482public:
483
484 GrGLConical2Gradient(const GrProgramStageFactory& factory,
485 const GrCustomStage&);
486 virtual ~GrGLConical2Gradient() { }
487
bsalomon@google.com032b2212012-07-16 13:36:18 +0000488 virtual void setupVariables(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000489 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000490 virtual void emitVS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000491 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000492 virtual void emitFS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000493 const char* outputColor,
494 const char* inputColor,
495 const char* samplerName) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000496 virtual void initUniforms(const GrGLShaderBuilder* builder,
497 const GrGLInterface*,
498 int programID) SK_OVERRIDE;
rileya@google.com3e332582012-07-03 13:43:35 +0000499 virtual void setData(const GrGLInterface*,
rileya@google.com3e332582012-07-03 13:43:35 +0000500 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000501 const GrRenderTarget*,
rileya@google.com3e332582012-07-03 13:43:35 +0000502 int stageNum) SK_OVERRIDE;
503
504 static StageKey GenKey(const GrCustomStage& s) {
505 return (static_cast<const GrConical2Gradient&>(s).isDegenerate());
506 }
507
508protected:
509
bsalomon@google.com032b2212012-07-16 13:36:18 +0000510 UniformHandle fVSParamUni;
511 GrGLint fVSParamLocation;
512 UniformHandle fFSParamUni;
513 GrGLint fFSParamLocation;
rileya@google.com3e332582012-07-03 13:43:35 +0000514
515 const char* fVSVaryingName;
516 const char* fFSVaryingName;
517
518 bool fIsDegenerate;
519
520 // @{
521 /// Values last uploaded as uniforms
522
523 GrScalar fCachedCenter;
524 GrScalar fCachedRadius;
525 GrScalar fCachedDiffRadius;
526
527 // @}
528
529private:
530
rileya@google.com22e57f92012-07-19 15:16:19 +0000531 typedef GrGLGradientStage INHERITED;
rileya@google.com3e332582012-07-03 13:43:35 +0000532
533};
534
535GrGLConical2Gradient::GrGLConical2Gradient(
536 const GrProgramStageFactory& factory,
537 const GrCustomStage& baseData)
538 : INHERITED(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000539 , fVSParamUni(kInvalidUniformHandle)
540 , fFSParamUni(kInvalidUniformHandle)
rileya@google.com3e332582012-07-03 13:43:35 +0000541 , fVSVaryingName(NULL)
542 , fFSVaryingName(NULL)
543 , fCachedCenter(GR_ScalarMax)
544 , fCachedRadius(-GR_ScalarMax)
545 , fCachedDiffRadius(-GR_ScalarMax) {
546
547 const GrConical2Gradient& data =
548 static_cast<const GrConical2Gradient&>(baseData);
549 fIsDegenerate = data.isDegenerate();
550}
551
bsalomon@google.com032b2212012-07-16 13:36:18 +0000552void GrGLConical2Gradient::setupVariables(GrGLShaderBuilder* builder, int stage) {
rileya@google.com3e332582012-07-03 13:43:35 +0000553 // 2 copies of uniform array, 1 for each of vertex & fragment shader,
554 // to work around Xoom bug. Doesn't seem to cause performance decrease
555 // in test apps, but need to keep an eye on it.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000556 fVSParamUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
557 kFloat_GrSLType, "uConical2VSParams", stage, 6);
558 fFSParamUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
559 kFloat_GrSLType, "uConical2FSParams", stage, 6);
rileya@google.com3e332582012-07-03 13:43:35 +0000560
561 fVSParamLocation = GrGLProgramStage::kUseUniform;
562 fFSParamLocation = GrGLProgramStage::kUseUniform;
563
564 // For radial gradients without perspective we can pass the linear
565 // part of the quadratic as a varying.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000566 if (builder->fVaryingDims == builder->fCoordDims) {
567 builder->addVarying(kFloat_GrSLType, "Conical2BCoeff", stage,
568 &fVSVaryingName, &fFSVaryingName);
rileya@google.com3e332582012-07-03 13:43:35 +0000569 }
570}
571
bsalomon@google.com032b2212012-07-16 13:36:18 +0000572void GrGLConical2Gradient::emitVS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000573 const char* vertexCoords) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000574 SkString* code = &builder->fVSCode;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000575 SkString p2; // distance between centers
576 SkString p3; // start radius
577 SkString p5; // difference in radii (r1 - r0)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000578 builder->getUniformVariable(fVSParamUni).appendArrayAccess(2, &p2);
579 builder->getUniformVariable(fVSParamUni).appendArrayAccess(3, &p3);
580 builder->getUniformVariable(fVSParamUni).appendArrayAccess(5, &p5);
rileya@google.com3e332582012-07-03 13:43:35 +0000581
582 // For radial gradients without perspective we can pass the linear
583 // part of the quadratic as a varying.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000584 if (builder->fVaryingDims == builder->fCoordDims) {
rileya@google.com3e332582012-07-03 13:43:35 +0000585 // r2Var = -2 * (r2Parm[2] * varCoord.x - r2Param[3] * r2Param[5])
586 code->appendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n",
587 fVSVaryingName, p2.c_str(),
588 vertexCoords, p3.c_str(), p5.c_str());
589 }
590}
591
bsalomon@google.com032b2212012-07-16 13:36:18 +0000592void GrGLConical2Gradient::emitFS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000593 const char* outputColor,
594 const char* inputColor,
595 const char* samplerName) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000596 SkString* code = &builder->fFSCode;
rileya@google.com3e332582012-07-03 13:43:35 +0000597
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000598 SkString cName("c");
599 SkString ac4Name("ac4");
600 SkString dName("d");
601 SkString qName("q");
602 SkString r0Name("r0");
603 SkString r1Name("r1");
604 SkString tName("t");
605 SkString p0; // 4a
rileya@google.com62197282012-07-10 20:05:23 +0000606 SkString p1; // 1/a
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000607 SkString p2; // distance between centers
608 SkString p3; // start radius
609 SkString p4; // start radius squared
610 SkString p5; // difference in radii (r1 - r0)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000611
bsalomon@google.comec4037f2012-07-16 13:46:39 +0000612 builder->getUniformVariable(fFSParamUni).appendArrayAccess(0, &p0);
613 builder->getUniformVariable(fFSParamUni).appendArrayAccess(1, &p1);
614 builder->getUniformVariable(fFSParamUni).appendArrayAccess(2, &p2);
615 builder->getUniformVariable(fFSParamUni).appendArrayAccess(3, &p3);
616 builder->getUniformVariable(fFSParamUni).appendArrayAccess(4, &p4);
617 builder->getUniformVariable(fFSParamUni).appendArrayAccess(5, &p5);
rileya@google.com3e332582012-07-03 13:43:35 +0000618
619 // If we we're able to interpolate the linear component,
620 // bVar is the varying; otherwise compute it
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000621 SkString bVar;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000622 if (builder->fCoordDims == builder->fVaryingDims) {
rileya@google.com3e332582012-07-03 13:43:35 +0000623 bVar = fFSVaryingName;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000624 GrAssert(2 == builder->fVaryingDims);
rileya@google.com3e332582012-07-03 13:43:35 +0000625 } else {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000626 GrAssert(3 == builder->fVaryingDims);
rileya@google.com3e332582012-07-03 13:43:35 +0000627 bVar = "b";
628 code->appendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n",
bsalomon@google.com032b2212012-07-16 13:36:18 +0000629 bVar.c_str(), p2.c_str(), builder->fSampleCoords.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000630 p3.c_str(), p5.c_str());
631 }
632
rileya@google.come38160c2012-07-03 18:03:04 +0000633 // output will default to transparent black (we simply won't write anything
634 // else to it if invalid, instead of discarding or returning prematurely)
635 code->appendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
636
rileya@google.com3e332582012-07-03 13:43:35 +0000637 // c = (x^2)+(y^2) - params[4]
638 code->appendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(),
bsalomon@google.com032b2212012-07-16 13:36:18 +0000639 builder->fSampleCoords.c_str(), builder->fSampleCoords.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000640 p4.c_str());
641
642 // Non-degenerate case (quadratic)
643 if (!fIsDegenerate) {
644
645 // ac4 = params[0] * c
646 code->appendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_str(),
647 cName.c_str());
648
649 // d = b^2 - ac4
650 code->appendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(),
651 bVar.c_str(), bVar.c_str(), ac4Name.c_str());
652
rileya@google.come38160c2012-07-03 18:03:04 +0000653 // only proceed if discriminant is >= 0
654 code->appendf("\tif (%s >= 0.0) {\n", dName.c_str());
rileya@google.com3e332582012-07-03 13:43:35 +0000655
656 // intermediate value we'll use to compute the roots
657 // q = -0.5 * (b +/- sqrt(d))
rileya@google.come38160c2012-07-03 18:03:04 +0000658 code->appendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)"
rileya@google.com3e332582012-07-03 13:43:35 +0000659 " * sqrt(%s));\n", qName.c_str(), bVar.c_str(),
660 bVar.c_str(), dName.c_str());
661
662 // compute both roots
663 // r0 = q * params[1]
rileya@google.come38160c2012-07-03 18:03:04 +0000664 code->appendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(),
665 qName.c_str(), p1.c_str());
rileya@google.com3e332582012-07-03 13:43:35 +0000666 // r1 = c / q
rileya@google.come38160c2012-07-03 18:03:04 +0000667 code->appendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(),
668 cName.c_str(), qName.c_str());
rileya@google.com3e332582012-07-03 13:43:35 +0000669
670 // Note: If there are two roots that both generate radius(t) > 0, the
671 // Canvas spec says to choose the larger t.
672
673 // so we'll look at the larger one first:
rileya@google.come38160c2012-07-03 18:03:04 +0000674 code->appendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000675 r0Name.c_str(), r1Name.c_str());
676
rileya@google.come38160c2012-07-03 18:03:04 +0000677 // if r(t) > 0, then we're done; t will be our x coordinate
678 code->appendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000679 p5.c_str(), p3.c_str());
rileya@google.come38160c2012-07-03 18:03:04 +0000680
rileya@google.come38160c2012-07-03 18:03:04 +0000681 code->appendf("\t\t");
rileya@google.com22e57f92012-07-19 15:16:19 +0000682 this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
rileya@google.come38160c2012-07-03 18:03:04 +0000683
684 // otherwise, if r(t) for the larger root was <= 0, try the other root
685 code->appendf("\t\t} else {\n");
686 code->appendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000687 r0Name.c_str(), r1Name.c_str());
688
rileya@google.come38160c2012-07-03 18:03:04 +0000689 // if r(t) > 0 for the smaller root, then t will be our x coordinate
690 code->appendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
rileya@google.com3e332582012-07-03 13:43:35 +0000691 tName.c_str(), p5.c_str(), p3.c_str());
rileya@google.come38160c2012-07-03 18:03:04 +0000692
rileya@google.come38160c2012-07-03 18:03:04 +0000693 code->appendf("\t\t\t");
rileya@google.com22e57f92012-07-19 15:16:19 +0000694 this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
rileya@google.come38160c2012-07-03 18:03:04 +0000695
696 // end if (r(t) > 0) for smaller root
697 code->appendf("\t\t\t}\n");
698 // end if (r(t) > 0), else, for larger root
699 code->appendf("\t\t}\n");
700 // end if (discriminant >= 0)
rileya@google.com3e332582012-07-03 13:43:35 +0000701 code->appendf("\t}\n");
702 } else {
703
704 // linear case: t = -c/b
705 code->appendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
706 cName.c_str(), bVar.c_str());
707
rileya@google.come38160c2012-07-03 18:03:04 +0000708 // if r(t) > 0, then t will be the x coordinate
709 code->appendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000710 p5.c_str(), p3.c_str());
rileya@google.come38160c2012-07-03 18:03:04 +0000711 code->appendf("\t");
rileya@google.com22e57f92012-07-19 15:16:19 +0000712 this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
rileya@google.come38160c2012-07-03 18:03:04 +0000713 code->appendf("\t}\n");
rileya@google.com3e332582012-07-03 13:43:35 +0000714 }
rileya@google.com3e332582012-07-03 13:43:35 +0000715}
716
bsalomon@google.com032b2212012-07-16 13:36:18 +0000717void GrGLConical2Gradient::initUniforms(const GrGLShaderBuilder* builder,
718 const GrGLInterface* gl,
719 int programID) {
720 const char* vsParam = builder->getUniformCStr(fVSParamUni);
721 const char* fsParam = builder->getUniformCStr(fFSParamUni);
722 GR_GL_CALL_RET(gl, fVSParamLocation, GetUniformLocation(programID, vsParam));
723 GR_GL_CALL_RET(gl, fFSParamLocation, GetUniformLocation(programID, fsParam));
rileya@google.com3e332582012-07-03 13:43:35 +0000724}
725
726void GrGLConical2Gradient::setData(const GrGLInterface* gl,
rileya@google.com3e332582012-07-03 13:43:35 +0000727 const GrCustomStage& baseData,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000728 const GrRenderTarget*,
rileya@google.com3e332582012-07-03 13:43:35 +0000729 int stageNum) {
730 const GrConical2Gradient& data =
731 static_cast<const GrConical2Gradient&>(baseData);
732 GrAssert(data.isDegenerate() == fIsDegenerate);
733 GrScalar centerX1 = data.center();
734 GrScalar radius0 = data.radius();
735 GrScalar diffRadius = data.diffRadius();
736
737 if (fCachedCenter != centerX1 ||
738 fCachedRadius != radius0 ||
739 fCachedDiffRadius != diffRadius) {
740
741 GrScalar a = GrMul(centerX1, centerX1) - diffRadius * diffRadius;
742
743 // When we're in the degenerate (linear) case, the second
744 // value will be INF but the program doesn't read it. (We
745 // use the same 6 uniforms even though we don't need them
746 // all in the linear case just to keep the code complexity
747 // down).
748 float values[6] = {
749 GrScalarToFloat(a * 4),
750 1.f / (GrScalarToFloat(a)),
751 GrScalarToFloat(centerX1),
752 GrScalarToFloat(radius0),
753 GrScalarToFloat(SkScalarMul(radius0, radius0)),
754 GrScalarToFloat(diffRadius)
755 };
756
757 GR_GL_CALL(gl, Uniform1fv(fVSParamLocation, 6, values));
758 GR_GL_CALL(gl, Uniform1fv(fFSParamLocation, 6, values));
759 fCachedCenter = centerX1;
760 fCachedRadius = radius0;
761 fCachedDiffRadius = diffRadius;
762 }
763}
764
765
766/////////////////////////////////////////////////////////////////////
767
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000768GrConical2Gradient::GrConical2Gradient(GrTexture* texture,
769 GrScalar center,
rileya@google.com3e332582012-07-03 13:43:35 +0000770 GrScalar radius,
771 GrScalar diffRadius)
rileya@google.com22e57f92012-07-19 15:16:19 +0000772 : INHERITED (texture)
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000773 , fCenterX1 (center)
rileya@google.com3e332582012-07-03 13:43:35 +0000774 , fRadius0 (radius)
775 , fDiffRadius (diffRadius) {
776
777}
778
rileya@google.com03c1c352012-07-20 20:02:43 +0000779GrConical2Gradient::GrConical2Gradient(GrContext* ctx, const SkShader& shader)
780 : INHERITED(ctx, shader) {
781 SkShader::GradientInfo info;
782 info.fColorCount = 0;
783 shader.asAGradient(&info);
784 fCenterX1 = SkPoint::Distance(info.fPoint[0], info.fPoint[1]);
785 fRadius0 = info.fRadius[0];
786 fDiffRadius = info.fRadius[1] - info.fRadius[0];
787}
788
rileya@google.com3e332582012-07-03 13:43:35 +0000789GrConical2Gradient::~GrConical2Gradient() {
790
791}
792
793
794const GrProgramStageFactory& GrConical2Gradient::getFactory() const {
795 return GrTProgramStageFactory<GrConical2Gradient>::getInstance();
796}
797
798bool GrConical2Gradient::isEqual(const GrCustomStage& sBase) const {
799 const GrConical2Gradient& s = static_cast<const GrConical2Gradient&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000800 return (INHERITED::isEqual(sBase) &&
801 this->fCenterX1 == s.fCenterX1 &&
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000802 this->fRadius0 == s.fRadius0 &&
803 this->fDiffRadius == s.fDiffRadius);
rileya@google.com3e332582012-07-03 13:43:35 +0000804}
805
806/////////////////////////////////////////////////////////////////////
807
808
rileya@google.com22e57f92012-07-19 15:16:19 +0000809class GrGLSweepGradient : public GrGLGradientStage {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000810
811public:
812
813 GrGLSweepGradient(const GrProgramStageFactory& factory,
814 const GrCustomStage&) : INHERITED (factory) { }
815 virtual ~GrGLSweepGradient() { }
816
bsalomon@google.com032b2212012-07-16 13:36:18 +0000817 virtual void emitVS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000818 const char* vertexCoords) SK_OVERRIDE { }
bsalomon@google.com032b2212012-07-16 13:36:18 +0000819 virtual void emitFS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000820 const char* outputColor,
821 const char* inputColor,
822 const char* samplerName) SK_OVERRIDE;
823
824 static StageKey GenKey(const GrCustomStage& s) { return 0; }
825
826private:
827
rileya@google.com22e57f92012-07-19 15:16:19 +0000828 typedef GrGLGradientStage INHERITED;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000829
830};
831
bsalomon@google.com032b2212012-07-16 13:36:18 +0000832void GrGLSweepGradient::emitFS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000833 const char* outputColor,
834 const char* inputColor,
835 const char* samplerName) {
rileya@google.com22e57f92012-07-19 15:16:19 +0000836 SkString t;
837 t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
bsalomon@google.com032b2212012-07-16 13:36:18 +0000838 builder->fSampleCoords.c_str(), builder->fSampleCoords.c_str());
rileya@google.com22e57f92012-07-19 15:16:19 +0000839 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000840}
841
842/////////////////////////////////////////////////////////////////////
843
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000844GrSweepGradient::GrSweepGradient(GrTexture* texture)
rileya@google.com22e57f92012-07-19 15:16:19 +0000845 : INHERITED(texture) {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000846
847}
848
rileya@google.com03c1c352012-07-20 20:02:43 +0000849GrSweepGradient::GrSweepGradient(GrContext* ctx, const SkShader& shader)
850 : INHERITED(ctx, shader) {
851}
852
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000853GrSweepGradient::~GrSweepGradient() {
854
855}
856
857const GrProgramStageFactory& GrSweepGradient::getFactory() const {
858 return GrTProgramStageFactory<GrSweepGradient>::getInstance();
859}
860