blob: 34bff09fa639940d0f6a02f7cedbc432a3e520d6 [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"
rileya@google.com91f319c2012-07-25 17:18:31 +000012#include "../core/SkShader.h"
tomhudson@google.com7fab52d2012-05-31 19:40:13 +000013
rileya@google.com22e57f92012-07-19 15:16:19 +000014// Base class for GL gradient custom stages
15class GrGLGradientStage : public GrGLProgramStage {
16public:
17
18 GrGLGradientStage(const GrProgramStageFactory& factory);
19 virtual ~GrGLGradientStage();
20
21 // emit code that gets a fragment's color from an expression for t; for now
22 // this always uses the texture, but for simpler cases we'll be able to lerp
23 void emitColorLookup(GrGLShaderBuilder* builder, const char* t,
24 const char* outputColor, const char* samplerName);
25
26private:
27
28 typedef GrGLProgramStage INHERITED;
29};
30
31GrGLGradientStage::GrGLGradientStage(const GrProgramStageFactory& factory)
32 : INHERITED(factory) { }
33
34GrGLGradientStage::~GrGLGradientStage() { }
35
36void GrGLGradientStage::emitColorLookup(GrGLShaderBuilder* builder,
37 const char* tName,
38 const char* outputColor,
39 const char* samplerName) {
40 // Texture is effectively 1D so the y coordinate is 0.5, if we pack multiple
41 // gradients into a texture, we could instead pick the appropriate row here
42 builder->fSampleCoords.printf("vec2(%s, 0.5)", tName);
43 builder->fComplexCoord = true;
44 builder->emitDefaultFetch(outputColor, samplerName);
45}
46
tomhudson@google.com7fab52d2012-05-31 19:40:13 +000047/////////////////////////////////////////////////////////////////////
48
rileya@google.com22e57f92012-07-19 15:16:19 +000049GrGradientEffect::GrGradientEffect(GrTexture* texture)
50 : fTexture (texture)
51 , fUseTexture(true) {
52 SkSafeRef(fTexture);
53}
54
rileya@google.com91f319c2012-07-25 17:18:31 +000055GrGradientEffect::GrGradientEffect(GrContext* ctx,
56 const SkShader& shader,
57 GrSamplerState* sampler)
rileya@google.com03c1c352012-07-20 20:02:43 +000058 : fTexture (NULL)
59 , fUseTexture (false) {
60 // TODO: check for simple cases where we don't need a texture:
61 //GradientInfo info;
62 //shader.asAGradient(&info);
63 //if (info.fColorCount == 2) { ...
64
65 SkBitmap bitmap;
rileya@google.com91f319c2012-07-25 17:18:31 +000066 shader.asABitmap(&bitmap, NULL, NULL);
rileya@google.com03c1c352012-07-20 20:02:43 +000067
68 GrContext::TextureCacheEntry entry = GrLockCachedBitmapTexture(ctx, bitmap,
rileya@google.com91f319c2012-07-25 17:18:31 +000069 sampler);
rileya@google.com03c1c352012-07-20 20:02:43 +000070 fTexture = entry.texture();
71 SkSafeRef(fTexture);
72 fUseTexture = true;
73
74 // Unlock immediately, this is not great, but we don't have a way of
75 // knowing when else to unlock it currently, so it may get purged from
76 // the cache, but it'll still be ref'd until it's no longer being used.
77 GrUnlockCachedBitmapTexture(ctx, entry);
78}
79
rileya@google.com22e57f92012-07-19 15:16:19 +000080GrGradientEffect::~GrGradientEffect() {
rileya@google.com03c1c352012-07-20 20:02:43 +000081 SkSafeUnref(fTexture);
rileya@google.com22e57f92012-07-19 15:16:19 +000082}
83
84unsigned int GrGradientEffect::numTextures() const {
85 return fUseTexture ? 1 : 0;
86}
87
88GrTexture* GrGradientEffect::texture(unsigned int index)
89 const {
90 GrAssert(fUseTexture && 0 == index);
91 return fTexture;
92}
93
94/////////////////////////////////////////////////////////////////////
95
96class GrGLLinearGradient : public GrGLGradientStage {
97public:
98
99 GrGLLinearGradient(const GrProgramStageFactory& factory,
100 const GrCustomStage&)
101 : INHERITED (factory) { }
102
103 virtual ~GrGLLinearGradient() { }
104
105 virtual void emitVS(GrGLShaderBuilder* builder,
106 const char* vertexCoords) SK_OVERRIDE { }
107 virtual void emitFS(GrGLShaderBuilder* builder,
108 const char* outputColor,
109 const char* inputColor,
110 const char* samplerName) SK_OVERRIDE;
111 static StageKey GenKey(const GrCustomStage& s) { return 0; }
112
113private:
114
115 typedef GrGLGradientStage INHERITED;
116};
117
118void GrGLLinearGradient::emitFS(GrGLShaderBuilder* builder,
119 const char* outputColor,
120 const char* inputColor,
121 const char* samplerName) {
122 SkString t;
123 t.printf("%s.x", builder->fSampleCoords.c_str());
124 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
125}
126
127/////////////////////////////////////////////////////////////////////
128
129GrLinearGradient::GrLinearGradient(GrTexture* texture)
130 : INHERITED(texture) {
131}
132
rileya@google.com91f319c2012-07-25 17:18:31 +0000133GrLinearGradient::GrLinearGradient(GrContext* ctx,
134 const SkShader& shader,
135 GrSamplerState* sampler)
136 : INHERITED(ctx, shader, sampler) {
rileya@google.com03c1c352012-07-20 20:02:43 +0000137}
138
rileya@google.com22e57f92012-07-19 15:16:19 +0000139GrLinearGradient::~GrLinearGradient() {
140
141}
142
143const GrProgramStageFactory& GrLinearGradient::getFactory() const {
144 return GrTProgramStageFactory<GrLinearGradient>::getInstance();
145}
146
rileya@google.com22e57f92012-07-19 15:16:19 +0000147/////////////////////////////////////////////////////////////////////
148
149class GrGLRadialGradient : public GrGLGradientStage {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000150
151public:
152
153 GrGLRadialGradient(const GrProgramStageFactory& factory,
154 const GrCustomStage&) : INHERITED (factory) { }
155 virtual ~GrGLRadialGradient() { }
156
bsalomon@google.com032b2212012-07-16 13:36:18 +0000157 virtual void emitVS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000158 const char* vertexCoords) SK_OVERRIDE { }
bsalomon@google.com032b2212012-07-16 13:36:18 +0000159 virtual void emitFS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000160 const char* outputColor,
161 const char* inputColor,
162 const char* samplerName) SK_OVERRIDE;
163
164 static StageKey GenKey(const GrCustomStage& s) { return 0; }
165
166private:
167
rileya@google.com22e57f92012-07-19 15:16:19 +0000168 typedef GrGLGradientStage INHERITED;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000169
170};
171
bsalomon@google.com032b2212012-07-16 13:36:18 +0000172void GrGLRadialGradient::emitFS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000173 const char* outputColor,
174 const char* inputColor,
175 const char* samplerName) {
rileya@google.com22e57f92012-07-19 15:16:19 +0000176 SkString t;
177 t.printf("length(%s.xy)", builder->fSampleCoords.c_str());
178 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000179}
180
181
182/////////////////////////////////////////////////////////////////////
183
184
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000185GrRadialGradient::GrRadialGradient(GrTexture* texture)
rileya@google.com22e57f92012-07-19 15:16:19 +0000186 : INHERITED(texture) {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000187
188}
189
rileya@google.com91f319c2012-07-25 17:18:31 +0000190GrRadialGradient::GrRadialGradient(GrContext* ctx, const SkShader& shader,
191 GrSamplerState* sampler)
192 : INHERITED(ctx, shader, sampler) {
rileya@google.com03c1c352012-07-20 20:02:43 +0000193}
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.com91f319c2012-07-25 17:18:31 +0000448GrRadial2Gradient::GrRadial2Gradient(GrContext* ctx,
449 const SkShader& shader,
450 GrSamplerState* sampler,
451 SkScalar center,
452 SkScalar startRadius,
453 SkScalar diffRadius)
454 : INHERITED(ctx, shader, sampler)
455 , fCenterX1(center)
456 , fRadius0(startRadius)
457 , fPosRoot(diffRadius < 0) {
rileya@google.com03c1c352012-07-20 20:02:43 +0000458}
459
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000460GrRadial2Gradient::~GrRadial2Gradient() {
461
462}
463
464
465const GrProgramStageFactory& GrRadial2Gradient::getFactory() const {
466 return GrTProgramStageFactory<GrRadial2Gradient>::getInstance();
467}
468
469bool GrRadial2Gradient::isEqual(const GrCustomStage& sBase) const {
470 const GrRadial2Gradient& s = static_cast<const GrRadial2Gradient&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000471 return (INHERITED::isEqual(sBase) &&
472 this->fCenterX1 == s.fCenterX1 &&
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000473 this->fRadius0 == s.fRadius0 &&
474 this->fPosRoot == s.fPosRoot);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000475}
476
477/////////////////////////////////////////////////////////////////////
478
rileya@google.com22e57f92012-07-19 15:16:19 +0000479class GrGLConical2Gradient : public GrGLGradientStage {
rileya@google.com3e332582012-07-03 13:43:35 +0000480
481public:
482
483 GrGLConical2Gradient(const GrProgramStageFactory& factory,
484 const GrCustomStage&);
485 virtual ~GrGLConical2Gradient() { }
486
bsalomon@google.com032b2212012-07-16 13:36:18 +0000487 virtual void setupVariables(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000488 int stage) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000489 virtual void emitVS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000490 const char* vertexCoords) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000491 virtual void emitFS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000492 const char* outputColor,
493 const char* inputColor,
494 const char* samplerName) SK_OVERRIDE;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000495 virtual void initUniforms(const GrGLShaderBuilder* builder,
496 const GrGLInterface*,
497 int programID) SK_OVERRIDE;
rileya@google.com3e332582012-07-03 13:43:35 +0000498 virtual void setData(const GrGLInterface*,
rileya@google.com3e332582012-07-03 13:43:35 +0000499 const GrCustomStage&,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000500 const GrRenderTarget*,
rileya@google.com3e332582012-07-03 13:43:35 +0000501 int stageNum) SK_OVERRIDE;
502
503 static StageKey GenKey(const GrCustomStage& s) {
504 return (static_cast<const GrConical2Gradient&>(s).isDegenerate());
505 }
506
507protected:
508
bsalomon@google.com032b2212012-07-16 13:36:18 +0000509 UniformHandle fVSParamUni;
510 GrGLint fVSParamLocation;
511 UniformHandle fFSParamUni;
512 GrGLint fFSParamLocation;
rileya@google.com3e332582012-07-03 13:43:35 +0000513
514 const char* fVSVaryingName;
515 const char* fFSVaryingName;
516
517 bool fIsDegenerate;
518
519 // @{
520 /// Values last uploaded as uniforms
521
522 GrScalar fCachedCenter;
523 GrScalar fCachedRadius;
524 GrScalar fCachedDiffRadius;
525
526 // @}
527
528private:
529
rileya@google.com22e57f92012-07-19 15:16:19 +0000530 typedef GrGLGradientStage INHERITED;
rileya@google.com3e332582012-07-03 13:43:35 +0000531
532};
533
534GrGLConical2Gradient::GrGLConical2Gradient(
535 const GrProgramStageFactory& factory,
536 const GrCustomStage& baseData)
537 : INHERITED(factory)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000538 , fVSParamUni(kInvalidUniformHandle)
539 , fFSParamUni(kInvalidUniformHandle)
rileya@google.com3e332582012-07-03 13:43:35 +0000540 , fVSVaryingName(NULL)
541 , fFSVaryingName(NULL)
542 , fCachedCenter(GR_ScalarMax)
543 , fCachedRadius(-GR_ScalarMax)
544 , fCachedDiffRadius(-GR_ScalarMax) {
545
546 const GrConical2Gradient& data =
547 static_cast<const GrConical2Gradient&>(baseData);
548 fIsDegenerate = data.isDegenerate();
549}
550
bsalomon@google.com032b2212012-07-16 13:36:18 +0000551void GrGLConical2Gradient::setupVariables(GrGLShaderBuilder* builder, int stage) {
rileya@google.com3e332582012-07-03 13:43:35 +0000552 // 2 copies of uniform array, 1 for each of vertex & fragment shader,
553 // to work around Xoom bug. Doesn't seem to cause performance decrease
554 // in test apps, but need to keep an eye on it.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000555 fVSParamUni = builder->addUniform(GrGLShaderBuilder::kVertex_ShaderType,
556 kFloat_GrSLType, "uConical2VSParams", stage, 6);
557 fFSParamUni = builder->addUniform(GrGLShaderBuilder::kFragment_ShaderType,
558 kFloat_GrSLType, "uConical2FSParams", stage, 6);
rileya@google.com3e332582012-07-03 13:43:35 +0000559
560 fVSParamLocation = GrGLProgramStage::kUseUniform;
561 fFSParamLocation = GrGLProgramStage::kUseUniform;
562
563 // For radial gradients without perspective we can pass the linear
564 // part of the quadratic as a varying.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000565 if (builder->fVaryingDims == builder->fCoordDims) {
566 builder->addVarying(kFloat_GrSLType, "Conical2BCoeff", stage,
567 &fVSVaryingName, &fFSVaryingName);
rileya@google.com3e332582012-07-03 13:43:35 +0000568 }
569}
570
bsalomon@google.com032b2212012-07-16 13:36:18 +0000571void GrGLConical2Gradient::emitVS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000572 const char* vertexCoords) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000573 SkString* code = &builder->fVSCode;
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000574 SkString p2; // distance between centers
575 SkString p3; // start radius
576 SkString p5; // difference in radii (r1 - r0)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000577 builder->getUniformVariable(fVSParamUni).appendArrayAccess(2, &p2);
578 builder->getUniformVariable(fVSParamUni).appendArrayAccess(3, &p3);
579 builder->getUniformVariable(fVSParamUni).appendArrayAccess(5, &p5);
rileya@google.com3e332582012-07-03 13:43:35 +0000580
581 // For radial gradients without perspective we can pass the linear
582 // part of the quadratic as a varying.
bsalomon@google.com032b2212012-07-16 13:36:18 +0000583 if (builder->fVaryingDims == builder->fCoordDims) {
rileya@google.com3e332582012-07-03 13:43:35 +0000584 // r2Var = -2 * (r2Parm[2] * varCoord.x - r2Param[3] * r2Param[5])
585 code->appendf("\t%s = -2.0 * (%s * %s.x + %s * %s);\n",
586 fVSVaryingName, p2.c_str(),
587 vertexCoords, p3.c_str(), p5.c_str());
588 }
589}
590
bsalomon@google.com032b2212012-07-16 13:36:18 +0000591void GrGLConical2Gradient::emitFS(GrGLShaderBuilder* builder,
rileya@google.com3e332582012-07-03 13:43:35 +0000592 const char* outputColor,
593 const char* inputColor,
594 const char* samplerName) {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000595 SkString* code = &builder->fFSCode;
rileya@google.com3e332582012-07-03 13:43:35 +0000596
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000597 SkString cName("c");
598 SkString ac4Name("ac4");
599 SkString dName("d");
600 SkString qName("q");
601 SkString r0Name("r0");
602 SkString r1Name("r1");
603 SkString tName("t");
604 SkString p0; // 4a
rileya@google.com62197282012-07-10 20:05:23 +0000605 SkString p1; // 1/a
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000606 SkString p2; // distance between centers
607 SkString p3; // start radius
608 SkString p4; // start radius squared
609 SkString p5; // difference in radii (r1 - r0)
bsalomon@google.com032b2212012-07-16 13:36:18 +0000610
bsalomon@google.comec4037f2012-07-16 13:46:39 +0000611 builder->getUniformVariable(fFSParamUni).appendArrayAccess(0, &p0);
612 builder->getUniformVariable(fFSParamUni).appendArrayAccess(1, &p1);
613 builder->getUniformVariable(fFSParamUni).appendArrayAccess(2, &p2);
614 builder->getUniformVariable(fFSParamUni).appendArrayAccess(3, &p3);
615 builder->getUniformVariable(fFSParamUni).appendArrayAccess(4, &p4);
616 builder->getUniformVariable(fFSParamUni).appendArrayAccess(5, &p5);
rileya@google.com3e332582012-07-03 13:43:35 +0000617
618 // If we we're able to interpolate the linear component,
619 // bVar is the varying; otherwise compute it
bsalomon@google.comf0a104e2012-07-10 17:51:07 +0000620 SkString bVar;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000621 if (builder->fCoordDims == builder->fVaryingDims) {
rileya@google.com3e332582012-07-03 13:43:35 +0000622 bVar = fFSVaryingName;
bsalomon@google.com032b2212012-07-16 13:36:18 +0000623 GrAssert(2 == builder->fVaryingDims);
rileya@google.com3e332582012-07-03 13:43:35 +0000624 } else {
bsalomon@google.com032b2212012-07-16 13:36:18 +0000625 GrAssert(3 == builder->fVaryingDims);
rileya@google.com3e332582012-07-03 13:43:35 +0000626 bVar = "b";
627 code->appendf("\tfloat %s = -2.0 * (%s * %s.x + %s * %s);\n",
bsalomon@google.com032b2212012-07-16 13:36:18 +0000628 bVar.c_str(), p2.c_str(), builder->fSampleCoords.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000629 p3.c_str(), p5.c_str());
630 }
631
rileya@google.come38160c2012-07-03 18:03:04 +0000632 // output will default to transparent black (we simply won't write anything
633 // else to it if invalid, instead of discarding or returning prematurely)
634 code->appendf("\t%s = vec4(0.0,0.0,0.0,0.0);\n", outputColor);
635
rileya@google.com3e332582012-07-03 13:43:35 +0000636 // c = (x^2)+(y^2) - params[4]
637 code->appendf("\tfloat %s = dot(%s, %s) - %s;\n", cName.c_str(),
bsalomon@google.com032b2212012-07-16 13:36:18 +0000638 builder->fSampleCoords.c_str(), builder->fSampleCoords.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000639 p4.c_str());
640
641 // Non-degenerate case (quadratic)
642 if (!fIsDegenerate) {
643
644 // ac4 = params[0] * c
645 code->appendf("\tfloat %s = %s * %s;\n", ac4Name.c_str(), p0.c_str(),
646 cName.c_str());
647
648 // d = b^2 - ac4
649 code->appendf("\tfloat %s = %s * %s - %s;\n", dName.c_str(),
650 bVar.c_str(), bVar.c_str(), ac4Name.c_str());
651
rileya@google.come38160c2012-07-03 18:03:04 +0000652 // only proceed if discriminant is >= 0
653 code->appendf("\tif (%s >= 0.0) {\n", dName.c_str());
rileya@google.com3e332582012-07-03 13:43:35 +0000654
655 // intermediate value we'll use to compute the roots
656 // q = -0.5 * (b +/- sqrt(d))
rileya@google.come38160c2012-07-03 18:03:04 +0000657 code->appendf("\t\tfloat %s = -0.5 * (%s + (%s < 0.0 ? -1.0 : 1.0)"
rileya@google.com3e332582012-07-03 13:43:35 +0000658 " * sqrt(%s));\n", qName.c_str(), bVar.c_str(),
659 bVar.c_str(), dName.c_str());
660
661 // compute both roots
662 // r0 = q * params[1]
rileya@google.come38160c2012-07-03 18:03:04 +0000663 code->appendf("\t\tfloat %s = %s * %s;\n", r0Name.c_str(),
664 qName.c_str(), p1.c_str());
rileya@google.com3e332582012-07-03 13:43:35 +0000665 // r1 = c / q
rileya@google.come38160c2012-07-03 18:03:04 +0000666 code->appendf("\t\tfloat %s = %s / %s;\n", r1Name.c_str(),
667 cName.c_str(), qName.c_str());
rileya@google.com3e332582012-07-03 13:43:35 +0000668
669 // Note: If there are two roots that both generate radius(t) > 0, the
670 // Canvas spec says to choose the larger t.
671
672 // so we'll look at the larger one first:
rileya@google.come38160c2012-07-03 18:03:04 +0000673 code->appendf("\t\tfloat %s = max(%s, %s);\n", tName.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000674 r0Name.c_str(), r1Name.c_str());
675
rileya@google.come38160c2012-07-03 18:03:04 +0000676 // if r(t) > 0, then we're done; t will be our x coordinate
677 code->appendf("\t\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000678 p5.c_str(), p3.c_str());
rileya@google.come38160c2012-07-03 18:03:04 +0000679
rileya@google.come38160c2012-07-03 18:03:04 +0000680 code->appendf("\t\t");
rileya@google.com22e57f92012-07-19 15:16:19 +0000681 this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
rileya@google.come38160c2012-07-03 18:03:04 +0000682
683 // otherwise, if r(t) for the larger root was <= 0, try the other root
684 code->appendf("\t\t} else {\n");
685 code->appendf("\t\t\t%s = min(%s, %s);\n", tName.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000686 r0Name.c_str(), r1Name.c_str());
687
rileya@google.come38160c2012-07-03 18:03:04 +0000688 // if r(t) > 0 for the smaller root, then t will be our x coordinate
689 code->appendf("\t\t\tif (%s * %s + %s > 0.0) {\n",
rileya@google.com3e332582012-07-03 13:43:35 +0000690 tName.c_str(), p5.c_str(), p3.c_str());
rileya@google.come38160c2012-07-03 18:03:04 +0000691
rileya@google.come38160c2012-07-03 18:03:04 +0000692 code->appendf("\t\t\t");
rileya@google.com22e57f92012-07-19 15:16:19 +0000693 this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
rileya@google.come38160c2012-07-03 18:03:04 +0000694
695 // end if (r(t) > 0) for smaller root
696 code->appendf("\t\t\t}\n");
697 // end if (r(t) > 0), else, for larger root
698 code->appendf("\t\t}\n");
699 // end if (discriminant >= 0)
rileya@google.com3e332582012-07-03 13:43:35 +0000700 code->appendf("\t}\n");
701 } else {
702
703 // linear case: t = -c/b
704 code->appendf("\tfloat %s = -(%s / %s);\n", tName.c_str(),
705 cName.c_str(), bVar.c_str());
706
rileya@google.come38160c2012-07-03 18:03:04 +0000707 // if r(t) > 0, then t will be the x coordinate
708 code->appendf("\tif (%s * %s + %s > 0.0) {\n", tName.c_str(),
rileya@google.com3e332582012-07-03 13:43:35 +0000709 p5.c_str(), p3.c_str());
rileya@google.come38160c2012-07-03 18:03:04 +0000710 code->appendf("\t");
rileya@google.com22e57f92012-07-19 15:16:19 +0000711 this->emitColorLookup(builder, tName.c_str(), outputColor, samplerName);
rileya@google.come38160c2012-07-03 18:03:04 +0000712 code->appendf("\t}\n");
rileya@google.com3e332582012-07-03 13:43:35 +0000713 }
rileya@google.com3e332582012-07-03 13:43:35 +0000714}
715
bsalomon@google.com032b2212012-07-16 13:36:18 +0000716void GrGLConical2Gradient::initUniforms(const GrGLShaderBuilder* builder,
717 const GrGLInterface* gl,
718 int programID) {
719 const char* vsParam = builder->getUniformCStr(fVSParamUni);
720 const char* fsParam = builder->getUniformCStr(fFSParamUni);
721 GR_GL_CALL_RET(gl, fVSParamLocation, GetUniformLocation(programID, vsParam));
722 GR_GL_CALL_RET(gl, fFSParamLocation, GetUniformLocation(programID, fsParam));
rileya@google.com3e332582012-07-03 13:43:35 +0000723}
724
725void GrGLConical2Gradient::setData(const GrGLInterface* gl,
rileya@google.com3e332582012-07-03 13:43:35 +0000726 const GrCustomStage& baseData,
senorblanco@chromium.orgf4770d72012-07-13 18:25:06 +0000727 const GrRenderTarget*,
rileya@google.com3e332582012-07-03 13:43:35 +0000728 int stageNum) {
729 const GrConical2Gradient& data =
730 static_cast<const GrConical2Gradient&>(baseData);
731 GrAssert(data.isDegenerate() == fIsDegenerate);
732 GrScalar centerX1 = data.center();
733 GrScalar radius0 = data.radius();
734 GrScalar diffRadius = data.diffRadius();
735
736 if (fCachedCenter != centerX1 ||
737 fCachedRadius != radius0 ||
738 fCachedDiffRadius != diffRadius) {
739
740 GrScalar a = GrMul(centerX1, centerX1) - diffRadius * diffRadius;
741
742 // When we're in the degenerate (linear) case, the second
743 // value will be INF but the program doesn't read it. (We
744 // use the same 6 uniforms even though we don't need them
745 // all in the linear case just to keep the code complexity
746 // down).
747 float values[6] = {
748 GrScalarToFloat(a * 4),
749 1.f / (GrScalarToFloat(a)),
750 GrScalarToFloat(centerX1),
751 GrScalarToFloat(radius0),
752 GrScalarToFloat(SkScalarMul(radius0, radius0)),
753 GrScalarToFloat(diffRadius)
754 };
755
756 GR_GL_CALL(gl, Uniform1fv(fVSParamLocation, 6, values));
757 GR_GL_CALL(gl, Uniform1fv(fFSParamLocation, 6, values));
758 fCachedCenter = centerX1;
759 fCachedRadius = radius0;
760 fCachedDiffRadius = diffRadius;
761 }
762}
763
764
765/////////////////////////////////////////////////////////////////////
766
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000767GrConical2Gradient::GrConical2Gradient(GrTexture* texture,
768 GrScalar center,
rileya@google.com3e332582012-07-03 13:43:35 +0000769 GrScalar radius,
770 GrScalar diffRadius)
rileya@google.com22e57f92012-07-19 15:16:19 +0000771 : INHERITED (texture)
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000772 , fCenterX1 (center)
rileya@google.com3e332582012-07-03 13:43:35 +0000773 , fRadius0 (radius)
774 , fDiffRadius (diffRadius) {
775
776}
777
rileya@google.com91f319c2012-07-25 17:18:31 +0000778GrConical2Gradient::GrConical2Gradient(GrContext* ctx,
779 const SkShader& shader,
780 GrSamplerState* sampler,
781 SkScalar center,
782 SkScalar startRadius,
783 SkScalar diffRadius)
784 : INHERITED(ctx, shader, sampler)
785 , fCenterX1(center)
786 , fRadius0(startRadius)
787 , fDiffRadius(diffRadius) {
rileya@google.com03c1c352012-07-20 20:02:43 +0000788}
789
rileya@google.com3e332582012-07-03 13:43:35 +0000790GrConical2Gradient::~GrConical2Gradient() {
791
792}
793
794
795const GrProgramStageFactory& GrConical2Gradient::getFactory() const {
796 return GrTProgramStageFactory<GrConical2Gradient>::getInstance();
797}
798
799bool GrConical2Gradient::isEqual(const GrCustomStage& sBase) const {
800 const GrConical2Gradient& s = static_cast<const GrConical2Gradient&>(sBase);
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000801 return (INHERITED::isEqual(sBase) &&
802 this->fCenterX1 == s.fCenterX1 &&
tomhudson@google.com1dcfa1f2012-07-09 18:21:28 +0000803 this->fRadius0 == s.fRadius0 &&
804 this->fDiffRadius == s.fDiffRadius);
rileya@google.com3e332582012-07-03 13:43:35 +0000805}
806
807/////////////////////////////////////////////////////////////////////
808
809
rileya@google.com22e57f92012-07-19 15:16:19 +0000810class GrGLSweepGradient : public GrGLGradientStage {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000811
812public:
813
814 GrGLSweepGradient(const GrProgramStageFactory& factory,
815 const GrCustomStage&) : INHERITED (factory) { }
816 virtual ~GrGLSweepGradient() { }
817
bsalomon@google.com032b2212012-07-16 13:36:18 +0000818 virtual void emitVS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000819 const char* vertexCoords) SK_OVERRIDE { }
bsalomon@google.com032b2212012-07-16 13:36:18 +0000820 virtual void emitFS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000821 const char* outputColor,
822 const char* inputColor,
823 const char* samplerName) SK_OVERRIDE;
824
825 static StageKey GenKey(const GrCustomStage& s) { return 0; }
826
827private:
828
rileya@google.com22e57f92012-07-19 15:16:19 +0000829 typedef GrGLGradientStage INHERITED;
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000830
831};
832
bsalomon@google.com032b2212012-07-16 13:36:18 +0000833void GrGLSweepGradient::emitFS(GrGLShaderBuilder* builder,
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000834 const char* outputColor,
835 const char* inputColor,
836 const char* samplerName) {
rileya@google.com22e57f92012-07-19 15:16:19 +0000837 SkString t;
838 t.printf("atan(- %s.y, - %s.x) * 0.1591549430918 + 0.5",
bsalomon@google.com032b2212012-07-16 13:36:18 +0000839 builder->fSampleCoords.c_str(), builder->fSampleCoords.c_str());
rileya@google.com22e57f92012-07-19 15:16:19 +0000840 this->emitColorLookup(builder, t.c_str(), outputColor, samplerName);
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000841}
842
843/////////////////////////////////////////////////////////////////////
844
tomhudson@google.comd0c1a062012-07-12 17:23:52 +0000845GrSweepGradient::GrSweepGradient(GrTexture* texture)
rileya@google.com22e57f92012-07-19 15:16:19 +0000846 : INHERITED(texture) {
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000847
848}
849
rileya@google.com91f319c2012-07-25 17:18:31 +0000850GrSweepGradient::GrSweepGradient(GrContext* ctx, const SkShader& shader,
851 GrSamplerState* sampler)
852 : INHERITED(ctx, shader, sampler) {
rileya@google.com03c1c352012-07-20 20:02:43 +0000853}
854
tomhudson@google.com7fab52d2012-05-31 19:40:13 +0000855GrSweepGradient::~GrSweepGradient() {
856
857}
858
859const GrProgramStageFactory& GrSweepGradient::getFactory() const {
860 return GrTProgramStageFactory<GrSweepGradient>::getInstance();
861}
862