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