blob: 08fa5ac6d55eebfd0b288716e23f991c367121bb [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"
egdaniel605dd0f2014-11-12 08:35:25 -08009#include "GrInvariantOutput.h"
joshualitteb2a6762014-12-04 11:35:33 -080010#include "GrTexture.h"
jvanverth21deace2015-04-01 12:43:48 -070011
joshualitteb2a6762014-12-04 11:35:33 -080012#include "SkDistanceFieldGen.h"
jvanverth21deace2015-04-01 12:43:48 -070013
wangyix6af0c932015-07-22 10:21:17 -070014#include "gl/GrGLFragmentProcessor.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000015#include "gl/GrGLTexture.h"
joshualitt249af152014-09-15 11:41:13 -070016#include "gl/GrGLGeometryProcessor.h"
joshualitteb2a6762014-12-04 11:35:33 -080017#include "gl/builders/GrGLProgramBuilder.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000018
jvanverth21deace2015-04-01 12:43:48 -070019// Assuming a radius of a little less than the diagonal of the fragment
jvanverth24ba0082015-03-19 11:34:13 -070020#define SK_DistanceFieldAAFactor "0.65"
jvanverth2d2a68c2014-06-10 06:42:56 -070021
jvanverth502286d2015-04-08 12:37:51 -070022class GrGLDistanceFieldA8TextGeoProc : public GrGLGeometryProcessor {
jvanverth@google.comd830d132013-11-11 20:54:09 +000023public:
joshualitt465283c2015-09-11 08:19:35 -070024 GrGLDistanceFieldA8TextGeoProc()
joshualitt5559ca22015-05-21 15:50:36 -070025 : fViewMatrix(SkMatrix::InvalidMatrix())
26 , fColor(GrColor_ILLEGAL)
jvanverth9564ce62014-09-16 05:45:19 -070027#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -070028 , fDistanceAdjust(-1.0f)
jvanverth9564ce62014-09-16 05:45:19 -070029#endif
30 {}
jvanverth@google.comd830d132013-11-11 20:54:09 +000031
mtklein36352bf2015-03-25 18:17:31 -070032 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
jvanverth502286d2015-04-08 12:37:51 -070033 const GrDistanceFieldA8TextGeoProc& dfTexEffect =
34 args.fGP.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt9b989322014-12-15 14:16:27 -080035 GrGLGPBuilder* pb = args.fPB;
egdaniel29bee0f2015-04-29 11:54:42 -070036 GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -070037 SkAssertResult(fsBuilder->enableFeature(
38 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
jvanverth@google.comd830d132013-11-11 20:54:09 +000039
joshualitt2dd1ae02014-12-03 06:24:10 -080040 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualittabb52a12015-01-13 15:02:10 -080041
42 // emit attributes
43 vsBuilder->emitAttributes(dfTexEffect);
44
jvanverth21deace2015-04-01 12:43:48 -070045#ifdef SK_GAMMA_APPLY_TO_A8
46 // adjust based on gamma
halcanary96fcdcc2015-08-27 07:41:13 -070047 const char* distanceAdjustUniName = nullptr;
jvanverth21deace2015-04-01 12:43:48 -070048 // width, height, 1/(3*width)
49 fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
50 kFloat_GrSLType, kDefault_GrSLPrecision,
51 "DistanceAdjust", &distanceAdjustUniName);
52#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000053
joshualitt9b989322014-12-15 14:16:27 -080054 // Setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -070055 if (!dfTexEffect.colorIgnored()) {
56 if (dfTexEffect.hasVertexColor()) {
57 pb->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
58 } else {
59 this->setupUniformColor(pb, args.fOutputColor, &fColorUniform);
60 }
61 }
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000062
joshualittabb52a12015-01-13 15:02:10 -080063 // Setup position
joshualitt5559ca22015-05-21 15:50:36 -070064 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(),
65 &fViewMatrixUniform);
joshualitt2dd1ae02014-12-03 06:24:10 -080066
joshualittabb52a12015-01-13 15:02:10 -080067 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -080068 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
joshualitte3ababe2015-05-15 07:56:07 -070069 args.fTransformsIn, args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -080070
jvanverthbb4a1cf2015-04-07 09:06:00 -070071 // add varyings
72 GrGLVertToFrag recipScale(kFloat_GrSLType);
73 GrGLVertToFrag st(kVec2f_GrSLType);
74 bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
jvanverth221360a2015-04-15 12:31:22 -070075 args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
76 vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
jvanverthbb4a1cf2015-04-07 09:06:00 -070077
joshualitt922c8b12015-08-07 09:55:23 -070078 // compute numbers to be hardcoded to convert texture coordinates from int to float
79 SkASSERT(dfTexEffect.numTextures() == 1);
80 GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
joshualitt7375d6b2015-08-07 13:36:44 -070081 SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
joshualitt922c8b12015-08-07 09:55:23 -070082 SkScalar recipWidth = 1.0f / atlas->width();
83 SkScalar recipHeight = 1.0f / atlas->height();
84
jvanverthbb4a1cf2015-04-07 09:06:00 -070085 GrGLVertToFrag uv(kVec2f_GrSLType);
86 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
joshualitt922c8b12015-08-07 09:55:23 -070087 vsBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(),
joshualitt7375d6b2015-08-07 13:36:44 -070088 GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth,
89 GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight,
jvanverthbb4a1cf2015-04-07 09:06:00 -070090 dfTexEffect.inTextureCoords()->fName);
91
jvanverthfdf7ccc2015-01-27 08:19:33 -080092 // Use highp to work around aliasing issues
93 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
94 pb->ctxInfo().standard()));
jvanverth5a105ff2015-02-18 11:36:35 -080095 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -080096
97 fsBuilder->codeAppend("\tfloat texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -070098 fsBuilder->appendTextureLookup(args.fSamplers[0],
jvanverthfdf7ccc2015-01-27 08:19:33 -080099 "uv",
jvanverth@google.comd830d132013-11-11 20:54:09 +0000100 kVec2f_GrSLType);
jvanverthfdf7ccc2015-01-27 08:19:33 -0800101 fsBuilder->codeAppend(".r;\n");
joshualitt30ba4362014-08-21 20:18:45 -0700102 fsBuilder->codeAppend("\tfloat distance = "
jvanverthfdf7ccc2015-01-27 08:19:33 -0800103 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
jvanverth21deace2015-04-01 12:43:48 -0700104#ifdef SK_GAMMA_APPLY_TO_A8
105 // adjust width based on gamma
106 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
107#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000108
jvanverth354eba52015-03-16 11:32:49 -0700109 fsBuilder->codeAppend("float afwidth;");
jvanverthbb4a1cf2015-04-07 09:06:00 -0700110 if (isSimilarity) {
jvanverth354eba52015-03-16 11:32:49 -0700111 // For uniform scale, we adjust for the effect of the transformation on the distance
112 // by using the length of the gradient of the texture coordinates. We use st coordinates
jvanverth221360a2015-04-15 12:31:22 -0700113 // to ensure we're mapping 1:1 from texel space to pixel space.
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000114
jvanverth354eba52015-03-16 11:32:49 -0700115 // this gives us a smooth step across approximately one fragment
jvanverth221360a2015-04-15 12:31:22 -0700116 // we use y to work around a Mali400 bug in the x direction
117 fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));",
jvanverthbb4a1cf2015-04-07 09:06:00 -0700118 st.fsIn());
jvanverth354eba52015-03-16 11:32:49 -0700119 } else {
120 // For general transforms, to determine the amount of correction we multiply a unit
121 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
122 // (which is the inverse transform for this fragment) and take the length of the result.
123 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
jvanverthd68a5502015-03-16 12:58:43 -0700124 // the length of the gradient may be 0, so we need to check for this
125 // this also compensates for the Adreno, which likes to drop tiles on division by 0
126 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
127 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
128 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
129 fsBuilder->codeAppend("} else {");
130 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
131 fsBuilder->codeAppend("}");
132
jvanverthbb4a1cf2015-04-07 09:06:00 -0700133 fsBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn());
134 fsBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn());
jvanverth354eba52015-03-16 11:32:49 -0700135 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
136 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000137
138 // this gives us a smooth step across approximately one fragment
jvanverth354eba52015-03-16 11:32:49 -0700139 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000140 }
jvanverth354eba52015-03-16 11:32:49 -0700141 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
jvanverth@google.comd830d132013-11-11 20:54:09 +0000142
joshualitt2dd1ae02014-12-03 06:24:10 -0800143 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000144 }
145
joshualitt465283c2015-09-11 08:19:35 -0700146 void setData(const GrGLProgramDataManager& pdman, const GrPrimitiveProcessor& proc) override {
jvanverth2d2a68c2014-06-10 06:42:56 -0700147#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth502286d2015-04-08 12:37:51 -0700148 const GrDistanceFieldA8TextGeoProc& dfTexEffect = proc.cast<GrDistanceFieldA8TextGeoProc>();
jvanverth21deace2015-04-01 12:43:48 -0700149 float distanceAdjust = dfTexEffect.getDistanceAdjust();
150 if (distanceAdjust != fDistanceAdjust) {
151 pdman.set1f(fDistanceAdjustUni, distanceAdjust);
152 fDistanceAdjust = distanceAdjust;
jvanverth2d2a68c2014-06-10 06:42:56 -0700153 }
154#endif
joshualitte578a952015-05-14 10:09:13 -0700155 const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt5559ca22015-05-21 15:50:36 -0700156
157 if (!dfa8gp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfa8gp.viewMatrix())) {
158 fViewMatrix = dfa8gp.viewMatrix();
159 GrGLfloat viewMatrix[3 * 3];
160 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
161 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
162 }
joshualittee2af952014-12-30 09:04:15 -0800163
joshualittb8c241a2015-05-19 08:23:30 -0700164 if (dfa8gp.color() != fColor && !dfa8gp.hasVertexColor()) {
joshualitt9b989322014-12-15 14:16:27 -0800165 GrGLfloat c[4];
joshualittb8c241a2015-05-19 08:23:30 -0700166 GrColorToRGBAFloat(dfa8gp.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800167 pdman.set4fv(fColorUniform, 1, c);
joshualittb8c241a2015-05-19 08:23:30 -0700168 fColor = dfa8gp.color();
joshualitt9b989322014-12-15 14:16:27 -0800169 }
commit-bot@chromium.org8fe2ee12014-03-26 18:03:05 +0000170 }
171
robertphillips46d36f02015-01-18 08:14:14 -0800172 static inline void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700173 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700174 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700175 const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800176 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700177 key |= dfTexEffect.hasVertexColor() << 16;
178 key |= dfTexEffect.colorIgnored() << 17;
joshualitte578a952015-05-14 10:09:13 -0700179 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800180 b->add32(key);
joshualitt922c8b12015-08-07 09:55:23 -0700181
182 // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
183 SkASSERT(gp.numTextures() == 1);
184 GrTexture* atlas = gp.textureAccess(0).getTexture();
185 SkASSERT(atlas);
186 b->add32(atlas->width());
187 b->add32(atlas->height());
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000188 }
189
jvanverth@google.comd830d132013-11-11 20:54:09 +0000190private:
joshualitt5559ca22015-05-21 15:50:36 -0700191 SkMatrix fViewMatrix;
joshualitt9b989322014-12-15 14:16:27 -0800192 GrColor fColor;
193 UniformHandle fColorUniform;
joshualitt5559ca22015-05-21 15:50:36 -0700194 UniformHandle fViewMatrixUniform;
mtklein50282b42015-01-22 07:59:52 -0800195#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700196 float fDistanceAdjust;
197 UniformHandle fDistanceAdjustUni;
mtklein50282b42015-01-22 07:59:52 -0800198#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000199
joshualitt249af152014-09-15 11:41:13 -0700200 typedef GrGLGeometryProcessor INHERITED;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000201};
202
203///////////////////////////////////////////////////////////////////////////////
204
jvanverth502286d2015-04-08 12:37:51 -0700205GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800206 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800207 GrTexture* texture,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000208 const GrTextureParams& params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700209#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700210 float distanceAdjust,
jvanverth2d2a68c2014-06-10 06:42:56 -0700211#endif
joshualittb8c241a2015-05-19 08:23:30 -0700212 uint32_t flags,
213 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700214 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700215 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800216 , fTextureAccess(texture, params)
jvanverth2d2a68c2014-06-10 06:42:56 -0700217#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700218 , fDistanceAdjust(distanceAdjust)
jvanverth2d2a68c2014-06-10 06:42:56 -0700219#endif
joshualitt249af152014-09-15 11:41:13 -0700220 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
halcanary96fcdcc2015-08-27 07:41:13 -0700221 , fInColor(nullptr)
joshualittb8c241a2015-05-19 08:23:30 -0700222 , fUsesLocalCoords(usesLocalCoords) {
jvanverth78f07182014-07-30 06:17:59 -0700223 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth502286d2015-04-08 12:37:51 -0700224 this->initClassID<GrDistanceFieldA8TextGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700225 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
226 kHigh_GrSLPrecision));
joshualitt2dd1ae02014-12-03 06:24:10 -0800227 if (flags & kColorAttr_DistanceFieldEffectFlag) {
joshualitt71c92602015-01-14 08:12:47 -0800228 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt2dd1ae02014-12-03 06:24:10 -0800229 }
joshualitt71c92602015-01-14 08:12:47 -0800230 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
jvanverth5a105ff2015-02-18 11:36:35 -0800231 kVec2s_GrVertexAttribType));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000232 this->addTextureAccess(&fTextureAccess);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000233}
234
joshualitt465283c2015-09-11 08:19:35 -0700235void GrDistanceFieldA8TextGeoProc::getGLProcessorKey(const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800236 GrProcessorKeyBuilder* b) const {
joshualitt465283c2015-09-11 08:19:35 -0700237 GrGLDistanceFieldA8TextGeoProc::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800238}
239
joshualitt465283c2015-09-11 08:19:35 -0700240GrGLPrimitiveProcessor* GrDistanceFieldA8TextGeoProc::createGLInstance(const GrGLSLCaps&) const {
241 return new GrGLDistanceFieldA8TextGeoProc();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000242}
243
244///////////////////////////////////////////////////////////////////////////////
245
jvanverth502286d2015-04-08 12:37:51 -0700246GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000247
bsalomonc21b09e2015-08-28 18:46:56 -0700248const GrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700249 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
250 GrProcessorUnitTest::kAlphaTextureIdx;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000251 static const SkShader::TileMode kTileModes[] = {
252 SkShader::kClamp_TileMode,
253 SkShader::kRepeat_TileMode,
254 SkShader::kMirror_TileMode,
255 };
256 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700257 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
258 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
jvanverth@google.comd830d132013-11-11 20:54:09 +0000259 };
joshualitt0067ff52015-07-08 14:26:19 -0700260 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
jvanverth@google.comd830d132013-11-11 20:54:09 +0000261 GrTextureParams::kNone_FilterMode);
262
joshualitt0067ff52015-07-08 14:26:19 -0700263 return GrDistanceFieldA8TextGeoProc::Create(GrRandomColor(d->fRandom),
264 GrTest::TestMatrix(d->fRandom),
265 d->fTextures[texIdx], params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700266#ifdef SK_GAMMA_APPLY_TO_A8
joshualitt0067ff52015-07-08 14:26:19 -0700267 d->fRandom->nextF(),
jvanverth2d2a68c2014-06-10 06:42:56 -0700268#endif
joshualitt0067ff52015-07-08 14:26:19 -0700269 d->fRandom->nextBool() ?
joshualittb8c241a2015-05-19 08:23:30 -0700270 kSimilarity_DistanceFieldEffectFlag : 0,
joshualitt0067ff52015-07-08 14:26:19 -0700271 d->fRandom->nextBool());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000272}
273
274///////////////////////////////////////////////////////////////////////////////
275
jvanverth502286d2015-04-08 12:37:51 -0700276class GrGLDistanceFieldPathGeoProc : public GrGLGeometryProcessor {
jvanverthfa38a302014-10-06 05:59:05 -0700277public:
joshualitt465283c2015-09-11 08:19:35 -0700278 GrGLDistanceFieldPathGeoProc()
joshualitt5559ca22015-05-21 15:50:36 -0700279 : fViewMatrix(SkMatrix::InvalidMatrix())
280 , fColor(GrColor_ILLEGAL)
281 , fTextureSize(SkISize::Make(-1, -1)) {}
jvanverthfa38a302014-10-06 05:59:05 -0700282
mtklein36352bf2015-03-25 18:17:31 -0700283 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
jvanverth502286d2015-04-08 12:37:51 -0700284 const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldPathGeoProc>();
jvanverthfa38a302014-10-06 05:59:05 -0700285
joshualitt9b989322014-12-15 14:16:27 -0800286 GrGLGPBuilder* pb = args.fPB;
egdaniel29bee0f2015-04-29 11:54:42 -0700287 GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
jvanverthfa38a302014-10-06 05:59:05 -0700288 SkAssertResult(fsBuilder->enableFeature(
289 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
290
joshualitt2dd1ae02014-12-03 06:24:10 -0800291 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualittabb52a12015-01-13 15:02:10 -0800292
293 // emit attributes
294 vsBuilder->emitAttributes(dfTexEffect);
295
reede4ef1ca2015-02-17 18:38:38 -0800296 GrGLVertToFrag v(kVec2f_GrSLType);
jvanverth9671ecd2015-02-23 13:08:39 -0800297 args.fPB->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
jvanverthfa38a302014-10-06 05:59:05 -0700298
joshualitt9b989322014-12-15 14:16:27 -0800299 // setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -0700300 if (!dfTexEffect.colorIgnored()) {
301 if (dfTexEffect.hasVertexColor()) {
302 pb->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
303 } else {
304 this->setupUniformColor(pb, args.fOutputColor, &fColorUniform);
305 }
306 }
reede4ef1ca2015-02-17 18:38:38 -0800307 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
308
joshualittabb52a12015-01-13 15:02:10 -0800309 // Setup position
joshualitt5559ca22015-05-21 15:50:36 -0700310 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(),
311 &fViewMatrixUniform);
joshualittabb52a12015-01-13 15:02:10 -0800312
313 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -0800314 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
joshualitte3ababe2015-05-15 07:56:07 -0700315 args.fTransformsIn, args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800316
halcanary96fcdcc2015-08-27 07:41:13 -0700317 const char* textureSizeUniName = nullptr;
reede4ef1ca2015-02-17 18:38:38 -0800318 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
319 kVec2f_GrSLType, kDefault_GrSLPrecision,
320 "TextureSize", &textureSizeUniName);
321
jvanverthfdf7ccc2015-01-27 08:19:33 -0800322 // Use highp to work around aliasing issues
323 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
324 pb->ctxInfo().standard()));
reede4ef1ca2015-02-17 18:38:38 -0800325 fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -0800326
327 fsBuilder->codeAppend("float texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700328 fsBuilder->appendTextureLookup(args.fSamplers[0],
jvanverthfdf7ccc2015-01-27 08:19:33 -0800329 "uv",
jvanverthfa38a302014-10-06 05:59:05 -0700330 kVec2f_GrSLType);
jvanverthfdf7ccc2015-01-27 08:19:33 -0800331 fsBuilder->codeAppend(".r;");
jvanverthfa38a302014-10-06 05:59:05 -0700332 fsBuilder->codeAppend("float distance = "
jvanverthfdf7ccc2015-01-27 08:19:33 -0800333 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
jvanverthfa38a302014-10-06 05:59:05 -0700334
jvanverthfdf7ccc2015-01-27 08:19:33 -0800335 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
336 pb->ctxInfo().standard()));
reede4ef1ca2015-02-17 18:38:38 -0800337 fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
jvanverthfa38a302014-10-06 05:59:05 -0700338 fsBuilder->codeAppend("float afwidth;");
339 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
jvanverth354eba52015-03-16 11:32:49 -0700340 // For uniform scale, we adjust for the effect of the transformation on the distance
341 // by using the length of the gradient of the texture coordinates. We use st coordinates
342 // to ensure we're mapping 1:1 from texel space to pixel space.
343
jvanverthfa38a302014-10-06 05:59:05 -0700344 // this gives us a smooth step across approximately one fragment
jvanverthbc027352015-04-15 13:41:31 -0700345 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));");
jvanverthfa38a302014-10-06 05:59:05 -0700346 } else {
jvanverth354eba52015-03-16 11:32:49 -0700347 // For general transforms, to determine the amount of correction we multiply a unit
348 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
349 // (which is the inverse transform for this fragment) and take the length of the result.
350 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
jvanverthd68a5502015-03-16 12:58:43 -0700351 // the length of the gradient may be 0, so we need to check for this
352 // this also compensates for the Adreno, which likes to drop tiles on division by 0
353 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
354 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
355 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
356 fsBuilder->codeAppend("} else {");
357 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
358 fsBuilder->codeAppend("}");
359
jvanverth354eba52015-03-16 11:32:49 -0700360 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
361 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
362 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
363 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
jvanverthfa38a302014-10-06 05:59:05 -0700364
365 // this gives us a smooth step across approximately one fragment
366 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
367 }
368 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
369
joshualitt2dd1ae02014-12-03 06:24:10 -0800370 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverthfa38a302014-10-06 05:59:05 -0700371 }
372
joshualitt465283c2015-09-11 08:19:35 -0700373 void setData(const GrGLProgramDataManager& pdman, const GrPrimitiveProcessor& proc) override {
reede4ef1ca2015-02-17 18:38:38 -0800374 SkASSERT(fTextureSizeUni.isValid());
jvanverthfa38a302014-10-06 05:59:05 -0700375
joshualitt87f48d92014-12-04 10:41:40 -0800376 GrTexture* texture = proc.texture(0);
jvanverthfa38a302014-10-06 05:59:05 -0700377 if (texture->width() != fTextureSize.width() ||
378 texture->height() != fTextureSize.height()) {
379 fTextureSize = SkISize::Make(texture->width(), texture->height());
reede4ef1ca2015-02-17 18:38:38 -0800380 pdman.set2f(fTextureSizeUni,
381 SkIntToScalar(fTextureSize.width()),
382 SkIntToScalar(fTextureSize.height()));
jvanverthfa38a302014-10-06 05:59:05 -0700383 }
joshualitt9b989322014-12-15 14:16:27 -0800384
joshualitte578a952015-05-14 10:09:13 -0700385 const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>();
joshualitt5559ca22015-05-21 15:50:36 -0700386
387 if (!dfpgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfpgp.viewMatrix())) {
388 fViewMatrix = dfpgp.viewMatrix();
389 GrGLfloat viewMatrix[3 * 3];
390 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
391 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
392 }
joshualittee2af952014-12-30 09:04:15 -0800393
joshualittb8c241a2015-05-19 08:23:30 -0700394 if (dfpgp.color() != fColor) {
joshualitt9b989322014-12-15 14:16:27 -0800395 GrGLfloat c[4];
joshualittb8c241a2015-05-19 08:23:30 -0700396 GrColorToRGBAFloat(dfpgp.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800397 pdman.set4fv(fColorUniform, 1, c);
joshualittb8c241a2015-05-19 08:23:30 -0700398 fColor = dfpgp.color();
joshualitt9b989322014-12-15 14:16:27 -0800399 }
jvanverthfa38a302014-10-06 05:59:05 -0700400 }
401
robertphillips46d36f02015-01-18 08:14:14 -0800402 static inline void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700403 const GrGLSLCaps&,
jvanverthfa38a302014-10-06 05:59:05 -0700404 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700405 const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>();
jvanverthfa38a302014-10-06 05:59:05 -0700406
joshualitt8fc6c2d2014-12-22 15:27:05 -0800407 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700408 key |= dfTexEffect.colorIgnored() << 16;
409 key |= dfTexEffect.hasVertexColor() << 17;
joshualitte578a952015-05-14 10:09:13 -0700410 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800411 b->add32(key);
jvanverthfa38a302014-10-06 05:59:05 -0700412 }
413
414private:
joshualitt9b989322014-12-15 14:16:27 -0800415 UniformHandle fColorUniform;
reede4ef1ca2015-02-17 18:38:38 -0800416 UniformHandle fTextureSizeUni;
joshualitt5559ca22015-05-21 15:50:36 -0700417 UniformHandle fViewMatrixUniform;
418 SkMatrix fViewMatrix;
joshualitt9b989322014-12-15 14:16:27 -0800419 GrColor fColor;
420 SkISize fTextureSize;
jvanverthfa38a302014-10-06 05:59:05 -0700421
422 typedef GrGLGeometryProcessor INHERITED;
423};
424
425///////////////////////////////////////////////////////////////////////////////
426
jvanverth502286d2015-04-08 12:37:51 -0700427GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
joshualitt2e3b3e32014-12-09 13:31:14 -0800428 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800429 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800430 GrTexture* texture,
431 const GrTextureParams& params,
joshualittb8c241a2015-05-19 08:23:30 -0700432 uint32_t flags,
433 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700434 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700435 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800436 , fTextureAccess(texture, params)
jvanverthfa38a302014-10-06 05:59:05 -0700437 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
halcanary96fcdcc2015-08-27 07:41:13 -0700438 , fInColor(nullptr)
joshualittb8c241a2015-05-19 08:23:30 -0700439 , fUsesLocalCoords(usesLocalCoords) {
jvanverthfa38a302014-10-06 05:59:05 -0700440 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth502286d2015-04-08 12:37:51 -0700441 this->initClassID<GrDistanceFieldPathGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700442 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
443 kHigh_GrSLPrecision));
joshualitt2dd1ae02014-12-03 06:24:10 -0800444 if (flags & kColorAttr_DistanceFieldEffectFlag) {
joshualitt71c92602015-01-14 08:12:47 -0800445 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt2dd1ae02014-12-03 06:24:10 -0800446 }
joshualitt71c92602015-01-14 08:12:47 -0800447 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
joshualittb8c241a2015-05-19 08:23:30 -0700448 kVec2f_GrVertexAttribType));
jvanverthfa38a302014-10-06 05:59:05 -0700449 this->addTextureAccess(&fTextureAccess);
450}
451
joshualitt465283c2015-09-11 08:19:35 -0700452void GrDistanceFieldPathGeoProc::getGLProcessorKey(const GrGLSLCaps& caps,
jvanverth502286d2015-04-08 12:37:51 -0700453 GrProcessorKeyBuilder* b) const {
joshualitt465283c2015-09-11 08:19:35 -0700454 GrGLDistanceFieldPathGeoProc::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800455}
456
joshualitt465283c2015-09-11 08:19:35 -0700457GrGLPrimitiveProcessor* GrDistanceFieldPathGeoProc::createGLInstance(const GrGLSLCaps&) const {
458 return new GrGLDistanceFieldPathGeoProc();
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
bsalomonc21b09e2015-08-28 18:46:56 -0700465const GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700466 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:
joshualitt465283c2015-09-11 08:19:35 -0700493 GrGLDistanceFieldLCDTextGeoProc()
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
joshualitt922c8b12015-08-07 09:55:23 -0700528 // compute numbers to be hardcoded to convert texture coordinates from int to float
529 SkASSERT(dfTexEffect.numTextures() == 1);
530 GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
joshualitt7375d6b2015-08-07 13:36:44 -0700531 SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
joshualitt922c8b12015-08-07 09:55:23 -0700532 SkScalar recipWidth = 1.0f / atlas->width();
533 SkScalar recipHeight = 1.0f / atlas->height();
534
jvanverthbb4a1cf2015-04-07 09:06:00 -0700535 GrGLVertToFrag uv(kVec2f_GrSLType);
536 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
joshualitt922c8b12015-08-07 09:55:23 -0700537 vsBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(),
joshualitt7375d6b2015-08-07 13:36:44 -0700538 GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipWidth,
539 GR_SIGNIFICANT_POW2_DECIMAL_DIG, recipHeight,
jvanverthbb4a1cf2015-04-07 09:06:00 -0700540 dfTexEffect.inTextureCoords()->fName);
541
542 // add frag shader code
egdaniel29bee0f2015-04-29 11:54:42 -0700543 GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -0700544
545 SkAssertResult(fsBuilder->enableFeature(
546 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
547
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000548 // create LCD offset adjusted by inverse of transform
jvanverthfdf7ccc2015-01-27 08:19:33 -0800549 // Use highp to work around aliasing issues
550 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
551 pb->ctxInfo().standard()));
jvanverth5a105ff2015-02-18 11:36:35 -0800552 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -0800553 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
554 pb->ctxInfo().standard()));
joshualitt922c8b12015-08-07 09:55:23 -0700555
556 SkScalar lcdDelta = 1.0f / (3.0f * atlas->width());
jvanverth5a105ff2015-02-18 11:36:35 -0800557 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
joshualitt922c8b12015-08-07 09:55:23 -0700558 fsBuilder->codeAppendf("float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
jvanverth5a105ff2015-02-18 11:36:35 -0800559 } else {
joshualitt922c8b12015-08-07 09:55:23 -0700560 fsBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
jvanverth5a105ff2015-02-18 11:36:35 -0800561 }
jvanverth78f07182014-07-30 06:17:59 -0700562 if (isUniformScale) {
jvanverthbc027352015-04-15 13:41:31 -0700563 fsBuilder->codeAppendf("float dy = abs(dFdy(%s.y));", st.fsIn());
jvanverth221360a2015-04-15 12:31:22 -0700564 fsBuilder->codeAppend("vec2 offset = vec2(dy*delta, 0.0);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000565 } else {
jvanverthbb4a1cf2015-04-07 09:06:00 -0700566 fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn());
567
568 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
569 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
570 fsBuilder->codeAppend("vec2 offset = delta*Jdx;");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000571 }
572
573 // green is distance to uv center
joshualitt30ba4362014-08-21 20:18:45 -0700574 fsBuilder->codeAppend("\tvec4 texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700575 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700576 fsBuilder->codeAppend(";\n");
577 fsBuilder->codeAppend("\tvec3 distance;\n");
578 fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000579 // red is distance to left offset
joshualitt30ba4362014-08-21 20:18:45 -0700580 fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
581 fsBuilder->codeAppend("\ttexColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700582 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700583 fsBuilder->codeAppend(";\n");
584 fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000585 // blue is distance to right offset
joshualitt30ba4362014-08-21 20:18:45 -0700586 fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
587 fsBuilder->codeAppend("\ttexColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700588 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700589 fsBuilder->codeAppend(";\n");
590 fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700591
joshualitt30ba4362014-08-21 20:18:45 -0700592 fsBuilder->codeAppend("\tdistance = "
jvanverthada68ef2014-11-03 14:00:24 -0800593 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
jvanverth2d2a68c2014-06-10 06:42:56 -0700594
jvanverth21deace2015-04-01 12:43:48 -0700595 // adjust width based on gamma
halcanary96fcdcc2015-08-27 07:41:13 -0700596 const char* distanceAdjustUniName = nullptr;
jvanverth21deace2015-04-01 12:43:48 -0700597 fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
598 kVec3f_GrSLType, kDefault_GrSLPrecision,
599 "DistanceAdjust", &distanceAdjustUniName);
600 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
601
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000602 // To be strictly correct, we should compute the anti-aliasing factor separately
603 // for each color component. However, this is only important when using perspective
604 // transformations, and even then using a single factor seems like a reasonable
605 // trade-off between quality and speed.
jvanverth354eba52015-03-16 11:32:49 -0700606 fsBuilder->codeAppend("float afwidth;");
jvanverth78f07182014-07-30 06:17:59 -0700607 if (isUniformScale) {
jvanverth354eba52015-03-16 11:32:49 -0700608 // For uniform scale, we adjust for the effect of the transformation on the distance
609 // by using the length of the gradient of the texture coordinates. We use st coordinates
610 // to ensure we're mapping 1:1 from texel space to pixel space.
611
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000612 // this gives us a smooth step across approximately one fragment
jvanverthbc027352015-04-15 13:41:31 -0700613 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*dy;");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000614 } else {
jvanverth354eba52015-03-16 11:32:49 -0700615 // For general transforms, to determine the amount of correction we multiply a unit
616 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
617 // (which is the inverse transform for this fragment) and take the length of the result.
618 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));");
jvanverthd68a5502015-03-16 12:58:43 -0700619 // the length of the gradient may be 0, so we need to check for this
620 // this also compensates for the Adreno, which likes to drop tiles on division by 0
621 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
622 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
623 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
624 fsBuilder->codeAppend("} else {");
625 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
626 fsBuilder->codeAppend("}");
jvanverth354eba52015-03-16 11:32:49 -0700627 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
628 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000629
630 // this gives us a smooth step across approximately one fragment
jvanverth354eba52015-03-16 11:32:49 -0700631 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000632 }
633
jvanverth21deace2015-04-01 12:43:48 -0700634 fsBuilder->codeAppend(
635 "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
jvanverth2d2a68c2014-06-10 06:42:56 -0700636
joshualitt2dd1ae02014-12-03 06:24:10 -0800637 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000638 }
639
joshualitt465283c2015-09-11 08:19:35 -0700640 void setData(const GrGLProgramDataManager& pdman,
641 const GrPrimitiveProcessor& processor) override {
jvanverth21deace2015-04-01 12:43:48 -0700642 SkASSERT(fDistanceAdjustUni.isValid());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000643
joshualitt5559ca22015-05-21 15:50:36 -0700644 const GrDistanceFieldLCDTextGeoProc& dflcd = processor.cast<GrDistanceFieldLCDTextGeoProc>();
645 GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.getDistanceAdjust();
jvanverth21deace2015-04-01 12:43:48 -0700646 if (wa != fDistanceAdjust) {
647 pdman.set3f(fDistanceAdjustUni,
648 wa.fR,
649 wa.fG,
650 wa.fB);
651 fDistanceAdjust = wa;
jvanverth2d2a68c2014-06-10 06:42:56 -0700652 }
joshualitt9b989322014-12-15 14:16:27 -0800653
joshualitt5559ca22015-05-21 15:50:36 -0700654 if (!dflcd.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dflcd.viewMatrix())) {
655 fViewMatrix = dflcd.viewMatrix();
656 GrGLfloat viewMatrix[3 * 3];
657 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
658 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
659 }
joshualittee2af952014-12-30 09:04:15 -0800660
joshualitt5559ca22015-05-21 15:50:36 -0700661 if (dflcd.color() != fColor) {
joshualitt9b989322014-12-15 14:16:27 -0800662 GrGLfloat c[4];
joshualitt5559ca22015-05-21 15:50:36 -0700663 GrColorToRGBAFloat(dflcd.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800664 pdman.set4fv(fColorUniform, 1, c);
joshualitt5559ca22015-05-21 15:50:36 -0700665 fColor = dflcd.color();
joshualitt9b989322014-12-15 14:16:27 -0800666 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000667 }
668
robertphillips46d36f02015-01-18 08:14:14 -0800669 static inline void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700670 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700671 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700672 const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000673
joshualitt8fc6c2d2014-12-22 15:27:05 -0800674 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700675 key |= dfTexEffect.colorIgnored() << 16;
joshualitte578a952015-05-14 10:09:13 -0700676 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800677 b->add32(key);
joshualitt922c8b12015-08-07 09:55:23 -0700678
679 // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
680 SkASSERT(gp.numTextures() == 1);
681 GrTexture* atlas = gp.textureAccess(0).getTexture();
682 SkASSERT(atlas);
683 b->add32(atlas->width());
684 b->add32(atlas->height());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000685 }
686
687private:
joshualitt5559ca22015-05-21 15:50:36 -0700688 SkMatrix fViewMatrix;
jvanverth21deace2015-04-01 12:43:48 -0700689 GrColor fColor;
joshualitt5559ca22015-05-21 15:50:36 -0700690 UniformHandle fViewMatrixUniform;
jvanverth21deace2015-04-01 12:43:48 -0700691 UniformHandle fColorUniform;
jvanverth502286d2015-04-08 12:37:51 -0700692 GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust;
jvanverth21deace2015-04-01 12:43:48 -0700693 UniformHandle fDistanceAdjustUni;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000694
joshualitt249af152014-09-15 11:41:13 -0700695 typedef GrGLGeometryProcessor INHERITED;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000696};
697
698///////////////////////////////////////////////////////////////////////////////
699
jvanverth502286d2015-04-08 12:37:51 -0700700GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(
joshualitt8059eb92014-12-29 15:10:07 -0800701 GrColor color, const SkMatrix& viewMatrix,
jvanverth2d2a68c2014-06-10 06:42:56 -0700702 GrTexture* texture, const GrTextureParams& params,
jvanverth21deace2015-04-01 12:43:48 -0700703 DistanceAdjust distanceAdjust,
joshualittb8c241a2015-05-19 08:23:30 -0700704 uint32_t flags, bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700705 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700706 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800707 , fTextureAccess(texture, params)
jvanverth21deace2015-04-01 12:43:48 -0700708 , fDistanceAdjust(distanceAdjust)
joshualittb8c241a2015-05-19 08:23:30 -0700709 , fFlags(flags & kLCD_DistanceFieldEffectMask)
710 , fUsesLocalCoords(usesLocalCoords) {
jvanverth78f07182014-07-30 06:17:59 -0700711 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
jvanverth502286d2015-04-08 12:37:51 -0700712 this->initClassID<GrDistanceFieldLCDTextGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700713 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
714 kHigh_GrSLPrecision));
joshualitt71c92602015-01-14 08:12:47 -0800715 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
joshualittb8c241a2015-05-19 08:23:30 -0700716 kVec2s_GrVertexAttribType));
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000717 this->addTextureAccess(&fTextureAccess);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000718}
719
joshualitt465283c2015-09-11 08:19:35 -0700720void GrDistanceFieldLCDTextGeoProc::getGLProcessorKey(const GrGLSLCaps& caps,
jvanverth502286d2015-04-08 12:37:51 -0700721 GrProcessorKeyBuilder* b) const {
joshualitt465283c2015-09-11 08:19:35 -0700722 GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800723}
724
joshualitt465283c2015-09-11 08:19:35 -0700725GrGLPrimitiveProcessor* GrDistanceFieldLCDTextGeoProc::createGLInstance(const GrGLSLCaps&) const {
726 return new GrGLDistanceFieldLCDTextGeoProc();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000727}
728
729///////////////////////////////////////////////////////////////////////////////
730
jvanverth502286d2015-04-08 12:37:51 -0700731GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000732
bsalomonc21b09e2015-08-28 18:46:56 -0700733const GrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700734 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
735 GrProcessorUnitTest::kAlphaTextureIdx;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000736 static const SkShader::TileMode kTileModes[] = {
737 SkShader::kClamp_TileMode,
738 SkShader::kRepeat_TileMode,
739 SkShader::kMirror_TileMode,
740 };
741 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700742 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
743 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000744 };
joshualitt0067ff52015-07-08 14:26:19 -0700745 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000746 GrTextureParams::kNone_FilterMode);
jvanverth21deace2015-04-01 12:43:48 -0700747 DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
jvanverth78f07182014-07-30 06:17:59 -0700748 uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
joshualitt0067ff52015-07-08 14:26:19 -0700749 flags |= d->fRandom->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
750 flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
751 return GrDistanceFieldLCDTextGeoProc::Create(GrRandomColor(d->fRandom),
752 GrTest::TestMatrix(d->fRandom),
753 d->fTextures[texIdx], params,
jvanverth502286d2015-04-08 12:37:51 -0700754 wa,
joshualittb8c241a2015-05-19 08:23:30 -0700755 flags,
joshualitt0067ff52015-07-08 14:26:19 -0700756 d->fRandom->nextBool());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000757}