Update To 11.40.268.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/GrGLProgramBuilder.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 // Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2
20 #define SK_DistanceFieldAAFactor     "0.7071"
21
22 class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
23 public:
24     GrGLDistanceFieldTextureEffect(const GrBackendProcessorFactory& factory,
25                                    const GrProcessor&)
26         : INHERITED (factory)
27         , fTextureSize(SkISize::Make(-1,-1))
28 #ifdef SK_GAMMA_APPLY_TO_A8
29         , fLuminance(-1.0f)
30 #endif
31         {}
32
33     virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
34         const GrDistanceFieldTextureEffect& dfTexEffect =
35                 args.fGP.cast<GrDistanceFieldTextureEffect>();
36         SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
37
38         GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
39         SkAssertResult(fsBuilder->enableFeature(
40                 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
41
42         GrGLVertToFrag v(kVec2f_GrSLType);
43         args.fPB->addVarying("TextureCoords", &v);
44
45         GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
46         vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
47
48         const char* textureSizeUniName = NULL;
49         fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
50                                                kVec2f_GrSLType, "TextureSize",
51                                                &textureSizeUniName);
52
53         fsBuilder->codeAppend("\tvec4 texColor = ");
54         fsBuilder->appendTextureLookup(args.fSamplers[0],
55                                        v.fsIn(),
56                                        kVec2f_GrSLType);
57         fsBuilder->codeAppend(";\n");
58         fsBuilder->codeAppend("\tfloat distance = "
59                        SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
60
61         // we adjust for the effect of the transformation on the distance by using
62         // the length of the gradient of the texture coordinates. We use st coordinates
63         // to ensure we're mapping 1:1 from texel space to pixel space.
64         fsBuilder->codeAppendf("\tvec2 uv = %s;\n", v.fsIn());
65         fsBuilder->codeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName);
66         fsBuilder->codeAppend("\tfloat afwidth;\n");
67         if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
68             // this gives us a smooth step across approximately one fragment
69             fsBuilder->codeAppend("\tafwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));\n");
70         } else {
71             fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
72             fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
73
74             fsBuilder->codeAppend("\tvec2 uv_grad;\n");
75             if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
76                 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
77                 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
78                 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
79                 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
80                 fsBuilder->codeAppend("\t} else {\n");
81                 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
82                 fsBuilder->codeAppend("\t}\n");
83             } else {
84                 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
85             }
86             fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
87             fsBuilder->codeAppend("\t                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
88
89             // this gives us a smooth step across approximately one fragment
90             fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
91         }
92         fsBuilder->codeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n");
93
94 #ifdef SK_GAMMA_APPLY_TO_A8
95         // adjust based on gamma
96         const char* luminanceUniName = NULL;
97         // width, height, 1/(3*width)
98         fLuminanceUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
99                                              kFloat_GrSLType, "Luminance",
100                                              &luminanceUniName);
101
102         fsBuilder->codeAppendf("\tuv = vec2(val, %s);\n", luminanceUniName);
103         fsBuilder->codeAppend("\tvec4 gammaColor = ");
104         fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
105         fsBuilder->codeAppend(";\n");
106         fsBuilder->codeAppend("\tval = gammaColor.r;\n");
107 #endif
108
109         fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
110                                    (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("val")).c_str());
111     }
112
113     virtual void setData(const GrGLProgramDataManager& pdman,
114                          const GrProcessor& effect) SK_OVERRIDE {
115         SkASSERT(fTextureSizeUni.isValid());
116
117         GrTexture* texture = effect.texture(0);
118         if (texture->width() != fTextureSize.width() ||
119             texture->height() != fTextureSize.height()) {
120             fTextureSize = SkISize::Make(texture->width(), texture->height());
121             pdman.set2f(fTextureSizeUni,
122                         SkIntToScalar(fTextureSize.width()),
123                         SkIntToScalar(fTextureSize.height()));
124         }
125 #ifdef SK_GAMMA_APPLY_TO_A8
126         const GrDistanceFieldTextureEffect& dfTexEffect =
127                 effect.cast<GrDistanceFieldTextureEffect>();
128         float luminance = dfTexEffect.getLuminance();
129         if (luminance != fLuminance) {
130             pdman.set1f(fLuminanceUni, luminance);
131             fLuminance = luminance;
132         }
133 #endif
134     }
135
136     static inline void GenKey(const GrProcessor& processor, const GrGLCaps&,
137                               GrProcessorKeyBuilder* b) {
138         const GrDistanceFieldTextureEffect& dfTexEffect =
139                 processor.cast<GrDistanceFieldTextureEffect>();
140
141         b->add32(dfTexEffect.getFlags());
142     }
143
144 private:
145     GrGLProgramDataManager::UniformHandle fTextureSizeUni;
146     SkISize                               fTextureSize;
147     GrGLProgramDataManager::UniformHandle fLuminanceUni;
148     float                                 fLuminance;
149
150     typedef GrGLGeometryProcessor INHERITED;
151 };
152
153 ///////////////////////////////////////////////////////////////////////////////
154
155 GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture,
156                                                            const GrTextureParams& params,
157 #ifdef SK_GAMMA_APPLY_TO_A8
158                                                            GrTexture* gamma,
159                                                            const GrTextureParams& gammaParams,
160                                                            float luminance,
161 #endif
162                                                            uint32_t flags)
163     : fTextureAccess(texture, params)
164 #ifdef SK_GAMMA_APPLY_TO_A8
165     , fGammaTextureAccess(gamma, gammaParams)
166     , fLuminance(luminance)
167 #endif
168     , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
169     , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
170                                                          kVec2f_GrSLType,
171                                                          GrShaderVar::kAttribute_TypeModifier))) {
172     SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
173     this->addTextureAccess(&fTextureAccess);
174 #ifdef SK_GAMMA_APPLY_TO_A8
175     this->addTextureAccess(&fGammaTextureAccess);
176 #endif
177 }
178
179 bool GrDistanceFieldTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
180     const GrDistanceFieldTextureEffect& cte = other.cast<GrDistanceFieldTextureEffect>();
181     return
182 #ifdef SK_GAMMA_APPLY_TO_A8
183            fLuminance == cte.fLuminance &&
184 #endif
185            fFlags == cte.fFlags;
186 }
187
188 void GrDistanceFieldTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
189     inout->mulByUnknownAlpha();
190 }
191
192 const GrBackendGeometryProcessorFactory& GrDistanceFieldTextureEffect::getFactory() const {
193     return GrTBackendGeometryProcessorFactory<GrDistanceFieldTextureEffect>::getInstance();
194 }
195
196 ///////////////////////////////////////////////////////////////////////////////
197
198 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect);
199
200 GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
201                                                               GrContext*,
202                                                               const GrDrawTargetCaps&,
203                                                               GrTexture* textures[]) {
204     int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
205                                       GrProcessorUnitTest::kAlphaTextureIdx;
206 #ifdef SK_GAMMA_APPLY_TO_A8
207     int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
208                                        GrProcessorUnitTest::kAlphaTextureIdx;
209 #endif
210     static const SkShader::TileMode kTileModes[] = {
211         SkShader::kClamp_TileMode,
212         SkShader::kRepeat_TileMode,
213         SkShader::kMirror_TileMode,
214     };
215     SkShader::TileMode tileModes[] = {
216         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
217         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
218     };
219     GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
220                                                            GrTextureParams::kNone_FilterMode);
221 #ifdef SK_GAMMA_APPLY_TO_A8
222     GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
223                                                             GrTextureParams::kNone_FilterMode);
224 #endif
225
226     return GrDistanceFieldTextureEffect::Create(textures[texIdx], params,
227 #ifdef SK_GAMMA_APPLY_TO_A8
228                                                 textures[texIdx2], params2,
229                                                 random->nextF(),
230 #endif
231                                                 random->nextBool() ?
232                                                     kSimilarity_DistanceFieldEffectFlag : 0);
233 }
234
235 ///////////////////////////////////////////////////////////////////////////////
236
237 class GrGLDistanceFieldNoGammaTextureEffect : public GrGLGeometryProcessor {
238 public:
239     GrGLDistanceFieldNoGammaTextureEffect(const GrBackendProcessorFactory& factory,
240                                           const GrProcessor& effect)
241         : INHERITED(factory)
242         , fTextureSize(SkISize::Make(-1, -1)) {}
243
244     virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
245         const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
246                 args.fGP.cast<GrDistanceFieldNoGammaTextureEffect>();
247         SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
248
249         GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
250         SkAssertResult(fsBuilder->enableFeature(
251                                      GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
252
253         GrGLVertToFrag v(kVec2f_GrSLType);
254         args.fPB->addVarying("TextureCoords", &v);
255
256         GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
257         vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
258
259         const char* textureSizeUniName = NULL;
260         fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
261                                               kVec2f_GrSLType, "TextureSize",
262                                               &textureSizeUniName);
263
264         fsBuilder->codeAppend("vec4 texColor = ");
265         fsBuilder->appendTextureLookup(args.fSamplers[0],
266                                        v.fsIn(),
267                                        kVec2f_GrSLType);
268         fsBuilder->codeAppend(";");
269         fsBuilder->codeAppend("float distance = "
270             SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
271
272         // we adjust for the effect of the transformation on the distance by using
273         // the length of the gradient of the texture coordinates. We use st coordinates
274         // to ensure we're mapping 1:1 from texel space to pixel space.
275         fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
276         fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
277         fsBuilder->codeAppend("float afwidth;");
278         if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
279             // this gives us a smooth step across approximately one fragment
280             fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));");
281         } else {
282             fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
283             fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
284
285             fsBuilder->codeAppend("vec2 uv_grad;");
286             if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
287                 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
288                 fsBuilder->codeAppend("float uv_len2 = dot(uv, uv);");
289                 fsBuilder->codeAppend("if (uv_len2 < 0.0001) {");
290                 fsBuilder->codeAppend("uv_grad = vec2(0.7071, 0.7071);");
291                 fsBuilder->codeAppend("} else {");
292                 fsBuilder->codeAppend("uv_grad = uv*inversesqrt(uv_len2);");
293                 fsBuilder->codeAppend("}");
294             } else {
295                 fsBuilder->codeAppend("uv_grad = normalize(uv);");
296             }
297             fsBuilder->codeAppend("vec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,");
298             fsBuilder->codeAppend("                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);");
299
300             // this gives us a smooth step across approximately one fragment
301             fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
302         }
303         fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
304
305         fsBuilder->codeAppendf("%s = %s;", args.fOutput,
306             (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("val")).c_str());
307     }
308
309     virtual void setData(const GrGLProgramDataManager& pdman,
310                          const GrProcessor& effect) SK_OVERRIDE {
311         SkASSERT(fTextureSizeUni.isValid());
312
313         GrTexture* texture = effect.texture(0);
314         if (texture->width() != fTextureSize.width() || 
315             texture->height() != fTextureSize.height()) {
316             fTextureSize = SkISize::Make(texture->width(), texture->height());
317             pdman.set2f(fTextureSizeUni,
318                         SkIntToScalar(fTextureSize.width()),
319                         SkIntToScalar(fTextureSize.height()));
320         }
321     }
322
323     static inline void GenKey(const GrProcessor& effect, const GrGLCaps&,
324                               GrProcessorKeyBuilder* b) {
325         const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
326             effect.cast<GrDistanceFieldNoGammaTextureEffect>();
327
328         b->add32(dfTexEffect.getFlags());
329     }
330
331 private:
332     GrGLProgramDataManager::UniformHandle fTextureSizeUni;
333     SkISize                               fTextureSize;
334
335     typedef GrGLGeometryProcessor INHERITED;
336 };
337
338 ///////////////////////////////////////////////////////////////////////////////
339
340 GrDistanceFieldNoGammaTextureEffect::GrDistanceFieldNoGammaTextureEffect(GrTexture* texture,
341                                                                     const GrTextureParams& params,
342                                                                     uint32_t flags)
343     : fTextureAccess(texture, params)
344     , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
345     , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
346                        kVec2f_GrSLType,
347                        GrShaderVar::kAttribute_TypeModifier))) {
348     SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
349     this->addTextureAccess(&fTextureAccess);
350 }
351
352 bool GrDistanceFieldNoGammaTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
353     const GrDistanceFieldNoGammaTextureEffect& cte = 
354                                                  other.cast<GrDistanceFieldNoGammaTextureEffect>();
355     return fFlags == cte.fFlags;
356 }
357
358 void GrDistanceFieldNoGammaTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
359     inout->mulByUnknownAlpha();
360 }
361
362 const GrBackendGeometryProcessorFactory& GrDistanceFieldNoGammaTextureEffect::getFactory() const {
363     return GrTBackendGeometryProcessorFactory<GrDistanceFieldNoGammaTextureEffect>::getInstance();
364 }
365
366 ///////////////////////////////////////////////////////////////////////////////
367
368 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldNoGammaTextureEffect);
369
370 GrGeometryProcessor* GrDistanceFieldNoGammaTextureEffect::TestCreate(SkRandom* random,
371                                                                      GrContext*,
372                                                                      const GrDrawTargetCaps&,
373                                                                      GrTexture* textures[]) {
374     int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx 
375                                     : GrProcessorUnitTest::kAlphaTextureIdx;
376     static const SkShader::TileMode kTileModes[] = {
377         SkShader::kClamp_TileMode,
378         SkShader::kRepeat_TileMode,
379         SkShader::kMirror_TileMode,
380     };
381     SkShader::TileMode tileModes[] = {
382         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
383         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
384     };
385     GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode 
386                                                          : GrTextureParams::kNone_FilterMode);
387
388     return GrDistanceFieldNoGammaTextureEffect::Create(textures[texIdx], params,
389         random->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0);
390 }
391
392 ///////////////////////////////////////////////////////////////////////////////
393
394 class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
395 public:
396     GrGLDistanceFieldLCDTextureEffect(const GrBackendProcessorFactory& factory,
397                                       const GrProcessor&)
398     : INHERITED (factory)
399     , fTextureSize(SkISize::Make(-1,-1))
400     , fTextColor(GrColor_ILLEGAL) {}
401
402     virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
403         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
404                 args.fGP.cast<GrDistanceFieldLCDTextureEffect>();
405         SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
406
407         GrGLVertToFrag v(kVec2f_GrSLType);
408         args.fPB->addVarying("TextureCoords", &v);
409
410         GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
411         vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
412
413         const char* textureSizeUniName = NULL;
414         // width, height, 1/(3*width)
415         fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
416                                               kVec3f_GrSLType, "TextureSize",
417                                               &textureSizeUniName);
418
419         GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
420
421         SkAssertResult(fsBuilder->enableFeature(
422                 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
423
424         // create LCD offset adjusted by inverse of transform
425         fsBuilder->codeAppendf("\tvec2 uv = %s;\n", v.fsIn());
426         fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
427         bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
428         if (isUniformScale) {
429             fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n");
430             fsBuilder->codeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName);
431         } else {
432             fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
433             fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
434             fsBuilder->codeAppendf("\tvec2 offset = %s.z*Jdx;\n", textureSizeUniName);
435         }
436
437         // green is distance to uv center
438         fsBuilder->codeAppend("\tvec4 texColor = ");
439         fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
440         fsBuilder->codeAppend(";\n");
441         fsBuilder->codeAppend("\tvec3 distance;\n");
442         fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
443         // red is distance to left offset
444         fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
445         fsBuilder->codeAppend("\ttexColor = ");
446         fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
447         fsBuilder->codeAppend(";\n");
448         fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
449         // blue is distance to right offset
450         fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
451         fsBuilder->codeAppend("\ttexColor = ");
452         fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
453         fsBuilder->codeAppend(";\n");
454         fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
455
456         fsBuilder->codeAppend("\tdistance = "
457            "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
458
459         // we adjust for the effect of the transformation on the distance by using
460         // the length of the gradient of the texture coordinates. We use st coordinates
461         // to ensure we're mapping 1:1 from texel space to pixel space.
462
463         // To be strictly correct, we should compute the anti-aliasing factor separately
464         // for each color component. However, this is only important when using perspective
465         // transformations, and even then using a single factor seems like a reasonable
466         // trade-off between quality and speed.
467         fsBuilder->codeAppend("\tfloat afwidth;\n");
468         if (isUniformScale) {
469             // this gives us a smooth step across approximately one fragment
470             fsBuilder->codeAppend("\tafwidth = abs(" SK_DistanceFieldAAFactor "*dx);\n");
471         } else {
472             fsBuilder->codeAppend("\tvec2 uv_grad;\n");
473             if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
474                 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
475                 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
476                 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
477                 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
478                 fsBuilder->codeAppend("\t} else {\n");
479                 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
480                 fsBuilder->codeAppend("\t}\n");
481             } else {
482                 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
483             }
484             fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
485             fsBuilder->codeAppend("\t                 uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
486
487             // this gives us a smooth step across approximately one fragment
488             fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
489         }
490
491         fsBuilder->codeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n");
492
493         // adjust based on gamma
494         const char* textColorUniName = NULL;
495         // width, height, 1/(3*width)
496         fTextColorUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
497                                              kVec3f_GrSLType, "TextColor",
498                                              &textColorUniName);
499
500         fsBuilder->codeAppendf("\tuv = vec2(val.x, %s.x);\n", textColorUniName);
501         fsBuilder->codeAppend("\tvec4 gammaColor = ");
502         fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
503         fsBuilder->codeAppend(";\n");
504         fsBuilder->codeAppend("\tval.x = gammaColor.r;\n");
505
506         fsBuilder->codeAppendf("\tuv = vec2(val.y, %s.y);\n", textColorUniName);
507         fsBuilder->codeAppend("\tgammaColor = ");
508         fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
509         fsBuilder->codeAppend(";\n");
510         fsBuilder->codeAppend("\tval.y = gammaColor.r;\n");
511
512         fsBuilder->codeAppendf("\tuv = vec2(val.z, %s.z);\n", textColorUniName);
513         fsBuilder->codeAppend("\tgammaColor = ");
514         fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
515         fsBuilder->codeAppend(";\n");
516         fsBuilder->codeAppend("\tval.z = gammaColor.r;\n");
517
518         fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
519                                (GrGLSLExpr4(args.fInput) * GrGLSLExpr4("val")).c_str());
520     }
521
522     virtual void setData(const GrGLProgramDataManager& pdman,
523                          const GrProcessor& processor) SK_OVERRIDE {
524         SkASSERT(fTextureSizeUni.isValid());
525         SkASSERT(fTextColorUni.isValid());
526
527         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
528                 processor.cast<GrDistanceFieldLCDTextureEffect>();
529         GrTexture* texture = processor.texture(0);
530         if (texture->width() != fTextureSize.width() ||
531             texture->height() != fTextureSize.height()) {
532             fTextureSize = SkISize::Make(texture->width(), texture->height());
533             float delta = 1.0f/(3.0f*texture->width());
534             if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
535                 delta = -delta;
536             }
537             pdman.set3f(fTextureSizeUni,
538                         SkIntToScalar(fTextureSize.width()),
539                         SkIntToScalar(fTextureSize.height()),
540                         delta);
541         }
542
543         GrColor textColor = dfTexEffect.getTextColor();
544         if (textColor != fTextColor) {
545             static const float ONE_OVER_255 = 1.f / 255.f;
546             pdman.set3f(fTextColorUni,
547                         GrColorUnpackR(textColor) * ONE_OVER_255,
548                         GrColorUnpackG(textColor) * ONE_OVER_255,
549                         GrColorUnpackB(textColor) * ONE_OVER_255);
550             fTextColor = textColor;
551         }
552     }
553
554     static inline void GenKey(const GrProcessor& processor, const GrGLCaps&,
555                               GrProcessorKeyBuilder* b) {
556         const GrDistanceFieldLCDTextureEffect& dfTexEffect =
557                 processor.cast<GrDistanceFieldLCDTextureEffect>();
558
559         b->add32(dfTexEffect.getFlags());
560     }
561
562 private:
563     GrGLProgramDataManager::UniformHandle fTextureSizeUni;
564     SkISize                               fTextureSize;
565     GrGLProgramDataManager::UniformHandle fTextColorUni;
566     SkColor                               fTextColor;
567
568     typedef GrGLGeometryProcessor INHERITED;
569 };
570
571 ///////////////////////////////////////////////////////////////////////////////
572
573 GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect(
574                                                   GrTexture* texture, const GrTextureParams& params,
575                                                   GrTexture* gamma, const GrTextureParams& gParams,
576                                                   SkColor textColor,
577                                                   uint32_t flags)
578     : fTextureAccess(texture, params)
579     , fGammaTextureAccess(gamma, gParams)
580     , fTextColor(textColor)
581     , fFlags(flags & kLCD_DistanceFieldEffectMask)
582     , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
583                                                          kVec2f_GrSLType,
584                                                          GrShaderVar::kAttribute_TypeModifier))) {
585     SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
586         
587     this->addTextureAccess(&fTextureAccess);
588     this->addTextureAccess(&fGammaTextureAccess);
589 }
590
591 bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
592     const GrDistanceFieldLCDTextureEffect& cte = other.cast<GrDistanceFieldLCDTextureEffect>();
593     return (fTextColor == cte.fTextColor &&
594             fFlags == cte.fFlags);
595 }
596
597 void GrDistanceFieldLCDTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
598     inout->mulByUnknownColor();
599 }
600
601 const GrBackendGeometryProcessorFactory& GrDistanceFieldLCDTextureEffect::getFactory() const {
602     return GrTBackendGeometryProcessorFactory<GrDistanceFieldLCDTextureEffect>::getInstance();
603 }
604
605 ///////////////////////////////////////////////////////////////////////////////
606
607 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect);
608
609 GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random,
610                                                                  GrContext*,
611                                                                  const GrDrawTargetCaps&,
612                                                                  GrTexture* textures[]) {
613     int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
614                                       GrProcessorUnitTest::kAlphaTextureIdx;
615     int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
616                                        GrProcessorUnitTest::kAlphaTextureIdx;
617     static const SkShader::TileMode kTileModes[] = {
618         SkShader::kClamp_TileMode,
619         SkShader::kRepeat_TileMode,
620         SkShader::kMirror_TileMode,
621     };
622     SkShader::TileMode tileModes[] = {
623         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
624         kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
625     };
626     GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
627                            GrTextureParams::kNone_FilterMode);
628     GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
629                            GrTextureParams::kNone_FilterMode);
630     GrColor textColor = GrColorPackRGBA(random->nextULessThan(256),
631                                         random->nextULessThan(256),
632                                         random->nextULessThan(256),
633                                         random->nextULessThan(256));
634     uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
635     flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
636     flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
637     return GrDistanceFieldLCDTextureEffect::Create(textures[texIdx], params,
638                                                    textures[texIdx2], params2,
639                                                    textColor,
640                                                    flags);
641 }