1d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com/*
2d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com * Copyright 2013 Google Inc.
3d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com *
4d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com * Use of this source code is governed by a BSD-style license that can be
5d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com * found in the LICENSE file.
6d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com */
7d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
88ed3b9a386374d7996dfbe0c9de13b42f3dd245djvanverth#include "GrDistanceFieldGeoProc.h"
9605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel#include "GrInvariantOutput.h"
10eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "GrTexture.h"
1121deace8efc8e167d8626187ef0e6b4c241324b6jvanverth
12eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "SkDistanceFieldGen.h"
1321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth
142d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel#include "glsl/GrGLSLFragmentShaderBuilder.h"
15e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel#include "glsl/GrGLSLGeometryProcessor.h"
16018fb62d12d1febf121fe265da5b6117b86a6541egdaniel#include "glsl/GrGLSLProgramDataManager.h"
177ea439b2203855db97330b25945b87dd4b170b8begdaniel#include "glsl/GrGLSLUniformHandler.h"
1864c4728c70001ed074fecf5c4e083781987b12e9egdaniel#include "glsl/GrGLSLUtil.h"
190eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel#include "glsl/GrGLSLVarying.h"
200eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel#include "glsl/GrGLSLVertexShaderBuilder.h"
21d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
2221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth// Assuming a radius of a little less than the diagonal of the fragment
2324ba00825092be0d400074e0121ffc7221950dd9jvanverth#define SK_DistanceFieldAAFactor     "0.65"
242d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth
25e659a581f63fdccb64dce2dc8a478cf56831feeaegdanielclass GrGLDistanceFieldA8TextGeoProc : public GrGLSLGeometryProcessor {
26d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.compublic:
27465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    GrGLDistanceFieldA8TextGeoProc()
285559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        : fViewMatrix(SkMatrix::InvalidMatrix())
299564ce60a657acce89fb956deb8645b324eaad1ejvanverth#ifdef SK_GAMMA_APPLY_TO_A8
3021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        , fDistanceAdjust(-1.0f)
319564ce60a657acce89fb956deb8645b324eaad1ejvanverth#endif
329564ce60a657acce89fb956deb8645b324eaad1ejvanverth        {}
33d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
3436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
35502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldA8TextGeoProc& dfTexEffect =
36502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                args.fGP.cast<GrDistanceFieldA8TextGeoProc>();
378528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton        GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
384ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        SkAssertResult(fragBuilder->enableFeature(
392d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
406c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org
414ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
420eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel        GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
437ea439b2203855db97330b25945b87dd4b170b8begdaniel        GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
44abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
45abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit attributes
460eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel        varyingHandler->emitAttributes(dfTexEffect);
47abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
4821deace8efc8e167d8626187ef0e6b4c241324b6jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
4921deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        // adjust based on gamma
5096fcdcc219d2a0d3579719b84b28bede76efba64halcanary        const char* distanceAdjustUniName = nullptr;
5121deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        // width, height, 1/(3*width)
525e58ceea8569f0d90ff7e3daf5de2def50407212cdalton        fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
537ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                        kFloat_GrSLType, kDefault_GrSLPrecision,
547ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                        "DistanceAdjust", &distanceAdjustUniName);
5521deace8efc8e167d8626187ef0e6b4c241324b6jvanverth#endif
56d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
579b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        // Setup pass through color
58b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        if (!dfTexEffect.colorIgnored()) {
5953f26aa045d58feb9f2114f53629024bffe52deajoshualitt            varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
60b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        }
616c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org
62abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // Setup position
637ea439b2203855db97330b25945b87dd4b170b8begdaniel        this->setupPosition(vertBuilder,
647ea439b2203855db97330b25945b87dd4b170b8begdaniel                            uniformHandler,
654ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            gpArgs,
664ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            dfTexEffect.inPosition()->fName,
674ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            dfTexEffect.viewMatrix(),
685559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt                            &fViewMatrixUniform);
694973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
70abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit transforms
717ea439b2203855db97330b25945b87dd4b170b8begdaniel        this->emitTransforms(vertBuilder,
720eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                             varyingHandler,
737ea439b2203855db97330b25945b87dd4b170b8begdaniel                             uniformHandler,
744ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             gpArgs->fPositionVar,
754ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             dfTexEffect.inPosition()->fName,
764ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             args.fTransformsIn,
774ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             args.fTransformsOut);
78abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
79bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        // add varyings
808dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel        GrGLSLVertToFrag recipScale(kFloat_GrSLType);
817023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        GrGLSLVertToFrag uv(kVec2f_GrSLType);
82bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
837023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
847023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName);
85bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
86922c8b13c512c3287509936795735c1b31bedba9joshualitt        // compute numbers to be hardcoded to convert texture coordinates from int to float
87922c8b13c512c3287509936795735c1b31bedba9joshualitt        SkASSERT(dfTexEffect.numTextures() == 1);
88922c8b13c512c3287509936795735c1b31bedba9joshualitt        GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
897375d6bab2ee8b02da276597ed4d60f22f54eb89joshualitt        SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
90922c8b13c512c3287509936795735c1b31bedba9joshualitt
917023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        GrGLSLVertToFrag st(kVec2f_GrSLType);
927023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
937023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        vertBuilder->codeAppendf("%s = vec2(%d, %d) * %s;", st.vsOut(),
947023a00c35d904e4ccff09c377e9ba26abba6181jvanverth                                 atlas->width(), atlas->height(),
954ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 dfTexEffect.inTextureCoords()->fName);
96bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
97fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        // Use highp to work around aliasing issues
98a2e3e0f7f8ceed2ab152428d7ee2812ad8c842c3egdaniel        fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
994ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                                                 kHigh_GrSLPrecision));
1004ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
1014ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
1024ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tfloat texColor = ");
1034ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->appendTextureLookup(args.fSamplers[0],
1044ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         "uv",
1054ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         kVec2f_GrSLType);
1064ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend(".r;\n");
1074ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tfloat distance = "
108fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                       SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
10921deace8efc8e167d8626187ef0e6b4c241324b6jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
11021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        // adjust width based on gamma
1114ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
11221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth#endif
1136c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org
1144ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("float afwidth;");
115bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        if (isSimilarity) {
116354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For uniform scale, we adjust for the effect of the transformation on the distance
117354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // by using the length of the gradient of the texture coordinates. We use st coordinates
118221360a514fb4bfff5b461e83262306b2a0f36afjvanverth            // to ensure we're mapping 1:1 from texel space to pixel space.
119354eba5cb61801130a84378356434d3cc0a4b71ajvanverth
1204362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org            // this gives us a smooth step across approximately one fragment
121221360a514fb4bfff5b461e83262306b2a0f36afjvanverth            // we use y to work around a Mali400 bug in the x direction
1224ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));",
1234ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                     st.fsIn());
1244362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org        } else {
125354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For general transforms, to determine the amount of correction we multiply a unit
126354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
127354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // (which is the inverse transform for this fragment) and take the length of the result.
1284ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
129d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // the length of the gradient may be 0, so we need to check for this
130d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // this also compensates for the Adreno, which likes to drop tiles on division by 0
1314ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
1324ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
1334ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
1344ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("} else {");
1354ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
1364ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("}");
1374ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
1384ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn());
1394ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn());
1404ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
1414ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
1424362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org
1434362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org            // this gives us a smooth step across approximately one fragment
1444ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
1454362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org        }
1464ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
1474d517fdbb145cb95e5e935470df331e1b6667cfcjvanverth
1484ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
149d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    }
150d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
151018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc) override {
1522d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
153502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldA8TextGeoProc& dfTexEffect = proc.cast<GrDistanceFieldA8TextGeoProc>();
15421deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        float distanceAdjust = dfTexEffect.getDistanceAdjust();
15521deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        if (distanceAdjust != fDistanceAdjust) {
15621deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            pdman.set1f(fDistanceAdjustUni, distanceAdjust);
15721deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            fDistanceAdjust = distanceAdjust;
1582d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth        }
1592d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#endif
160e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>();
1615559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt
1625559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        if (!dfa8gp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfa8gp.viewMatrix())) {
1635559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt            fViewMatrix = dfa8gp.viewMatrix();
164018fb62d12d1febf121fe265da5b6117b86a6541egdaniel            float viewMatrix[3 * 3];
16564c4728c70001ed074fecf5c4e083781987b12e9egdaniel            GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
1665559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt            pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
1675559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        }
1686c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org    }
169d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
17046d36f0e7b709a077c647841eee23bd3efdc4117robertphillips    static inline void GenKey(const GrGeometryProcessor& gp,
171cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                              const GrGLSLCaps&,
172b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                              GrProcessorKeyBuilder* b) {
173502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>();
1748fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        uint32_t key = dfTexEffect.getFlags();
17553f26aa045d58feb9f2114f53629024bffe52deajoshualitt        key |= dfTexEffect.colorIgnored() << 16;
176e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
1778fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        b->add32(key);
178922c8b13c512c3287509936795735c1b31bedba9joshualitt
179922c8b13c512c3287509936795735c1b31bedba9joshualitt        // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
180922c8b13c512c3287509936795735c1b31bedba9joshualitt        SkASSERT(gp.numTextures() == 1);
181922c8b13c512c3287509936795735c1b31bedba9joshualitt        GrTexture* atlas = gp.textureAccess(0).getTexture();
182922c8b13c512c3287509936795735c1b31bedba9joshualitt        SkASSERT(atlas);
183922c8b13c512c3287509936795735c1b31bedba9joshualitt        b->add32(atlas->width());
184922c8b13c512c3287509936795735c1b31bedba9joshualitt        b->add32(atlas->height());
1854362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org    }
1864362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org
187d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.comprivate:
1885559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt    SkMatrix      fViewMatrix;
1895559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt    UniformHandle fViewMatrixUniform;
19050282b4390dcddcf3b1d51631c0133045ae1f233mtklein#ifdef SK_GAMMA_APPLY_TO_A8
19121deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    float         fDistanceAdjust;
19221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    UniformHandle fDistanceAdjustUni;
19350282b4390dcddcf3b1d51631c0133045ae1f233mtklein#endif
1946c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org
195e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel    typedef GrGLSLGeometryProcessor INHERITED;
196d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com};
197d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
198d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com///////////////////////////////////////////////////////////////////////////////
199d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
200502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color,
2018059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                           const SkMatrix& viewMatrix,
2022e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt                                                           GrTexture* texture,
2036c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org                                                           const GrTextureParams& params,
2042d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
20521deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                                                           float distanceAdjust,
2062d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#endif
207b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt                                                           uint32_t flags,
208b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt                                                           bool usesLocalCoords)
209e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    : fColor(color)
210e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    , fViewMatrix(viewMatrix)
2112e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt    , fTextureAccess(texture, params)
2122d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
21321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    , fDistanceAdjust(distanceAdjust)
2142d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#endif
215249af15fb82833d2274850c589812b6e69df0033joshualitt    , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
21696fcdcc219d2a0d3579719b84b28bede76efba64halcanary    , fInColor(nullptr)
217b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt    , fUsesLocalCoords(usesLocalCoords) {
21878f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth    SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
219502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    this->initClassID<GrDistanceFieldA8TextGeoProc>();
220f2539d50f911914af0f80f0092ff8c654869e650senorblanco    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
221f2539d50f911914af0f80f0092ff8c654869e650senorblanco                                                   kHigh_GrSLPrecision));
22253f26aa045d58feb9f2114f53629024bffe52deajoshualitt    fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
22371c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
2247023a00c35d904e4ccff09c377e9ba26abba6181jvanverth                                                        kVec2us_GrVertexAttribType,
2257023a00c35d904e4ccff09c377e9ba26abba6181jvanverth                                                        kHigh_GrSLPrecision));
226d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    this->addTextureAccess(&fTextureAccess);
227d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com}
228d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
22957d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielvoid GrDistanceFieldA8TextGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps,
23057d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel                                                       GrProcessorKeyBuilder* b) const {
231465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    GrGLDistanceFieldA8TextGeoProc::GenKey(*this, caps, b);
232eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
233eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
23457d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielGrGLSLPrimitiveProcessor* GrDistanceFieldA8TextGeoProc::createGLSLInstance(const GrGLSLCaps&) const {
235465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    return new GrGLDistanceFieldA8TextGeoProc();
236d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com}
237d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
238d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com///////////////////////////////////////////////////////////////////////////////
239d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
240502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc);
241d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
242c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomonconst GrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) {
2430067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
2440067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                          GrProcessorUnitTest::kAlphaTextureIdx;
245d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    static const SkShader::TileMode kTileModes[] = {
246d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com        SkShader::kClamp_TileMode,
247d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com        SkShader::kRepeat_TileMode,
248d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com        SkShader::kMirror_TileMode,
249d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    };
250d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    SkShader::TileMode tileModes[] = {
2510067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt        kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
2520067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt        kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
253d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    };
2540067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
255d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com                                                           GrTextureParams::kNone_FilterMode);
256d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
2570067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    return GrDistanceFieldA8TextGeoProc::Create(GrRandomColor(d->fRandom),
2580067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                GrTest::TestMatrix(d->fRandom),
2590067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                d->fTextures[texIdx], params,
2602d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
2610067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                d->fRandom->nextF(),
2622d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#endif
2630067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                d->fRandom->nextBool() ?
264b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt                                                    kSimilarity_DistanceFieldEffectFlag : 0,
2650067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                    d->fRandom->nextBool());
266609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org}
267609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
268609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
269609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
270e659a581f63fdccb64dce2dc8a478cf56831feeaegdanielclass GrGLDistanceFieldPathGeoProc : public GrGLSLGeometryProcessor {
271fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverthpublic:
272465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    GrGLDistanceFieldPathGeoProc()
2735559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        : fViewMatrix(SkMatrix::InvalidMatrix())
2745559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        , fTextureSize(SkISize::Make(-1, -1)) {}
275fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
27636352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
277502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldPathGeoProc>();
278fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
2798528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton        GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
2804ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        SkAssertResult(fragBuilder->enableFeature(
2812d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                                     GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
282fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
2834ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
2840eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel        GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
2857ea439b2203855db97330b25945b87dd4b170b8begdaniel        GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
286abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
287abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit attributes
2880eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel        varyingHandler->emitAttributes(dfTexEffect);
289abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
2908dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel        GrGLSLVertToFrag v(kVec2f_GrSLType);
2910eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel        varyingHandler->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
292fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
2939b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        // setup pass through color
294b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        if (!dfTexEffect.colorIgnored()) {
29553f26aa045d58feb9f2114f53629024bffe52deajoshualitt            varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
296b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        }
2974ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        vertBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
298e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed
299abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // Setup position
3007ea439b2203855db97330b25945b87dd4b170b8begdaniel        this->setupPosition(vertBuilder,
3017ea439b2203855db97330b25945b87dd4b170b8begdaniel                            uniformHandler,
3024ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            gpArgs,
3034ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            dfTexEffect.inPosition()->fName,
3044ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            dfTexEffect.viewMatrix(),
3055559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt                            &fViewMatrixUniform);
306abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
307abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit transforms
3087ea439b2203855db97330b25945b87dd4b170b8begdaniel        this->emitTransforms(vertBuilder,
3090eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                             varyingHandler,
3107ea439b2203855db97330b25945b87dd4b170b8begdaniel                             uniformHandler,
3114ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             gpArgs->fPositionVar,
3124ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             dfTexEffect.inPosition()->fName,
3134ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             args.fTransformsIn,
3144ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             args.fTransformsOut);
3154973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
31696fcdcc219d2a0d3579719b84b28bede76efba64halcanary        const char* textureSizeUniName = nullptr;
3175e58ceea8569f0d90ff7e3daf5de2def50407212cdalton        fTextureSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
3187ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                     kVec2f_GrSLType, kDefault_GrSLPrecision,
3197ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                     "TextureSize", &textureSizeUniName);
320e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed
321fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        // Use highp to work around aliasing issues
322a2e3e0f7f8ceed2ab152428d7ee2812ad8c842c3egdaniel        fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
3234ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                                                 kHigh_GrSLPrecision));
3244ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
3254ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
3264ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("float texColor = ");
3274ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->appendTextureLookup(args.fSamplers[0],
3284ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         "uv",
3294ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                         kVec2f_GrSLType);
3304ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend(".r;");
3314ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("float distance = "
332fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth            SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
333fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
334a2e3e0f7f8ceed2ab152428d7ee2812ad8c842c3egdaniel        fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
3354ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                                                 kHigh_GrSLPrecision));
3364ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
3374ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("float afwidth;");
338fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
339354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For uniform scale, we adjust for the effect of the transformation on the distance
340354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // by using the length of the gradient of the texture coordinates. We use st coordinates
341354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // to ensure we're mapping 1:1 from texel space to pixel space.
342354eba5cb61801130a84378356434d3cc0a4b71ajvanverth
343fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            // this gives us a smooth step across approximately one fragment
3444ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));");
345fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        } else {
346354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For general transforms, to determine the amount of correction we multiply a unit
347354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
348354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // (which is the inverse transform for this fragment) and take the length of the result.
3494ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
350d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // the length of the gradient may be 0, so we need to check for this
351d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // this also compensates for the Adreno, which likes to drop tiles on division by 0
3524ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
3534ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
3544ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
3554ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("} else {");
3564ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
3574ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("}");
3584ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
3594ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 Jdx = dFdx(st);");
3604ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 Jdy = dFdy(st);");
3614ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
3624ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
363fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
364fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            // this gives us a smooth step across approximately one fragment
3654ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
366fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        }
3674ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
368fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
3694ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
370fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    }
371fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
372018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc) override {
373e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        SkASSERT(fTextureSizeUni.isValid());
374fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
37587f48d997ec29e5eeaa7567355775e93465dd60djoshualitt        GrTexture* texture = proc.texture(0);
376fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        if (texture->width() != fTextureSize.width() ||
377fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            texture->height() != fTextureSize.height()) {
378fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            fTextureSize = SkISize::Make(texture->width(), texture->height());
379e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed            pdman.set2f(fTextureSizeUni,
380e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed                        SkIntToScalar(fTextureSize.width()),
381e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed                        SkIntToScalar(fTextureSize.height()));
382fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        }
3839b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
384e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>();
3855559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt
3865559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        if (!dfpgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfpgp.viewMatrix())) {
3875559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt            fViewMatrix = dfpgp.viewMatrix();
388018fb62d12d1febf121fe265da5b6117b86a6541egdaniel            float viewMatrix[3 * 3];
38964c4728c70001ed074fecf5c4e083781987b12e9egdaniel            GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
3905559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt            pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
3915559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        }
392fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    }
393fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
39446d36f0e7b709a077c647841eee23bd3efdc4117robertphillips    static inline void GenKey(const GrGeometryProcessor& gp,
395cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                              const GrGLSLCaps&,
396fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth                              GrProcessorKeyBuilder* b) {
397502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>();
398fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
3998fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        uint32_t key = dfTexEffect.getFlags();
400b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        key |= dfTexEffect.colorIgnored() << 16;
401e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
4028fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        b->add32(key);
403fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    }
404fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
405fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverthprivate:
406e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed    UniformHandle fTextureSizeUni;
4075559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt    UniformHandle fViewMatrixUniform;
4085559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt    SkMatrix      fViewMatrix;
4099b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    SkISize       fTextureSize;
410fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
411e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel    typedef GrGLSLGeometryProcessor INHERITED;
412fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth};
413fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
414fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth///////////////////////////////////////////////////////////////////////////////
415fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
416502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
4172e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt        GrColor color,
4188059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        const SkMatrix& viewMatrix,
4192e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt        GrTexture* texture,
4202e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt        const GrTextureParams& params,
421b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        uint32_t flags,
422b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        bool usesLocalCoords)
423e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    : fColor(color)
424e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    , fViewMatrix(viewMatrix)
4252e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt    , fTextureAccess(texture, params)
426fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
42796fcdcc219d2a0d3579719b84b28bede76efba64halcanary    , fInColor(nullptr)
428b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt    , fUsesLocalCoords(usesLocalCoords) {
429fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
430502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    this->initClassID<GrDistanceFieldPathGeoProc>();
431f2539d50f911914af0f80f0092ff8c654869e650senorblanco    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
432f2539d50f911914af0f80f0092ff8c654869e650senorblanco                                                   kHigh_GrSLPrecision));
43353f26aa045d58feb9f2114f53629024bffe52deajoshualitt    fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
43471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
435b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt                                                        kVec2f_GrVertexAttribType));
436fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    this->addTextureAccess(&fTextureAccess);
437fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth}
438fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
43957d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielvoid GrDistanceFieldPathGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps,
44057d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel                                                     GrProcessorKeyBuilder* b) const {
441465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    GrGLDistanceFieldPathGeoProc::GenKey(*this, caps, b);
442eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
443eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
44457d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielGrGLSLPrimitiveProcessor* GrDistanceFieldPathGeoProc::createGLSLInstance(const GrGLSLCaps&) const {
445465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    return new GrGLDistanceFieldPathGeoProc();
446fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth}
447fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
448fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth///////////////////////////////////////////////////////////////////////////////
449fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
450502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc);
451fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
452c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomonconst GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) {
4530067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
4540067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                        : GrProcessorUnitTest::kAlphaTextureIdx;
455fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    static const SkShader::TileMode kTileModes[] = {
456fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        SkShader::kClamp_TileMode,
457fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        SkShader::kRepeat_TileMode,
458fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        SkShader::kMirror_TileMode,
459fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    };
460fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    SkShader::TileMode tileModes[] = {
4610067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt        kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
4620067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt        kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
463fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    };
4640067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode
4650067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                             : GrTextureParams::kNone_FilterMode);
466fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
4670067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    return GrDistanceFieldPathGeoProc::Create(GrRandomColor(d->fRandom),
4680067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                              GrTest::TestMatrix(d->fRandom),
4690067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                              d->fTextures[texIdx],
470502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                              params,
4710067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                              d->fRandom->nextBool() ?
472b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt                                                      kSimilarity_DistanceFieldEffectFlag : 0,
4730067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                      d->fRandom->nextBool());
474fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth}
475fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
476fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth///////////////////////////////////////////////////////////////////////////////
477fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
478e659a581f63fdccb64dce2dc8a478cf56831feeaegdanielclass GrGLDistanceFieldLCDTextGeoProc : public GrGLSLGeometryProcessor {
479609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.orgpublic:
480465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    GrGLDistanceFieldLCDTextGeoProc()
48153f26aa045d58feb9f2114f53629024bffe52deajoshualitt        : fViewMatrix(SkMatrix::InvalidMatrix()) {
482502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f);
48321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    }
484609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
48536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
486502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldLCDTextGeoProc& dfTexEffect =
487502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                args.fGP.cast<GrDistanceFieldLCDTextGeoProc>();
488609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
4894ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
4900eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel        GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
4917ea439b2203855db97330b25945b87dd4b170b8begdaniel        GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
492abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
493abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit attributes
4940eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel        varyingHandler->emitAttributes(dfTexEffect);
4954ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel
4968528541dd7f09f5bd76f3f1ce5f45d08ac7347c7cdalton        GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
497abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
4989b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        // setup pass through color
499b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        if (!dfTexEffect.colorIgnored()) {
50053f26aa045d58feb9f2114f53629024bffe52deajoshualitt            varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
501b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        }
5029b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
503abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // Setup position
5047ea439b2203855db97330b25945b87dd4b170b8begdaniel        this->setupPosition(vertBuilder,
5057ea439b2203855db97330b25945b87dd4b170b8begdaniel                            uniformHandler,
5064ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            gpArgs,
5074ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            dfTexEffect.inPosition()->fName,
5084ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                            dfTexEffect.viewMatrix(),
5095559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt                            &fViewMatrixUniform);
5104973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
511abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit transforms
5127ea439b2203855db97330b25945b87dd4b170b8begdaniel        this->emitTransforms(vertBuilder,
5130eafe79f42e3c675f3c504aed4a41abf511df2b7egdaniel                             varyingHandler,
5147ea439b2203855db97330b25945b87dd4b170b8begdaniel                             uniformHandler,
5154ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             gpArgs->fPositionVar,
5164ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             dfTexEffect.inPosition()->fName,
5174ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             args.fTransformsIn,
5184ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                             args.fTransformsOut);
5195b143038cb47763974d2750ed78d436eb6c38beajvanverth
520bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        // set up varyings
521bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
5228dcdedc4a087ea46ce1e2458d335d60918e56310egdaniel        GrGLSLVertToFrag recipScale(kFloat_GrSLType);
5237023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        GrGLSLVertToFrag uv(kVec2f_GrSLType);
5247023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
5257023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName);
526bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
527922c8b13c512c3287509936795735c1b31bedba9joshualitt        // compute numbers to be hardcoded to convert texture coordinates from int to float
528922c8b13c512c3287509936795735c1b31bedba9joshualitt        SkASSERT(dfTexEffect.numTextures() == 1);
529922c8b13c512c3287509936795735c1b31bedba9joshualitt        GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
5307375d6bab2ee8b02da276597ed4d60f22f54eb89joshualitt        SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
531922c8b13c512c3287509936795735c1b31bedba9joshualitt
5327023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        GrGLSLVertToFrag st(kVec2f_GrSLType);
5337023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
5347023a00c35d904e4ccff09c377e9ba26abba6181jvanverth        vertBuilder->codeAppendf("%s = vec2(%d, %d) * %s;", st.vsOut(),
5357023a00c35d904e4ccff09c377e9ba26abba6181jvanverth                                 atlas->width(), atlas->height(),
5364ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                 dfTexEffect.inTextureCoords()->fName);
537bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
538bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        // add frag shader code
53930ba436f04e61d4505fb854d5fc56079636e0788joshualitt
5404ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        SkAssertResult(fragBuilder->enableFeature(
5412d721d33aad192cc8a7a1321504b39bdca2a57ceegdaniel                GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
54230ba436f04e61d4505fb854d5fc56079636e0788joshualitt
543609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // create LCD offset adjusted by inverse of transform
544fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        // Use highp to work around aliasing issues
545a2e3e0f7f8ceed2ab152428d7ee2812ad8c842c3egdaniel        fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
5464ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                                                 kHigh_GrSLPrecision));
5474ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
548a2e3e0f7f8ceed2ab152428d7ee2812ad8c842c3egdaniel        fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
5494ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel                                                                 kHigh_GrSLPrecision));
550922c8b13c512c3287509936795735c1b31bedba9joshualitt
551922c8b13c512c3287509936795735c1b31bedba9joshualitt        SkScalar lcdDelta = 1.0f / (3.0f * atlas->width());
5525a105ff05303ac82a867b8b84a1edd145bd46218jvanverth        if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
5534ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
5545a105ff05303ac82a867b8b84a1edd145bd46218jvanverth        } else {
5554ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
5565a105ff05303ac82a867b8b84a1edd145bd46218jvanverth        }
55778f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth        if (isUniformScale) {
5584ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("float dy = abs(dFdy(%s.y));", st.fsIn());
5594ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 offset = vec2(dy*delta, 0.0);");
560609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        } else {
5614ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn());
562bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
5634ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 Jdx = dFdx(st);");
5644ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 Jdy = dFdy(st);");
5654ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 offset = delta*Jdx;");
566609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        }
567609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
568609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // green is distance to uv center
5694ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tvec4 texColor = ");
5704ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
5714ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend(";\n");
5724ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tvec3 distance;\n");
5734ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tdistance.y = texColor.r;\n");
574609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // red is distance to left offset
5754ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
5764ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\ttexColor = ");
5774ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
5784ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend(";\n");
5794ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tdistance.x = texColor.r;\n");
580609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // blue is distance to right offset
5814ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
5824ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\ttexColor = ");
5834ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
5844ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend(";\n");
5854ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tdistance.z = texColor.r;\n");
5862d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth
5874ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("\tdistance = "
588ada68ef2dc986478288a8b8ad867fd3aca431162jvanverth           "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
5892d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth
59021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        // adjust width based on gamma
59196fcdcc219d2a0d3579719b84b28bede76efba64halcanary        const char* distanceAdjustUniName = nullptr;
5925e58ceea8569f0d90ff7e3daf5de2def50407212cdalton        fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
5937ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                        kVec3f_GrSLType, kDefault_GrSLPrecision,
5947ea439b2203855db97330b25945b87dd4b170b8begdaniel                                                        "DistanceAdjust", &distanceAdjustUniName);
5954ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
59621deace8efc8e167d8626187ef0e6b4c241324b6jvanverth
597609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // To be strictly correct, we should compute the anti-aliasing factor separately
598609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // for each color component. However, this is only important when using perspective
599609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // transformations, and even then using a single factor seems like a reasonable
600609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // trade-off between quality and speed.
6014ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("float afwidth;");
60278f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth        if (isUniformScale) {
603354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For uniform scale, we adjust for the effect of the transformation on the distance
604354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // by using the length of the gradient of the texture coordinates. We use st coordinates
605354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // to ensure we're mapping 1:1 from texel space to pixel space.
606354eba5cb61801130a84378356434d3cc0a4b71ajvanverth
607609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org            // this gives us a smooth step across approximately one fragment
6084ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*dy;");
609609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        } else {
610354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For general transforms, to determine the amount of correction we multiply a unit
611354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
612354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // (which is the inverse transform for this fragment) and take the length of the result.
6134ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));");
614d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // the length of the gradient may be 0, so we need to check for this
615d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // this also compensates for the Adreno, which likes to drop tiles on division by 0
6164ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
6174ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
6184ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
6194ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("} else {");
6204ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
6214ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("}");
6224ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
6234ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
624609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
625609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org            // this gives us a smooth step across approximately one fragment
6264ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel            fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
627609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        }
628609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
6294ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend(
63021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                      "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
63127b6335c71bccb96206ff0495793433bfa982777egdaniel        // set alpha to be max of rgb coverage
6324ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppend("val.a = max(max(val.r, val.g), val.b);");
63330ba436f04e61d4505fb854d5fc56079636e0788joshualitt
6344ca2e6034365ad280ec64473f7f1d72ebd8335e4egdaniel        fragBuilder->codeAppendf("%s = val;", args.fOutputCoverage);
635609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    }
636609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
637018fb62d12d1febf121fe265da5b6117b86a6541egdaniel    void setData(const GrGLSLProgramDataManager& pdman,
638465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt                 const GrPrimitiveProcessor& processor) override {
63921deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        SkASSERT(fDistanceAdjustUni.isValid());
640609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
6415559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        const GrDistanceFieldLCDTextGeoProc& dflcd = processor.cast<GrDistanceFieldLCDTextGeoProc>();
6425559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.getDistanceAdjust();
64321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        if (wa != fDistanceAdjust) {
64421deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            pdman.set3f(fDistanceAdjustUni,
64521deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                        wa.fR,
64621deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                        wa.fG,
64721deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                        wa.fB);
64821deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            fDistanceAdjust = wa;
6492d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth        }
6509b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
6515559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        if (!dflcd.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dflcd.viewMatrix())) {
6525559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt            fViewMatrix = dflcd.viewMatrix();
653018fb62d12d1febf121fe265da5b6117b86a6541egdaniel            float viewMatrix[3 * 3];
65464c4728c70001ed074fecf5c4e083781987b12e9egdaniel            GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
6555559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt            pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
6565559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt        }
657609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    }
658609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
65946d36f0e7b709a077c647841eee23bd3efdc4117robertphillips    static inline void GenKey(const GrGeometryProcessor& gp,
660cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                              const GrGLSLCaps&,
661b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                              GrProcessorKeyBuilder* b) {
662502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>();
663609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
6648fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        uint32_t key = dfTexEffect.getFlags();
665b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt        key |= dfTexEffect.colorIgnored() << 16;
666e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
6678fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        b->add32(key);
668922c8b13c512c3287509936795735c1b31bedba9joshualitt
669922c8b13c512c3287509936795735c1b31bedba9joshualitt        // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
670922c8b13c512c3287509936795735c1b31bedba9joshualitt        SkASSERT(gp.numTextures() == 1);
671922c8b13c512c3287509936795735c1b31bedba9joshualitt        GrTexture* atlas = gp.textureAccess(0).getTexture();
672922c8b13c512c3287509936795735c1b31bedba9joshualitt        SkASSERT(atlas);
673922c8b13c512c3287509936795735c1b31bedba9joshualitt        b->add32(atlas->width());
674922c8b13c512c3287509936795735c1b31bedba9joshualitt        b->add32(atlas->height());
675609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    }
676609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
677609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.orgprivate:
6785559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt    SkMatrix                                     fViewMatrix;
6795559ca2a18687ef16b2fc92d8fcacbc1c3e93d54joshualitt    UniformHandle                                fViewMatrixUniform;
68021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    UniformHandle                                fColorUniform;
681502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust;
68221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    UniformHandle                                fDistanceAdjustUni;
683609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
684e659a581f63fdccb64dce2dc8a478cf56831feeaegdaniel    typedef GrGLSLGeometryProcessor INHERITED;
685609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org};
686609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
687609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
688609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
689502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(
6908059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                  GrColor color, const SkMatrix& viewMatrix,
6912d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth                                                  GrTexture* texture, const GrTextureParams& params,
69221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                                                  DistanceAdjust distanceAdjust,
693b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt                                                  uint32_t flags, bool usesLocalCoords)
694e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    : fColor(color)
695e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    , fViewMatrix(viewMatrix)
6962e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt    , fTextureAccess(texture, params)
69721deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    , fDistanceAdjust(distanceAdjust)
698b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt    , fFlags(flags & kLCD_DistanceFieldEffectMask)
699b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt    , fUsesLocalCoords(usesLocalCoords) {
70078f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth    SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
701502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    this->initClassID<GrDistanceFieldLCDTextGeoProc>();
702f2539d50f911914af0f80f0092ff8c654869e650senorblanco    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
703f2539d50f911914af0f80f0092ff8c654869e650senorblanco                                                   kHigh_GrSLPrecision));
70453f26aa045d58feb9f2114f53629024bffe52deajoshualitt    fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
70571c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
7067023a00c35d904e4ccff09c377e9ba26abba6181jvanverth                                                        kVec2us_GrVertexAttribType,
7077023a00c35d904e4ccff09c377e9ba26abba6181jvanverth                                                        kHigh_GrSLPrecision));
708609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    this->addTextureAccess(&fTextureAccess);
709609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org}
710609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
71157d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielvoid GrDistanceFieldLCDTextGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps,
71257d3b039c635945e1dc2fcbac3462ed8bfedb068egdaniel                                                        GrProcessorKeyBuilder* b) const {
713465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, caps, b);
714eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
715eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
71657d3b039c635945e1dc2fcbac3462ed8bfedb068egdanielGrGLSLPrimitiveProcessor* GrDistanceFieldLCDTextGeoProc::createGLSLInstance(const GrGLSLCaps&) const {
717465283cdf98ed9ab5285ca7b9814e430fca1d452joshualitt    return new GrGLDistanceFieldLCDTextGeoProc();
718609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org}
719609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
720609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
721609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
722502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc);
723609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
724c21b09eec91c9e263cb0b88467ea44e348ed4962bsalomonconst GrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) {
7250067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
7260067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                          GrProcessorUnitTest::kAlphaTextureIdx;
727609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    static const SkShader::TileMode kTileModes[] = {
728609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        SkShader::kClamp_TileMode,
729609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        SkShader::kRepeat_TileMode,
730609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        SkShader::kMirror_TileMode,
731609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    };
732609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    SkShader::TileMode tileModes[] = {
7330067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt        kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
7340067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt        kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
735609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    };
7360067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
737609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org                           GrTextureParams::kNone_FilterMode);
73821deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
73978f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth    uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
7400067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    flags |= d->fRandom->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
7410067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
7420067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt    return GrDistanceFieldLCDTextGeoProc::Create(GrRandomColor(d->fRandom),
7430067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                 GrTest::TestMatrix(d->fRandom),
7440067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                 d->fTextures[texIdx], params,
745502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                 wa,
746b8c241ad099f3f0c2cbf3e7c10f5f6207175d490joshualitt                                                 flags,
7470067ff5e0f85084dd2b5ad9886b526482b89a116joshualitt                                                 d->fRandom->nextBool());
748d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com}
749