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/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 }
    530