GrDistanceFieldGeoProc.cpp revision bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1
16255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt/*
26255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt * Copyright 2013 Google Inc.
36255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt *
46255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt * Use of this source code is governed by a BSD-style license that can be
56255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt * found in the LICENSE file.
66255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt */
76255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt
86255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "GrDistanceFieldTextureEffect.h"
96255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "GrFontAtlasSizes.h"
106255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "GrInvariantOutput.h"
116255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "GrTexture.h"
126255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt
136255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "SkDistanceFieldGen.h"
146255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt
156255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/GrGLProcessor.h"
166255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/GrGLSL.h"
176255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/GrGLTexture.h"
186255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/GrGLGeometryProcessor.h"
196255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/builders/GrGLProgramBuilder.h"
206255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt
216255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt// Assuming a radius of a little less than the diagonal of the fragment
226255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#define SK_DistanceFieldAAFactor     "0.65"
236255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt
246255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholtstruct DistanceFieldBatchTracker {
256255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt    GrGPInput fInputColorType;
266255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt    GrColor fColor;
276255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt    bool fUsesLocalCoords;
286255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt};
296255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt
306255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholtclass GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
31bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholtpublic:
32bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt    GrGLDistanceFieldTextureEffect(const GrGeometryProcessor&,
33bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt                                   const GrBatchTracker&)
346255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt        : fColor(GrColor_ILLEGAL)
35bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt#ifdef SK_GAMMA_APPLY_TO_A8
36bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt        , fDistanceAdjust(-1.0f)
37bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt#endif
3849a5d5c4f5bf6e8d6ba344e8496d1d1fa0b4586dEric Anholt        {}
39b145e903694fa932ab1e0d955e889555193ab604Eric Anholt
40    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
41        const GrDistanceFieldTextureEffect& dfTexEffect =
42                args.fGP.cast<GrDistanceFieldTextureEffect>();
43        const DistanceFieldBatchTracker& local = args.fBT.cast<DistanceFieldBatchTracker>();
44        GrGLGPBuilder* pb = args.fPB;
45        GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
46        SkAssertResult(fsBuilder->enableFeature(
47                GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
48
49        GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
50
51        // emit attributes
52        vsBuilder->emitAttributes(dfTexEffect);
53
54#ifdef SK_GAMMA_APPLY_TO_A8
55        // adjust based on gamma
56        const char* distanceAdjustUniName = NULL;
57        // width, height, 1/(3*width)
58        fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
59            kFloat_GrSLType, kDefault_GrSLPrecision,
60            "DistanceAdjust", &distanceAdjustUniName);
61#endif
62
63        // Setup pass through color
64        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor,
65                                    dfTexEffect.inColor(), &fColorUniform);
66
67        // Setup position
68        this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix());
69
70        // emit transforms
71        const SkMatrix& localMatrix = dfTexEffect.localMatrix();
72        this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
73                             localMatrix, args.fTransformsIn, args.fTransformsOut);
74
75        // add varyings
76        GrGLVertToFrag recipScale(kFloat_GrSLType);
77        GrGLVertToFrag st(kVec2f_GrSLType);
78        bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
79        const char* viewMatrixName = this->uViewM();
80        // view matrix name is NULL if identity matrix
81        bool useInverseScale = !localMatrix.isIdentity() && viewMatrixName;
82        if (isSimilarity && useInverseScale) {
83            args.fPB->addVarying("RecipScale", &recipScale, kHigh_GrSLPrecision);
84            vsBuilder->codeAppendf("vec2 tx = vec2(%s[0][0], %s[1][0]);",
85                                   viewMatrixName, viewMatrixName);
86            vsBuilder->codeAppend("float tx2 = dot(tx, tx);");
87            vsBuilder->codeAppendf("%s = inversesqrt(tx2);", recipScale.vsOut());
88        } else {
89            args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
90            vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
91        }
92
93        GrGLVertToFrag uv(kVec2f_GrSLType);
94        args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
95        // this is only used with text, so our texture bounds always match the glyph atlas
96        vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", "
97                               GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(),
98                               dfTexEffect.inTextureCoords()->fName);
99
100        // Use highp to work around aliasing issues
101        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
102                                                             pb->ctxInfo().standard()));
103        fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
104
105        fsBuilder->codeAppend("\tfloat texColor = ");
106        fsBuilder->appendTextureLookup(args.fSamplers[0],
107                                       "uv",
108                                       kVec2f_GrSLType);
109        fsBuilder->codeAppend(".r;\n");
110        fsBuilder->codeAppend("\tfloat distance = "
111                       SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
112#ifdef SK_GAMMA_APPLY_TO_A8
113        // adjust width based on gamma
114        fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
115#endif
116
117        fsBuilder->codeAppend("float afwidth;");
118        if (isSimilarity) {
119            // For uniform scale, we adjust for the effect of the transformation on the distance
120            // either by using the inverse scale in the view matrix, or (if there is no view matrix)
121            // by using the length of the gradient of the texture coordinates. We use st coordinates
122            // with the latter to ensure we're mapping 1:1 from texel space to pixel space.
123
124            // this gives us a smooth step across approximately one fragment
125            if (useInverseScale) {
126                fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*%s);",
127                                       recipScale.fsIn());
128            } else {
129                fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(%s.x));",
130                                       st.fsIn());
131            }
132        } else {
133            // For general transforms, to determine the amount of correction we multiply a unit
134            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
135            // (which is the inverse transform for this fragment) and take the length of the result.
136            fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
137            // the length of the gradient may be 0, so we need to check for this
138            // this also compensates for the Adreno, which likes to drop tiles on division by 0
139            fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
140            fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
141            fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
142            fsBuilder->codeAppend("} else {");
143            fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
144            fsBuilder->codeAppend("}");
145
146            fsBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn());
147            fsBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn());
148            fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
149            fsBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
150
151            // this gives us a smooth step across approximately one fragment
152            fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
153        }
154        fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
155
156        fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
157    }
158
159    virtual void setData(const GrGLProgramDataManager& pdman,
160                         const GrPrimitiveProcessor& proc,
161                         const GrBatchTracker& bt) override {
162#ifdef SK_GAMMA_APPLY_TO_A8
163        const GrDistanceFieldTextureEffect& dfTexEffect =
164                proc.cast<GrDistanceFieldTextureEffect>();
165        float distanceAdjust = dfTexEffect.getDistanceAdjust();
166        if (distanceAdjust != fDistanceAdjust) {
167            pdman.set1f(fDistanceAdjustUni, distanceAdjust);
168            fDistanceAdjust = distanceAdjust;
169        }
170#endif
171
172        this->setUniformViewMatrix(pdman, proc.viewMatrix());
173
174        const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
175        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
176            GrGLfloat c[4];
177            GrColorToRGBAFloat(local.fColor, c);
178            pdman.set4fv(fColorUniform, 1, c);
179            fColor = local.fColor;
180        }
181    }
182
183    static inline void GenKey(const GrGeometryProcessor& gp,
184                              const GrBatchTracker& bt,
185                              const GrGLCaps&,
186                              GrProcessorKeyBuilder* b) {
187        const GrDistanceFieldTextureEffect& dfTexEffect = gp.cast<GrDistanceFieldTextureEffect>();
188        const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
189        uint32_t key = dfTexEffect.getFlags();
190        key |= local.fInputColorType << 16;
191        key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
192        key |= ComputePosKey(gp.viewMatrix()) << 25;
193        key |= (!gp.viewMatrix().isIdentity() && !gp.localMatrix().isIdentity()) ? 0x1 << 27 : 0x0;
194        b->add32(key);
195    }
196
197private:
198    GrColor       fColor;
199    UniformHandle fColorUniform;
200#ifdef SK_GAMMA_APPLY_TO_A8
201    float         fDistanceAdjust;
202    UniformHandle fDistanceAdjustUni;
203#endif
204
205    typedef GrGLGeometryProcessor INHERITED;
206};
207
208///////////////////////////////////////////////////////////////////////////////
209
210GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrColor color,
211                                                           const SkMatrix& viewMatrix,
212                                                           const SkMatrix& localMatrix,
213                                                           GrTexture* texture,
214                                                           const GrTextureParams& params,
215#ifdef SK_GAMMA_APPLY_TO_A8
216                                                           float distanceAdjust,
217#endif
218                                                           uint32_t flags, bool opaqueVertexColors)
219    : INHERITED(color, viewMatrix, localMatrix, opaqueVertexColors)
220    , fTextureAccess(texture, params)
221#ifdef SK_GAMMA_APPLY_TO_A8
222    , fDistanceAdjust(distanceAdjust)
223#endif
224    , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
225    , fInColor(NULL) {
226    SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
227    this->initClassID<GrDistanceFieldTextureEffect>();
228    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
229    if (flags & kColorAttr_DistanceFieldEffectFlag) {
230        fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
231        this->setHasVertexColor();
232    }
233    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
234                                                          kVec2s_GrVertexAttribType));
235    this->addTextureAccess(&fTextureAccess);
236}
237
238bool GrDistanceFieldTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
239    const GrDistanceFieldTextureEffect& cte = other.cast<GrDistanceFieldTextureEffect>();
240    return
241#ifdef SK_GAMMA_APPLY_TO_A8
242           fDistanceAdjust == cte.fDistanceAdjust &&
243#endif
244           fFlags == cte.fFlags;
245}
246
247void GrDistanceFieldTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
248    out->setUnknownSingleComponent();
249}
250
251void GrDistanceFieldTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
252                                                     const GrGLCaps& caps,
253                                                     GrProcessorKeyBuilder* b) const {
254    GrGLDistanceFieldTextureEffect::GenKey(*this, bt, caps, b);
255}
256
257GrGLPrimitiveProcessor*
258GrDistanceFieldTextureEffect::createGLInstance(const GrBatchTracker& bt,
259                                               const GrGLCaps&) const {
260    return SkNEW_ARGS(GrGLDistanceFieldTextureEffect, (*this, bt));
261}
262
263void GrDistanceFieldTextureEffect::initBatchTracker(GrBatchTracker* bt,
264                                                    const GrPipelineInfo& init) const {
265    DistanceFieldBatchTracker* local = bt->cast<DistanceFieldBatchTracker>();
266    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
267                                               SkToBool(fInColor));
268    local->fUsesLocalCoords = init.fUsesLocalCoords;
269}
270
271bool GrDistanceFieldTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
272                                                  const GrGeometryProcessor& that,
273                                                  const GrBatchTracker& t) const {
274    const DistanceFieldBatchTracker& mine = m.cast<DistanceFieldBatchTracker>();
275    const DistanceFieldBatchTracker& theirs = t.cast<DistanceFieldBatchTracker>();
276    return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
277                                   that, theirs.fUsesLocalCoords) &&
278           CanCombineOutput(mine.fInputColorType, mine.fColor,
279                            theirs.fInputColorType, theirs.fColor);
280}
281
282///////////////////////////////////////////////////////////////////////////////
283
284GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect);
285
286GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
287                                                              GrContext*,
288                                                              const GrDrawTargetCaps&,
289                                                              GrTexture* textures[]) {
290    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
291                                      GrProcessorUnitTest::kAlphaTextureIdx;
292    static const SkShader::TileMode kTileModes[] = {
293        SkShader::kClamp_TileMode,
294        SkShader::kRepeat_TileMode,
295        SkShader::kMirror_TileMode,
296    };
297    SkShader::TileMode tileModes[] = {
298        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
299        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
300    };
301    GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
302                                                           GrTextureParams::kNone_FilterMode);
303
304    return GrDistanceFieldTextureEffect::Create(GrRandomColor(random),
305                                                GrProcessorUnitTest::TestMatrix(random),
306                                                GrProcessorUnitTest::TestMatrix(random),
307                                                textures[texIdx], params,
308#ifdef SK_GAMMA_APPLY_TO_A8
309                                                random->nextF(),
310#endif
311                                                random->nextBool() ?
312                                                    kSimilarity_DistanceFieldEffectFlag : 0,
313                                                random->nextBool());
314}
315
316///////////////////////////////////////////////////////////////////////////////
317
318struct DistanceFieldNoGammaBatchTracker {
319    GrGPInput fInputColorType;
320    GrColor fColor;
321    bool fUsesLocalCoords;
322};
323
324class GrGLDistanceFieldNoGammaTextureEffect : public GrGLGeometryProcessor {
325public:
326    GrGLDistanceFieldNoGammaTextureEffect(const GrGeometryProcessor&,
327                                          const GrBatchTracker&)
328        : fColor(GrColor_ILLEGAL), fTextureSize(SkISize::Make(-1, -1)) {}
329
330    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
331        const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
332                args.fGP.cast<GrDistanceFieldNoGammaTextureEffect>();
333
334        const DistanceFieldNoGammaBatchTracker& local =
335                args.fBT.cast<DistanceFieldNoGammaBatchTracker>();
336        GrGLGPBuilder* pb = args.fPB;
337        GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
338        SkAssertResult(fsBuilder->enableFeature(
339                                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
340
341        GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
342
343        // emit attributes
344        vsBuilder->emitAttributes(dfTexEffect);
345
346        GrGLVertToFrag v(kVec2f_GrSLType);
347        args.fPB->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
348
349        // setup pass through color
350        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor,
351                                    dfTexEffect.inColor(), &fColorUniform);
352
353        vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
354
355        // Setup position
356        this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix());
357
358        // emit transforms
359        this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
360                             dfTexEffect.localMatrix(), args.fTransformsIn, args.fTransformsOut);
361
362        const char* textureSizeUniName = NULL;
363        fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
364                                              kVec2f_GrSLType, kDefault_GrSLPrecision,
365                                              "TextureSize", &textureSizeUniName);
366
367        // Use highp to work around aliasing issues
368        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
369                                                             pb->ctxInfo().standard()));
370        fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
371
372        fsBuilder->codeAppend("float texColor = ");
373        fsBuilder->appendTextureLookup(args.fSamplers[0],
374                                       "uv",
375                                       kVec2f_GrSLType);
376        fsBuilder->codeAppend(".r;");
377        fsBuilder->codeAppend("float distance = "
378            SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
379
380        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
381                                                             pb->ctxInfo().standard()));
382        fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
383        fsBuilder->codeAppend("float afwidth;");
384        if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
385            // For uniform scale, we adjust for the effect of the transformation on the distance
386            // by using the length of the gradient of the texture coordinates. We use st coordinates
387            // to ensure we're mapping 1:1 from texel space to pixel space.
388
389            // this gives us a smooth step across approximately one fragment
390            fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));");
391        } else {
392            // For general transforms, to determine the amount of correction we multiply a unit
393            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
394            // (which is the inverse transform for this fragment) and take the length of the result.
395            fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
396            // the length of the gradient may be 0, so we need to check for this
397            // this also compensates for the Adreno, which likes to drop tiles on division by 0
398            fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
399            fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
400            fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
401            fsBuilder->codeAppend("} else {");
402            fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
403            fsBuilder->codeAppend("}");
404
405            fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
406            fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
407            fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
408            fsBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
409
410            // this gives us a smooth step across approximately one fragment
411            fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
412        }
413        fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
414
415        fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
416    }
417
418    virtual void setData(const GrGLProgramDataManager& pdman,
419                         const GrPrimitiveProcessor& proc,
420                         const GrBatchTracker& bt) override {
421        SkASSERT(fTextureSizeUni.isValid());
422
423        GrTexture* texture = proc.texture(0);
424        if (texture->width() != fTextureSize.width() ||
425            texture->height() != fTextureSize.height()) {
426            fTextureSize = SkISize::Make(texture->width(), texture->height());
427            pdman.set2f(fTextureSizeUni,
428                        SkIntToScalar(fTextureSize.width()),
429                        SkIntToScalar(fTextureSize.height()));
430        }
431
432        this->setUniformViewMatrix(pdman, proc.viewMatrix());
433
434        const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>();
435        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
436            GrGLfloat c[4];
437            GrColorToRGBAFloat(local.fColor, c);
438            pdman.set4fv(fColorUniform, 1, c);
439            fColor = local.fColor;
440        }
441    }
442
443    static inline void GenKey(const GrGeometryProcessor& gp,
444                              const GrBatchTracker& bt,
445                              const GrGLCaps&,
446                              GrProcessorKeyBuilder* b) {
447        const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
448            gp.cast<GrDistanceFieldNoGammaTextureEffect>();
449
450        const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>();
451        uint32_t key = dfTexEffect.getFlags();
452        key |= local.fInputColorType << 16;
453        key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
454        key |= ComputePosKey(gp.viewMatrix()) << 25;
455        b->add32(key);
456    }
457
458private:
459    UniformHandle fColorUniform;
460    UniformHandle fTextureSizeUni;
461    GrColor       fColor;
462    SkISize       fTextureSize;
463
464    typedef GrGLGeometryProcessor INHERITED;
465};
466
467///////////////////////////////////////////////////////////////////////////////
468
469GrDistanceFieldNoGammaTextureEffect::GrDistanceFieldNoGammaTextureEffect(
470        GrColor color,
471        const SkMatrix& viewMatrix,
472        GrTexture* texture,
473        const GrTextureParams& params,
474        uint32_t flags,
475        bool opaqueVertexColors)
476    : INHERITED(color, viewMatrix, SkMatrix::I(), opaqueVertexColors)
477    , fTextureAccess(texture, params)
478    , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
479    , fInColor(NULL) {
480    SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
481    this->initClassID<GrDistanceFieldNoGammaTextureEffect>();
482    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
483    if (flags & kColorAttr_DistanceFieldEffectFlag) {
484        fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
485        this->setHasVertexColor();
486    }
487    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
488                                                          kVec2f_GrVertexAttribType));
489    this->addTextureAccess(&fTextureAccess);
490}
491
492bool GrDistanceFieldNoGammaTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
493    const GrDistanceFieldNoGammaTextureEffect& cte =
494                                                 other.cast<GrDistanceFieldNoGammaTextureEffect>();
495    return fFlags == cte.fFlags;
496}
497
498void GrDistanceFieldNoGammaTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out)
499                                                                                             const {
500    out->setUnknownSingleComponent();
501}
502
503void GrDistanceFieldNoGammaTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
504                                                            const GrGLCaps& caps,
505                                                            GrProcessorKeyBuilder* b) const {
506    GrGLDistanceFieldNoGammaTextureEffect::GenKey(*this, bt, caps, b);
507}
508
509GrGLPrimitiveProcessor*
510GrDistanceFieldNoGammaTextureEffect::createGLInstance(const GrBatchTracker& bt,
511                                                      const GrGLCaps&) const {
512    return SkNEW_ARGS(GrGLDistanceFieldNoGammaTextureEffect, (*this, bt));
513}
514
515void GrDistanceFieldNoGammaTextureEffect::initBatchTracker(GrBatchTracker* bt,
516                                                           const GrPipelineInfo& init) const {
517    DistanceFieldNoGammaBatchTracker* local = bt->cast<DistanceFieldNoGammaBatchTracker>();
518    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
519                                               SkToBool(fInColor));
520    local->fUsesLocalCoords = init.fUsesLocalCoords;
521}
522
523bool GrDistanceFieldNoGammaTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
524                                                         const GrGeometryProcessor& that,
525                                                         const GrBatchTracker& t) const {
526    const DistanceFieldNoGammaBatchTracker& mine = m.cast<DistanceFieldNoGammaBatchTracker>();
527    const DistanceFieldNoGammaBatchTracker& theirs = t.cast<DistanceFieldNoGammaBatchTracker>();
528    return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
529                                   that, theirs.fUsesLocalCoords) &&
530           CanCombineOutput(mine.fInputColorType, mine.fColor,
531                            theirs.fInputColorType, theirs.fColor);
532}
533
534///////////////////////////////////////////////////////////////////////////////
535
536GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldNoGammaTextureEffect);
537
538GrGeometryProcessor* GrDistanceFieldNoGammaTextureEffect::TestCreate(SkRandom* random,
539                                                                     GrContext*,
540                                                                     const GrDrawTargetCaps&,
541                                                                     GrTexture* textures[]) {
542    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
543                                    : GrProcessorUnitTest::kAlphaTextureIdx;
544    static const SkShader::TileMode kTileModes[] = {
545        SkShader::kClamp_TileMode,
546        SkShader::kRepeat_TileMode,
547        SkShader::kMirror_TileMode,
548    };
549    SkShader::TileMode tileModes[] = {
550        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
551        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
552    };
553    GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode
554                                                         : GrTextureParams::kNone_FilterMode);
555
556    return GrDistanceFieldNoGammaTextureEffect::Create(GrRandomColor(random),
557                                                       GrProcessorUnitTest::TestMatrix(random),
558                                                       textures[texIdx],
559                                                       params,
560        random->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0, random->nextBool());
561}
562
563///////////////////////////////////////////////////////////////////////////////
564
565struct DistanceFieldLCDBatchTracker {
566    GrGPInput fInputColorType;
567    GrColor fColor;
568    bool fUsesLocalCoords;
569};
570
571class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
572public:
573    GrGLDistanceFieldLCDTextureEffect(const GrGeometryProcessor&,
574                                      const GrBatchTracker&)
575        : fColor(GrColor_ILLEGAL) {
576        fDistanceAdjust = GrDistanceFieldLCDTextureEffect::DistanceAdjust::Make(1.0f, 1.0f, 1.0f);
577    }
578
579    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
580        const GrDistanceFieldLCDTextureEffect& dfTexEffect =
581                args.fGP.cast<GrDistanceFieldLCDTextureEffect>();
582        const DistanceFieldLCDBatchTracker& local = args.fBT.cast<DistanceFieldLCDBatchTracker>();
583        GrGLGPBuilder* pb = args.fPB;
584
585        GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
586
587        // emit attributes
588        vsBuilder->emitAttributes(dfTexEffect);
589
590        // setup pass through color
591        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
592                                    &fColorUniform);
593
594        // Setup position
595        this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix());
596
597        // emit transforms
598        const SkMatrix& localMatrix = dfTexEffect.localMatrix();
599        this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
600                             localMatrix, args.fTransformsIn, args.fTransformsOut);
601
602        // set up varyings
603        bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
604        GrGLVertToFrag recipScale(kFloat_GrSLType);
605        GrGLVertToFrag st(kVec2f_GrSLType);
606        const char* viewMatrixName = this->uViewM();
607        // view matrix name is NULL if identity matrix
608        bool useInverseScale = !localMatrix.isIdentity() && viewMatrixName;
609        if (isUniformScale && useInverseScale) {
610            args.fPB->addVarying("RecipScale", &recipScale, kHigh_GrSLPrecision);
611            vsBuilder->codeAppendf("vec2 tx = vec2(%s[0][0], %s[1][0]);",
612                                   viewMatrixName, viewMatrixName);
613            vsBuilder->codeAppend("float tx2 = dot(tx, tx);");
614            vsBuilder->codeAppendf("%s = inversesqrt(tx2);", recipScale.vsOut());
615        } else {
616            args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
617            vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
618        }
619
620        GrGLVertToFrag uv(kVec2f_GrSLType);
621        args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
622        // this is only used with text, so our texture bounds always match the glyph atlas
623        vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", "
624                               GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(),
625                               dfTexEffect.inTextureCoords()->fName);
626
627        // add frag shader code
628        GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
629
630        SkAssertResult(fsBuilder->enableFeature(
631                GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
632
633        // create LCD offset adjusted by inverse of transform
634        // Use highp to work around aliasing issues
635        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
636                                                             pb->ctxInfo().standard()));
637        fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
638        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
639                                                             pb->ctxInfo().standard()));
640        if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
641            fsBuilder->codeAppend("float delta = -" GR_FONT_ATLAS_LCD_DELTA ";\n");
642        } else {
643            fsBuilder->codeAppend("float delta = " GR_FONT_ATLAS_LCD_DELTA ";\n");
644        }
645        if (isUniformScale) {
646            if (useInverseScale) {
647                fsBuilder->codeAppendf("float dx = %s;", recipScale.fsIn());
648            } else {
649                fsBuilder->codeAppendf("float dx = dFdx(%s.x);", st.fsIn());
650            }
651            fsBuilder->codeAppend("vec2 offset = vec2(dx*delta, 0.0);");
652        } else {
653            fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn());
654
655            fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
656            fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
657            fsBuilder->codeAppend("vec2 offset = delta*Jdx;");
658        }
659
660        // green is distance to uv center
661        fsBuilder->codeAppend("\tvec4 texColor = ");
662        fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
663        fsBuilder->codeAppend(";\n");
664        fsBuilder->codeAppend("\tvec3 distance;\n");
665        fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
666        // red is distance to left offset
667        fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
668        fsBuilder->codeAppend("\ttexColor = ");
669        fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
670        fsBuilder->codeAppend(";\n");
671        fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
672        // blue is distance to right offset
673        fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
674        fsBuilder->codeAppend("\ttexColor = ");
675        fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
676        fsBuilder->codeAppend(";\n");
677        fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
678
679        fsBuilder->codeAppend("\tdistance = "
680           "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
681
682        // adjust width based on gamma
683        const char* distanceAdjustUniName = NULL;
684        fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
685            kVec3f_GrSLType, kDefault_GrSLPrecision,
686            "DistanceAdjust", &distanceAdjustUniName);
687        fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
688
689        // To be strictly correct, we should compute the anti-aliasing factor separately
690        // for each color component. However, this is only important when using perspective
691        // transformations, and even then using a single factor seems like a reasonable
692        // trade-off between quality and speed.
693        fsBuilder->codeAppend("float afwidth;");
694        if (isUniformScale) {
695            // For uniform scale, we adjust for the effect of the transformation on the distance
696            // by using the length of the gradient of the texture coordinates. We use st coordinates
697            // to ensure we're mapping 1:1 from texel space to pixel space.
698
699            // this gives us a smooth step across approximately one fragment
700            fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dx);");
701        } else {
702            // For general transforms, to determine the amount of correction we multiply a unit
703            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
704            // (which is the inverse transform for this fragment) and take the length of the result.
705            fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));");
706            // the length of the gradient may be 0, so we need to check for this
707            // this also compensates for the Adreno, which likes to drop tiles on division by 0
708            fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
709            fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
710            fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
711            fsBuilder->codeAppend("} else {");
712            fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
713            fsBuilder->codeAppend("}");
714            fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
715            fsBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
716
717            // this gives us a smooth step across approximately one fragment
718            fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
719        }
720
721        fsBuilder->codeAppend(
722                      "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
723
724        fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
725    }
726
727    virtual void setData(const GrGLProgramDataManager& pdman,
728                         const GrPrimitiveProcessor& processor,
729                         const GrBatchTracker& bt) override {
730        SkASSERT(fDistanceAdjustUni.isValid());
731
732        const GrDistanceFieldLCDTextureEffect& dfTexEffect =
733                processor.cast<GrDistanceFieldLCDTextureEffect>();
734        GrDistanceFieldLCDTextureEffect::DistanceAdjust wa = dfTexEffect.getDistanceAdjust();
735        if (wa != fDistanceAdjust) {
736            pdman.set3f(fDistanceAdjustUni,
737                        wa.fR,
738                        wa.fG,
739                        wa.fB);
740            fDistanceAdjust = wa;
741        }
742
743        this->setUniformViewMatrix(pdman, processor.viewMatrix());
744
745        const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
746        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
747            GrGLfloat c[4];
748            GrColorToRGBAFloat(local.fColor, c);
749            pdman.set4fv(fColorUniform, 1, c);
750            fColor = local.fColor;
751        }
752    }
753
754    static inline void GenKey(const GrGeometryProcessor& gp,
755                              const GrBatchTracker& bt,
756                              const GrGLCaps&,
757                              GrProcessorKeyBuilder* b) {
758        const GrDistanceFieldLCDTextureEffect& dfTexEffect =
759                gp.cast<GrDistanceFieldLCDTextureEffect>();
760
761        const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
762        uint32_t key = dfTexEffect.getFlags();
763        key |= local.fInputColorType << 16;
764        key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
765        key |= ComputePosKey(gp.viewMatrix()) << 25;
766        key |= (!gp.viewMatrix().isIdentity() && !gp.localMatrix().isIdentity()) ? 0x1 << 27 : 0x0;
767        b->add32(key);
768    }
769
770private:
771    GrColor                                      fColor;
772    UniformHandle                                fColorUniform;
773    GrDistanceFieldLCDTextureEffect::DistanceAdjust fDistanceAdjust;
774    UniformHandle                                fDistanceAdjustUni;
775
776    typedef GrGLGeometryProcessor INHERITED;
777};
778
779///////////////////////////////////////////////////////////////////////////////
780
781GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect(
782                                                  GrColor color, const SkMatrix& viewMatrix,
783                                                  const SkMatrix& localMatrix,
784                                                  GrTexture* texture, const GrTextureParams& params,
785                                                  DistanceAdjust distanceAdjust,
786                                                  uint32_t flags)
787    : INHERITED(color, viewMatrix, localMatrix)
788    , fTextureAccess(texture, params)
789    , fDistanceAdjust(distanceAdjust)
790    , fFlags(flags & kLCD_DistanceFieldEffectMask){
791    SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
792    this->initClassID<GrDistanceFieldLCDTextureEffect>();
793    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType));
794    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
795                                                          kVec2s_GrVertexAttribType));
796    this->addTextureAccess(&fTextureAccess);
797}
798
799bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
800    const GrDistanceFieldLCDTextureEffect& cte = other.cast<GrDistanceFieldLCDTextureEffect>();
801    return (fDistanceAdjust == cte.fDistanceAdjust &&
802            fFlags == cte.fFlags);
803}
804
805void GrDistanceFieldLCDTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out)
806                                                                                             const {
807    out->setUnknownFourComponents();
808    out->setUsingLCDCoverage();
809}
810
811void GrDistanceFieldLCDTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
812                                                        const GrGLCaps& caps,
813                                                        GrProcessorKeyBuilder* b) const {
814    GrGLDistanceFieldLCDTextureEffect::GenKey(*this, bt, caps, b);
815}
816
817GrGLPrimitiveProcessor*
818GrDistanceFieldLCDTextureEffect::createGLInstance(const GrBatchTracker& bt,
819                                                  const GrGLCaps&) const {
820    return SkNEW_ARGS(GrGLDistanceFieldLCDTextureEffect, (*this, bt));
821}
822
823void GrDistanceFieldLCDTextureEffect::initBatchTracker(GrBatchTracker* bt,
824                                                       const GrPipelineInfo& init) const {
825    DistanceFieldLCDBatchTracker* local = bt->cast<DistanceFieldLCDBatchTracker>();
826    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
827    local->fUsesLocalCoords = init.fUsesLocalCoords;
828}
829
830bool GrDistanceFieldLCDTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
831                                                     const GrGeometryProcessor& that,
832                                                     const GrBatchTracker& t) const {
833    const DistanceFieldLCDBatchTracker& mine = m.cast<DistanceFieldLCDBatchTracker>();
834    const DistanceFieldLCDBatchTracker& theirs = t.cast<DistanceFieldLCDBatchTracker>();
835    return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
836                                   that, theirs.fUsesLocalCoords) &&
837           CanCombineOutput(mine.fInputColorType, mine.fColor,
838                            theirs.fInputColorType, theirs.fColor);
839}
840
841///////////////////////////////////////////////////////////////////////////////
842
843GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect);
844
845GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random,
846                                                                 GrContext*,
847                                                                 const GrDrawTargetCaps&,
848                                                                 GrTexture* textures[]) {
849    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
850                                      GrProcessorUnitTest::kAlphaTextureIdx;
851    static const SkShader::TileMode kTileModes[] = {
852        SkShader::kClamp_TileMode,
853        SkShader::kRepeat_TileMode,
854        SkShader::kMirror_TileMode,
855    };
856    SkShader::TileMode tileModes[] = {
857        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
858        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
859    };
860    GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
861                           GrTextureParams::kNone_FilterMode);
862    DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
863    uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
864    flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
865    flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
866    return GrDistanceFieldLCDTextureEffect::Create(GrRandomColor(random),
867                                                   GrProcessorUnitTest::TestMatrix(random),
868                                                   GrProcessorUnitTest::TestMatrix(random),
869                                                   textures[texIdx], params,
870                                                   wa,
871                                                   flags);
872}
873