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"
95a105ff05303ac82a867b8b84a1edd145bd46218jvanverth#include "GrFontAtlasSizes.h"
10605dd0fbce9dbb2a0d3313e13e161f2bd54870d7egdaniel#include "GrInvariantOutput.h"
11eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "GrTexture.h"
1221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth
13eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "SkDistanceFieldGen.h"
1421deace8efc8e167d8626187ef0e6b4c241324b6jvanverth
15b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt#include "gl/GrGLProcessor.h"
16d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com#include "gl/GrGLSL.h"
17d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com#include "gl/GrGLTexture.h"
18249af15fb82833d2274850c589812b6e69df0033joshualitt#include "gl/GrGLGeometryProcessor.h"
19eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt#include "gl/builders/GrGLProgramBuilder.h"
20d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
2121deace8efc8e167d8626187ef0e6b4c241324b6jvanverth// Assuming a radius of a little less than the diagonal of the fragment
2224ba00825092be0d400074e0121ffc7221950dd9jvanverth#define SK_DistanceFieldAAFactor     "0.65"
232d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth
249b98932adaceb7ad0a617ade16616923f6bffe84joshualittstruct DistanceFieldBatchTracker {
259b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    GrGPInput fInputColorType;
269b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    GrColor fColor;
27290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt    bool fUsesLocalCoords;
289b98932adaceb7ad0a617ade16616923f6bffe84joshualitt};
299b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
30502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthclass GrGLDistanceFieldA8TextGeoProc : public GrGLGeometryProcessor {
31d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.compublic:
32502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    GrGLDistanceFieldA8TextGeoProc(const GrGeometryProcessor&,
3387f48d997ec29e5eeaa7567355775e93465dd60djoshualitt                                   const GrBatchTracker&)
349b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        : fColor(GrColor_ILLEGAL)
359564ce60a657acce89fb956deb8645b324eaad1ejvanverth#ifdef SK_GAMMA_APPLY_TO_A8
3621deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        , fDistanceAdjust(-1.0f)
379564ce60a657acce89fb956deb8645b324eaad1ejvanverth#endif
389564ce60a657acce89fb956deb8645b324eaad1ejvanverth        {}
39d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
4036352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
41502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldA8TextGeoProc& dfTexEffect =
42502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                args.fGP.cast<GrDistanceFieldA8TextGeoProc>();
439b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        const DistanceFieldBatchTracker& local = args.fBT.cast<DistanceFieldBatchTracker>();
449b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrGLGPBuilder* pb = args.fPB;
4529bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel        GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
4630ba436f04e61d4505fb854d5fc56079636e0788joshualitt        SkAssertResult(fsBuilder->enableFeature(
4730ba436f04e61d4505fb854d5fc56079636e0788joshualitt                GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
486c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org
492dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt        GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
50abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
51abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit attributes
52abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        vsBuilder->emitAttributes(dfTexEffect);
53abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
5421deace8efc8e167d8626187ef0e6b4c241324b6jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
5521deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        // adjust based on gamma
5621deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        const char* distanceAdjustUniName = NULL;
5721deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        // width, height, 1/(3*width)
5821deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
5921deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            kFloat_GrSLType, kDefault_GrSLPrecision,
6021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            "DistanceAdjust", &distanceAdjustUniName);
6121deace8efc8e167d8626187ef0e6b4c241324b6jvanverth#endif
62d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
639b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        // Setup pass through color
649b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor,
659b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                                    dfTexEffect.inColor(), &fColorUniform);
666c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org
67abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // Setup position
68dd2198701b0ec9da61ecf73418cad03642d715e7joshualitt        this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix());
694973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
70abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit transforms
7146d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
72e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                             args.fTransformsIn, args.fTransformsOut);
73abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
74bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        // add varyings
75bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        GrGLVertToFrag recipScale(kFloat_GrSLType);
76bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        GrGLVertToFrag st(kVec2f_GrSLType);
77bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
78221360a514fb4bfff5b461e83262306b2a0f36afjvanverth        args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
79221360a514fb4bfff5b461e83262306b2a0f36afjvanverth        vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
80bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
81bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        GrGLVertToFrag uv(kVec2f_GrSLType);
82bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
83bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        // this is only used with text, so our texture bounds always match the glyph atlas
84bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", "
85bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth                               GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(),
86bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth                               dfTexEffect.inTextureCoords()->fName);
87bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
88fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        // Use highp to work around aliasing issues
89fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
90fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                                                             pb->ctxInfo().standard()));
915a105ff05303ac82a867b8b84a1edd145bd46218jvanverth        fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
92fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth
93fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend("\tfloat texColor = ");
94c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt        fsBuilder->appendTextureLookup(args.fSamplers[0],
95fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                                       "uv",
96d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com                                       kVec2f_GrSLType);
97fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend(".r;\n");
9830ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tfloat distance = "
99fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                       SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
10021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
10121deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        // adjust width based on gamma
10221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
10321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth#endif
1046c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org
105354eba5cb61801130a84378356434d3cc0a4b71ajvanverth        fsBuilder->codeAppend("float afwidth;");
106bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        if (isSimilarity) {
107354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For uniform scale, we adjust for the effect of the transformation on the distance
108354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // by using the length of the gradient of the texture coordinates. We use st coordinates
109221360a514fb4bfff5b461e83262306b2a0f36afjvanverth            // to ensure we're mapping 1:1 from texel space to pixel space.
110354eba5cb61801130a84378356434d3cc0a4b71ajvanverth
1114362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org            // this gives us a smooth step across approximately one fragment
112221360a514fb4bfff5b461e83262306b2a0f36afjvanverth            // we use y to work around a Mali400 bug in the x direction
113221360a514fb4bfff5b461e83262306b2a0f36afjvanverth            fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));",
114bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth                                       st.fsIn());
1154362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org        } else {
116354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For general transforms, to determine the amount of correction we multiply a unit
117354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
118354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // (which is the inverse transform for this fragment) and take the length of the result.
119354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
120d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // the length of the gradient may be 0, so we need to check for this
121d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // this also compensates for the Adreno, which likes to drop tiles on division by 0
122d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
123d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
124d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
125d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("} else {");
126d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
127d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("}");
128d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth
129bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth            fsBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn());
130bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth            fsBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn());
131354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
132354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
1334362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org
1344362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org            // this gives us a smooth step across approximately one fragment
135354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
1364362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org        }
137354eba5cb61801130a84378356434d3cc0a4b71ajvanverth        fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
1384d517fdbb145cb95e5e935470df331e1b6667cfcjvanverth
1392dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt        fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
140d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    }
141d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
1427510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    virtual void setData(const GrGLProgramDataManager& pdman,
1439b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                         const GrPrimitiveProcessor& proc,
14436352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                         const GrBatchTracker& bt) override {
1452d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
146502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldA8TextGeoProc& dfTexEffect = proc.cast<GrDistanceFieldA8TextGeoProc>();
14721deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        float distanceAdjust = dfTexEffect.getDistanceAdjust();
14821deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        if (distanceAdjust != fDistanceAdjust) {
14921deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            pdman.set1f(fDistanceAdjustUni, distanceAdjust);
15021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            fDistanceAdjust = distanceAdjust;
1512d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth        }
1522d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#endif
1539b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
154e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>();
155e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        this->setUniformViewMatrix(pdman, dfa8gp.viewMatrix());
156ee2af95db72152dfa61c841875df0594ca93437djoshualitt
1579b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
1589b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
1599b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrGLfloat c[4];
1609b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrColorToRGBAFloat(local.fColor, c);
1619b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            pdman.set4fv(fColorUniform, 1, c);
1629b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            fColor = local.fColor;
1639b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        }
1646c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org    }
165d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
16646d36f0e7b709a077c647841eee23bd3efdc4117robertphillips    static inline void GenKey(const GrGeometryProcessor& gp,
1679b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                              const GrBatchTracker& bt,
168cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                              const GrGLSLCaps&,
169b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                              GrProcessorKeyBuilder* b) {
170502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>();
1719b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
1728fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        uint32_t key = dfTexEffect.getFlags();
1738fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        key |= local.fInputColorType << 16;
174e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
1758fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        b->add32(key);
1764362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org    }
1774362a38563a958083aca2b456aaaa9f756f6f4e1commit-bot@chromium.org
178d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.comprivate:
1799b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    GrColor       fColor;
1809b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    UniformHandle fColorUniform;
18150282b4390dcddcf3b1d51631c0133045ae1f233mtklein#ifdef SK_GAMMA_APPLY_TO_A8
18221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    float         fDistanceAdjust;
18321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    UniformHandle fDistanceAdjustUni;
18450282b4390dcddcf3b1d51631c0133045ae1f233mtklein#endif
1856c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org
186249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGLGeometryProcessor INHERITED;
187d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com};
188d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
189d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com///////////////////////////////////////////////////////////////////////////////
190d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
191502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color,
1928059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                           const SkMatrix& viewMatrix,
1932e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt                                                           GrTexture* texture,
1946c89c34614573797ce63e429229b6f7848df0bb7commit-bot@chromium.org                                                           const GrTextureParams& params,
1952d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
19621deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                                                           float distanceAdjust,
1972d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#endif
1981ba8cc9193f13a812401e14b8037fdcf3f3acbacjoshualitt                                                           uint32_t flags)
199e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    : fColor(color)
200e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    , fViewMatrix(viewMatrix)
2012e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt    , fTextureAccess(texture, params)
2022d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
20321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    , fDistanceAdjust(distanceAdjust)
2042d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#endif
205249af15fb82833d2274850c589812b6e69df0033joshualitt    , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
2062dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt    , fInColor(NULL) {
20778f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth    SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
208502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    this->initClassID<GrDistanceFieldA8TextGeoProc>();
209c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
210c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco                                                   kHigh_GrSLPrecision));
2112dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt    if (flags & kColorAttr_DistanceFieldEffectFlag) {
21271c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt        fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
2132dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt    }
21471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
2155a105ff05303ac82a867b8b84a1edd145bd46218jvanverth                                                          kVec2s_GrVertexAttribType));
216d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    this->addTextureAccess(&fTextureAccess);
217d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com}
218d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
219502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthvoid GrDistanceFieldA8TextGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
220cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                                     const GrGLSLCaps& caps,
221eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt                                                     GrProcessorKeyBuilder* b) const {
222502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    GrGLDistanceFieldA8TextGeoProc::GenKey(*this, bt, caps, b);
223eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
224eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
225abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualittGrGLPrimitiveProcessor*
226502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrDistanceFieldA8TextGeoProc::createGLInstance(const GrBatchTracker& bt,
227cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                               const GrGLSLCaps&) const {
228502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    return SkNEW_ARGS(GrGLDistanceFieldA8TextGeoProc, (*this, bt));
229d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com}
230d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
231502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthvoid GrDistanceFieldA8TextGeoProc::initBatchTracker(GrBatchTracker* bt,
23221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                                                    const GrPipelineInfo& init) const {
2339b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    DistanceFieldBatchTracker* local = bt->cast<DistanceFieldBatchTracker>();
2349b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
2359b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                                               SkToBool(fInColor));
236290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt    local->fUsesLocalCoords = init.fUsesLocalCoords;
2379b98932adaceb7ad0a617ade16616923f6bffe84joshualitt}
2389b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
239d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com///////////////////////////////////////////////////////////////////////////////
240d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
241502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc);
242d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
243502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(SkRandom* random,
244b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                              GrContext*,
245b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                              const GrDrawTargetCaps&,
246b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                              GrTexture* textures[]) {
247b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
248b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                      GrProcessorUnitTest::kAlphaTextureIdx;
249d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    static const SkShader::TileMode kTileModes[] = {
250d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com        SkShader::kClamp_TileMode,
251d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com        SkShader::kRepeat_TileMode,
252d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com        SkShader::kMirror_TileMode,
253d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    };
254d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    SkShader::TileMode tileModes[] = {
255d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
256d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
257d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    };
258d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com    GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
259d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com                                                           GrTextureParams::kNone_FilterMode);
260d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com
261502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    return GrDistanceFieldA8TextGeoProc::Create(GrRandomColor(random),
2624eaf9cef5a76098f78efac30beb966ac833d32c2joshualitt                                                GrTest::TestMatrix(random),
2638059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                textures[texIdx], params,
2642d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#ifdef SK_GAMMA_APPLY_TO_A8
2652d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth                                                random->nextF(),
2662d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth#endif
26778f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth                                                random->nextBool() ?
2681ba8cc9193f13a812401e14b8037fdcf3f3acbacjoshualitt                                                    kSimilarity_DistanceFieldEffectFlag : 0);
269609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org}
270609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
271609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
272609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
273502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthstruct DistanceFieldPathBatchTracker {
2749b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    GrGPInput fInputColorType;
2759b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    GrColor fColor;
276290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt    bool fUsesLocalCoords;
2779b98932adaceb7ad0a617ade16616923f6bffe84joshualitt};
2789b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
279502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthclass GrGLDistanceFieldPathGeoProc : public GrGLGeometryProcessor {
280fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverthpublic:
281502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    GrGLDistanceFieldPathGeoProc(const GrGeometryProcessor&,
28287f48d997ec29e5eeaa7567355775e93465dd60djoshualitt                                          const GrBatchTracker&)
283e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        : fColor(GrColor_ILLEGAL), fTextureSize(SkISize::Make(-1, -1)) {}
284fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
28536352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
286502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldPathGeoProc>();
287fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
288502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const DistanceFieldPathBatchTracker& local = args.fBT.cast<DistanceFieldPathBatchTracker>();
2899b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrGLGPBuilder* pb = args.fPB;
29029bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel        GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
291fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        SkAssertResult(fsBuilder->enableFeature(
292fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth                                     GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
293fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
2942dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt        GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
295abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
296abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit attributes
297abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        vsBuilder->emitAttributes(dfTexEffect);
298abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
299e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        GrGLVertToFrag v(kVec2f_GrSLType);
3009671ecd44e48e8bbe1361830717b79c9c4dc9d17jvanverth        args.fPB->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
301fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
3029b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        // setup pass through color
3039b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor,
3049b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                                    dfTexEffect.inColor(), &fColorUniform);
3052dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt
306e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
307e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed
308abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // Setup position
309dd2198701b0ec9da61ecf73418cad03642d715e7joshualitt        this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix());
310abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
311abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit transforms
31246d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
313e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                             args.fTransformsIn, args.fTransformsOut);
3144973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
315e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        const char* textureSizeUniName = NULL;
316e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
317e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed                                              kVec2f_GrSLType, kDefault_GrSLPrecision,
318e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed                                              "TextureSize", &textureSizeUniName);
319e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed
320fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        // Use highp to work around aliasing issues
321fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
322fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                                                             pb->ctxInfo().standard()));
323e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
324fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth
325fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend("float texColor = ");
326c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt        fsBuilder->appendTextureLookup(args.fSamplers[0],
327fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                                       "uv",
328fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth                                       kVec2f_GrSLType);
329fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend(".r;");
330fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        fsBuilder->codeAppend("float distance = "
331fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth            SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
332fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
333fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
334fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                                                             pb->ctxInfo().standard()));
335e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
336fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        fsBuilder->codeAppend("float afwidth;");
337fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
338354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For uniform scale, we adjust for the effect of the transformation on the distance
339354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // by using the length of the gradient of the texture coordinates. We use st coordinates
340354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // to ensure we're mapping 1:1 from texel space to pixel space.
341354eba5cb61801130a84378356434d3cc0a4b71ajvanverth
342fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            // this gives us a smooth step across approximately one fragment
343bc0273524b039c45dcea2c1ab5ab379c75486c07jvanverth            fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));");
344fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        } else {
345354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For general transforms, to determine the amount of correction we multiply a unit
346354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
347354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // (which is the inverse transform for this fragment) and take the length of the result.
348354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
349d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // the length of the gradient may be 0, so we need to check for this
350d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // this also compensates for the Adreno, which likes to drop tiles on division by 0
351d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
352d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
353d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
354d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("} else {");
355d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
356d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("}");
357d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth
358354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
359354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
360354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
361354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
362fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
363fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            // this gives us a smooth step across approximately one fragment
364fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
365fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        }
366fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
367fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
3682dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt        fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
369fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    }
370fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
371fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    virtual void setData(const GrGLProgramDataManager& pdman,
3729b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                         const GrPrimitiveProcessor& proc,
37336352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                         const GrBatchTracker& bt) override {
374e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed        SkASSERT(fTextureSizeUni.isValid());
375fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
37687f48d997ec29e5eeaa7567355775e93465dd60djoshualitt        GrTexture* texture = proc.texture(0);
377fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        if (texture->width() != fTextureSize.width() ||
378fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            texture->height() != fTextureSize.height()) {
379fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth            fTextureSize = SkISize::Make(texture->width(), texture->height());
380e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed            pdman.set2f(fTextureSizeUni,
381e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed                        SkIntToScalar(fTextureSize.width()),
382e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed                        SkIntToScalar(fTextureSize.height()));
383fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        }
3849b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
385e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>();
386e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        this->setUniformViewMatrix(pdman, dfpgp.viewMatrix());
387ee2af95db72152dfa61c841875df0594ca93437djoshualitt
388502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const DistanceFieldPathBatchTracker& local = bt.cast<DistanceFieldPathBatchTracker>();
3899b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
3909b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrGLfloat c[4];
3919b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrColorToRGBAFloat(local.fColor, c);
3929b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            pdman.set4fv(fColorUniform, 1, c);
3939b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            fColor = local.fColor;
3949b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        }
395fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    }
396fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
39746d36f0e7b709a077c647841eee23bd3efdc4117robertphillips    static inline void GenKey(const GrGeometryProcessor& gp,
3989b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                              const GrBatchTracker& bt,
399cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                              const GrGLSLCaps&,
400fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth                              GrProcessorKeyBuilder* b) {
401502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>();
402fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
403502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const DistanceFieldPathBatchTracker& local = bt.cast<DistanceFieldPathBatchTracker>();
4048fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        uint32_t key = dfTexEffect.getFlags();
4058fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        key |= local.fInputColorType << 16;
406e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
4078fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        b->add32(key);
408fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    }
409fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
410fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverthprivate:
4119b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    UniformHandle fColorUniform;
412e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed    UniformHandle fTextureSizeUni;
4139b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    GrColor       fColor;
4149b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    SkISize       fTextureSize;
415fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
416fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    typedef GrGLGeometryProcessor INHERITED;
417fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth};
418fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
419fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth///////////////////////////////////////////////////////////////////////////////
420fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
421502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
4222e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt        GrColor color,
4238059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt        const SkMatrix& viewMatrix,
4242e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt        GrTexture* texture,
4252e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt        const GrTextureParams& params,
4261ba8cc9193f13a812401e14b8037fdcf3f3acbacjoshualitt        uint32_t flags)
427e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    : fColor(color)
428e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    , fViewMatrix(viewMatrix)
4292e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt    , fTextureAccess(texture, params)
430fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
4312dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt    , fInColor(NULL) {
432fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
433502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    this->initClassID<GrDistanceFieldPathGeoProc>();
434c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
435c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco                                                   kHigh_GrSLPrecision));
4362dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt    if (flags & kColorAttr_DistanceFieldEffectFlag) {
43771c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt        fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
4382dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt    }
43971c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
440e4ef1ca5be11aed67c0ed0c7eb1862696fb063e3reed                                                          kVec2f_GrVertexAttribType));
441fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    this->addTextureAccess(&fTextureAccess);
442fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth}
443fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
444502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthvoid GrDistanceFieldPathGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
445cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                                   const GrGLSLCaps& caps,
446502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                   GrProcessorKeyBuilder* b) const {
447502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    GrGLDistanceFieldPathGeoProc::GenKey(*this, bt, caps, b);
448eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
449eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
450abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualittGrGLPrimitiveProcessor*
451cfc18867d982119d9dc2888bf09f1093012daaddjvanverthGrDistanceFieldPathGeoProc::createGLInstance(const GrBatchTracker& bt, const GrGLSLCaps&) const {
452502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    return SkNEW_ARGS(GrGLDistanceFieldPathGeoProc, (*this, bt));
453fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth}
454fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
455502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthvoid GrDistanceFieldPathGeoProc::initBatchTracker(GrBatchTracker* bt,
456502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                  const GrPipelineInfo& init) const {
457502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    DistanceFieldPathBatchTracker* local = bt->cast<DistanceFieldPathBatchTracker>();
4589b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
4599b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                                               SkToBool(fInColor));
460290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt    local->fUsesLocalCoords = init.fUsesLocalCoords;
4619b98932adaceb7ad0a617ade16616923f6bffe84joshualitt}
4629b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
463fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth///////////////////////////////////////////////////////////////////////////////
464fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
465502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc);
466fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
467502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(SkRandom* random,
468502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                            GrContext*,
469502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                            const GrDrawTargetCaps&,
470502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                            GrTexture* textures[]) {
471fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
472fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth                                    : GrProcessorUnitTest::kAlphaTextureIdx;
473fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    static const SkShader::TileMode kTileModes[] = {
474fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        SkShader::kClamp_TileMode,
475fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        SkShader::kRepeat_TileMode,
476fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        SkShader::kMirror_TileMode,
477fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    };
478fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    SkShader::TileMode tileModes[] = {
479fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
480fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
481fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    };
482fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth    GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode
483fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth                                                         : GrTextureParams::kNone_FilterMode);
484fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
485502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    return GrDistanceFieldPathGeoProc::Create(GrRandomColor(random),
4864eaf9cef5a76098f78efac30beb966ac833d32c2joshualitt                                              GrTest::TestMatrix(random),
487502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                              textures[texIdx],
488502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                              params,
4891ba8cc9193f13a812401e14b8037fdcf3f3acbacjoshualitt        random->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0);
490fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth}
491fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
492fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth///////////////////////////////////////////////////////////////////////////////
493fa38a30897ceda3e93355d69b8a6812c823f41f6jvanverth
4949b98932adaceb7ad0a617ade16616923f6bffe84joshualittstruct DistanceFieldLCDBatchTracker {
4959b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    GrGPInput fInputColorType;
4969b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    GrColor fColor;
497290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt    bool fUsesLocalCoords;
4989b98932adaceb7ad0a617ade16616923f6bffe84joshualitt};
4999b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
500502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthclass GrGLDistanceFieldLCDTextGeoProc : public GrGLGeometryProcessor {
501609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.orgpublic:
502502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    GrGLDistanceFieldLCDTextGeoProc(const GrGeometryProcessor&, const GrBatchTracker&)
50321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        : fColor(GrColor_ILLEGAL) {
504502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f);
50521deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    }
506609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
50736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
508502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldLCDTextGeoProc& dfTexEffect =
509502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                args.fGP.cast<GrDistanceFieldLCDTextGeoProc>();
5109b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        const DistanceFieldLCDBatchTracker& local = args.fBT.cast<DistanceFieldLCDBatchTracker>();
5119b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        GrGLGPBuilder* pb = args.fPB;
512609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
5132dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt        GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
514abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
515abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit attributes
516abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        vsBuilder->emitAttributes(dfTexEffect);
517abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt
5189b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        // setup pass through color
5199b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
5209b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                                    &fColorUniform);
5219b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
522abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // Setup position
523dd2198701b0ec9da61ecf73418cad03642d715e7joshualitt        this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix());
5244973d9da4aeb7c4d8b8e67e167586c7cc9534eeejoshualitt
525abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualitt        // emit transforms
52646d36f0e7b709a077c647841eee23bd3efdc4117robertphillips        this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
527e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt                             args.fTransformsIn, args.fTransformsOut);
5285b143038cb47763974d2750ed78d436eb6c38beajvanverth
529bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        // set up varyings
530bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
531bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        GrGLVertToFrag recipScale(kFloat_GrSLType);
532bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        GrGLVertToFrag st(kVec2f_GrSLType);
533221360a514fb4bfff5b461e83262306b2a0f36afjvanverth        args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
534221360a514fb4bfff5b461e83262306b2a0f36afjvanverth        vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
535bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
536bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        GrGLVertToFrag uv(kVec2f_GrSLType);
537bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
538bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        // this is only used with text, so our texture bounds always match the glyph atlas
539bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", "
540bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth                               GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(),
541bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth                               dfTexEffect.inTextureCoords()->fName);
542bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
543bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth        // add frag shader code
54429bee0fe657fabf7c396502b69c9167fba13eaaaegdaniel        GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
54530ba436f04e61d4505fb854d5fc56079636e0788joshualitt
54630ba436f04e61d4505fb854d5fc56079636e0788joshualitt        SkAssertResult(fsBuilder->enableFeature(
54730ba436f04e61d4505fb854d5fc56079636e0788joshualitt                GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
54830ba436f04e61d4505fb854d5fc56079636e0788joshualitt
549609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // create LCD offset adjusted by inverse of transform
550fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        // Use highp to work around aliasing issues
551fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
552fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                                                             pb->ctxInfo().standard()));
5535a105ff05303ac82a867b8b84a1edd145bd46218jvanverth        fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
554fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth        fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
555fdf7ccc2012dd06305cc3a0fbc788a483fce7b6ajvanverth                                                             pb->ctxInfo().standard()));
5565a105ff05303ac82a867b8b84a1edd145bd46218jvanverth        if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
5575a105ff05303ac82a867b8b84a1edd145bd46218jvanverth            fsBuilder->codeAppend("float delta = -" GR_FONT_ATLAS_LCD_DELTA ";\n");
5585a105ff05303ac82a867b8b84a1edd145bd46218jvanverth        } else {
5595a105ff05303ac82a867b8b84a1edd145bd46218jvanverth            fsBuilder->codeAppend("float delta = " GR_FONT_ATLAS_LCD_DELTA ";\n");
5605a105ff05303ac82a867b8b84a1edd145bd46218jvanverth        }
56178f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth        if (isUniformScale) {
562bc0273524b039c45dcea2c1ab5ab379c75486c07jvanverth            fsBuilder->codeAppendf("float dy = abs(dFdy(%s.y));", st.fsIn());
563221360a514fb4bfff5b461e83262306b2a0f36afjvanverth            fsBuilder->codeAppend("vec2 offset = vec2(dy*delta, 0.0);");
564609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        } else {
565bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth            fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn());
566bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth
567bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth            fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
568bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth            fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
569bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1jvanverth            fsBuilder->codeAppend("vec2 offset = delta*Jdx;");
570609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        }
571609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
572609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // green is distance to uv center
57330ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tvec4 texColor = ");
574c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt        fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
57530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend(";\n");
57630ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tvec3 distance;\n");
57730ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
578609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // red is distance to left offset
57930ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
58030ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\ttexColor = ");
581c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt        fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
58230ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend(";\n");
58330ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
584609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // blue is distance to right offset
58530ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
58630ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\ttexColor = ");
587c369e7c9992a86151a3ea0516ce5308c211b196bjoshualitt        fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
58830ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend(";\n");
58930ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
5902d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth
59130ba436f04e61d4505fb854d5fc56079636e0788joshualitt        fsBuilder->codeAppend("\tdistance = "
592ada68ef2dc986478288a8b8ad867fd3aca431162jvanverth           "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
5932d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth
59421deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        // adjust width based on gamma
59521deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        const char* distanceAdjustUniName = NULL;
59621deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
59721deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            kVec3f_GrSLType, kDefault_GrSLPrecision,
59821deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            "DistanceAdjust", &distanceAdjustUniName);
59921deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
60021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth
601609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // To be strictly correct, we should compute the anti-aliasing factor separately
602609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // for each color component. However, this is only important when using perspective
603609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // transformations, and even then using a single factor seems like a reasonable
604609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        // trade-off between quality and speed.
605354eba5cb61801130a84378356434d3cc0a4b71ajvanverth        fsBuilder->codeAppend("float afwidth;");
60678f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth        if (isUniformScale) {
607354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For uniform scale, we adjust for the effect of the transformation on the distance
608354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // by using the length of the gradient of the texture coordinates. We use st coordinates
609354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // to ensure we're mapping 1:1 from texel space to pixel space.
610354eba5cb61801130a84378356434d3cc0a4b71ajvanverth
611609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org            // this gives us a smooth step across approximately one fragment
612bc0273524b039c45dcea2c1ab5ab379c75486c07jvanverth            fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*dy;");
613609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        } else {
614354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // For general transforms, to determine the amount of correction we multiply a unit
615354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // vector pointing along the SDF gradient direction by the Jacobian of the st coords
616354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            // (which is the inverse transform for this fragment) and take the length of the result.
617354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));");
618d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // the length of the gradient may be 0, so we need to check for this
619d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            // this also compensates for the Adreno, which likes to drop tiles on division by 0
620d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
621d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
622d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
623d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("} else {");
624d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
625d68a550ec890c3e3135ffa119621e17e55d58dd6jvanverth            fsBuilder->codeAppend("}");
626354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
627354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("                 dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
628609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
629609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org            // this gives us a smooth step across approximately one fragment
630354eba5cb61801130a84378356434d3cc0a4b71ajvanverth            fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
631609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        }
632609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
63321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        fsBuilder->codeAppend(
63421deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                      "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
63530ba436f04e61d4505fb854d5fc56079636e0788joshualitt
6362dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt        fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
637609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    }
638609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
6397510b224e52b9518a8ddf7418db0e9c258f79539kkinnunen    virtual void setData(const GrGLProgramDataManager& pdman,
6409b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                         const GrPrimitiveProcessor& processor,
64136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein                         const GrBatchTracker& bt) override {
64221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        SkASSERT(fDistanceAdjustUni.isValid());
643609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
644502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldLCDTextGeoProc& dfTexEffect =
645502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                processor.cast<GrDistanceFieldLCDTextGeoProc>();
646502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dfTexEffect.getDistanceAdjust();
64721deace8efc8e167d8626187ef0e6b4c241324b6jvanverth        if (wa != fDistanceAdjust) {
64821deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            pdman.set3f(fDistanceAdjustUni,
64921deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                        wa.fR,
65021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                        wa.fG,
65121deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                        wa.fB);
65221deace8efc8e167d8626187ef0e6b4c241324b6jvanverth            fDistanceAdjust = wa;
6532d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth        }
6549b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
655e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        this->setUniformViewMatrix(pdman, dfTexEffect.viewMatrix());
656ee2af95db72152dfa61c841875df0594ca93437djoshualitt
6579b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
6589b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
6599b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrGLfloat c[4];
6609b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            GrColorToRGBAFloat(local.fColor, c);
6619b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            pdman.set4fv(fColorUniform, 1, c);
6629b98932adaceb7ad0a617ade16616923f6bffe84joshualitt            fColor = local.fColor;
6639b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        }
664609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    }
665609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
66646d36f0e7b709a077c647841eee23bd3efdc4117robertphillips    static inline void GenKey(const GrGeometryProcessor& gp,
6679b98932adaceb7ad0a617ade16616923f6bffe84joshualitt                              const GrBatchTracker& bt,
668cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                              const GrGLSLCaps&,
669b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                              GrProcessorKeyBuilder* b) {
670502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth        const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>();
671609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
6729b98932adaceb7ad0a617ade16616923f6bffe84joshualitt        const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
6738fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        uint32_t key = dfTexEffect.getFlags();
6748fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        key |= local.fInputColorType << 16;
675e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt        key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
6768fc6c2d82c1f30ff82274334c01f0799def6a609joshualitt        b->add32(key);
677609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    }
678609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
679609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.orgprivate:
68021deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    GrColor                                      fColor;
68121deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    UniformHandle                                fColorUniform;
682502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust;
68321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    UniformHandle                                fDistanceAdjustUni;
684609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
685249af15fb82833d2274850c589812b6e69df0033joshualitt    typedef GrGLGeometryProcessor INHERITED;
686609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org};
687609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
688609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
689609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
690502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(
6918059eb9f6e24ed609393fbda4ad71edea03ac258joshualitt                                                  GrColor color, const SkMatrix& viewMatrix,
6922d2a68c51b4a71bd60760510bf2b2e58bc9890b2jvanverth                                                  GrTexture* texture, const GrTextureParams& params,
69321deace8efc8e167d8626187ef0e6b4c241324b6jvanverth                                                  DistanceAdjust distanceAdjust,
69478f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth                                                  uint32_t flags)
695e3ababe44315452cd33b96a18ce316ede09ff3c3joshualitt    : fColor(color)
696e578a95d3ab16544794b94da4e7ae13fc2ce6244joshualitt    , fViewMatrix(viewMatrix)
6972e3b3e369d79e78f7635d4c20e83a47ab571bdf2joshualitt    , fTextureAccess(texture, params)
69821deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    , fDistanceAdjust(distanceAdjust)
6992dd1ae016d7f297b433c3ea3a771ef8e01657c1fjoshualitt    , fFlags(flags & kLCD_DistanceFieldEffectMask){
70078f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth    SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
701502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    this->initClassID<GrDistanceFieldLCDTextGeoProc>();
702c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco    fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
703c375b0b5c5c03d381111bf7bff12507d5ed24769senorblanco                                                   kHigh_GrSLPrecision));
70471c9260e6fa1798ad1e41b2c2ae9b3cce08bb610joshualitt    fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
7055a105ff05303ac82a867b8b84a1edd145bd46218jvanverth                                                          kVec2s_GrVertexAttribType));
706609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    this->addTextureAccess(&fTextureAccess);
707609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org}
708609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
709502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthvoid GrDistanceFieldLCDTextGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
710cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                                      const GrGLSLCaps& caps,
711502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                      GrProcessorKeyBuilder* b) const {
712502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, bt, caps, b);
713eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt}
714eb2a6761654307e8aeeeaabdd63c6bf9ab0411e9joshualitt
715abb52a1a70a81915c6196e0fb3e9bcb05e8be14djoshualittGrGLPrimitiveProcessor*
716502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrDistanceFieldLCDTextGeoProc::createGLInstance(const GrBatchTracker& bt,
717cfc18867d982119d9dc2888bf09f1093012daaddjvanverth                                                const GrGLSLCaps&) const {
718502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    return SkNEW_ARGS(GrGLDistanceFieldLCDTextGeoProc, (*this, bt));
719609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org}
720609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
721502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthvoid GrDistanceFieldLCDTextGeoProc::initBatchTracker(GrBatchTracker* bt,
722502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                     const GrPipelineInfo& init) const {
7239b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    DistanceFieldLCDBatchTracker* local = bt->cast<DistanceFieldLCDBatchTracker>();
7249b98932adaceb7ad0a617ade16616923f6bffe84joshualitt    local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
725290c09b8bbd8d221d363150e2ce87158f4668df0joshualitt    local->fUsesLocalCoords = init.fUsesLocalCoords;
7269b98932adaceb7ad0a617ade16616923f6bffe84joshualitt}
7279b98932adaceb7ad0a617ade16616923f6bffe84joshualitt
728609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org///////////////////////////////////////////////////////////////////////////////
729609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
730502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc);
731609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org
732502286d7b8ecf26a3a33e8098335034e21e4b082jvanverthGrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(SkRandom* random,
733b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                                 GrContext*,
734b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                                 const GrDrawTargetCaps&,
735b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                                                 GrTexture* textures[]) {
736b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt    int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
737b0a8a377f832c59cee939ad721e1f87d378b7142joshualitt                                      GrProcessorUnitTest::kAlphaTextureIdx;
738609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    static const SkShader::TileMode kTileModes[] = {
739609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        SkShader::kClamp_TileMode,
740609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        SkShader::kRepeat_TileMode,
741609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        SkShader::kMirror_TileMode,
742609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    };
743609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    SkShader::TileMode tileModes[] = {
744609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
745609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org        kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
746609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    };
747609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org    GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
748609ced42e7cebef533cf9c1622280f5cdda1faaecommit-bot@chromium.org                           GrTextureParams::kNone_FilterMode);
74921deace8efc8e167d8626187ef0e6b4c241324b6jvanverth    DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
75078f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth    uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
75178f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth    flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
75278f0718f4dac8bdcc0df43a3280cf8a89d8cf87ajvanverth    flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
753502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth    return GrDistanceFieldLCDTextGeoProc::Create(GrRandomColor(random),
7544eaf9cef5a76098f78efac30beb966ac833d32c2joshualitt                                                 GrTest::TestMatrix(random),
755502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                 textures[texIdx], params,
756502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                 wa,
757502286d7b8ecf26a3a33e8098335034e21e4b082jvanverth                                                 flags);
758d830d13c27437b4677a4a1abfa866d98dc2d2ab9jvanverth@google.com}
759