blob: 393a99db570be2aa43e743b6447af93466f3e6d1 [file] [log] [blame]
jvanverth@google.comd830d132013-11-11 20:54:09 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
jvanverth8ed3b9a2015-04-09 08:00:49 -07008#include "GrDistanceFieldGeoProc.h"
jvanverth5a105ff2015-02-18 11:36:35 -08009#include "GrFontAtlasSizes.h"
egdaniel605dd0f2014-11-12 08:35:25 -080010#include "GrInvariantOutput.h"
joshualitteb2a6762014-12-04 11:35:33 -080011#include "GrTexture.h"
jvanverth21deace2015-04-01 12:43:48 -070012
joshualitteb2a6762014-12-04 11:35:33 -080013#include "SkDistanceFieldGen.h"
jvanverth21deace2015-04-01 12:43:48 -070014
joshualittb0a8a372014-09-23 09:50:21 -070015#include "gl/GrGLProcessor.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000016#include "gl/GrGLTexture.h"
joshualitt249af152014-09-15 11:41:13 -070017#include "gl/GrGLGeometryProcessor.h"
joshualitteb2a6762014-12-04 11:35:33 -080018#include "gl/builders/GrGLProgramBuilder.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000019
jvanverth21deace2015-04-01 12:43:48 -070020// Assuming a radius of a little less than the diagonal of the fragment
jvanverth24ba0082015-03-19 11:34:13 -070021#define SK_DistanceFieldAAFactor "0.65"
jvanverth2d2a68c2014-06-10 06:42:56 -070022
jvanverth502286d2015-04-08 12:37:51 -070023class GrGLDistanceFieldA8TextGeoProc : public GrGLGeometryProcessor {
jvanverth@google.comd830d132013-11-11 20:54:09 +000024public:
jvanverth502286d2015-04-08 12:37:51 -070025 GrGLDistanceFieldA8TextGeoProc(const GrGeometryProcessor&,
joshualitt87f48d92014-12-04 10:41:40 -080026 const GrBatchTracker&)
joshualitt5559ca22015-05-21 15:50:36 -070027 : fViewMatrix(SkMatrix::InvalidMatrix())
28 , fColor(GrColor_ILLEGAL)
jvanverth9564ce62014-09-16 05:45:19 -070029#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -070030 , fDistanceAdjust(-1.0f)
jvanverth9564ce62014-09-16 05:45:19 -070031#endif
32 {}
jvanverth@google.comd830d132013-11-11 20:54:09 +000033
mtklein36352bf2015-03-25 18:17:31 -070034 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
jvanverth502286d2015-04-08 12:37:51 -070035 const GrDistanceFieldA8TextGeoProc& dfTexEffect =
36 args.fGP.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt9b989322014-12-15 14:16:27 -080037 GrGLGPBuilder* pb = args.fPB;
egdaniel29bee0f2015-04-29 11:54:42 -070038 GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -070039 SkAssertResult(fsBuilder->enableFeature(
40 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
jvanverth@google.comd830d132013-11-11 20:54:09 +000041
joshualitt2dd1ae02014-12-03 06:24:10 -080042 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualittabb52a12015-01-13 15:02:10 -080043
44 // emit attributes
45 vsBuilder->emitAttributes(dfTexEffect);
46
jvanverth21deace2015-04-01 12:43:48 -070047#ifdef SK_GAMMA_APPLY_TO_A8
48 // adjust based on gamma
49 const char* distanceAdjustUniName = NULL;
50 // width, height, 1/(3*width)
51 fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
52 kFloat_GrSLType, kDefault_GrSLPrecision,
53 "DistanceAdjust", &distanceAdjustUniName);
54#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000055
joshualitt9b989322014-12-15 14:16:27 -080056 // Setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -070057 if (!dfTexEffect.colorIgnored()) {
58 if (dfTexEffect.hasVertexColor()) {
59 pb->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
60 } else {
61 this->setupUniformColor(pb, args.fOutputColor, &fColorUniform);
62 }
63 }
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000064
joshualittabb52a12015-01-13 15:02:10 -080065 // Setup position
joshualitt5559ca22015-05-21 15:50:36 -070066 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(),
67 &fViewMatrixUniform);
joshualitt2dd1ae02014-12-03 06:24:10 -080068
joshualittabb52a12015-01-13 15:02:10 -080069 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -080070 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
joshualitte3ababe2015-05-15 07:56:07 -070071 args.fTransformsIn, args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -080072
jvanverthbb4a1cf2015-04-07 09:06:00 -070073 // add varyings
74 GrGLVertToFrag recipScale(kFloat_GrSLType);
75 GrGLVertToFrag st(kVec2f_GrSLType);
76 bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
jvanverth221360a2015-04-15 12:31:22 -070077 args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
78 vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
jvanverthbb4a1cf2015-04-07 09:06:00 -070079
80 GrGLVertToFrag uv(kVec2f_GrSLType);
81 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
82 // this is only used with text, so our texture bounds always match the glyph atlas
83 vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", "
84 GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(),
85 dfTexEffect.inTextureCoords()->fName);
86
jvanverthfdf7ccc2015-01-27 08:19:33 -080087 // Use highp to work around aliasing issues
88 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
89 pb->ctxInfo().standard()));
jvanverth5a105ff2015-02-18 11:36:35 -080090 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -080091
92 fsBuilder->codeAppend("\tfloat texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -070093 fsBuilder->appendTextureLookup(args.fSamplers[0],
jvanverthfdf7ccc2015-01-27 08:19:33 -080094 "uv",
jvanverth@google.comd830d132013-11-11 20:54:09 +000095 kVec2f_GrSLType);
jvanverthfdf7ccc2015-01-27 08:19:33 -080096 fsBuilder->codeAppend(".r;\n");
joshualitt30ba4362014-08-21 20:18:45 -070097 fsBuilder->codeAppend("\tfloat distance = "
jvanverthfdf7ccc2015-01-27 08:19:33 -080098 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
jvanverth21deace2015-04-01 12:43:48 -070099#ifdef SK_GAMMA_APPLY_TO_A8
100 // adjust width based on gamma
101 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
102#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000103
jvanverth354eba52015-03-16 11:32:49 -0700104 fsBuilder->codeAppend("float afwidth;");
jvanverthbb4a1cf2015-04-07 09:06:00 -0700105 if (isSimilarity) {
jvanverth354eba52015-03-16 11:32:49 -0700106 // For uniform scale, we adjust for the effect of the transformation on the distance
107 // by using the length of the gradient of the texture coordinates. We use st coordinates
jvanverth221360a2015-04-15 12:31:22 -0700108 // to ensure we're mapping 1:1 from texel space to pixel space.
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000109
jvanverth354eba52015-03-16 11:32:49 -0700110 // this gives us a smooth step across approximately one fragment
jvanverth221360a2015-04-15 12:31:22 -0700111 // we use y to work around a Mali400 bug in the x direction
112 fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));",
jvanverthbb4a1cf2015-04-07 09:06:00 -0700113 st.fsIn());
jvanverth354eba52015-03-16 11:32:49 -0700114 } else {
115 // For general transforms, to determine the amount of correction we multiply a unit
116 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
117 // (which is the inverse transform for this fragment) and take the length of the result.
118 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
jvanverthd68a5502015-03-16 12:58:43 -0700119 // the length of the gradient may be 0, so we need to check for this
120 // this also compensates for the Adreno, which likes to drop tiles on division by 0
121 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
122 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
123 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
124 fsBuilder->codeAppend("} else {");
125 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
126 fsBuilder->codeAppend("}");
127
jvanverthbb4a1cf2015-04-07 09:06:00 -0700128 fsBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn());
129 fsBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn());
jvanverth354eba52015-03-16 11:32:49 -0700130 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
131 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000132
133 // this gives us a smooth step across approximately one fragment
jvanverth354eba52015-03-16 11:32:49 -0700134 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000135 }
jvanverth354eba52015-03-16 11:32:49 -0700136 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
jvanverth@google.comd830d132013-11-11 20:54:09 +0000137
joshualitt2dd1ae02014-12-03 06:24:10 -0800138 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000139 }
140
kkinnunen7510b222014-07-30 00:04:16 -0700141 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800142 const GrPrimitiveProcessor& proc,
mtklein36352bf2015-03-25 18:17:31 -0700143 const GrBatchTracker& bt) override {
jvanverth2d2a68c2014-06-10 06:42:56 -0700144#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth502286d2015-04-08 12:37:51 -0700145 const GrDistanceFieldA8TextGeoProc& dfTexEffect = proc.cast<GrDistanceFieldA8TextGeoProc>();
jvanverth21deace2015-04-01 12:43:48 -0700146 float distanceAdjust = dfTexEffect.getDistanceAdjust();
147 if (distanceAdjust != fDistanceAdjust) {
148 pdman.set1f(fDistanceAdjustUni, distanceAdjust);
149 fDistanceAdjust = distanceAdjust;
jvanverth2d2a68c2014-06-10 06:42:56 -0700150 }
151#endif
joshualitte578a952015-05-14 10:09:13 -0700152 const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt5559ca22015-05-21 15:50:36 -0700153
154 if (!dfa8gp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfa8gp.viewMatrix())) {
155 fViewMatrix = dfa8gp.viewMatrix();
156 GrGLfloat viewMatrix[3 * 3];
157 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
158 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
159 }
joshualittee2af952014-12-30 09:04:15 -0800160
joshualittb8c241a2015-05-19 08:23:30 -0700161 if (dfa8gp.color() != fColor && !dfa8gp.hasVertexColor()) {
joshualitt9b989322014-12-15 14:16:27 -0800162 GrGLfloat c[4];
joshualittb8c241a2015-05-19 08:23:30 -0700163 GrColorToRGBAFloat(dfa8gp.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800164 pdman.set4fv(fColorUniform, 1, c);
joshualittb8c241a2015-05-19 08:23:30 -0700165 fColor = dfa8gp.color();
joshualitt9b989322014-12-15 14:16:27 -0800166 }
commit-bot@chromium.org8fe2ee12014-03-26 18:03:05 +0000167 }
168
robertphillips46d36f02015-01-18 08:14:14 -0800169 static inline void GenKey(const GrGeometryProcessor& gp,
joshualitt9b989322014-12-15 14:16:27 -0800170 const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700171 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700172 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700173 const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800174 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700175 key |= dfTexEffect.hasVertexColor() << 16;
176 key |= dfTexEffect.colorIgnored() << 17;
joshualitte578a952015-05-14 10:09:13 -0700177 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800178 b->add32(key);
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000179 }
180
jvanverth@google.comd830d132013-11-11 20:54:09 +0000181private:
joshualitt5559ca22015-05-21 15:50:36 -0700182 SkMatrix fViewMatrix;
joshualitt9b989322014-12-15 14:16:27 -0800183 GrColor fColor;
184 UniformHandle fColorUniform;
joshualitt5559ca22015-05-21 15:50:36 -0700185 UniformHandle fViewMatrixUniform;
mtklein50282b42015-01-22 07:59:52 -0800186#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700187 float fDistanceAdjust;
188 UniformHandle fDistanceAdjustUni;
mtklein50282b42015-01-22 07:59:52 -0800189#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000190
joshualitt249af152014-09-15 11:41:13 -0700191 typedef GrGLGeometryProcessor INHERITED;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000192};
193
194///////////////////////////////////////////////////////////////////////////////
195
jvanverth502286d2015-04-08 12:37:51 -0700196GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800197 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800198 GrTexture* texture,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000199 const GrTextureParams& params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700200#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700201 float distanceAdjust,
jvanverth2d2a68c2014-06-10 06:42:56 -0700202#endif
joshualittb8c241a2015-05-19 08:23:30 -0700203 uint32_t flags,
204 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700205 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700206 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800207 , fTextureAccess(texture, params)
jvanverth2d2a68c2014-06-10 06:42:56 -0700208#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700209 , fDistanceAdjust(distanceAdjust)
jvanverth2d2a68c2014-06-10 06:42:56 -0700210#endif
joshualitt249af152014-09-15 11:41:13 -0700211 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
joshualittb8c241a2015-05-19 08:23:30 -0700212 , fInColor(NULL)
213 , fUsesLocalCoords(usesLocalCoords) {
jvanverth78f07182014-07-30 06:17:59 -0700214 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth502286d2015-04-08 12:37:51 -0700215 this->initClassID<GrDistanceFieldA8TextGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700216 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
217 kHigh_GrSLPrecision));
joshualitt2dd1ae02014-12-03 06:24:10 -0800218 if (flags & kColorAttr_DistanceFieldEffectFlag) {
joshualitt71c92602015-01-14 08:12:47 -0800219 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt2dd1ae02014-12-03 06:24:10 -0800220 }
joshualitt71c92602015-01-14 08:12:47 -0800221 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
jvanverth5a105ff2015-02-18 11:36:35 -0800222 kVec2s_GrVertexAttribType));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000223 this->addTextureAccess(&fTextureAccess);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000224}
225
jvanverth502286d2015-04-08 12:37:51 -0700226void GrDistanceFieldA8TextGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700227 const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800228 GrProcessorKeyBuilder* b) const {
jvanverth502286d2015-04-08 12:37:51 -0700229 GrGLDistanceFieldA8TextGeoProc::GenKey(*this, bt, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800230}
231
joshualittabb52a12015-01-13 15:02:10 -0800232GrGLPrimitiveProcessor*
jvanverth502286d2015-04-08 12:37:51 -0700233GrDistanceFieldA8TextGeoProc::createGLInstance(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700234 const GrGLSLCaps&) const {
jvanverth502286d2015-04-08 12:37:51 -0700235 return SkNEW_ARGS(GrGLDistanceFieldA8TextGeoProc, (*this, bt));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000236}
237
238///////////////////////////////////////////////////////////////////////////////
239
jvanverth502286d2015-04-08 12:37:51 -0700240GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000241
joshualitt0067ff52015-07-08 14:26:19 -0700242GrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) {
243 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
244 GrProcessorUnitTest::kAlphaTextureIdx;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000245 static const SkShader::TileMode kTileModes[] = {
246 SkShader::kClamp_TileMode,
247 SkShader::kRepeat_TileMode,
248 SkShader::kMirror_TileMode,
249 };
250 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700251 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
252 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
jvanverth@google.comd830d132013-11-11 20:54:09 +0000253 };
joshualitt0067ff52015-07-08 14:26:19 -0700254 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
jvanverth@google.comd830d132013-11-11 20:54:09 +0000255 GrTextureParams::kNone_FilterMode);
256
joshualitt0067ff52015-07-08 14:26:19 -0700257 return GrDistanceFieldA8TextGeoProc::Create(GrRandomColor(d->fRandom),
258 GrTest::TestMatrix(d->fRandom),
259 d->fTextures[texIdx], params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700260#ifdef SK_GAMMA_APPLY_TO_A8
joshualitt0067ff52015-07-08 14:26:19 -0700261 d->fRandom->nextF(),
jvanverth2d2a68c2014-06-10 06:42:56 -0700262#endif
joshualitt0067ff52015-07-08 14:26:19 -0700263 d->fRandom->nextBool() ?
joshualittb8c241a2015-05-19 08:23:30 -0700264 kSimilarity_DistanceFieldEffectFlag : 0,
joshualitt0067ff52015-07-08 14:26:19 -0700265 d->fRandom->nextBool());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000266}
267
268///////////////////////////////////////////////////////////////////////////////
269
jvanverth502286d2015-04-08 12:37:51 -0700270class GrGLDistanceFieldPathGeoProc : public GrGLGeometryProcessor {
jvanverthfa38a302014-10-06 05:59:05 -0700271public:
jvanverth502286d2015-04-08 12:37:51 -0700272 GrGLDistanceFieldPathGeoProc(const GrGeometryProcessor&,
joshualitt87f48d92014-12-04 10:41:40 -0800273 const GrBatchTracker&)
joshualitt5559ca22015-05-21 15:50:36 -0700274 : fViewMatrix(SkMatrix::InvalidMatrix())
275 , fColor(GrColor_ILLEGAL)
276 , fTextureSize(SkISize::Make(-1, -1)) {}
jvanverthfa38a302014-10-06 05:59:05 -0700277
mtklein36352bf2015-03-25 18:17:31 -0700278 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
jvanverth502286d2015-04-08 12:37:51 -0700279 const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldPathGeoProc>();
jvanverthfa38a302014-10-06 05:59:05 -0700280
joshualitt9b989322014-12-15 14:16:27 -0800281 GrGLGPBuilder* pb = args.fPB;
egdaniel29bee0f2015-04-29 11:54:42 -0700282 GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
jvanverthfa38a302014-10-06 05:59:05 -0700283 SkAssertResult(fsBuilder->enableFeature(
284 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
285
joshualitt2dd1ae02014-12-03 06:24:10 -0800286 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualittabb52a12015-01-13 15:02:10 -0800287
288 // emit attributes
289 vsBuilder->emitAttributes(dfTexEffect);
290
reede4ef1ca2015-02-17 18:38:38 -0800291 GrGLVertToFrag v(kVec2f_GrSLType);
jvanverth9671ecd2015-02-23 13:08:39 -0800292 args.fPB->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
jvanverthfa38a302014-10-06 05:59:05 -0700293
joshualitt9b989322014-12-15 14:16:27 -0800294 // setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -0700295 if (!dfTexEffect.colorIgnored()) {
296 if (dfTexEffect.hasVertexColor()) {
297 pb->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
298 } else {
299 this->setupUniformColor(pb, args.fOutputColor, &fColorUniform);
300 }
301 }
reede4ef1ca2015-02-17 18:38:38 -0800302 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
303
joshualittabb52a12015-01-13 15:02:10 -0800304 // Setup position
joshualitt5559ca22015-05-21 15:50:36 -0700305 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(),
306 &fViewMatrixUniform);
joshualittabb52a12015-01-13 15:02:10 -0800307
308 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -0800309 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
joshualitte3ababe2015-05-15 07:56:07 -0700310 args.fTransformsIn, args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800311
reede4ef1ca2015-02-17 18:38:38 -0800312 const char* textureSizeUniName = NULL;
313 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
314 kVec2f_GrSLType, kDefault_GrSLPrecision,
315 "TextureSize", &textureSizeUniName);
316
jvanverthfdf7ccc2015-01-27 08:19:33 -0800317 // Use highp to work around aliasing issues
318 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
319 pb->ctxInfo().standard()));
reede4ef1ca2015-02-17 18:38:38 -0800320 fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -0800321
322 fsBuilder->codeAppend("float texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700323 fsBuilder->appendTextureLookup(args.fSamplers[0],
jvanverthfdf7ccc2015-01-27 08:19:33 -0800324 "uv",
jvanverthfa38a302014-10-06 05:59:05 -0700325 kVec2f_GrSLType);
jvanverthfdf7ccc2015-01-27 08:19:33 -0800326 fsBuilder->codeAppend(".r;");
jvanverthfa38a302014-10-06 05:59:05 -0700327 fsBuilder->codeAppend("float distance = "
jvanverthfdf7ccc2015-01-27 08:19:33 -0800328 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
jvanverthfa38a302014-10-06 05:59:05 -0700329
jvanverthfdf7ccc2015-01-27 08:19:33 -0800330 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
331 pb->ctxInfo().standard()));
reede4ef1ca2015-02-17 18:38:38 -0800332 fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
jvanverthfa38a302014-10-06 05:59:05 -0700333 fsBuilder->codeAppend("float afwidth;");
334 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
jvanverth354eba52015-03-16 11:32:49 -0700335 // For uniform scale, we adjust for the effect of the transformation on the distance
336 // by using the length of the gradient of the texture coordinates. We use st coordinates
337 // to ensure we're mapping 1:1 from texel space to pixel space.
338
jvanverthfa38a302014-10-06 05:59:05 -0700339 // this gives us a smooth step across approximately one fragment
jvanverthbc027352015-04-15 13:41:31 -0700340 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));");
jvanverthfa38a302014-10-06 05:59:05 -0700341 } else {
jvanverth354eba52015-03-16 11:32:49 -0700342 // For general transforms, to determine the amount of correction we multiply a unit
343 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
344 // (which is the inverse transform for this fragment) and take the length of the result.
345 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
jvanverthd68a5502015-03-16 12:58:43 -0700346 // the length of the gradient may be 0, so we need to check for this
347 // this also compensates for the Adreno, which likes to drop tiles on division by 0
348 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
349 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
350 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
351 fsBuilder->codeAppend("} else {");
352 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
353 fsBuilder->codeAppend("}");
354
jvanverth354eba52015-03-16 11:32:49 -0700355 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
356 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
357 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
358 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
jvanverthfa38a302014-10-06 05:59:05 -0700359
360 // this gives us a smooth step across approximately one fragment
361 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
362 }
363 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
364
joshualitt2dd1ae02014-12-03 06:24:10 -0800365 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverthfa38a302014-10-06 05:59:05 -0700366 }
367
368 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800369 const GrPrimitiveProcessor& proc,
mtklein36352bf2015-03-25 18:17:31 -0700370 const GrBatchTracker& bt) override {
reede4ef1ca2015-02-17 18:38:38 -0800371 SkASSERT(fTextureSizeUni.isValid());
jvanverthfa38a302014-10-06 05:59:05 -0700372
joshualitt87f48d92014-12-04 10:41:40 -0800373 GrTexture* texture = proc.texture(0);
jvanverthfa38a302014-10-06 05:59:05 -0700374 if (texture->width() != fTextureSize.width() ||
375 texture->height() != fTextureSize.height()) {
376 fTextureSize = SkISize::Make(texture->width(), texture->height());
reede4ef1ca2015-02-17 18:38:38 -0800377 pdman.set2f(fTextureSizeUni,
378 SkIntToScalar(fTextureSize.width()),
379 SkIntToScalar(fTextureSize.height()));
jvanverthfa38a302014-10-06 05:59:05 -0700380 }
joshualitt9b989322014-12-15 14:16:27 -0800381
joshualitte578a952015-05-14 10:09:13 -0700382 const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>();
joshualitt5559ca22015-05-21 15:50:36 -0700383
384 if (!dfpgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfpgp.viewMatrix())) {
385 fViewMatrix = dfpgp.viewMatrix();
386 GrGLfloat viewMatrix[3 * 3];
387 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
388 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
389 }
joshualittee2af952014-12-30 09:04:15 -0800390
joshualittb8c241a2015-05-19 08:23:30 -0700391 if (dfpgp.color() != fColor) {
joshualitt9b989322014-12-15 14:16:27 -0800392 GrGLfloat c[4];
joshualittb8c241a2015-05-19 08:23:30 -0700393 GrColorToRGBAFloat(dfpgp.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800394 pdman.set4fv(fColorUniform, 1, c);
joshualittb8c241a2015-05-19 08:23:30 -0700395 fColor = dfpgp.color();
joshualitt9b989322014-12-15 14:16:27 -0800396 }
jvanverthfa38a302014-10-06 05:59:05 -0700397 }
398
robertphillips46d36f02015-01-18 08:14:14 -0800399 static inline void GenKey(const GrGeometryProcessor& gp,
joshualitt9b989322014-12-15 14:16:27 -0800400 const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700401 const GrGLSLCaps&,
jvanverthfa38a302014-10-06 05:59:05 -0700402 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700403 const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>();
jvanverthfa38a302014-10-06 05:59:05 -0700404
joshualitt8fc6c2d2014-12-22 15:27:05 -0800405 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700406 key |= dfTexEffect.colorIgnored() << 16;
407 key |= dfTexEffect.hasVertexColor() << 17;
joshualitte578a952015-05-14 10:09:13 -0700408 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800409 b->add32(key);
jvanverthfa38a302014-10-06 05:59:05 -0700410 }
411
412private:
joshualitt9b989322014-12-15 14:16:27 -0800413 UniformHandle fColorUniform;
reede4ef1ca2015-02-17 18:38:38 -0800414 UniformHandle fTextureSizeUni;
joshualitt5559ca22015-05-21 15:50:36 -0700415 UniformHandle fViewMatrixUniform;
416 SkMatrix fViewMatrix;
joshualitt9b989322014-12-15 14:16:27 -0800417 GrColor fColor;
418 SkISize fTextureSize;
jvanverthfa38a302014-10-06 05:59:05 -0700419
420 typedef GrGLGeometryProcessor INHERITED;
421};
422
423///////////////////////////////////////////////////////////////////////////////
424
jvanverth502286d2015-04-08 12:37:51 -0700425GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
joshualitt2e3b3e32014-12-09 13:31:14 -0800426 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800427 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800428 GrTexture* texture,
429 const GrTextureParams& params,
joshualittb8c241a2015-05-19 08:23:30 -0700430 uint32_t flags,
431 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700432 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700433 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800434 , fTextureAccess(texture, params)
jvanverthfa38a302014-10-06 05:59:05 -0700435 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
joshualittb8c241a2015-05-19 08:23:30 -0700436 , fInColor(NULL)
437 , fUsesLocalCoords(usesLocalCoords) {
jvanverthfa38a302014-10-06 05:59:05 -0700438 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth502286d2015-04-08 12:37:51 -0700439 this->initClassID<GrDistanceFieldPathGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700440 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
441 kHigh_GrSLPrecision));
joshualitt2dd1ae02014-12-03 06:24:10 -0800442 if (flags & kColorAttr_DistanceFieldEffectFlag) {
joshualitt71c92602015-01-14 08:12:47 -0800443 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt2dd1ae02014-12-03 06:24:10 -0800444 }
joshualitt71c92602015-01-14 08:12:47 -0800445 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
joshualittb8c241a2015-05-19 08:23:30 -0700446 kVec2f_GrVertexAttribType));
jvanverthfa38a302014-10-06 05:59:05 -0700447 this->addTextureAccess(&fTextureAccess);
448}
449
jvanverth502286d2015-04-08 12:37:51 -0700450void GrDistanceFieldPathGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700451 const GrGLSLCaps& caps,
jvanverth502286d2015-04-08 12:37:51 -0700452 GrProcessorKeyBuilder* b) const {
453 GrGLDistanceFieldPathGeoProc::GenKey(*this, bt, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800454}
455
joshualittabb52a12015-01-13 15:02:10 -0800456GrGLPrimitiveProcessor*
jvanverthcfc18862015-04-28 08:48:20 -0700457GrDistanceFieldPathGeoProc::createGLInstance(const GrBatchTracker& bt, const GrGLSLCaps&) const {
jvanverth502286d2015-04-08 12:37:51 -0700458 return SkNEW_ARGS(GrGLDistanceFieldPathGeoProc, (*this, bt));
jvanverthfa38a302014-10-06 05:59:05 -0700459}
460
461///////////////////////////////////////////////////////////////////////////////
462
jvanverth502286d2015-04-08 12:37:51 -0700463GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc);
jvanverthfa38a302014-10-06 05:59:05 -0700464
joshualitt0067ff52015-07-08 14:26:19 -0700465GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) {
466 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
467 : GrProcessorUnitTest::kAlphaTextureIdx;
jvanverthfa38a302014-10-06 05:59:05 -0700468 static const SkShader::TileMode kTileModes[] = {
469 SkShader::kClamp_TileMode,
470 SkShader::kRepeat_TileMode,
471 SkShader::kMirror_TileMode,
472 };
473 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700474 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
475 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
jvanverthfa38a302014-10-06 05:59:05 -0700476 };
joshualitt0067ff52015-07-08 14:26:19 -0700477 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode
478 : GrTextureParams::kNone_FilterMode);
jvanverthfa38a302014-10-06 05:59:05 -0700479
joshualitt0067ff52015-07-08 14:26:19 -0700480 return GrDistanceFieldPathGeoProc::Create(GrRandomColor(d->fRandom),
481 GrTest::TestMatrix(d->fRandom),
482 d->fTextures[texIdx],
jvanverth502286d2015-04-08 12:37:51 -0700483 params,
joshualitt0067ff52015-07-08 14:26:19 -0700484 d->fRandom->nextBool() ?
joshualittb8c241a2015-05-19 08:23:30 -0700485 kSimilarity_DistanceFieldEffectFlag : 0,
joshualitt0067ff52015-07-08 14:26:19 -0700486 d->fRandom->nextBool());
jvanverthfa38a302014-10-06 05:59:05 -0700487}
488
489///////////////////////////////////////////////////////////////////////////////
490
jvanverth502286d2015-04-08 12:37:51 -0700491class GrGLDistanceFieldLCDTextGeoProc : public GrGLGeometryProcessor {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000492public:
jvanverth502286d2015-04-08 12:37:51 -0700493 GrGLDistanceFieldLCDTextGeoProc(const GrGeometryProcessor&, const GrBatchTracker&)
joshualitt5559ca22015-05-21 15:50:36 -0700494 : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL) {
jvanverth502286d2015-04-08 12:37:51 -0700495 fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f);
jvanverth21deace2015-04-01 12:43:48 -0700496 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000497
mtklein36352bf2015-03-25 18:17:31 -0700498 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
jvanverth502286d2015-04-08 12:37:51 -0700499 const GrDistanceFieldLCDTextGeoProc& dfTexEffect =
500 args.fGP.cast<GrDistanceFieldLCDTextGeoProc>();
joshualitt9b989322014-12-15 14:16:27 -0800501 GrGLGPBuilder* pb = args.fPB;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000502
joshualittc369e7c2014-10-22 10:56:26 -0700503 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualittabb52a12015-01-13 15:02:10 -0800504
505 // emit attributes
506 vsBuilder->emitAttributes(dfTexEffect);
507
joshualitt9b989322014-12-15 14:16:27 -0800508 // setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -0700509 if (!dfTexEffect.colorIgnored()) {
510 this->setupUniformColor(pb, args.fOutputColor, &fColorUniform);
511 }
joshualitt9b989322014-12-15 14:16:27 -0800512
joshualittabb52a12015-01-13 15:02:10 -0800513 // Setup position
joshualitt5559ca22015-05-21 15:50:36 -0700514 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(),
515 &fViewMatrixUniform);
joshualitt4973d9d2014-11-08 09:24:25 -0800516
joshualittabb52a12015-01-13 15:02:10 -0800517 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -0800518 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
joshualitte3ababe2015-05-15 07:56:07 -0700519 args.fTransformsIn, args.fTransformsOut);
joshualittabb52a12015-01-13 15:02:10 -0800520
jvanverthbb4a1cf2015-04-07 09:06:00 -0700521 // set up varyings
522 bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
523 GrGLVertToFrag recipScale(kFloat_GrSLType);
524 GrGLVertToFrag st(kVec2f_GrSLType);
jvanverth221360a2015-04-15 12:31:22 -0700525 args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
526 vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
jvanverthbb4a1cf2015-04-07 09:06:00 -0700527
528 GrGLVertToFrag uv(kVec2f_GrSLType);
529 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
530 // this is only used with text, so our texture bounds always match the glyph atlas
531 vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", "
532 GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(),
533 dfTexEffect.inTextureCoords()->fName);
534
535 // add frag shader code
egdaniel29bee0f2015-04-29 11:54:42 -0700536 GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -0700537
538 SkAssertResult(fsBuilder->enableFeature(
539 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
540
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000541 // create LCD offset adjusted by inverse of transform
jvanverthfdf7ccc2015-01-27 08:19:33 -0800542 // Use highp to work around aliasing issues
543 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
544 pb->ctxInfo().standard()));
jvanverth5a105ff2015-02-18 11:36:35 -0800545 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -0800546 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
547 pb->ctxInfo().standard()));
jvanverth5a105ff2015-02-18 11:36:35 -0800548 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
549 fsBuilder->codeAppend("float delta = -" GR_FONT_ATLAS_LCD_DELTA ";\n");
550 } else {
551 fsBuilder->codeAppend("float delta = " GR_FONT_ATLAS_LCD_DELTA ";\n");
552 }
jvanverth78f07182014-07-30 06:17:59 -0700553 if (isUniformScale) {
jvanverthbc027352015-04-15 13:41:31 -0700554 fsBuilder->codeAppendf("float dy = abs(dFdy(%s.y));", st.fsIn());
jvanverth221360a2015-04-15 12:31:22 -0700555 fsBuilder->codeAppend("vec2 offset = vec2(dy*delta, 0.0);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000556 } else {
jvanverthbb4a1cf2015-04-07 09:06:00 -0700557 fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn());
558
559 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
560 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
561 fsBuilder->codeAppend("vec2 offset = delta*Jdx;");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000562 }
563
564 // green is distance to uv center
joshualitt30ba4362014-08-21 20:18:45 -0700565 fsBuilder->codeAppend("\tvec4 texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700566 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700567 fsBuilder->codeAppend(";\n");
568 fsBuilder->codeAppend("\tvec3 distance;\n");
569 fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000570 // red is distance to left offset
joshualitt30ba4362014-08-21 20:18:45 -0700571 fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
572 fsBuilder->codeAppend("\ttexColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700573 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700574 fsBuilder->codeAppend(";\n");
575 fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000576 // blue is distance to right offset
joshualitt30ba4362014-08-21 20:18:45 -0700577 fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
578 fsBuilder->codeAppend("\ttexColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700579 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700580 fsBuilder->codeAppend(";\n");
581 fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700582
joshualitt30ba4362014-08-21 20:18:45 -0700583 fsBuilder->codeAppend("\tdistance = "
jvanverthada68ef2014-11-03 14:00:24 -0800584 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
jvanverth2d2a68c2014-06-10 06:42:56 -0700585
jvanverth21deace2015-04-01 12:43:48 -0700586 // adjust width based on gamma
587 const char* distanceAdjustUniName = NULL;
588 fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
589 kVec3f_GrSLType, kDefault_GrSLPrecision,
590 "DistanceAdjust", &distanceAdjustUniName);
591 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
592
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000593 // To be strictly correct, we should compute the anti-aliasing factor separately
594 // for each color component. However, this is only important when using perspective
595 // transformations, and even then using a single factor seems like a reasonable
596 // trade-off between quality and speed.
jvanverth354eba52015-03-16 11:32:49 -0700597 fsBuilder->codeAppend("float afwidth;");
jvanverth78f07182014-07-30 06:17:59 -0700598 if (isUniformScale) {
jvanverth354eba52015-03-16 11:32:49 -0700599 // For uniform scale, we adjust for the effect of the transformation on the distance
600 // by using the length of the gradient of the texture coordinates. We use st coordinates
601 // to ensure we're mapping 1:1 from texel space to pixel space.
602
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000603 // this gives us a smooth step across approximately one fragment
jvanverthbc027352015-04-15 13:41:31 -0700604 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*dy;");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000605 } else {
jvanverth354eba52015-03-16 11:32:49 -0700606 // For general transforms, to determine the amount of correction we multiply a unit
607 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
608 // (which is the inverse transform for this fragment) and take the length of the result.
609 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));");
jvanverthd68a5502015-03-16 12:58:43 -0700610 // the length of the gradient may be 0, so we need to check for this
611 // this also compensates for the Adreno, which likes to drop tiles on division by 0
612 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
613 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
614 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
615 fsBuilder->codeAppend("} else {");
616 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
617 fsBuilder->codeAppend("}");
jvanverth354eba52015-03-16 11:32:49 -0700618 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
619 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000620
621 // this gives us a smooth step across approximately one fragment
jvanverth354eba52015-03-16 11:32:49 -0700622 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000623 }
624
jvanverth21deace2015-04-01 12:43:48 -0700625 fsBuilder->codeAppend(
626 "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
jvanverth2d2a68c2014-06-10 06:42:56 -0700627
joshualitt2dd1ae02014-12-03 06:24:10 -0800628 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000629 }
630
kkinnunen7510b222014-07-30 00:04:16 -0700631 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800632 const GrPrimitiveProcessor& processor,
mtklein36352bf2015-03-25 18:17:31 -0700633 const GrBatchTracker& bt) override {
jvanverth21deace2015-04-01 12:43:48 -0700634 SkASSERT(fDistanceAdjustUni.isValid());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000635
joshualitt5559ca22015-05-21 15:50:36 -0700636 const GrDistanceFieldLCDTextGeoProc& dflcd = processor.cast<GrDistanceFieldLCDTextGeoProc>();
637 GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.getDistanceAdjust();
jvanverth21deace2015-04-01 12:43:48 -0700638 if (wa != fDistanceAdjust) {
639 pdman.set3f(fDistanceAdjustUni,
640 wa.fR,
641 wa.fG,
642 wa.fB);
643 fDistanceAdjust = wa;
jvanverth2d2a68c2014-06-10 06:42:56 -0700644 }
joshualitt9b989322014-12-15 14:16:27 -0800645
joshualitt5559ca22015-05-21 15:50:36 -0700646 if (!dflcd.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dflcd.viewMatrix())) {
647 fViewMatrix = dflcd.viewMatrix();
648 GrGLfloat viewMatrix[3 * 3];
649 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
650 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
651 }
joshualittee2af952014-12-30 09:04:15 -0800652
joshualitt5559ca22015-05-21 15:50:36 -0700653 if (dflcd.color() != fColor) {
joshualitt9b989322014-12-15 14:16:27 -0800654 GrGLfloat c[4];
joshualitt5559ca22015-05-21 15:50:36 -0700655 GrColorToRGBAFloat(dflcd.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800656 pdman.set4fv(fColorUniform, 1, c);
joshualitt5559ca22015-05-21 15:50:36 -0700657 fColor = dflcd.color();
joshualitt9b989322014-12-15 14:16:27 -0800658 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000659 }
660
robertphillips46d36f02015-01-18 08:14:14 -0800661 static inline void GenKey(const GrGeometryProcessor& gp,
joshualitt9b989322014-12-15 14:16:27 -0800662 const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700663 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700664 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700665 const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000666
joshualitt8fc6c2d2014-12-22 15:27:05 -0800667 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700668 key |= dfTexEffect.colorIgnored() << 16;
joshualitte578a952015-05-14 10:09:13 -0700669 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800670 b->add32(key);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000671 }
672
673private:
joshualitt5559ca22015-05-21 15:50:36 -0700674 SkMatrix fViewMatrix;
jvanverth21deace2015-04-01 12:43:48 -0700675 GrColor fColor;
joshualitt5559ca22015-05-21 15:50:36 -0700676 UniformHandle fViewMatrixUniform;
jvanverth21deace2015-04-01 12:43:48 -0700677 UniformHandle fColorUniform;
jvanverth502286d2015-04-08 12:37:51 -0700678 GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust;
jvanverth21deace2015-04-01 12:43:48 -0700679 UniformHandle fDistanceAdjustUni;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000680
joshualitt249af152014-09-15 11:41:13 -0700681 typedef GrGLGeometryProcessor INHERITED;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000682};
683
684///////////////////////////////////////////////////////////////////////////////
685
jvanverth502286d2015-04-08 12:37:51 -0700686GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(
joshualitt8059eb92014-12-29 15:10:07 -0800687 GrColor color, const SkMatrix& viewMatrix,
jvanverth2d2a68c2014-06-10 06:42:56 -0700688 GrTexture* texture, const GrTextureParams& params,
jvanverth21deace2015-04-01 12:43:48 -0700689 DistanceAdjust distanceAdjust,
joshualittb8c241a2015-05-19 08:23:30 -0700690 uint32_t flags, bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700691 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700692 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800693 , fTextureAccess(texture, params)
jvanverth21deace2015-04-01 12:43:48 -0700694 , fDistanceAdjust(distanceAdjust)
joshualittb8c241a2015-05-19 08:23:30 -0700695 , fFlags(flags & kLCD_DistanceFieldEffectMask)
696 , fUsesLocalCoords(usesLocalCoords) {
jvanverth78f07182014-07-30 06:17:59 -0700697 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
jvanverth502286d2015-04-08 12:37:51 -0700698 this->initClassID<GrDistanceFieldLCDTextGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700699 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
700 kHigh_GrSLPrecision));
joshualitt71c92602015-01-14 08:12:47 -0800701 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
joshualittb8c241a2015-05-19 08:23:30 -0700702 kVec2s_GrVertexAttribType));
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000703 this->addTextureAccess(&fTextureAccess);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000704}
705
jvanverth502286d2015-04-08 12:37:51 -0700706void GrDistanceFieldLCDTextGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700707 const GrGLSLCaps& caps,
jvanverth502286d2015-04-08 12:37:51 -0700708 GrProcessorKeyBuilder* b) const {
709 GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, bt, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800710}
711
joshualittabb52a12015-01-13 15:02:10 -0800712GrGLPrimitiveProcessor*
jvanverth502286d2015-04-08 12:37:51 -0700713GrDistanceFieldLCDTextGeoProc::createGLInstance(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700714 const GrGLSLCaps&) const {
jvanverth502286d2015-04-08 12:37:51 -0700715 return SkNEW_ARGS(GrGLDistanceFieldLCDTextGeoProc, (*this, bt));
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000716}
717
718///////////////////////////////////////////////////////////////////////////////
719
jvanverth502286d2015-04-08 12:37:51 -0700720GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000721
joshualitt0067ff52015-07-08 14:26:19 -0700722GrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) {
723 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
724 GrProcessorUnitTest::kAlphaTextureIdx;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000725 static const SkShader::TileMode kTileModes[] = {
726 SkShader::kClamp_TileMode,
727 SkShader::kRepeat_TileMode,
728 SkShader::kMirror_TileMode,
729 };
730 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700731 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
732 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000733 };
joshualitt0067ff52015-07-08 14:26:19 -0700734 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000735 GrTextureParams::kNone_FilterMode);
jvanverth21deace2015-04-01 12:43:48 -0700736 DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
jvanverth78f07182014-07-30 06:17:59 -0700737 uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
joshualitt0067ff52015-07-08 14:26:19 -0700738 flags |= d->fRandom->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
739 flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
740 return GrDistanceFieldLCDTextGeoProc::Create(GrRandomColor(d->fRandom),
741 GrTest::TestMatrix(d->fRandom),
742 d->fTextures[texIdx], params,
jvanverth502286d2015-04-08 12:37:51 -0700743 wa,
joshualittb8c241a2015-05-19 08:23:30 -0700744 flags,
joshualitt0067ff52015-07-08 14:26:19 -0700745 d->fRandom->nextBool());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000746}