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