LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/gpu/effects - GrDistanceFieldGeoProc.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 384 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 30 0.0 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13