blob: 0b97bb2b94980b225dd2ed7186b6cd70d4f1a4e1 [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
wangyix6af0c932015-07-22 10:21:17 -070015#include "gl/GrGLFragmentProcessor.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
joshualitt922c8b12015-08-07 09:55:23 -070080 // compute numbers to be hardcoded to convert texture coordinates from int to float
81 SkASSERT(dfTexEffect.numTextures() == 1);
82 GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
83 SkASSERT(atlas);
84 SkScalar recipWidth = 1.0f / atlas->width();
85 SkScalar recipHeight = 1.0f / atlas->height();
86
jvanverthbb4a1cf2015-04-07 09:06:00 -070087 GrGLVertToFrag uv(kVec2f_GrSLType);
88 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
joshualitt922c8b12015-08-07 09:55:23 -070089 vsBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(),
90 SK_FLT_DECIMAL_DIG, recipWidth,
91 SK_FLT_DECIMAL_DIG, recipHeight,
jvanverthbb4a1cf2015-04-07 09:06:00 -070092 dfTexEffect.inTextureCoords()->fName);
93
jvanverthfdf7ccc2015-01-27 08:19:33 -080094 // Use highp to work around aliasing issues
95 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
96 pb->ctxInfo().standard()));
jvanverth5a105ff2015-02-18 11:36:35 -080097 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -080098
99 fsBuilder->codeAppend("\tfloat texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700100 fsBuilder->appendTextureLookup(args.fSamplers[0],
jvanverthfdf7ccc2015-01-27 08:19:33 -0800101 "uv",
jvanverth@google.comd830d132013-11-11 20:54:09 +0000102 kVec2f_GrSLType);
jvanverthfdf7ccc2015-01-27 08:19:33 -0800103 fsBuilder->codeAppend(".r;\n");
joshualitt30ba4362014-08-21 20:18:45 -0700104 fsBuilder->codeAppend("\tfloat distance = "
jvanverthfdf7ccc2015-01-27 08:19:33 -0800105 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
jvanverth21deace2015-04-01 12:43:48 -0700106#ifdef SK_GAMMA_APPLY_TO_A8
107 // adjust width based on gamma
108 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
109#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000110
jvanverth354eba52015-03-16 11:32:49 -0700111 fsBuilder->codeAppend("float afwidth;");
jvanverthbb4a1cf2015-04-07 09:06:00 -0700112 if (isSimilarity) {
jvanverth354eba52015-03-16 11:32:49 -0700113 // For uniform scale, we adjust for the effect of the transformation on the distance
114 // by using the length of the gradient of the texture coordinates. We use st coordinates
jvanverth221360a2015-04-15 12:31:22 -0700115 // to ensure we're mapping 1:1 from texel space to pixel space.
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000116
jvanverth354eba52015-03-16 11:32:49 -0700117 // this gives us a smooth step across approximately one fragment
jvanverth221360a2015-04-15 12:31:22 -0700118 // we use y to work around a Mali400 bug in the x direction
119 fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));",
jvanverthbb4a1cf2015-04-07 09:06:00 -0700120 st.fsIn());
jvanverth354eba52015-03-16 11:32:49 -0700121 } else {
122 // For general transforms, to determine the amount of correction we multiply a unit
123 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
124 // (which is the inverse transform for this fragment) and take the length of the result.
125 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
jvanverthd68a5502015-03-16 12:58:43 -0700126 // the length of the gradient may be 0, so we need to check for this
127 // this also compensates for the Adreno, which likes to drop tiles on division by 0
128 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
129 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
130 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
131 fsBuilder->codeAppend("} else {");
132 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
133 fsBuilder->codeAppend("}");
134
jvanverthbb4a1cf2015-04-07 09:06:00 -0700135 fsBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn());
136 fsBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn());
jvanverth354eba52015-03-16 11:32:49 -0700137 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
138 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000139
140 // this gives us a smooth step across approximately one fragment
jvanverth354eba52015-03-16 11:32:49 -0700141 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000142 }
jvanverth354eba52015-03-16 11:32:49 -0700143 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
jvanverth@google.comd830d132013-11-11 20:54:09 +0000144
joshualitt2dd1ae02014-12-03 06:24:10 -0800145 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000146 }
147
kkinnunen7510b222014-07-30 00:04:16 -0700148 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800149 const GrPrimitiveProcessor& proc,
mtklein36352bf2015-03-25 18:17:31 -0700150 const GrBatchTracker& bt) override {
jvanverth2d2a68c2014-06-10 06:42:56 -0700151#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth502286d2015-04-08 12:37:51 -0700152 const GrDistanceFieldA8TextGeoProc& dfTexEffect = proc.cast<GrDistanceFieldA8TextGeoProc>();
jvanverth21deace2015-04-01 12:43:48 -0700153 float distanceAdjust = dfTexEffect.getDistanceAdjust();
154 if (distanceAdjust != fDistanceAdjust) {
155 pdman.set1f(fDistanceAdjustUni, distanceAdjust);
156 fDistanceAdjust = distanceAdjust;
jvanverth2d2a68c2014-06-10 06:42:56 -0700157 }
158#endif
joshualitte578a952015-05-14 10:09:13 -0700159 const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt5559ca22015-05-21 15:50:36 -0700160
161 if (!dfa8gp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfa8gp.viewMatrix())) {
162 fViewMatrix = dfa8gp.viewMatrix();
163 GrGLfloat viewMatrix[3 * 3];
164 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
165 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
166 }
joshualittee2af952014-12-30 09:04:15 -0800167
joshualittb8c241a2015-05-19 08:23:30 -0700168 if (dfa8gp.color() != fColor && !dfa8gp.hasVertexColor()) {
joshualitt9b989322014-12-15 14:16:27 -0800169 GrGLfloat c[4];
joshualittb8c241a2015-05-19 08:23:30 -0700170 GrColorToRGBAFloat(dfa8gp.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800171 pdman.set4fv(fColorUniform, 1, c);
joshualittb8c241a2015-05-19 08:23:30 -0700172 fColor = dfa8gp.color();
joshualitt9b989322014-12-15 14:16:27 -0800173 }
commit-bot@chromium.org8fe2ee12014-03-26 18:03:05 +0000174 }
175
robertphillips46d36f02015-01-18 08:14:14 -0800176 static inline void GenKey(const GrGeometryProcessor& gp,
joshualitt9b989322014-12-15 14:16:27 -0800177 const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700178 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700179 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700180 const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800181 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700182 key |= dfTexEffect.hasVertexColor() << 16;
183 key |= dfTexEffect.colorIgnored() << 17;
joshualitte578a952015-05-14 10:09:13 -0700184 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800185 b->add32(key);
joshualitt922c8b12015-08-07 09:55:23 -0700186
187 // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
188 SkASSERT(gp.numTextures() == 1);
189 GrTexture* atlas = gp.textureAccess(0).getTexture();
190 SkASSERT(atlas);
191 b->add32(atlas->width());
192 b->add32(atlas->height());
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000193 }
194
jvanverth@google.comd830d132013-11-11 20:54:09 +0000195private:
joshualitt5559ca22015-05-21 15:50:36 -0700196 SkMatrix fViewMatrix;
joshualitt9b989322014-12-15 14:16:27 -0800197 GrColor fColor;
198 UniformHandle fColorUniform;
joshualitt5559ca22015-05-21 15:50:36 -0700199 UniformHandle fViewMatrixUniform;
mtklein50282b42015-01-22 07:59:52 -0800200#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700201 float fDistanceAdjust;
202 UniformHandle fDistanceAdjustUni;
mtklein50282b42015-01-22 07:59:52 -0800203#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000204
joshualitt249af152014-09-15 11:41:13 -0700205 typedef GrGLGeometryProcessor INHERITED;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000206};
207
208///////////////////////////////////////////////////////////////////////////////
209
jvanverth502286d2015-04-08 12:37:51 -0700210GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800211 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800212 GrTexture* texture,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000213 const GrTextureParams& params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700214#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700215 float distanceAdjust,
jvanverth2d2a68c2014-06-10 06:42:56 -0700216#endif
joshualittb8c241a2015-05-19 08:23:30 -0700217 uint32_t flags,
218 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700219 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700220 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800221 , fTextureAccess(texture, params)
jvanverth2d2a68c2014-06-10 06:42:56 -0700222#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700223 , fDistanceAdjust(distanceAdjust)
jvanverth2d2a68c2014-06-10 06:42:56 -0700224#endif
joshualitt249af152014-09-15 11:41:13 -0700225 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
joshualittb8c241a2015-05-19 08:23:30 -0700226 , fInColor(NULL)
227 , fUsesLocalCoords(usesLocalCoords) {
jvanverth78f07182014-07-30 06:17:59 -0700228 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth502286d2015-04-08 12:37:51 -0700229 this->initClassID<GrDistanceFieldA8TextGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700230 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
231 kHigh_GrSLPrecision));
joshualitt2dd1ae02014-12-03 06:24:10 -0800232 if (flags & kColorAttr_DistanceFieldEffectFlag) {
joshualitt71c92602015-01-14 08:12:47 -0800233 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt2dd1ae02014-12-03 06:24:10 -0800234 }
joshualitt71c92602015-01-14 08:12:47 -0800235 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
jvanverth5a105ff2015-02-18 11:36:35 -0800236 kVec2s_GrVertexAttribType));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000237 this->addTextureAccess(&fTextureAccess);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000238}
239
jvanverth502286d2015-04-08 12:37:51 -0700240void GrDistanceFieldA8TextGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700241 const GrGLSLCaps& caps,
joshualitteb2a6762014-12-04 11:35:33 -0800242 GrProcessorKeyBuilder* b) const {
jvanverth502286d2015-04-08 12:37:51 -0700243 GrGLDistanceFieldA8TextGeoProc::GenKey(*this, bt, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800244}
245
joshualittabb52a12015-01-13 15:02:10 -0800246GrGLPrimitiveProcessor*
jvanverth502286d2015-04-08 12:37:51 -0700247GrDistanceFieldA8TextGeoProc::createGLInstance(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700248 const GrGLSLCaps&) const {
jvanverth502286d2015-04-08 12:37:51 -0700249 return SkNEW_ARGS(GrGLDistanceFieldA8TextGeoProc, (*this, bt));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000250}
251
252///////////////////////////////////////////////////////////////////////////////
253
jvanverth502286d2015-04-08 12:37:51 -0700254GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000255
joshualitt0067ff52015-07-08 14:26:19 -0700256GrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) {
257 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
258 GrProcessorUnitTest::kAlphaTextureIdx;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000259 static const SkShader::TileMode kTileModes[] = {
260 SkShader::kClamp_TileMode,
261 SkShader::kRepeat_TileMode,
262 SkShader::kMirror_TileMode,
263 };
264 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700265 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
266 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
jvanverth@google.comd830d132013-11-11 20:54:09 +0000267 };
joshualitt0067ff52015-07-08 14:26:19 -0700268 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
jvanverth@google.comd830d132013-11-11 20:54:09 +0000269 GrTextureParams::kNone_FilterMode);
270
joshualitt0067ff52015-07-08 14:26:19 -0700271 return GrDistanceFieldA8TextGeoProc::Create(GrRandomColor(d->fRandom),
272 GrTest::TestMatrix(d->fRandom),
273 d->fTextures[texIdx], params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700274#ifdef SK_GAMMA_APPLY_TO_A8
joshualitt0067ff52015-07-08 14:26:19 -0700275 d->fRandom->nextF(),
jvanverth2d2a68c2014-06-10 06:42:56 -0700276#endif
joshualitt0067ff52015-07-08 14:26:19 -0700277 d->fRandom->nextBool() ?
joshualittb8c241a2015-05-19 08:23:30 -0700278 kSimilarity_DistanceFieldEffectFlag : 0,
joshualitt0067ff52015-07-08 14:26:19 -0700279 d->fRandom->nextBool());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000280}
281
282///////////////////////////////////////////////////////////////////////////////
283
jvanverth502286d2015-04-08 12:37:51 -0700284class GrGLDistanceFieldPathGeoProc : public GrGLGeometryProcessor {
jvanverthfa38a302014-10-06 05:59:05 -0700285public:
jvanverth502286d2015-04-08 12:37:51 -0700286 GrGLDistanceFieldPathGeoProc(const GrGeometryProcessor&,
joshualitt87f48d92014-12-04 10:41:40 -0800287 const GrBatchTracker&)
joshualitt5559ca22015-05-21 15:50:36 -0700288 : fViewMatrix(SkMatrix::InvalidMatrix())
289 , fColor(GrColor_ILLEGAL)
290 , fTextureSize(SkISize::Make(-1, -1)) {}
jvanverthfa38a302014-10-06 05:59:05 -0700291
mtklein36352bf2015-03-25 18:17:31 -0700292 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
jvanverth502286d2015-04-08 12:37:51 -0700293 const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast<GrDistanceFieldPathGeoProc>();
jvanverthfa38a302014-10-06 05:59:05 -0700294
joshualitt9b989322014-12-15 14:16:27 -0800295 GrGLGPBuilder* pb = args.fPB;
egdaniel29bee0f2015-04-29 11:54:42 -0700296 GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
jvanverthfa38a302014-10-06 05:59:05 -0700297 SkAssertResult(fsBuilder->enableFeature(
298 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
299
joshualitt2dd1ae02014-12-03 06:24:10 -0800300 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualittabb52a12015-01-13 15:02:10 -0800301
302 // emit attributes
303 vsBuilder->emitAttributes(dfTexEffect);
304
reede4ef1ca2015-02-17 18:38:38 -0800305 GrGLVertToFrag v(kVec2f_GrSLType);
jvanverth9671ecd2015-02-23 13:08:39 -0800306 args.fPB->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
jvanverthfa38a302014-10-06 05:59:05 -0700307
joshualitt9b989322014-12-15 14:16:27 -0800308 // setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -0700309 if (!dfTexEffect.colorIgnored()) {
310 if (dfTexEffect.hasVertexColor()) {
311 pb->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
312 } else {
313 this->setupUniformColor(pb, args.fOutputColor, &fColorUniform);
314 }
315 }
reede4ef1ca2015-02-17 18:38:38 -0800316 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
317
joshualittabb52a12015-01-13 15:02:10 -0800318 // Setup position
joshualitt5559ca22015-05-21 15:50:36 -0700319 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(),
320 &fViewMatrixUniform);
joshualittabb52a12015-01-13 15:02:10 -0800321
322 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -0800323 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
joshualitte3ababe2015-05-15 07:56:07 -0700324 args.fTransformsIn, args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800325
reede4ef1ca2015-02-17 18:38:38 -0800326 const char* textureSizeUniName = NULL;
327 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
328 kVec2f_GrSLType, kDefault_GrSLPrecision,
329 "TextureSize", &textureSizeUniName);
330
jvanverthfdf7ccc2015-01-27 08:19:33 -0800331 // Use highp to work around aliasing issues
332 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
333 pb->ctxInfo().standard()));
reede4ef1ca2015-02-17 18:38:38 -0800334 fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -0800335
336 fsBuilder->codeAppend("float texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700337 fsBuilder->appendTextureLookup(args.fSamplers[0],
jvanverthfdf7ccc2015-01-27 08:19:33 -0800338 "uv",
jvanverthfa38a302014-10-06 05:59:05 -0700339 kVec2f_GrSLType);
jvanverthfdf7ccc2015-01-27 08:19:33 -0800340 fsBuilder->codeAppend(".r;");
jvanverthfa38a302014-10-06 05:59:05 -0700341 fsBuilder->codeAppend("float distance = "
jvanverthfdf7ccc2015-01-27 08:19:33 -0800342 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
jvanverthfa38a302014-10-06 05:59:05 -0700343
jvanverthfdf7ccc2015-01-27 08:19:33 -0800344 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
345 pb->ctxInfo().standard()));
reede4ef1ca2015-02-17 18:38:38 -0800346 fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
jvanverthfa38a302014-10-06 05:59:05 -0700347 fsBuilder->codeAppend("float afwidth;");
348 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
jvanverth354eba52015-03-16 11:32:49 -0700349 // For uniform scale, we adjust for the effect of the transformation on the distance
350 // by using the length of the gradient of the texture coordinates. We use st coordinates
351 // to ensure we're mapping 1:1 from texel space to pixel space.
352
jvanverthfa38a302014-10-06 05:59:05 -0700353 // this gives us a smooth step across approximately one fragment
jvanverthbc027352015-04-15 13:41:31 -0700354 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));");
jvanverthfa38a302014-10-06 05:59:05 -0700355 } else {
jvanverth354eba52015-03-16 11:32:49 -0700356 // For general transforms, to determine the amount of correction we multiply a unit
357 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
358 // (which is the inverse transform for this fragment) and take the length of the result.
359 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
jvanverthd68a5502015-03-16 12:58:43 -0700360 // the length of the gradient may be 0, so we need to check for this
361 // this also compensates for the Adreno, which likes to drop tiles on division by 0
362 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
363 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
364 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
365 fsBuilder->codeAppend("} else {");
366 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
367 fsBuilder->codeAppend("}");
368
jvanverth354eba52015-03-16 11:32:49 -0700369 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
370 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
371 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
372 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
jvanverthfa38a302014-10-06 05:59:05 -0700373
374 // this gives us a smooth step across approximately one fragment
375 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
376 }
377 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
378
joshualitt2dd1ae02014-12-03 06:24:10 -0800379 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverthfa38a302014-10-06 05:59:05 -0700380 }
381
382 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800383 const GrPrimitiveProcessor& proc,
mtklein36352bf2015-03-25 18:17:31 -0700384 const GrBatchTracker& bt) override {
reede4ef1ca2015-02-17 18:38:38 -0800385 SkASSERT(fTextureSizeUni.isValid());
jvanverthfa38a302014-10-06 05:59:05 -0700386
joshualitt87f48d92014-12-04 10:41:40 -0800387 GrTexture* texture = proc.texture(0);
jvanverthfa38a302014-10-06 05:59:05 -0700388 if (texture->width() != fTextureSize.width() ||
389 texture->height() != fTextureSize.height()) {
390 fTextureSize = SkISize::Make(texture->width(), texture->height());
reede4ef1ca2015-02-17 18:38:38 -0800391 pdman.set2f(fTextureSizeUni,
392 SkIntToScalar(fTextureSize.width()),
393 SkIntToScalar(fTextureSize.height()));
jvanverthfa38a302014-10-06 05:59:05 -0700394 }
joshualitt9b989322014-12-15 14:16:27 -0800395
joshualitte578a952015-05-14 10:09:13 -0700396 const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>();
joshualitt5559ca22015-05-21 15:50:36 -0700397
398 if (!dfpgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfpgp.viewMatrix())) {
399 fViewMatrix = dfpgp.viewMatrix();
400 GrGLfloat viewMatrix[3 * 3];
401 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
402 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
403 }
joshualittee2af952014-12-30 09:04:15 -0800404
joshualittb8c241a2015-05-19 08:23:30 -0700405 if (dfpgp.color() != fColor) {
joshualitt9b989322014-12-15 14:16:27 -0800406 GrGLfloat c[4];
joshualittb8c241a2015-05-19 08:23:30 -0700407 GrColorToRGBAFloat(dfpgp.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800408 pdman.set4fv(fColorUniform, 1, c);
joshualittb8c241a2015-05-19 08:23:30 -0700409 fColor = dfpgp.color();
joshualitt9b989322014-12-15 14:16:27 -0800410 }
jvanverthfa38a302014-10-06 05:59:05 -0700411 }
412
robertphillips46d36f02015-01-18 08:14:14 -0800413 static inline void GenKey(const GrGeometryProcessor& gp,
joshualitt9b989322014-12-15 14:16:27 -0800414 const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700415 const GrGLSLCaps&,
jvanverthfa38a302014-10-06 05:59:05 -0700416 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700417 const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>();
jvanverthfa38a302014-10-06 05:59:05 -0700418
joshualitt8fc6c2d2014-12-22 15:27:05 -0800419 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700420 key |= dfTexEffect.colorIgnored() << 16;
421 key |= dfTexEffect.hasVertexColor() << 17;
joshualitte578a952015-05-14 10:09:13 -0700422 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800423 b->add32(key);
jvanverthfa38a302014-10-06 05:59:05 -0700424 }
425
426private:
joshualitt9b989322014-12-15 14:16:27 -0800427 UniformHandle fColorUniform;
reede4ef1ca2015-02-17 18:38:38 -0800428 UniformHandle fTextureSizeUni;
joshualitt5559ca22015-05-21 15:50:36 -0700429 UniformHandle fViewMatrixUniform;
430 SkMatrix fViewMatrix;
joshualitt9b989322014-12-15 14:16:27 -0800431 GrColor fColor;
432 SkISize fTextureSize;
jvanverthfa38a302014-10-06 05:59:05 -0700433
434 typedef GrGLGeometryProcessor INHERITED;
435};
436
437///////////////////////////////////////////////////////////////////////////////
438
jvanverth502286d2015-04-08 12:37:51 -0700439GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
joshualitt2e3b3e32014-12-09 13:31:14 -0800440 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800441 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800442 GrTexture* texture,
443 const GrTextureParams& params,
joshualittb8c241a2015-05-19 08:23:30 -0700444 uint32_t flags,
445 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700446 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700447 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800448 , fTextureAccess(texture, params)
jvanverthfa38a302014-10-06 05:59:05 -0700449 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
joshualittb8c241a2015-05-19 08:23:30 -0700450 , fInColor(NULL)
451 , fUsesLocalCoords(usesLocalCoords) {
jvanverthfa38a302014-10-06 05:59:05 -0700452 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth502286d2015-04-08 12:37:51 -0700453 this->initClassID<GrDistanceFieldPathGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700454 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
455 kHigh_GrSLPrecision));
joshualitt2dd1ae02014-12-03 06:24:10 -0800456 if (flags & kColorAttr_DistanceFieldEffectFlag) {
joshualitt71c92602015-01-14 08:12:47 -0800457 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt2dd1ae02014-12-03 06:24:10 -0800458 }
joshualitt71c92602015-01-14 08:12:47 -0800459 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
joshualittb8c241a2015-05-19 08:23:30 -0700460 kVec2f_GrVertexAttribType));
jvanverthfa38a302014-10-06 05:59:05 -0700461 this->addTextureAccess(&fTextureAccess);
462}
463
jvanverth502286d2015-04-08 12:37:51 -0700464void GrDistanceFieldPathGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700465 const GrGLSLCaps& caps,
jvanverth502286d2015-04-08 12:37:51 -0700466 GrProcessorKeyBuilder* b) const {
467 GrGLDistanceFieldPathGeoProc::GenKey(*this, bt, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800468}
469
joshualittabb52a12015-01-13 15:02:10 -0800470GrGLPrimitiveProcessor*
jvanverthcfc18862015-04-28 08:48:20 -0700471GrDistanceFieldPathGeoProc::createGLInstance(const GrBatchTracker& bt, const GrGLSLCaps&) const {
jvanverth502286d2015-04-08 12:37:51 -0700472 return SkNEW_ARGS(GrGLDistanceFieldPathGeoProc, (*this, bt));
jvanverthfa38a302014-10-06 05:59:05 -0700473}
474
475///////////////////////////////////////////////////////////////////////////////
476
jvanverth502286d2015-04-08 12:37:51 -0700477GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc);
jvanverthfa38a302014-10-06 05:59:05 -0700478
joshualitt0067ff52015-07-08 14:26:19 -0700479GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) {
480 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
481 : GrProcessorUnitTest::kAlphaTextureIdx;
jvanverthfa38a302014-10-06 05:59:05 -0700482 static const SkShader::TileMode kTileModes[] = {
483 SkShader::kClamp_TileMode,
484 SkShader::kRepeat_TileMode,
485 SkShader::kMirror_TileMode,
486 };
487 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700488 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
489 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
jvanverthfa38a302014-10-06 05:59:05 -0700490 };
joshualitt0067ff52015-07-08 14:26:19 -0700491 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode
492 : GrTextureParams::kNone_FilterMode);
jvanverthfa38a302014-10-06 05:59:05 -0700493
joshualitt0067ff52015-07-08 14:26:19 -0700494 return GrDistanceFieldPathGeoProc::Create(GrRandomColor(d->fRandom),
495 GrTest::TestMatrix(d->fRandom),
496 d->fTextures[texIdx],
jvanverth502286d2015-04-08 12:37:51 -0700497 params,
joshualitt0067ff52015-07-08 14:26:19 -0700498 d->fRandom->nextBool() ?
joshualittb8c241a2015-05-19 08:23:30 -0700499 kSimilarity_DistanceFieldEffectFlag : 0,
joshualitt0067ff52015-07-08 14:26:19 -0700500 d->fRandom->nextBool());
jvanverthfa38a302014-10-06 05:59:05 -0700501}
502
503///////////////////////////////////////////////////////////////////////////////
504
jvanverth502286d2015-04-08 12:37:51 -0700505class GrGLDistanceFieldLCDTextGeoProc : public GrGLGeometryProcessor {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000506public:
jvanverth502286d2015-04-08 12:37:51 -0700507 GrGLDistanceFieldLCDTextGeoProc(const GrGeometryProcessor&, const GrBatchTracker&)
joshualitt5559ca22015-05-21 15:50:36 -0700508 : fViewMatrix(SkMatrix::InvalidMatrix()), fColor(GrColor_ILLEGAL) {
jvanverth502286d2015-04-08 12:37:51 -0700509 fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f);
jvanverth21deace2015-04-01 12:43:48 -0700510 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000511
mtklein36352bf2015-03-25 18:17:31 -0700512 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
jvanverth502286d2015-04-08 12:37:51 -0700513 const GrDistanceFieldLCDTextGeoProc& dfTexEffect =
514 args.fGP.cast<GrDistanceFieldLCDTextGeoProc>();
joshualitt9b989322014-12-15 14:16:27 -0800515 GrGLGPBuilder* pb = args.fPB;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000516
joshualittc369e7c2014-10-22 10:56:26 -0700517 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualittabb52a12015-01-13 15:02:10 -0800518
519 // emit attributes
520 vsBuilder->emitAttributes(dfTexEffect);
521
joshualitt9b989322014-12-15 14:16:27 -0800522 // setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -0700523 if (!dfTexEffect.colorIgnored()) {
524 this->setupUniformColor(pb, args.fOutputColor, &fColorUniform);
525 }
joshualitt9b989322014-12-15 14:16:27 -0800526
joshualittabb52a12015-01-13 15:02:10 -0800527 // Setup position
joshualitt5559ca22015-05-21 15:50:36 -0700528 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix(),
529 &fViewMatrixUniform);
joshualitt4973d9d2014-11-08 09:24:25 -0800530
joshualittabb52a12015-01-13 15:02:10 -0800531 // emit transforms
robertphillips46d36f02015-01-18 08:14:14 -0800532 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName,
joshualitte3ababe2015-05-15 07:56:07 -0700533 args.fTransformsIn, args.fTransformsOut);
joshualittabb52a12015-01-13 15:02:10 -0800534
jvanverthbb4a1cf2015-04-07 09:06:00 -0700535 // set up varyings
536 bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
537 GrGLVertToFrag recipScale(kFloat_GrSLType);
538 GrGLVertToFrag st(kVec2f_GrSLType);
jvanverth221360a2015-04-15 12:31:22 -0700539 args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
540 vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName);
jvanverthbb4a1cf2015-04-07 09:06:00 -0700541
joshualitt922c8b12015-08-07 09:55:23 -0700542 // compute numbers to be hardcoded to convert texture coordinates from int to float
543 SkASSERT(dfTexEffect.numTextures() == 1);
544 GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
545 SkASSERT(atlas);
546 SkScalar recipWidth = 1.0f / atlas->width();
547 SkScalar recipHeight = 1.0f / atlas->height();
548
jvanverthbb4a1cf2015-04-07 09:06:00 -0700549 GrGLVertToFrag uv(kVec2f_GrSLType);
550 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
joshualitt922c8b12015-08-07 09:55:23 -0700551 vsBuilder->codeAppendf("%s = vec2(%.*f, %.*f) * %s;", uv.vsOut(),
552 SK_FLT_DECIMAL_DIG, recipWidth,
553 SK_FLT_DECIMAL_DIG, recipHeight,
jvanverthbb4a1cf2015-04-07 09:06:00 -0700554 dfTexEffect.inTextureCoords()->fName);
555
556 // add frag shader code
egdaniel29bee0f2015-04-29 11:54:42 -0700557 GrGLFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -0700558
559 SkAssertResult(fsBuilder->enableFeature(
560 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
561
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000562 // create LCD offset adjusted by inverse of transform
jvanverthfdf7ccc2015-01-27 08:19:33 -0800563 // Use highp to work around aliasing issues
564 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
565 pb->ctxInfo().standard()));
jvanverth5a105ff2015-02-18 11:36:35 -0800566 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -0800567 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision,
568 pb->ctxInfo().standard()));
joshualitt922c8b12015-08-07 09:55:23 -0700569
570 SkScalar lcdDelta = 1.0f / (3.0f * atlas->width());
jvanverth5a105ff2015-02-18 11:36:35 -0800571 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
joshualitt922c8b12015-08-07 09:55:23 -0700572 fsBuilder->codeAppendf("float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
jvanverth5a105ff2015-02-18 11:36:35 -0800573 } else {
joshualitt922c8b12015-08-07 09:55:23 -0700574 fsBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
jvanverth5a105ff2015-02-18 11:36:35 -0800575 }
jvanverth78f07182014-07-30 06:17:59 -0700576 if (isUniformScale) {
jvanverthbc027352015-04-15 13:41:31 -0700577 fsBuilder->codeAppendf("float dy = abs(dFdy(%s.y));", st.fsIn());
jvanverth221360a2015-04-15 12:31:22 -0700578 fsBuilder->codeAppend("vec2 offset = vec2(dy*delta, 0.0);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000579 } else {
jvanverthbb4a1cf2015-04-07 09:06:00 -0700580 fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn());
581
582 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
583 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
584 fsBuilder->codeAppend("vec2 offset = delta*Jdx;");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000585 }
586
587 // green is distance to uv center
joshualitt30ba4362014-08-21 20:18:45 -0700588 fsBuilder->codeAppend("\tvec4 texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700589 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700590 fsBuilder->codeAppend(";\n");
591 fsBuilder->codeAppend("\tvec3 distance;\n");
592 fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000593 // red is distance to left offset
joshualitt30ba4362014-08-21 20:18:45 -0700594 fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
595 fsBuilder->codeAppend("\ttexColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700596 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700597 fsBuilder->codeAppend(";\n");
598 fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000599 // blue is distance to right offset
joshualitt30ba4362014-08-21 20:18:45 -0700600 fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
601 fsBuilder->codeAppend("\ttexColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700602 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700603 fsBuilder->codeAppend(";\n");
604 fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700605
joshualitt30ba4362014-08-21 20:18:45 -0700606 fsBuilder->codeAppend("\tdistance = "
jvanverthada68ef2014-11-03 14:00:24 -0800607 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
jvanverth2d2a68c2014-06-10 06:42:56 -0700608
jvanverth21deace2015-04-01 12:43:48 -0700609 // adjust width based on gamma
610 const char* distanceAdjustUniName = NULL;
611 fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
612 kVec3f_GrSLType, kDefault_GrSLPrecision,
613 "DistanceAdjust", &distanceAdjustUniName);
614 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
615
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000616 // To be strictly correct, we should compute the anti-aliasing factor separately
617 // for each color component. However, this is only important when using perspective
618 // transformations, and even then using a single factor seems like a reasonable
619 // trade-off between quality and speed.
jvanverth354eba52015-03-16 11:32:49 -0700620 fsBuilder->codeAppend("float afwidth;");
jvanverth78f07182014-07-30 06:17:59 -0700621 if (isUniformScale) {
jvanverth354eba52015-03-16 11:32:49 -0700622 // For uniform scale, we adjust for the effect of the transformation on the distance
623 // by using the length of the gradient of the texture coordinates. We use st coordinates
624 // to ensure we're mapping 1:1 from texel space to pixel space.
625
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000626 // this gives us a smooth step across approximately one fragment
jvanverthbc027352015-04-15 13:41:31 -0700627 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*dy;");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000628 } else {
jvanverth354eba52015-03-16 11:32:49 -0700629 // For general transforms, to determine the amount of correction we multiply a unit
630 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
631 // (which is the inverse transform for this fragment) and take the length of the result.
632 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));");
jvanverthd68a5502015-03-16 12:58:43 -0700633 // the length of the gradient may be 0, so we need to check for this
634 // this also compensates for the Adreno, which likes to drop tiles on division by 0
635 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
636 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {");
637 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
638 fsBuilder->codeAppend("} else {");
639 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
640 fsBuilder->codeAppend("}");
jvanverth354eba52015-03-16 11:32:49 -0700641 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
642 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000643
644 // this gives us a smooth step across approximately one fragment
jvanverth354eba52015-03-16 11:32:49 -0700645 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000646 }
647
jvanverth21deace2015-04-01 12:43:48 -0700648 fsBuilder->codeAppend(
649 "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
jvanverth2d2a68c2014-06-10 06:42:56 -0700650
joshualitt2dd1ae02014-12-03 06:24:10 -0800651 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000652 }
653
kkinnunen7510b222014-07-30 00:04:16 -0700654 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800655 const GrPrimitiveProcessor& processor,
mtklein36352bf2015-03-25 18:17:31 -0700656 const GrBatchTracker& bt) override {
jvanverth21deace2015-04-01 12:43:48 -0700657 SkASSERT(fDistanceAdjustUni.isValid());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000658
joshualitt5559ca22015-05-21 15:50:36 -0700659 const GrDistanceFieldLCDTextGeoProc& dflcd = processor.cast<GrDistanceFieldLCDTextGeoProc>();
660 GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.getDistanceAdjust();
jvanverth21deace2015-04-01 12:43:48 -0700661 if (wa != fDistanceAdjust) {
662 pdman.set3f(fDistanceAdjustUni,
663 wa.fR,
664 wa.fG,
665 wa.fB);
666 fDistanceAdjust = wa;
jvanverth2d2a68c2014-06-10 06:42:56 -0700667 }
joshualitt9b989322014-12-15 14:16:27 -0800668
joshualitt5559ca22015-05-21 15:50:36 -0700669 if (!dflcd.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dflcd.viewMatrix())) {
670 fViewMatrix = dflcd.viewMatrix();
671 GrGLfloat viewMatrix[3 * 3];
672 GrGLGetMatrix<3>(viewMatrix, fViewMatrix);
673 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
674 }
joshualittee2af952014-12-30 09:04:15 -0800675
joshualitt5559ca22015-05-21 15:50:36 -0700676 if (dflcd.color() != fColor) {
joshualitt9b989322014-12-15 14:16:27 -0800677 GrGLfloat c[4];
joshualitt5559ca22015-05-21 15:50:36 -0700678 GrColorToRGBAFloat(dflcd.color(), c);
joshualitt9b989322014-12-15 14:16:27 -0800679 pdman.set4fv(fColorUniform, 1, c);
joshualitt5559ca22015-05-21 15:50:36 -0700680 fColor = dflcd.color();
joshualitt9b989322014-12-15 14:16:27 -0800681 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000682 }
683
robertphillips46d36f02015-01-18 08:14:14 -0800684 static inline void GenKey(const GrGeometryProcessor& gp,
joshualitt9b989322014-12-15 14:16:27 -0800685 const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700686 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700687 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700688 const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000689
joshualitt8fc6c2d2014-12-22 15:27:05 -0800690 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700691 key |= dfTexEffect.colorIgnored() << 16;
joshualitte578a952015-05-14 10:09:13 -0700692 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800693 b->add32(key);
joshualitt922c8b12015-08-07 09:55:23 -0700694
695 // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
696 SkASSERT(gp.numTextures() == 1);
697 GrTexture* atlas = gp.textureAccess(0).getTexture();
698 SkASSERT(atlas);
699 b->add32(atlas->width());
700 b->add32(atlas->height());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000701 }
702
703private:
joshualitt5559ca22015-05-21 15:50:36 -0700704 SkMatrix fViewMatrix;
jvanverth21deace2015-04-01 12:43:48 -0700705 GrColor fColor;
joshualitt5559ca22015-05-21 15:50:36 -0700706 UniformHandle fViewMatrixUniform;
jvanverth21deace2015-04-01 12:43:48 -0700707 UniformHandle fColorUniform;
jvanverth502286d2015-04-08 12:37:51 -0700708 GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust;
jvanverth21deace2015-04-01 12:43:48 -0700709 UniformHandle fDistanceAdjustUni;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000710
joshualitt249af152014-09-15 11:41:13 -0700711 typedef GrGLGeometryProcessor INHERITED;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000712};
713
714///////////////////////////////////////////////////////////////////////////////
715
jvanverth502286d2015-04-08 12:37:51 -0700716GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(
joshualitt8059eb92014-12-29 15:10:07 -0800717 GrColor color, const SkMatrix& viewMatrix,
jvanverth2d2a68c2014-06-10 06:42:56 -0700718 GrTexture* texture, const GrTextureParams& params,
jvanverth21deace2015-04-01 12:43:48 -0700719 DistanceAdjust distanceAdjust,
joshualittb8c241a2015-05-19 08:23:30 -0700720 uint32_t flags, bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700721 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700722 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800723 , fTextureAccess(texture, params)
jvanverth21deace2015-04-01 12:43:48 -0700724 , fDistanceAdjust(distanceAdjust)
joshualittb8c241a2015-05-19 08:23:30 -0700725 , fFlags(flags & kLCD_DistanceFieldEffectMask)
726 , fUsesLocalCoords(usesLocalCoords) {
jvanverth78f07182014-07-30 06:17:59 -0700727 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
jvanverth502286d2015-04-08 12:37:51 -0700728 this->initClassID<GrDistanceFieldLCDTextGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700729 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
730 kHigh_GrSLPrecision));
joshualitt71c92602015-01-14 08:12:47 -0800731 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
joshualittb8c241a2015-05-19 08:23:30 -0700732 kVec2s_GrVertexAttribType));
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000733 this->addTextureAccess(&fTextureAccess);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000734}
735
jvanverth502286d2015-04-08 12:37:51 -0700736void GrDistanceFieldLCDTextGeoProc::getGLProcessorKey(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700737 const GrGLSLCaps& caps,
jvanverth502286d2015-04-08 12:37:51 -0700738 GrProcessorKeyBuilder* b) const {
739 GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, bt, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800740}
741
joshualittabb52a12015-01-13 15:02:10 -0800742GrGLPrimitiveProcessor*
jvanverth502286d2015-04-08 12:37:51 -0700743GrDistanceFieldLCDTextGeoProc::createGLInstance(const GrBatchTracker& bt,
jvanverthcfc18862015-04-28 08:48:20 -0700744 const GrGLSLCaps&) const {
jvanverth502286d2015-04-08 12:37:51 -0700745 return SkNEW_ARGS(GrGLDistanceFieldLCDTextGeoProc, (*this, bt));
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000746}
747
748///////////////////////////////////////////////////////////////////////////////
749
jvanverth502286d2015-04-08 12:37:51 -0700750GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000751
joshualitt0067ff52015-07-08 14:26:19 -0700752GrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) {
753 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
754 GrProcessorUnitTest::kAlphaTextureIdx;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000755 static const SkShader::TileMode kTileModes[] = {
756 SkShader::kClamp_TileMode,
757 SkShader::kRepeat_TileMode,
758 SkShader::kMirror_TileMode,
759 };
760 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700761 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
762 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000763 };
joshualitt0067ff52015-07-08 14:26:19 -0700764 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000765 GrTextureParams::kNone_FilterMode);
jvanverth21deace2015-04-01 12:43:48 -0700766 DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
jvanverth78f07182014-07-30 06:17:59 -0700767 uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
joshualitt0067ff52015-07-08 14:26:19 -0700768 flags |= d->fRandom->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
769 flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
770 return GrDistanceFieldLCDTextGeoProc::Create(GrRandomColor(d->fRandom),
771 GrTest::TestMatrix(d->fRandom),
772 d->fTextures[texIdx], params,
jvanverth502286d2015-04-08 12:37:51 -0700773 wa,
joshualittb8c241a2015-05-19 08:23:30 -0700774 flags,
joshualitt0067ff52015-07-08 14:26:19 -0700775 d->fRandom->nextBool());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000776}