Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / skia / src / gpu / effects / GrDistanceFieldTextureEffect.cpp
1 /*
2  * Copyright 2013 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 "GrDistanceFieldTextureEffect.h"
9 #include "gl/builders/GrGLFullProgramBuilder.h"
10 #include "gl/GrGLProcessor.h"
11 #include "gl/GrGLSL.h"
12 #include "gl/GrGLTexture.h"
13 #include "gl/GrGLGeometryProcessor.h"
14 #include "GrTBackendProcessorFactory.h"
15 #include "GrTexture.h"
16
17 #include "SkDistanceFieldGen.h"
18
19 // To get optical sizes people don't complain about when we blit correctly,
20 // we need to slightly bold each glyph. On the Mac, we need a larger bold value.
21 #if defined(SK_BUILD_FOR_MAC)
22 #define SK_DistanceFieldLCDFactor    "0.33"
23 #define SK_DistanceFieldNonLCDFactor "0.25"
24 #else
25 #define SK_DistanceFieldLCDFactor    "0.05"
26 #define SK_DistanceFieldNonLCDFactor "0.05"
27 #endif
28
29 // Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2
30 #define SK_DistanceFieldAAFactor     "0.7071"
31
32 class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
33 public:
34     GrGLDistanceFieldTextureEffect(const GrBackendProcessorFactory& factory,
35                                    const GrProcessor&)
36         : INHERITED (factory)
37         , fTextureSize(SkISize::Make(-1,-1))
38 #ifdef SK_GAMMA_APPLY_TO_A8
39         , fLuminance(-1.0f)
40 #endif
41         {}
42
43     virtual void emitCode(GrGLFullProgramBuilder* builder,
44                           const GrGeometryProcessor& geometryProcessor,
45                           const GrProcessorKey& key,
46                           const char* outputColor,
47                           const char* inputColor,
48                           const TransformedCoordsArray&,
49                           const TextureSamplerArray& samplers) SK_OVERRIDE {
50         const GrDistanceFieldTextureEffect& dfTexEffect =
51                 geometryProcessor.cast<GrDistanceFieldTextureEffect>();
52         SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
53
54         GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
55         SkAssertResult(fsBuilder->enableFeature(
56                 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
57
58         SkString fsCoordName;
59         const char* vsCoordName;
60         const char* fsCoordNamePtr;
61         builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
62         fsCoordName = fsCoordNamePtr;
63
64         GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
65         vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
66
67         const char* textureSizeUniName = NULL;
68         fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
69                                               kVec2f_GrSLType, "TextureSize",
70                                               &textureSizeUniName);
71
72         fsBuilder->codeAppend("\tvec4 texColor = ");
73         fsBuilder->appendTextureLookup(samplers[0],
74                                        fsCoordName.c_str(),
75                                        kVec2f_GrSLType);
76         fsBuilder->codeAppend(";\n");
77         fsBuilder->codeAppend("\tfloat distance = "
78                           SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ")"
79                           "+ " SK_DistanceFieldNonLCDFactor ";\n");
80
81         // we adjust for the effect of the transformation on the distance by using
82         // the length of the gradient of the texture coordinates. We use st coordinates
83         // to ensure we're mapping 1:1 from texel space to pixel space.
84         fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
85         fsBuilder->codeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName);
86         fsBuilder->codeAppend("\tfloat afwidth;\n");
87         if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
88             // this gives us a smooth step across approximately one fragment
89             fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dFdx(st.x);\n");
90         } else {
91             fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
92             fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
93
94             fsBuilder->codeAppend("\tvec2 uv_grad;\n");
95             if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) {
96                 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
97                 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
98                 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
99                 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
100                 fsBuilder->codeAppend("\t} else {\n");
101                 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
102                 fsBuilder->codeAppend("\t}\n");
103             } else {
104                 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
105             }
106             fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
107             fsBuilder->codeAppend("\t                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
108
109             // this gives us a smooth step across approximately one fragment
110             fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
111         }
112         fsBuilder->codeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n");
113
114 #ifdef SK_GAMMA_APPLY_TO_A8
115         // adjust based on gamma
116         const char* luminanceUniName = NULL;
117         // width, height, 1/(3*width)
118         fLuminanceUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
119                                             kFloat_GrSLType, "Luminance",
120                                             &luminanceUniName);
121
122         fsBuilder->codeAppendf("\tuv = vec2(val, %s);\n", luminanceUniName);
123         fsBuilder->codeAppend("\tvec4 gammaColor = ");
124         fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
125         fsBuilder->codeAppend(";\n");
126         fsBuilder->codeAppend("\tval = gammaColor.r;\n");
127 #endif
128
129         fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
130                                    (GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str());
131     }
132
133     virtual void setData(const GrGLProgramDataManager& pdman,
134                          const GrProcessor& effect) SK_OVERRIDE {
135         SkASSERT(fTextureSizeUni.isValid());
136
137         GrTexture* texture = effect.texture(0);
138         if (texture->width() != fTextureSize.width() ||
139             texture->height() != fTextureSize.height()) {
140             fTextureSize = SkISize::Make(texture->width(), texture->height());
141             pdman.set2f(fTextureSizeUni,
142                         SkIntToScalar(fTextureSize.width()),
143                         SkIntToScalar(fTextureSize.height()));
144         }
145 #ifdef SK_GAMMA_APPLY_TO_A8
146         const GrDistanceFieldTextureEffect& dfTexEffect =
147                 effect.cast<GrDistanceFieldTextureEffect>();
148         float luminance = dfTexEffect.getLuminance();
149         if (luminance != fLuminance) {
150             pdman.set1f(fLuminanceUni, luminance);
151             fLuminance = luminance;
152         }
153 #endif
154     }
155
156     static inline void GenKey(const GrProcessor& processor, const GrGLCaps&,
157                               GrProcessorKeyBuilder* b) {
158         const GrDistanceFieldTextureEffect& dfTexEffect =
159                 processor.cast<GrDistanceFieldTextureEffect>();
160
161         b->add32(dfTexEffect.getFlags());
162     }
163
164 private:
165     GrGLProgramDataManager::UniformHandle fTextureSizeUni;
166     SkISize                               fTextureSize;
167     GrGLProgramDataManager::UniformHandle fLuminanceUni;
168     float                                 fLuminance;
169
170     typedef GrGLGeometryProcessor INHERITED;
171 };
172
173 ///////////////////////////////////////////////////////////////////////////////
174
175 GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture,
176                                                            const GrTextureParams& params,
177 #ifdef SK_GAMMA_APPLY_TO_A8
178                                                            GrTexture* gamma,
179                                                            const GrTextureParams& gammaParams,
180                                                            float luminance,
181 #endif
182                                                            uint32_t flags)
183     : fTextureAccess(texture, params)
184 #ifdef SK_GAMMA_APPLY_TO_A8
185     , fGammaTextureAccess(gamma, gammaParams)
186     , fLuminance(luminance)
187 #endif
188     , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
189     , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
190                                                          kVec2f_GrSLType,
191                                                          GrShaderVar::kAttribute_TypeModifier))) {
192     SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
193     this->addTextureAccess(&fTextureAccess);
194 #ifdef SK_GAMMA_APPLY_TO_A8
195     this->addTextureAccess(&fGammaTextureAccess);
196 #endif
197 }
198
199 bool GrDistanceFieldTextureEffect::onIsEqual(const GrProcessor& other) const {
200     const GrDistanceFieldTextureEffect& cte = other.cast<GrDistanceFieldTextureEffect>();
201     return fTextureAccess == cte.fTextureAccess &&
202 #ifdef SK_GAMMA_APPLY_TO_A8
203            fGammaTextureAccess == cte.fGammaTextureAccess &&
204            fLuminance == cte.fLuminance &&
205 #endif
206            fFlags == cte.fFlags;
207 }
208
209 void GrDistanceFieldTextureEffect::getConstantColorComponents(GrColor* color,
210                                                              uint32_t* validFlags) const {
211     if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) &&
212         GrPixelConfigIsOpaque(this->texture(0)->config())) {
213         *validFlags = kA_GrColorComponentFlag;
214     } else {
215         *validFlags = 0;
216     }
217 }
218
219 const GrBackendGeometryProcessorFactory& GrDistanceFieldTextureEffect::getFactory() const {
220     return GrTBackendGeometryProcessorFactory<GrDistanceFieldTextureEffect>::getInstance();
221 }
222
223 ///////////////////////////////////////////////////////////////////////////////
224
225 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect);
226
227 GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
228                                                               GrContext*,
229                                                               const GrDrawTargetCaps&,
230                                                               GrTexture* textures[]) {
231     int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
232                                       GrProcessorUnitTest::kAlphaTextureIdx;
233 #ifdef SK_GAMMA_APPLY_TO_A8
234     int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
235                                        GrProcessorUnitTest::kAlphaTextureIdx;
236 #endif
237     static const SkShader::TileMode kTileModes[] = {
238         SkShader::kClamp_TileMode,
239         SkShader::kRepeat_TileMode,
240         SkShader::kMirror_TileMode,
241     };
242     SkShader::TileMode tileModes[] = {
243         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
244         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
245     };
246     GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
247                                                            GrTextureParams::kNone_FilterMode);
248 #ifdef SK_GAMMA_APPLY_TO_A8
249     GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
250                                                             GrTextureParams::kNone_FilterMode);
251 #endif
252
253     return GrDistanceFieldTextureEffect::Create(textures[texIdx], params,
254 #ifdef SK_GAMMA_APPLY_TO_A8
255                                                 textures[texIdx2], params2,
256                                                 random->nextF(),
257 #endif
258                                                 random->nextBool() ?
259                                                     kSimilarity_DistanceFieldEffectFlag : 0);
260 }
261
262 ///////////////////////////////////////////////////////////////////////////////
263
264 class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
265 public:
266     GrGLDistanceFieldLCDTextureEffect(const GrBackendProcessorFactory& factory,
267                                       const GrProcessor&)
268     : INHERITED (factory)
269     , fTextureSize(SkISize::Make(-1,-1))
270     , fTextColor(GrColor_ILLEGAL) {}
271
272     virtual void emitCode(GrGLFullProgramBuilder* builder,
273                           const GrGeometryProcessor& geometryProcessor,
274                           const GrProcessorKey& key,
275                           const char* outputColor,
276                           const char* inputColor,
277                           const TransformedCoordsArray&,
278                           const TextureSamplerArray& samplers) SK_OVERRIDE {
279         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
280                 geometryProcessor.cast<GrDistanceFieldLCDTextureEffect>();
281         SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
282
283         SkString fsCoordName;
284         const char* vsCoordName;
285         const char* fsCoordNamePtr;
286         builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
287         fsCoordName = fsCoordNamePtr;
288
289         GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
290         vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
291
292         const char* textureSizeUniName = NULL;
293         // width, height, 1/(3*width)
294         fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
295                                               kVec3f_GrSLType, "TextureSize",
296                                               &textureSizeUniName);
297
298         GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
299
300         SkAssertResult(fsBuilder->enableFeature(
301                 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
302
303         // create LCD offset adjusted by inverse of transform
304         fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
305         fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
306         bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
307         if (isUniformScale) {
308             fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n");
309             fsBuilder->codeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName);
310         } else {
311             fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
312             fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
313             fsBuilder->codeAppendf("\tvec2 offset = %s.z*Jdx;\n", textureSizeUniName);
314         }
315
316         // green is distance to uv center
317         fsBuilder->codeAppend("\tvec4 texColor = ");
318         fsBuilder->appendTextureLookup(samplers[0], "uv", kVec2f_GrSLType);
319         fsBuilder->codeAppend(";\n");
320         fsBuilder->codeAppend("\tvec3 distance;\n");
321         fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
322         // red is distance to left offset
323         fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
324         fsBuilder->codeAppend("\ttexColor = ");
325         fsBuilder->appendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
326         fsBuilder->codeAppend(";\n");
327         fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
328         // blue is distance to right offset
329         fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
330         fsBuilder->codeAppend("\ttexColor = ");
331         fsBuilder->appendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
332         fsBuilder->codeAppend(";\n");
333         fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
334
335         fsBuilder->codeAppend("\tdistance = "
336             "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"))"
337             "+ vec3(" SK_DistanceFieldLCDFactor ");\n");
338
339         // we adjust for the effect of the transformation on the distance by using
340         // the length of the gradient of the texture coordinates. We use st coordinates
341         // to ensure we're mapping 1:1 from texel space to pixel space.
342
343         // To be strictly correct, we should compute the anti-aliasing factor separately
344         // for each color component. However, this is only important when using perspective
345         // transformations, and even then using a single factor seems like a reasonable
346         // trade-off between quality and speed.
347         fsBuilder->codeAppend("\tfloat afwidth;\n");
348         if (isUniformScale) {
349             // this gives us a smooth step across approximately one fragment
350             fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dx;\n");
351         } else {
352             fsBuilder->codeAppend("\tvec2 uv_grad;\n");
353             if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) {
354                 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
355                 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
356                 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
357                 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
358                 fsBuilder->codeAppend("\t} else {\n");
359                 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
360                 fsBuilder->codeAppend("\t}\n");
361             } else {
362                 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
363             }
364             fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
365             fsBuilder->codeAppend("\t                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
366
367             // this gives us a smooth step across approximately one fragment
368             fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
369         }
370
371         fsBuilder->codeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n");
372
373         // adjust based on gamma
374         const char* textColorUniName = NULL;
375         // width, height, 1/(3*width)
376         fTextColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
377                                             kVec3f_GrSLType, "TextColor",
378                                             &textColorUniName);
379
380         fsBuilder->codeAppendf("\tuv = vec2(val.x, %s.x);\n", textColorUniName);
381         fsBuilder->codeAppend("\tvec4 gammaColor = ");
382         fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
383         fsBuilder->codeAppend(";\n");
384         fsBuilder->codeAppend("\tval.x = gammaColor.r;\n");
385
386         fsBuilder->codeAppendf("\tuv = vec2(val.y, %s.y);\n", textColorUniName);
387         fsBuilder->codeAppend("\tgammaColor = ");
388         fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
389         fsBuilder->codeAppend(";\n");
390         fsBuilder->codeAppend("\tval.y = gammaColor.r;\n");
391
392         fsBuilder->codeAppendf("\tuv = vec2(val.z, %s.z);\n", textColorUniName);
393         fsBuilder->codeAppend("\tgammaColor = ");
394         fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
395         fsBuilder->codeAppend(";\n");
396         fsBuilder->codeAppend("\tval.z = gammaColor.r;\n");
397
398         fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
399                                (GrGLSLExpr4(inputColor) * GrGLSLExpr4("val")).c_str());
400     }
401
402     virtual void setData(const GrGLProgramDataManager& pdman,
403                          const GrProcessor& processor) SK_OVERRIDE {
404         SkASSERT(fTextureSizeUni.isValid());
405         SkASSERT(fTextColorUni.isValid());
406
407         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
408                 processor.cast<GrDistanceFieldLCDTextureEffect>();
409         GrTexture* texture = processor.texture(0);
410         if (texture->width() != fTextureSize.width() ||
411             texture->height() != fTextureSize.height()) {
412             fTextureSize = SkISize::Make(texture->width(), texture->height());
413             float delta = 1.0f/(3.0f*texture->width());
414             if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
415                 delta = -delta;
416             }
417             pdman.set3f(fTextureSizeUni,
418                         SkIntToScalar(fTextureSize.width()),
419                         SkIntToScalar(fTextureSize.height()),
420                         delta);
421         }
422
423         GrColor textColor = dfTexEffect.getTextColor();
424         if (textColor != fTextColor) {
425             static const float ONE_OVER_255 = 1.f / 255.f;
426             pdman.set3f(fTextColorUni,
427                         GrColorUnpackR(textColor) * ONE_OVER_255,
428                         GrColorUnpackG(textColor) * ONE_OVER_255,
429                         GrColorUnpackB(textColor) * ONE_OVER_255);
430             fTextColor = textColor;
431         }
432     }
433
434     static inline void GenKey(const GrProcessor& processor, const GrGLCaps&,
435                               GrProcessorKeyBuilder* b) {
436         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
437                 processor.cast<GrDistanceFieldLCDTextureEffect>();
438
439         b->add32(dfTexEffect.getFlags());
440     }
441
442 private:
443     GrGLProgramDataManager::UniformHandle fTextureSizeUni;
444     SkISize                               fTextureSize;
445     GrGLProgramDataManager::UniformHandle fTextColorUni;
446     SkColor                               fTextColor;
447
448     typedef GrGLGeometryProcessor INHERITED;
449 };
450
451 ///////////////////////////////////////////////////////////////////////////////
452
453 GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect(
454                                                   GrTexture* texture, const GrTextureParams& params,
455                                                   GrTexture* gamma, const GrTextureParams& gParams,
456                                                   SkColor textColor,
457                                                   uint32_t flags)
458     : fTextureAccess(texture, params)
459     , fGammaTextureAccess(gamma, gParams)
460     , fTextColor(textColor)
461     , fFlags(flags & kLCD_DistanceFieldEffectMask)
462     , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
463                                                          kVec2f_GrSLType,
464                                                          GrShaderVar::kAttribute_TypeModifier))) {
465     SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
466         
467     this->addTextureAccess(&fTextureAccess);
468     this->addTextureAccess(&fGammaTextureAccess);
469 }
470
471 bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrProcessor& other) const {
472     const GrDistanceFieldLCDTextureEffect& cte = other.cast<GrDistanceFieldLCDTextureEffect>();
473     return (fTextureAccess == cte.fTextureAccess &&
474             fGammaTextureAccess == cte.fGammaTextureAccess &&
475             fTextColor == cte.fTextColor &&
476             fFlags == cte.fFlags);
477 }
478
479 void GrDistanceFieldLCDTextureEffect::getConstantColorComponents(GrColor* color,
480                                                                  uint32_t* validFlags) const {
481     if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) &&
482         GrPixelConfigIsOpaque(this->texture(0)->config())) {
483         *validFlags = kA_GrColorComponentFlag;
484     } else {
485         *validFlags = 0;
486     }
487 }
488
489 const GrBackendGeometryProcessorFactory& GrDistanceFieldLCDTextureEffect::getFactory() const {
490     return GrTBackendGeometryProcessorFactory<GrDistanceFieldLCDTextureEffect>::getInstance();
491 }
492
493 ///////////////////////////////////////////////////////////////////////////////
494
495 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect);
496
497 GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random,
498                                                                  GrContext*,
499                                                                  const GrDrawTargetCaps&,
500                                                                  GrTexture* textures[]) {
501     int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
502                                       GrProcessorUnitTest::kAlphaTextureIdx;
503     int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
504                                        GrProcessorUnitTest::kAlphaTextureIdx;
505     static const SkShader::TileMode kTileModes[] = {
506         SkShader::kClamp_TileMode,
507         SkShader::kRepeat_TileMode,
508         SkShader::kMirror_TileMode,
509     };
510     SkShader::TileMode tileModes[] = {
511         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
512         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
513     };
514     GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
515                            GrTextureParams::kNone_FilterMode);
516     GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
517                            GrTextureParams::kNone_FilterMode);
518     GrColor textColor = GrColorPackRGBA(random->nextULessThan(256),
519                                         random->nextULessThan(256),
520                                         random->nextULessThan(256),
521                                         random->nextULessThan(256));
522     uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
523     flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
524     flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
525     return GrDistanceFieldLCDTextureEffect::Create(textures[texIdx], params,
526                                                    textures[texIdx2], params2,
527                                                    textColor,
528                                                    flags);
529 }