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
31class GrGLDistanceFieldTextureEffect : public GrGLVertexEffect {
32public:
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
157private:
158    GrGLUniformManager::UniformHandle fTextureSizeUni;
159    SkISize                           fTextureSize;
160    GrGLUniformManager::UniformHandle fLuminanceUni;
161    float                             fLuminance;
162
163    typedef GrGLVertexEffect INHERITED;
164};
165
166///////////////////////////////////////////////////////////////////////////////
167
168GrDistanceFieldTextureEffect::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
189bool GrDistanceFieldTextureEffect::onIsEqual(const GrEffect& other) const {
190    const GrDistanceFieldTextureEffect& cte = CastEffect<GrDistanceFieldTextureEffect>(other);
191    return fTextureAccess == cte.fTextureAccess;
192}
193
194void 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
204const GrBackendEffectFactory& GrDistanceFieldTextureEffect::getFactory() const {
205    return GrTBackendEffectFactory<GrDistanceFieldTextureEffect>::getInstance();
206}
207
208///////////////////////////////////////////////////////////////////////////////
209
210GR_DEFINE_EFFECT_TEST(GrDistanceFieldTextureEffect);
211
212GrEffectRef* 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
248class GrGLDistanceFieldLCDTextureEffect : public GrGLVertexEffect {
249public:
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
421private:
422    GrGLUniformManager::UniformHandle fTextureSizeUni;
423    SkISize                           fTextureSize;
424    GrGLUniformManager::UniformHandle fTextColorUni;
425    SkColor                           fTextColor;
426
427    typedef GrGLVertexEffect INHERITED;
428};
429
430///////////////////////////////////////////////////////////////////////////////
431
432GrDistanceFieldLCDTextureEffect::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
447bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrEffect& other) const {
448    const GrDistanceFieldLCDTextureEffect& cte =
449                                            CastEffect<GrDistanceFieldLCDTextureEffect>(other);
450    return (fTextureAccess == cte.fTextureAccess && fGammaTextureAccess == cte.fGammaTextureAccess);
451}
452
453void 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
463const GrBackendEffectFactory& GrDistanceFieldLCDTextureEffect::getFactory() const {
464    return GrTBackendEffectFactory<GrDistanceFieldLCDTextureEffect>::getInstance();
465}
466
467///////////////////////////////////////////////////////////////////////////////
468
469GR_DEFINE_EFFECT_TEST(GrDistanceFieldLCDTextureEffect);
470
471GrEffectRef* 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