• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "GrDistanceFieldGeoProc.h"
9 #include "GrAtlasedShaderHelpers.h"
10 #include "GrCaps.h"
11 #include "GrShaderCaps.h"
12 #include "GrTexture.h"
13 #include "SkDistanceFieldGen.h"
14 #include "glsl/GrGLSLFragmentShaderBuilder.h"
15 #include "glsl/GrGLSLGeometryProcessor.h"
16 #include "glsl/GrGLSLProgramDataManager.h"
17 #include "glsl/GrGLSLUniformHandler.h"
18 #include "glsl/GrGLSLUtil.h"
19 #include "glsl/GrGLSLVarying.h"
20 #include "glsl/GrGLSLVertexGeoBuilder.h"
21 
22 // Assuming a radius of a little less than the diagonal of the fragment
23 #define SK_DistanceFieldAAFactor     "0.65"
24 
25 class GrGLDistanceFieldA8TextGeoProc : public GrGLSLGeometryProcessor {
26 public:
27     GrGLDistanceFieldA8TextGeoProc() = default;
28 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)29     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
30         const GrDistanceFieldA8TextGeoProc& dfTexEffect =
31                 args.fGP.cast<GrDistanceFieldA8TextGeoProc>();
32         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
33 
34         GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
35         GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
36         GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
37 
38         // emit attributes
39         varyingHandler->emitAttributes(dfTexEffect);
40 
41         const char* atlasSizeInvName;
42         fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
43                                                           kFloat2_GrSLType,
44                                                           "AtlasSizeInv",
45                                                           &atlasSizeInvName);
46 #ifdef SK_GAMMA_APPLY_TO_A8
47         // adjust based on gamma
48         const char* distanceAdjustUniName = nullptr;
49         // width, height, 1/(3*width)
50         fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
51                                                         "DistanceAdjust", &distanceAdjustUniName);
52 #endif
53 
54         // Setup pass through color
55         varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
56 
57         // Setup position
58         gpArgs->fPositionVar = dfTexEffect.inPosition().asShaderVar();
59 
60         // emit transforms
61         this->emitTransforms(vertBuilder,
62                              varyingHandler,
63                              uniformHandler,
64                              dfTexEffect.inPosition().asShaderVar(),
65                              dfTexEffect.localMatrix(),
66                              args.fFPCoordTransformHandler);
67 
68         // add varyings
69         GrGLSLVarying uv(kFloat2_GrSLType);
70         GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
71         GrGLSLVarying texIdx(texIdxType);
72         GrGLSLVarying st(kFloat2_GrSLType);
73         append_index_uv_varyings(args, dfTexEffect.inTextureCoords().name(), atlasSizeInvName, &uv,
74                                  &texIdx, &st);
75 
76         bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
77                               kUniformScale_DistanceFieldEffectMask;
78         bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
79         bool isGammaCorrect =
80             SkToBool(dfTexEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag);
81         bool isAliased =
82             SkToBool(dfTexEffect.getFlags() & kAliased_DistanceFieldEffectFlag);
83 
84         // Use highp to work around aliasing issues
85         fragBuilder->codeAppendf("float2 uv = %s;\n", uv.fsIn());
86         fragBuilder->codeAppend("half4 texColor;");
87         append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(),
88                                    texIdx, "uv", "texColor");
89 
90         fragBuilder->codeAppend("half distance = "
91                       SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
92 #ifdef SK_GAMMA_APPLY_TO_A8
93         // adjust width based on gamma
94         fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
95 #endif
96 
97         fragBuilder->codeAppend("half afwidth;");
98         if (isUniformScale) {
99             // For uniform scale, we adjust for the effect of the transformation on the distance
100             // by using the length of the gradient of the t coordinate in the y direction.
101             // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space.
102 
103             // this gives us a smooth step across approximately one fragment
104 #ifdef SK_VULKAN
105             fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor
106                                     "*half(dFdx(%s.x)));", st.fsIn());
107 #else
108             // We use the y gradient because there is a bug in the Mali 400 in the x direction.
109             fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor
110                                      "*half(dFdy(%s.y)));", st.fsIn());
111 #endif
112         } else if (isSimilarity) {
113             // For similarity transform, we adjust the effect of the transformation on the distance
114             // by using the length of the gradient of the texture coordinates. We use st coordinates
115             // to ensure we're mapping 1:1 from texel space to pixel space.
116             // We use the y gradient because there is a bug in the Mali 400 in the x direction.
117 
118             // this gives us a smooth step across approximately one fragment
119 #ifdef SK_VULKAN
120             fragBuilder->codeAppendf("half st_grad_len = length(half2(dFdx(%s)));", st.fsIn());
121 #else
122             // We use the y gradient because there is a bug in the Mali 400 in the x direction.
123             fragBuilder->codeAppendf("half st_grad_len = length(half2(dFdy(%s)));", st.fsIn());
124 #endif
125             fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);");
126         } else {
127             // For general transforms, to determine the amount of correction we multiply a unit
128             // vector pointing along the SDF gradient direction by the Jacobian of the st coords
129             // (which is the inverse transform for this fragment) and take the length of the result.
130             fragBuilder->codeAppend("half2 dist_grad = half2(float2(dFdx(distance), "
131                                                                    "dFdy(distance)));");
132             // the length of the gradient may be 0, so we need to check for this
133             // this also compensates for the Adreno, which likes to drop tiles on division by 0
134             fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);");
135             fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
136             fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);");
137             fragBuilder->codeAppend("} else {");
138             fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));");
139             fragBuilder->codeAppend("}");
140 
141             fragBuilder->codeAppendf("half2 Jdx = half2(dFdx(%s));", st.fsIn());
142             fragBuilder->codeAppendf("half2 Jdy = half2(dFdy(%s));", st.fsIn());
143             fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
144             fragBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
145 
146             // this gives us a smooth step across approximately one fragment
147             fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
148         }
149 
150         if (isAliased) {
151             fragBuilder->codeAppend("half val = distance > 0 ? 1.0 : 0.0;");
152         } else if (isGammaCorrect) {
153             // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
154             // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want
155             // distance mapped linearly to coverage, so use a linear step:
156             fragBuilder->codeAppend(
157                 "half val = saturate((distance + afwidth) / (2.0 * afwidth));");
158         } else {
159             fragBuilder->codeAppend("half val = smoothstep(-afwidth, afwidth, distance);");
160         }
161 
162         fragBuilder->codeAppendf("%s = half4(val);", args.fOutputCoverage);
163     }
164 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & proc,FPCoordTransformIter && transformIter)165     void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
166                  FPCoordTransformIter&& transformIter) override {
167         const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>();
168 
169 #ifdef SK_GAMMA_APPLY_TO_A8
170         float distanceAdjust = dfa8gp.getDistanceAdjust();
171         if (distanceAdjust != fDistanceAdjust) {
172             fDistanceAdjust = distanceAdjust;
173             pdman.set1f(fDistanceAdjustUni, distanceAdjust);
174         }
175 #endif
176 
177         const SkISize& atlasSize = dfa8gp.atlasSize();
178         SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
179 
180         if (fAtlasSize != atlasSize) {
181             pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
182             fAtlasSize = atlasSize;
183         }
184         this->setTransformDataHelper(dfa8gp.localMatrix(), pdman, &transformIter);
185     }
186 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)187     static inline void GenKey(const GrGeometryProcessor& gp,
188                               const GrShaderCaps&,
189                               GrProcessorKeyBuilder* b) {
190         const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>();
191         uint32_t key = dfTexEffect.getFlags();
192         b->add32(key);
193         b->add32(dfTexEffect.numTextureSamplers());
194     }
195 
196 private:
197 #ifdef SK_GAMMA_APPLY_TO_A8
198     float fDistanceAdjust = -1.f;
199     UniformHandle fDistanceAdjustUni;
200 #endif
201     SkISize fAtlasSize = {0, 0};
202     UniformHandle fAtlasSizeInvUniform;
203 
204     typedef GrGLSLGeometryProcessor INHERITED;
205 };
206 
207 ///////////////////////////////////////////////////////////////////////////////
208 
GrDistanceFieldA8TextGeoProc(const GrShaderCaps & caps,const sk_sp<GrTextureProxy> * proxies,int numProxies,const GrSamplerState & params,float distanceAdjust,uint32_t flags,const SkMatrix & localMatrix)209 GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(const GrShaderCaps& caps,
210                                                            const sk_sp<GrTextureProxy>* proxies,
211                                                            int numProxies,
212                                                            const GrSamplerState& params,
213 #ifdef SK_GAMMA_APPLY_TO_A8
214                                                            float distanceAdjust,
215 #endif
216                                                            uint32_t flags,
217                                                            const SkMatrix& localMatrix)
218         : INHERITED(kGrDistanceFieldA8TextGeoProc_ClassID)
219         , fLocalMatrix(localMatrix)
220         , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
221 #ifdef SK_GAMMA_APPLY_TO_A8
222         , fDistanceAdjust(distanceAdjust)
223 #endif
224 {
225     SkASSERT(numProxies <= kMaxTextures);
226     SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
227 
228     if (flags & kPerspective_DistanceFieldEffectFlag) {
229         fInPosition = {"inPosition", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
230     } else {
231         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
232     }
233     fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType };
234     fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
235                         caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
236     this->setVertexAttributes(&fInPosition, 3);
237 
238     if (numProxies) {
239         fAtlasSize = proxies[0]->isize();
240     }
241     for (int i = 0; i < numProxies; ++i) {
242         SkASSERT(proxies[i]);
243         SkASSERT(proxies[i]->isize() == fAtlasSize);
244         fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
245     }
246     this->setTextureSamplerCnt(numProxies);
247 }
248 
addNewProxies(const sk_sp<GrTextureProxy> * proxies,int numProxies,const GrSamplerState & params)249 void GrDistanceFieldA8TextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
250                                                  int numProxies,
251                                                  const GrSamplerState& params) {
252     SkASSERT(numProxies <= kMaxTextures);
253 
254     if (!fTextureSamplers[0].isInitialized()) {
255         fAtlasSize = proxies[0]->isize();
256     }
257 
258     for (int i = 0; i < numProxies; ++i) {
259         SkASSERT(proxies[i]);
260         SkASSERT(proxies[i]->isize() == fAtlasSize);
261         if (!fTextureSamplers[i].isInitialized()) {
262             fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
263         }
264     }
265     this->setTextureSamplerCnt(numProxies);
266 }
267 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const268 void GrDistanceFieldA8TextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
269                                                        GrProcessorKeyBuilder* b) const {
270     GrGLDistanceFieldA8TextGeoProc::GenKey(*this, caps, b);
271 }
272 
273 GrGLSLPrimitiveProcessor*
createGLSLInstance(const GrShaderCaps &) const274 GrDistanceFieldA8TextGeoProc::createGLSLInstance(const GrShaderCaps&) const {
275     return new GrGLDistanceFieldA8TextGeoProc();
276 }
277 
278 ///////////////////////////////////////////////////////////////////////////////
279 
280 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc);
281 
282 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)283 sk_sp<GrGeometryProcessor> GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) {
284     int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
285                                         : GrProcessorUnitTest::kAlphaTextureIdx;
286     sk_sp<GrTextureProxy> proxies[kMaxTextures] = {
287         d->textureProxy(texIdx),
288         nullptr,
289         nullptr,
290         nullptr
291     };
292 
293     GrSamplerState::WrapMode wrapModes[2];
294     GrTest::TestWrapModes(d->fRandom, wrapModes);
295     GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
296                                                    ? GrSamplerState::Filter::kBilerp
297                                                    : GrSamplerState::Filter::kNearest);
298 
299     uint32_t flags = 0;
300     flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
301     if (flags & kSimilarity_DistanceFieldEffectFlag) {
302         flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
303     }
304     SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
305 #ifdef SK_GAMMA_APPLY_TO_A8
306     float lum = d->fRandom->nextF();
307 #endif
308     return GrDistanceFieldA8TextGeoProc::Make(*d->caps()->shaderCaps(),
309                                               proxies, 1,
310                                               samplerState,
311 #ifdef SK_GAMMA_APPLY_TO_A8
312                                               lum,
313 #endif
314                                               flags, localMatrix);
315 }
316 #endif
317 
318 ///////////////////////////////////////////////////////////////////////////////
319 
320 class GrGLDistanceFieldPathGeoProc : public GrGLSLGeometryProcessor {
321 public:
GrGLDistanceFieldPathGeoProc()322     GrGLDistanceFieldPathGeoProc()
323             : fMatrix(SkMatrix::InvalidMatrix())
324             , fAtlasSize({0,0}) {
325     }
326 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)327     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
328         const GrDistanceFieldPathGeoProc& dfPathEffect =
329                 args.fGP.cast<GrDistanceFieldPathGeoProc>();
330 
331         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
332 
333         GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
334         GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
335         GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
336 
337         // emit attributes
338         varyingHandler->emitAttributes(dfPathEffect);
339 
340         const char* atlasSizeInvName;
341         fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
342                                                           kFloat2_GrSLType,
343                                                           "AtlasSizeInv",
344                                                           &atlasSizeInvName);
345 
346         GrGLSLVarying uv(kFloat2_GrSLType);
347         GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
348         GrGLSLVarying texIdx(texIdxType);
349         GrGLSLVarying st(kFloat2_GrSLType);
350         append_index_uv_varyings(args, dfPathEffect.inTextureCoords().name(), atlasSizeInvName, &uv,
351                                  &texIdx, &st);
352 
353         // setup pass through color
354         varyingHandler->addPassThroughAttribute(dfPathEffect.inColor(), args.fOutputColor);
355 
356         if (dfPathEffect.matrix().hasPerspective()) {
357             // Setup position
358             this->writeOutputPosition(vertBuilder,
359                                       uniformHandler,
360                                       gpArgs,
361                                       dfPathEffect.inPosition().name(),
362                                       dfPathEffect.matrix(),
363                                       &fMatrixUniform);
364 
365             // emit transforms
366             this->emitTransforms(vertBuilder,
367                                  varyingHandler,
368                                  uniformHandler,
369                                  dfPathEffect.inPosition().asShaderVar(),
370                                  args.fFPCoordTransformHandler);
371         } else {
372             // Setup position
373             this->writeOutputPosition(vertBuilder, gpArgs, dfPathEffect.inPosition().name());
374 
375             // emit transforms
376             this->emitTransforms(vertBuilder,
377                                  varyingHandler,
378                                  uniformHandler,
379                                  dfPathEffect.inPosition().asShaderVar(),
380                                  dfPathEffect.matrix(),
381                                  args.fFPCoordTransformHandler);
382         }
383 
384         // Use highp to work around aliasing issues
385         fragBuilder->codeAppendf("float2 uv = %s;", uv.fsIn());
386         fragBuilder->codeAppend("half4 texColor;");
387         append_multitexture_lookup(args, dfPathEffect.numTextureSamplers(), texIdx, "uv",
388                                    "texColor");
389 
390         fragBuilder->codeAppend("half distance = "
391             SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
392 
393         fragBuilder->codeAppend("half afwidth;");
394         bool isUniformScale = (dfPathEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
395                               kUniformScale_DistanceFieldEffectMask;
396         bool isSimilarity = SkToBool(dfPathEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
397         bool isGammaCorrect =
398                 SkToBool(dfPathEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag);
399         if (isUniformScale) {
400             // For uniform scale, we adjust for the effect of the transformation on the distance
401             // by using the length of the gradient of the t coordinate in the y direction.
402             // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space.
403 
404             // this gives us a smooth step across approximately one fragment
405 #ifdef SK_VULKAN
406             fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor
407                                      "*half(dFdx(%s.x)));", st.fsIn());
408 #else
409             // We use the y gradient because there is a bug in the Mali 400 in the x direction.
410             fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor
411                                      "*half(dFdy(%s.y)));", st.fsIn());
412 #endif
413         } else if (isSimilarity) {
414             // For similarity transform, we adjust the effect of the transformation on the distance
415             // by using the length of the gradient of the texture coordinates. We use st coordinates
416             // to ensure we're mapping 1:1 from texel space to pixel space.
417 
418             // this gives us a smooth step across approximately one fragment
419 #ifdef SK_VULKAN
420             fragBuilder->codeAppendf("half st_grad_len = half(length(dFdx(%s)));", st.fsIn());
421 #else
422             // We use the y gradient because there is a bug in the Mali 400 in the x direction.
423             fragBuilder->codeAppendf("half st_grad_len = half(length(dFdy(%s)));", st.fsIn());
424 #endif
425             fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);");
426         } else {
427             // For general transforms, to determine the amount of correction we multiply a unit
428             // vector pointing along the SDF gradient direction by the Jacobian of the st coords
429             // (which is the inverse transform for this fragment) and take the length of the result.
430             fragBuilder->codeAppend("half2 dist_grad = half2(dFdx(distance), "
431                                                             "dFdy(distance));");
432             // the length of the gradient may be 0, so we need to check for this
433             // this also compensates for the Adreno, which likes to drop tiles on division by 0
434             fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);");
435             fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
436             fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);");
437             fragBuilder->codeAppend("} else {");
438             fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));");
439             fragBuilder->codeAppend("}");
440 
441             fragBuilder->codeAppendf("half2 Jdx = half2(dFdx(%s));", st.fsIn());
442             fragBuilder->codeAppendf("half2 Jdy = half2(dFdy(%s));", st.fsIn());
443             fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
444             fragBuilder->codeAppend("                   dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
445 
446             // this gives us a smooth step across approximately one fragment
447             fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
448         }
449         // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
450         // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance
451         // mapped linearly to coverage, so use a linear step:
452         if (isGammaCorrect) {
453             fragBuilder->codeAppend(
454                 "half val = saturate((distance + afwidth) / (2.0 * afwidth));");
455         } else {
456             fragBuilder->codeAppend("half val = smoothstep(-afwidth, afwidth, distance);");
457         }
458 
459         fragBuilder->codeAppendf("%s = half4(val);", args.fOutputCoverage);
460     }
461 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & proc,FPCoordTransformIter && transformIter)462     void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
463                  FPCoordTransformIter&& transformIter) override {
464 
465         const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>();
466 
467         if (dfpgp.matrix().hasPerspective() && !fMatrix.cheapEqualTo(dfpgp.matrix())) {
468             fMatrix = dfpgp.matrix();
469             float matrix[3 * 3];
470             GrGLSLGetMatrix<3>(matrix, fMatrix);
471             pdman.setMatrix3f(fMatrixUniform, matrix);
472         }
473 
474         const SkISize& atlasSize = dfpgp.atlasSize();
475         SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
476         if (fAtlasSize != atlasSize) {
477             pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
478             fAtlasSize = atlasSize;
479         }
480 
481         if (dfpgp.matrix().hasPerspective()) {
482             this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
483         } else {
484             this->setTransformDataHelper(dfpgp.matrix(), pdman, &transformIter);
485         }
486     }
487 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)488     static inline void GenKey(const GrGeometryProcessor& gp,
489                               const GrShaderCaps&,
490                               GrProcessorKeyBuilder* b) {
491         const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>();
492 
493         uint32_t key = dfTexEffect.getFlags();
494         key |= ComputePosKey(dfTexEffect.matrix()) << 16;
495         b->add32(key);
496         b->add32(dfTexEffect.matrix().hasPerspective());
497         b->add32(dfTexEffect.numTextureSamplers());
498     }
499 
500 private:
501     SkMatrix      fMatrix;        // view matrix if perspective, local matrix otherwise
502     UniformHandle fMatrixUniform;
503 
504     SkISize       fAtlasSize;
505     UniformHandle fAtlasSizeInvUniform;
506 
507     typedef GrGLSLGeometryProcessor INHERITED;
508 };
509 
510 ///////////////////////////////////////////////////////////////////////////////
511 
GrDistanceFieldPathGeoProc(const GrShaderCaps & caps,const SkMatrix & matrix,bool wideColor,const sk_sp<GrTextureProxy> * proxies,int numProxies,const GrSamplerState & params,uint32_t flags)512 GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(const GrShaderCaps& caps,
513                                                        const SkMatrix& matrix,
514                                                        bool wideColor,
515                                                        const sk_sp<GrTextureProxy>* proxies,
516                                                        int numProxies,
517                                                        const GrSamplerState& params,
518                                                        uint32_t flags)
519         : INHERITED(kGrDistanceFieldPathGeoProc_ClassID)
520         , fMatrix(matrix)
521         , fFlags(flags & kNonLCD_DistanceFieldEffectMask) {
522     SkASSERT(numProxies <= kMaxTextures);
523     SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
524 
525     fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
526     fInColor = MakeColorAttribute("inColor", wideColor);
527     fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
528                         caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
529     this->setVertexAttributes(&fInPosition, 3);
530 
531     if (numProxies) {
532         fAtlasSize = proxies[0]->isize();
533     }
534 
535     for (int i = 0; i < numProxies; ++i) {
536         SkASSERT(proxies[i]);
537         SkASSERT(proxies[i]->isize() == fAtlasSize);
538         fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
539     }
540     this->setTextureSamplerCnt(numProxies);
541 }
542 
addNewProxies(const sk_sp<GrTextureProxy> * proxies,int numProxies,const GrSamplerState & params)543 void GrDistanceFieldPathGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
544                                                int numProxies,
545                                                const GrSamplerState& params) {
546     SkASSERT(numProxies <= kMaxTextures);
547 
548     if (!fTextureSamplers[0].isInitialized()) {
549         fAtlasSize = proxies[0]->isize();
550     }
551 
552     for (int i = 0; i < numProxies; ++i) {
553         SkASSERT(proxies[i]);
554         SkASSERT(proxies[i]->isize() == fAtlasSize);
555 
556         if (!fTextureSamplers[i].isInitialized()) {
557             fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
558         }
559     }
560     this->setTextureSamplerCnt(numProxies);
561 }
562 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const563 void GrDistanceFieldPathGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
564                                                      GrProcessorKeyBuilder* b) const {
565     GrGLDistanceFieldPathGeoProc::GenKey(*this, caps, b);
566 }
567 
568 GrGLSLPrimitiveProcessor*
createGLSLInstance(const GrShaderCaps &) const569 GrDistanceFieldPathGeoProc::createGLSLInstance(const GrShaderCaps&) const {
570     return new GrGLDistanceFieldPathGeoProc();
571 }
572 
573 ///////////////////////////////////////////////////////////////////////////////
574 
575 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc);
576 
577 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)578 sk_sp<GrGeometryProcessor> GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) {
579     int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
580                                         : GrProcessorUnitTest::kAlphaTextureIdx;
581     sk_sp<GrTextureProxy> proxies[kMaxTextures] = {
582         d->textureProxy(texIdx),
583         nullptr,
584         nullptr,
585         nullptr
586     };
587 
588     GrSamplerState::WrapMode wrapModes[2];
589     GrTest::TestWrapModes(d->fRandom, wrapModes);
590     GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
591                                                    ? GrSamplerState::Filter::kBilerp
592                                                    : GrSamplerState::Filter::kNearest);
593 
594     uint32_t flags = 0;
595     flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
596     if (flags & kSimilarity_DistanceFieldEffectFlag) {
597         flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
598     }
599 
600     return GrDistanceFieldPathGeoProc::Make(*d->caps()->shaderCaps(),
601                                             GrTest::TestMatrix(d->fRandom),
602                                             d->fRandom->nextBool(),
603                                             proxies, 1,
604                                             samplerState,
605                                             flags);
606 }
607 #endif
608 
609 ///////////////////////////////////////////////////////////////////////////////
610 
611 class GrGLDistanceFieldLCDTextGeoProc : public GrGLSLGeometryProcessor {
612 public:
GrGLDistanceFieldLCDTextGeoProc()613     GrGLDistanceFieldLCDTextGeoProc() : fAtlasSize({0, 0}) {
614         fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f);
615     }
616 
onEmitCode(EmitArgs & args,GrGPArgs * gpArgs)617     void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
618         const GrDistanceFieldLCDTextGeoProc& dfTexEffect =
619                 args.fGP.cast<GrDistanceFieldLCDTextGeoProc>();
620 
621         GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
622         GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
623         GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
624 
625         // emit attributes
626         varyingHandler->emitAttributes(dfTexEffect);
627 
628         const char* atlasSizeInvName;
629         fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
630                                                           kFloat2_GrSLType,
631                                                           "AtlasSizeInv",
632                                                           &atlasSizeInvName);
633 
634         GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
635 
636         // setup pass through color
637         varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
638 
639         // Setup position
640         gpArgs->fPositionVar = dfTexEffect.inPosition().asShaderVar();
641 
642         // emit transforms
643         this->emitTransforms(vertBuilder,
644                              varyingHandler,
645                              uniformHandler,
646                              dfTexEffect.inPosition().asShaderVar(),
647                              dfTexEffect.localMatrix(),
648                              args.fFPCoordTransformHandler);
649 
650         // set up varyings
651         GrGLSLVarying uv(kFloat2_GrSLType);
652         GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
653         GrGLSLVarying texIdx(texIdxType);
654         GrGLSLVarying st(kFloat2_GrSLType);
655         append_index_uv_varyings(args, dfTexEffect.inTextureCoords().name(), atlasSizeInvName, &uv,
656                                  &texIdx, &st);
657 
658         GrGLSLVarying delta(kFloat_GrSLType);
659         varyingHandler->addVarying("Delta", &delta);
660         if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
661             vertBuilder->codeAppendf("%s = -%s.x/3.0;", delta.vsOut(), atlasSizeInvName);
662         } else {
663             vertBuilder->codeAppendf("%s = %s.x/3.0;", delta.vsOut(), atlasSizeInvName);
664         }
665 
666         // add frag shader code
667         bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
668                               kUniformScale_DistanceFieldEffectMask;
669         bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
670         bool isGammaCorrect =
671             SkToBool(dfTexEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag);
672 
673         // create LCD offset adjusted by inverse of transform
674         // Use highp to work around aliasing issues
675         fragBuilder->codeAppendf("float2 uv = %s;\n", uv.fsIn());
676 
677         if (isUniformScale) {
678 #ifdef SK_VULKAN
679             fragBuilder->codeAppendf("half st_grad_len = half(abs(dFdx(%s.x)));", st.fsIn());
680 #else
681             // We use the y gradient because there is a bug in the Mali 400 in the x direction.
682             fragBuilder->codeAppendf("half st_grad_len = half(abs(dFdy(%s.y)));", st.fsIn());
683 #endif
684             fragBuilder->codeAppendf("half2 offset = half2(half(st_grad_len*%s), 0.0);",
685                                      delta.fsIn());
686         } else if (isSimilarity) {
687             // For a similarity matrix with rotation, the gradient will not be aligned
688             // with the texel coordinate axes, so we need to calculate it.
689 #ifdef SK_VULKAN
690             fragBuilder->codeAppendf("half2 st_grad = half2(dFdx(%s));", st.fsIn());
691             fragBuilder->codeAppendf("half2 offset = half(%s)*st_grad;", delta.fsIn());
692 #else
693             // We use dFdy because of a Mali 400 bug, and rotate -90 degrees to
694             // get the gradient in the x direction.
695             fragBuilder->codeAppendf("half2 st_grad = half2(dFdy(%s));", st.fsIn());
696             fragBuilder->codeAppendf("half2 offset = half2(%s*float2(st_grad.y, -st_grad.x));",
697                                      delta.fsIn());
698 #endif
699             fragBuilder->codeAppend("half st_grad_len = length(st_grad);");
700         } else {
701             fragBuilder->codeAppendf("half2 st = half2(%s);\n", st.fsIn());
702 
703             fragBuilder->codeAppend("half2 Jdx = half2(dFdx(st));");
704             fragBuilder->codeAppend("half2 Jdy = half2(dFdy(st));");
705             fragBuilder->codeAppendf("half2 offset = half2(half(%s))*Jdx;", delta.fsIn());
706         }
707 
708         // sample the texture by index
709         fragBuilder->codeAppend("half4 texColor;");
710         append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(),
711                                    texIdx, "uv", "texColor");
712 
713         // green is distance to uv center
714         fragBuilder->codeAppend("half3 distance;");
715         fragBuilder->codeAppend("distance.y = texColor.r;");
716         // red is distance to left offset
717         fragBuilder->codeAppend("half2 uv_adjusted = half2(uv) - offset;");
718         append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(),
719                                    texIdx, "uv_adjusted", "texColor");
720         fragBuilder->codeAppend("distance.x = texColor.r;");
721         // blue is distance to right offset
722         fragBuilder->codeAppend("uv_adjusted = half2(uv) + offset;");
723         append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(),
724                                    texIdx, "uv_adjusted", "texColor");
725         fragBuilder->codeAppend("distance.z = texColor.r;");
726 
727         fragBuilder->codeAppend("distance = "
728            "half3(" SK_DistanceFieldMultiplier ")*(distance - half3(" SK_DistanceFieldThreshold"));");
729 
730         // adjust width based on gamma
731         const char* distanceAdjustUniName = nullptr;
732         fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType,
733                                                         "DistanceAdjust", &distanceAdjustUniName);
734         fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
735 
736         // To be strictly correct, we should compute the anti-aliasing factor separately
737         // for each color component. However, this is only important when using perspective
738         // transformations, and even then using a single factor seems like a reasonable
739         // trade-off between quality and speed.
740         fragBuilder->codeAppend("half afwidth;");
741         if (isSimilarity) {
742             // For similarity transform (uniform scale-only is a subset of this), we adjust for the
743             // effect of the transformation on the distance by using the length of the gradient of
744             // the texture coordinates. We use st coordinates to ensure we're mapping 1:1 from texel
745             // space to pixel space.
746 
747             // this gives us a smooth step across approximately one fragment
748             fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*st_grad_len;");
749         } else {
750             // For general transforms, to determine the amount of correction we multiply a unit
751             // vector pointing along the SDF gradient direction by the Jacobian of the st coords
752             // (which is the inverse transform for this fragment) and take the length of the result.
753             fragBuilder->codeAppend("half2 dist_grad = half2(half(dFdx(distance.r)), "
754                                                             "half(dFdy(distance.r)));");
755             // the length of the gradient may be 0, so we need to check for this
756             // this also compensates for the Adreno, which likes to drop tiles on division by 0
757             fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);");
758             fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
759             fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);");
760             fragBuilder->codeAppend("} else {");
761             fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));");
762             fragBuilder->codeAppend("}");
763             fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
764             fragBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
765 
766             // this gives us a smooth step across approximately one fragment
767             fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
768         }
769 
770         // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
771         // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance
772         // mapped linearly to coverage, so use a linear step:
773         if (isGammaCorrect) {
774             fragBuilder->codeAppendf("%s = "
775                 "half4(saturate((distance + half3(afwidth)) / half3(2.0 * afwidth)), 1.0);",
776                 args.fOutputCoverage);
777         } else {
778             fragBuilder->codeAppendf(
779                 "%s = half4(smoothstep(half3(-afwidth), half3(afwidth), distance), 1.0);",
780                 args.fOutputCoverage);
781         }
782     }
783 
setData(const GrGLSLProgramDataManager & pdman,const GrPrimitiveProcessor & processor,FPCoordTransformIter && transformIter)784     void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& processor,
785                  FPCoordTransformIter&& transformIter) override {
786         SkASSERT(fDistanceAdjustUni.isValid());
787 
788         const GrDistanceFieldLCDTextGeoProc& dflcd = processor.cast<GrDistanceFieldLCDTextGeoProc>();
789         GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.getDistanceAdjust();
790         if (wa != fDistanceAdjust) {
791             pdman.set3f(fDistanceAdjustUni,
792                         wa.fR,
793                         wa.fG,
794                         wa.fB);
795             fDistanceAdjust = wa;
796         }
797 
798         const SkISize& atlasSize = dflcd.atlasSize();
799         SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
800         if (fAtlasSize != atlasSize) {
801             pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
802             fAtlasSize = atlasSize;
803         }
804         this->setTransformDataHelper(dflcd.localMatrix(), pdman, &transformIter);
805     }
806 
GenKey(const GrGeometryProcessor & gp,const GrShaderCaps &,GrProcessorKeyBuilder * b)807     static inline void GenKey(const GrGeometryProcessor& gp,
808                               const GrShaderCaps&,
809                               GrProcessorKeyBuilder* b) {
810         const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>();
811 
812         uint32_t key = dfTexEffect.getFlags();
813         b->add32(key);
814         b->add32(dfTexEffect.numTextureSamplers());
815     }
816 
817 private:
818     GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust;
819     UniformHandle                                 fDistanceAdjustUni;
820 
821     SkISize                                       fAtlasSize;
822     UniformHandle                                 fAtlasSizeInvUniform;
823 
824     typedef GrGLSLGeometryProcessor INHERITED;
825 };
826 
827 ///////////////////////////////////////////////////////////////////////////////
828 
GrDistanceFieldLCDTextGeoProc(const GrShaderCaps & caps,const sk_sp<GrTextureProxy> * proxies,int numProxies,const GrSamplerState & params,DistanceAdjust distanceAdjust,uint32_t flags,const SkMatrix & localMatrix)829 GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(const GrShaderCaps& caps,
830                                                              const sk_sp<GrTextureProxy>* proxies,
831                                                              int numProxies,
832                                                              const GrSamplerState& params,
833                                                              DistanceAdjust distanceAdjust,
834                                                              uint32_t flags,
835                                                              const SkMatrix& localMatrix)
836         : INHERITED(kGrDistanceFieldLCDTextGeoProc_ClassID)
837         , fLocalMatrix(localMatrix)
838         , fDistanceAdjust(distanceAdjust)
839         , fFlags(flags & kLCD_DistanceFieldEffectMask) {
840     SkASSERT(numProxies <= kMaxTextures);
841     SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
842 
843     if (fFlags & kPerspective_DistanceFieldEffectFlag) {
844         fInPosition = {"inPosition", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
845     } else {
846         fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
847     }
848     fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
849     fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
850                         caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
851     this->setVertexAttributes(&fInPosition, 3);
852 
853     if (numProxies) {
854         fAtlasSize = proxies[0]->isize();
855     }
856 
857     for (int i = 0; i < numProxies; ++i) {
858         SkASSERT(proxies[i]);
859         SkASSERT(proxies[i]->isize() == fAtlasSize);
860         fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
861     }
862     this->setTextureSamplerCnt(numProxies);
863 }
864 
addNewProxies(const sk_sp<GrTextureProxy> * proxies,int numProxies,const GrSamplerState & params)865 void GrDistanceFieldLCDTextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
866                                                   int numProxies,
867                                                   const GrSamplerState& params) {
868     SkASSERT(numProxies <= kMaxTextures);
869 
870     if (!fTextureSamplers[0].isInitialized()) {
871         fAtlasSize = proxies[0]->isize();
872     }
873 
874     for (int i = 0; i < numProxies; ++i) {
875         SkASSERT(proxies[i]);
876         SkASSERT(proxies[i]->isize() == fAtlasSize);
877 
878         if (!fTextureSamplers[i].isInitialized()) {
879             fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params);
880         }
881     }
882     this->setTextureSamplerCnt(numProxies);
883 }
884 
getGLSLProcessorKey(const GrShaderCaps & caps,GrProcessorKeyBuilder * b) const885 void GrDistanceFieldLCDTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
886                                                         GrProcessorKeyBuilder* b) const {
887     GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, caps, b);
888 }
889 
createGLSLInstance(const GrShaderCaps &) const890 GrGLSLPrimitiveProcessor* GrDistanceFieldLCDTextGeoProc::createGLSLInstance(const GrShaderCaps&) const {
891     return new GrGLDistanceFieldLCDTextGeoProc();
892 }
893 
894 ///////////////////////////////////////////////////////////////////////////////
895 
896 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc);
897 
898 #if GR_TEST_UTILS
TestCreate(GrProcessorTestData * d)899 sk_sp<GrGeometryProcessor> GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) {
900     int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
901                                           GrProcessorUnitTest::kAlphaTextureIdx;
902     sk_sp<GrTextureProxy> proxies[kMaxTextures] = {
903         d->textureProxy(texIdx),
904         nullptr,
905         nullptr,
906         nullptr
907     };
908 
909     GrSamplerState::WrapMode wrapModes[2];
910     GrTest::TestWrapModes(d->fRandom, wrapModes);
911     GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
912                                                    ? GrSamplerState::Filter::kBilerp
913                                                    : GrSamplerState::Filter::kNearest);
914     DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
915     uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
916     flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
917     if (flags & kSimilarity_DistanceFieldEffectFlag) {
918         flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
919     }
920     flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
921     SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
922     return GrDistanceFieldLCDTextGeoProc::Make(*d->caps()->shaderCaps(), proxies, 1, samplerState,
923                                                wa, flags, localMatrix);
924 }
925 #endif
926