blob: 7d474a16e157ca7f65c1dc8338d466793c1200f2 [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
egdaniel2d721d32015-11-11 13:06:05 -080014#include "glsl/GrGLSLFragmentShaderBuilder.h"
egdaniele659a582015-11-13 09:55:43 -080015#include "glsl/GrGLSLGeometryProcessor.h"
egdaniel018fb622015-10-28 07:26:40 -070016#include "glsl/GrGLSLProgramDataManager.h"
egdaniel7ea439b2015-12-03 09:20:44 -080017#include "glsl/GrGLSLUniformHandler.h"
egdaniel64c47282015-11-13 06:54:19 -080018#include "glsl/GrGLSLUtil.h"
egdaniel0eafe792015-11-20 14:01:22 -080019#include "glsl/GrGLSLVarying.h"
20#include "glsl/GrGLSLVertexShaderBuilder.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000021
jvanverth21deace2015-04-01 12:43:48 -070022// Assuming a radius of a little less than the diagonal of the fragment
jvanverth24ba0082015-03-19 11:34:13 -070023#define SK_DistanceFieldAAFactor "0.65"
jvanverth2d2a68c2014-06-10 06:42:56 -070024
egdaniele659a582015-11-13 09:55:43 -080025class GrGLDistanceFieldA8TextGeoProc : public GrGLSLGeometryProcessor {
jvanverth@google.comd830d132013-11-11 20:54:09 +000026public:
joshualitt465283c2015-09-11 08:19:35 -070027 GrGLDistanceFieldA8TextGeoProc()
joshualitt5559ca22015-05-21 15:50:36 -070028 : fViewMatrix(SkMatrix::InvalidMatrix())
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>();
cdalton85285412016-02-18 12:37:07 -080037 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel4ca2e602015-11-18 08:01:26 -080038 SkAssertResult(fragBuilder->enableFeature(
egdaniel2d721d32015-11-11 13:06:05 -080039 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
jvanverth@google.comd830d132013-11-11 20:54:09 +000040
egdaniel4ca2e602015-11-18 08:01:26 -080041 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -080042 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -080043 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
joshualittabb52a12015-01-13 15:02:10 -080044
45 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -080046 varyingHandler->emitAttributes(dfTexEffect);
joshualittabb52a12015-01-13 15:02:10 -080047
jvanverth21deace2015-04-01 12:43:48 -070048#ifdef SK_GAMMA_APPLY_TO_A8
49 // adjust based on gamma
halcanary96fcdcc2015-08-27 07:41:13 -070050 const char* distanceAdjustUniName = nullptr;
jvanverth21deace2015-04-01 12:43:48 -070051 // width, height, 1/(3*width)
cdalton5e58cee2016-02-11 12:49:47 -080052 fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -080053 kFloat_GrSLType, kDefault_GrSLPrecision,
54 "DistanceAdjust", &distanceAdjustUniName);
jvanverth21deace2015-04-01 12:43:48 -070055#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000056
joshualitt9b989322014-12-15 14:16:27 -080057 // Setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -070058 if (!dfTexEffect.colorIgnored()) {
joshualitt53f26aa2015-12-10 07:29:54 -080059 varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -070060 }
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000061
joshualittabb52a12015-01-13 15:02:10 -080062 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -080063 this->setupPosition(vertBuilder,
64 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -080065 gpArgs,
66 dfTexEffect.inPosition()->fName,
67 dfTexEffect.viewMatrix(),
joshualitt5559ca22015-05-21 15:50:36 -070068 &fViewMatrixUniform);
joshualitt2dd1ae02014-12-03 06:24:10 -080069
joshualittabb52a12015-01-13 15:02:10 -080070 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -080071 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -080072 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -080073 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -080074 gpArgs->fPositionVar,
75 dfTexEffect.inPosition()->fName,
76 args.fTransformsIn,
77 args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -080078
jvanverthbb4a1cf2015-04-07 09:06:00 -070079 // add varyings
egdaniel8dcdedc2015-11-11 06:27:20 -080080 GrGLSLVertToFrag recipScale(kFloat_GrSLType);
jvanverth7023a002016-02-22 11:25:32 -080081 GrGLSLVertToFrag uv(kVec2f_GrSLType);
jvanverthcf371bb2016-03-10 11:10:43 -080082 bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
83 kUniformScale_DistanceFieldEffectMask;
jvanverthbb4a1cf2015-04-07 09:06:00 -070084 bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
jvanverth7023a002016-02-22 11:25:32 -080085 varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
86 vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName);
jvanverthbb4a1cf2015-04-07 09:06:00 -070087
jvanverthcf371bb2016-03-10 11:10:43 -080088 // compute numbers to be hardcoded to convert texture coordinates from float to int
joshualitt922c8b12015-08-07 09:55:23 -070089 SkASSERT(dfTexEffect.numTextures() == 1);
90 GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
joshualitt7375d6b2015-08-07 13:36:44 -070091 SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
joshualitt922c8b12015-08-07 09:55:23 -070092
jvanverth7023a002016-02-22 11:25:32 -080093 GrGLSLVertToFrag st(kVec2f_GrSLType);
94 varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
95 vertBuilder->codeAppendf("%s = vec2(%d, %d) * %s;", st.vsOut(),
96 atlas->width(), atlas->height(),
egdaniel4ca2e602015-11-18 08:01:26 -080097 dfTexEffect.inTextureCoords()->fName);
halcanary9d524f22016-03-29 09:03:52 -070098
jvanverthfdf7ccc2015-01-27 08:19:33 -080099 // Use highp to work around aliasing issues
egdaniela2e3e0f2015-11-19 07:23:45 -0800100 fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800101 kHigh_GrSLPrecision));
102 fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -0800103
egdaniel4ca2e602015-11-18 08:01:26 -0800104 fragBuilder->codeAppend("\tfloat texColor = ");
105 fragBuilder->appendTextureLookup(args.fSamplers[0],
106 "uv",
107 kVec2f_GrSLType);
108 fragBuilder->codeAppend(".r;\n");
109 fragBuilder->codeAppend("\tfloat distance = "
jvanverthfdf7ccc2015-01-27 08:19:33 -0800110 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
jvanverth21deace2015-04-01 12:43:48 -0700111#ifdef SK_GAMMA_APPLY_TO_A8
112 // adjust width based on gamma
egdaniel4ca2e602015-11-18 08:01:26 -0800113 fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
jvanverth21deace2015-04-01 12:43:48 -0700114#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000115
egdaniel4ca2e602015-11-18 08:01:26 -0800116 fragBuilder->codeAppend("float afwidth;");
jvanverthcf371bb2016-03-10 11:10:43 -0800117 if (isUniformScale) {
jvanverth354eba52015-03-16 11:32:49 -0700118 // For uniform scale, we adjust for the effect of the transformation on the distance
halcanary9d524f22016-03-29 09:03:52 -0700119 // by using the length of the gradient of the t coordinate in the y direction.
jvanverthcf371bb2016-03-10 11:10:43 -0800120 // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space.
121 // We use the y gradient because there is a bug in the Mali 400 in the x direction.
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000122
jvanverth354eba52015-03-16 11:32:49 -0700123 // this gives us a smooth step across approximately one fragment
egdaniel4ca2e602015-11-18 08:01:26 -0800124 fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(%s.y));",
125 st.fsIn());
jvanverthcf371bb2016-03-10 11:10:43 -0800126 } else if (isSimilarity) {
127 // For similarity transform, we adjust the effect of the transformation on the distance
128 // by using the length of the gradient of the texture coordinates. We use st coordinates
129 // to ensure we're mapping 1:1 from texel space to pixel space.
130 // We use the y gradient because there is a bug in the Mali 400 in the x direction.
131
132 // this gives us a smooth step across approximately one fragment
133 fragBuilder->codeAppendf("float st_grad_len = length(dFdy(%s));", st.fsIn());
134 fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);");
jvanverth354eba52015-03-16 11:32:49 -0700135 } else {
136 // For general transforms, to determine the amount of correction we multiply a unit
137 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
138 // (which is the inverse transform for this fragment) and take the length of the result.
egdaniel4ca2e602015-11-18 08:01:26 -0800139 fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
jvanverthd68a5502015-03-16 12:58:43 -0700140 // the length of the gradient may be 0, so we need to check for this
141 // this also compensates for the Adreno, which likes to drop tiles on division by 0
egdaniel4ca2e602015-11-18 08:01:26 -0800142 fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
143 fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
144 fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
145 fragBuilder->codeAppend("} else {");
146 fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
147 fragBuilder->codeAppend("}");
jvanverthd68a5502015-03-16 12:58:43 -0700148
egdaniel4ca2e602015-11-18 08:01:26 -0800149 fragBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn());
150 fragBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn());
151 fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
152 fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000153
154 // this gives us a smooth step across approximately one fragment
egdaniel4ca2e602015-11-18 08:01:26 -0800155 fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000156 }
egdaniel4ca2e602015-11-18 08:01:26 -0800157 fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
jvanverth@google.comd830d132013-11-11 20:54:09 +0000158
egdaniel4ca2e602015-11-18 08:01:26 -0800159 fragBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000160 }
161
egdaniel018fb622015-10-28 07:26:40 -0700162 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc) override {
jvanverth2d2a68c2014-06-10 06:42:56 -0700163#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth502286d2015-04-08 12:37:51 -0700164 const GrDistanceFieldA8TextGeoProc& dfTexEffect = proc.cast<GrDistanceFieldA8TextGeoProc>();
jvanverth21deace2015-04-01 12:43:48 -0700165 float distanceAdjust = dfTexEffect.getDistanceAdjust();
166 if (distanceAdjust != fDistanceAdjust) {
167 pdman.set1f(fDistanceAdjustUni, distanceAdjust);
168 fDistanceAdjust = distanceAdjust;
jvanverth2d2a68c2014-06-10 06:42:56 -0700169 }
170#endif
joshualitte578a952015-05-14 10:09:13 -0700171 const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt5559ca22015-05-21 15:50:36 -0700172
173 if (!dfa8gp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfa8gp.viewMatrix())) {
174 fViewMatrix = dfa8gp.viewMatrix();
egdaniel018fb622015-10-28 07:26:40 -0700175 float viewMatrix[3 * 3];
egdaniel64c47282015-11-13 06:54:19 -0800176 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
joshualitt5559ca22015-05-21 15:50:36 -0700177 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
178 }
commit-bot@chromium.org8fe2ee12014-03-26 18:03:05 +0000179 }
180
robertphillips46d36f02015-01-18 08:14:14 -0800181 static inline void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700182 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700183 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700184 const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800185 uint32_t key = dfTexEffect.getFlags();
joshualitt53f26aa2015-12-10 07:29:54 -0800186 key |= dfTexEffect.colorIgnored() << 16;
joshualitte578a952015-05-14 10:09:13 -0700187 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800188 b->add32(key);
joshualitt922c8b12015-08-07 09:55:23 -0700189
190 // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
191 SkASSERT(gp.numTextures() == 1);
192 GrTexture* atlas = gp.textureAccess(0).getTexture();
193 SkASSERT(atlas);
194 b->add32(atlas->width());
195 b->add32(atlas->height());
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000196 }
197
jvanverth@google.comd830d132013-11-11 20:54:09 +0000198private:
joshualitt5559ca22015-05-21 15:50:36 -0700199 SkMatrix fViewMatrix;
joshualitt5559ca22015-05-21 15:50:36 -0700200 UniformHandle fViewMatrixUniform;
mtklein50282b42015-01-22 07:59:52 -0800201#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700202 float fDistanceAdjust;
203 UniformHandle fDistanceAdjustUni;
mtklein50282b42015-01-22 07:59:52 -0800204#endif
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000205
egdaniele659a582015-11-13 09:55:43 -0800206 typedef GrGLSLGeometryProcessor INHERITED;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000207};
208
209///////////////////////////////////////////////////////////////////////////////
210
jvanverth502286d2015-04-08 12:37:51 -0700211GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800212 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800213 GrTexture* texture,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000214 const GrTextureParams& params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700215#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700216 float distanceAdjust,
jvanverth2d2a68c2014-06-10 06:42:56 -0700217#endif
joshualittb8c241a2015-05-19 08:23:30 -0700218 uint32_t flags,
219 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700220 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700221 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800222 , fTextureAccess(texture, params)
jvanverth2d2a68c2014-06-10 06:42:56 -0700223#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth21deace2015-04-01 12:43:48 -0700224 , fDistanceAdjust(distanceAdjust)
jvanverth2d2a68c2014-06-10 06:42:56 -0700225#endif
joshualitt249af152014-09-15 11:41:13 -0700226 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
halcanary96fcdcc2015-08-27 07:41:13 -0700227 , fInColor(nullptr)
joshualittb8c241a2015-05-19 08:23:30 -0700228 , fUsesLocalCoords(usesLocalCoords) {
jvanverth78f07182014-07-30 06:17:59 -0700229 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth502286d2015-04-08 12:37:51 -0700230 this->initClassID<GrDistanceFieldA8TextGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700231 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
232 kHigh_GrSLPrecision));
joshualitt53f26aa2015-12-10 07:29:54 -0800233 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800234 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
jvanverth7023a002016-02-22 11:25:32 -0800235 kVec2us_GrVertexAttribType,
236 kHigh_GrSLPrecision));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000237 this->addTextureAccess(&fTextureAccess);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000238}
239
egdaniel57d3b032015-11-13 11:57:27 -0800240void GrDistanceFieldA8TextGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps,
241 GrProcessorKeyBuilder* b) const {
joshualitt465283c2015-09-11 08:19:35 -0700242 GrGLDistanceFieldA8TextGeoProc::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800243}
244
egdaniel57d3b032015-11-13 11:57:27 -0800245GrGLSLPrimitiveProcessor* GrDistanceFieldA8TextGeoProc::createGLSLInstance(const GrGLSLCaps&) const {
joshualitt465283c2015-09-11 08:19:35 -0700246 return new GrGLDistanceFieldA8TextGeoProc();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000247}
248
249///////////////////////////////////////////////////////////////////////////////
250
jvanverth502286d2015-04-08 12:37:51 -0700251GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000252
bsalomonc21b09e2015-08-28 18:46:56 -0700253const GrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700254 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
255 GrProcessorUnitTest::kAlphaTextureIdx;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000256 static const SkShader::TileMode kTileModes[] = {
257 SkShader::kClamp_TileMode,
258 SkShader::kRepeat_TileMode,
259 SkShader::kMirror_TileMode,
260 };
261 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700262 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
263 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
jvanverth@google.comd830d132013-11-11 20:54:09 +0000264 };
joshualitt0067ff52015-07-08 14:26:19 -0700265 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
jvanverth@google.comd830d132013-11-11 20:54:09 +0000266 GrTextureParams::kNone_FilterMode);
267
jvanverthcf371bb2016-03-10 11:10:43 -0800268 uint32_t flags = 0;
269 flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
270 if (flags & kSimilarity_DistanceFieldEffectFlag) {
271 flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
272 }
273
joshualitt0067ff52015-07-08 14:26:19 -0700274 return GrDistanceFieldA8TextGeoProc::Create(GrRandomColor(d->fRandom),
275 GrTest::TestMatrix(d->fRandom),
276 d->fTextures[texIdx], params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700277#ifdef SK_GAMMA_APPLY_TO_A8
joshualitt0067ff52015-07-08 14:26:19 -0700278 d->fRandom->nextF(),
jvanverth2d2a68c2014-06-10 06:42:56 -0700279#endif
jvanverthcf371bb2016-03-10 11:10:43 -0800280 flags,
281 d->fRandom->nextBool());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000282}
283
284///////////////////////////////////////////////////////////////////////////////
285
egdaniele659a582015-11-13 09:55:43 -0800286class GrGLDistanceFieldPathGeoProc : public GrGLSLGeometryProcessor {
jvanverthfa38a302014-10-06 05:59:05 -0700287public:
joshualitt465283c2015-09-11 08:19:35 -0700288 GrGLDistanceFieldPathGeoProc()
joshualitt5559ca22015-05-21 15:50:36 -0700289 : fViewMatrix(SkMatrix::InvalidMatrix())
joshualitt5559ca22015-05-21 15:50:36 -0700290 , 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
cdalton85285412016-02-18 12:37:07 -0800295 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
egdaniel4ca2e602015-11-18 08:01:26 -0800296 SkAssertResult(fragBuilder->enableFeature(
egdaniel2d721d32015-11-11 13:06:05 -0800297 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
jvanverthfa38a302014-10-06 05:59:05 -0700298
egdaniel4ca2e602015-11-18 08:01:26 -0800299 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800300 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800301 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
joshualittabb52a12015-01-13 15:02:10 -0800302
303 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800304 varyingHandler->emitAttributes(dfTexEffect);
joshualittabb52a12015-01-13 15:02:10 -0800305
egdaniel8dcdedc2015-11-11 06:27:20 -0800306 GrGLSLVertToFrag v(kVec2f_GrSLType);
egdaniel0eafe792015-11-20 14:01:22 -0800307 varyingHandler->addVarying("TextureCoords", &v, kHigh_GrSLPrecision);
jvanverthfa38a302014-10-06 05:59:05 -0700308
joshualitt9b989322014-12-15 14:16:27 -0800309 // setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -0700310 if (!dfTexEffect.colorIgnored()) {
joshualitt53f26aa2015-12-10 07:29:54 -0800311 varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -0700312 }
egdaniel4ca2e602015-11-18 08:01:26 -0800313 vertBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
reede4ef1ca2015-02-17 18:38:38 -0800314
joshualittabb52a12015-01-13 15:02:10 -0800315 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -0800316 this->setupPosition(vertBuilder,
317 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800318 gpArgs,
319 dfTexEffect.inPosition()->fName,
320 dfTexEffect.viewMatrix(),
joshualitt5559ca22015-05-21 15:50:36 -0700321 &fViewMatrixUniform);
joshualittabb52a12015-01-13 15:02:10 -0800322
323 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800324 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800325 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800326 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800327 gpArgs->fPositionVar,
328 dfTexEffect.inPosition()->fName,
329 args.fTransformsIn,
330 args.fTransformsOut);
joshualitt4973d9d2014-11-08 09:24:25 -0800331
halcanary96fcdcc2015-08-27 07:41:13 -0700332 const char* textureSizeUniName = nullptr;
cdalton5e58cee2016-02-11 12:49:47 -0800333 fTextureSizeUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800334 kVec2f_GrSLType, kDefault_GrSLPrecision,
335 "TextureSize", &textureSizeUniName);
reede4ef1ca2015-02-17 18:38:38 -0800336
jvanverthfdf7ccc2015-01-27 08:19:33 -0800337 // Use highp to work around aliasing issues
egdaniela2e3e0f2015-11-19 07:23:45 -0800338 fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800339 kHigh_GrSLPrecision));
340 fragBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
jvanverthfdf7ccc2015-01-27 08:19:33 -0800341
egdaniel4ca2e602015-11-18 08:01:26 -0800342 fragBuilder->codeAppend("float texColor = ");
343 fragBuilder->appendTextureLookup(args.fSamplers[0],
344 "uv",
345 kVec2f_GrSLType);
346 fragBuilder->codeAppend(".r;");
347 fragBuilder->codeAppend("float distance = "
jvanverthfdf7ccc2015-01-27 08:19:33 -0800348 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");");
jvanverthfa38a302014-10-06 05:59:05 -0700349
egdaniela2e3e0f2015-11-19 07:23:45 -0800350 fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800351 kHigh_GrSLPrecision));
352 fragBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
353 fragBuilder->codeAppend("float afwidth;");
jvanverthcf371bb2016-03-10 11:10:43 -0800354 bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
355 kUniformScale_DistanceFieldEffectMask;
356 bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
357 if (isUniformScale) {
jvanverth354eba52015-03-16 11:32:49 -0700358 // For uniform scale, we adjust for the effect of the transformation on the distance
halcanary9d524f22016-03-29 09:03:52 -0700359 // by using the length of the gradient of the t coordinate in the y direction.
jvanverthcf371bb2016-03-10 11:10:43 -0800360 // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space.
361 // We use the y gradient because there is a bug in the Mali 400 in the x direction.
jvanverth354eba52015-03-16 11:32:49 -0700362
jvanverthfa38a302014-10-06 05:59:05 -0700363 // this gives us a smooth step across approximately one fragment
egdaniel4ca2e602015-11-18 08:01:26 -0800364 fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdy(st.y));");
jvanverthcf371bb2016-03-10 11:10:43 -0800365
366 } else if (isSimilarity) {
367 // For similarity transform, we adjust the effect of the transformation on the distance
368 // by using the length of the gradient of the texture coordinates. We use st coordinates
369 // to ensure we're mapping 1:1 from texel space to pixel space.
370 // We use the y gradient because there is a bug in the Mali 400 in the x direction.
371
372 // this gives us a smooth step across approximately one fragment
373 fragBuilder->codeAppend("float st_grad_len = length(dFdy(st));");
374 fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);");
jvanverthfa38a302014-10-06 05:59:05 -0700375 } else {
jvanverth354eba52015-03-16 11:32:49 -0700376 // For general transforms, to determine the amount of correction we multiply a unit
377 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
378 // (which is the inverse transform for this fragment) and take the length of the result.
egdaniel4ca2e602015-11-18 08:01:26 -0800379 fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));");
jvanverthd68a5502015-03-16 12:58:43 -0700380 // the length of the gradient may be 0, so we need to check for this
381 // this also compensates for the Adreno, which likes to drop tiles on division by 0
egdaniel4ca2e602015-11-18 08:01:26 -0800382 fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
383 fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
384 fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
385 fragBuilder->codeAppend("} else {");
386 fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
387 fragBuilder->codeAppend("}");
jvanverthd68a5502015-03-16 12:58:43 -0700388
egdaniel4ca2e602015-11-18 08:01:26 -0800389 fragBuilder->codeAppend("vec2 Jdx = dFdx(st);");
390 fragBuilder->codeAppend("vec2 Jdy = dFdy(st);");
391 fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
392 fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
jvanverthfa38a302014-10-06 05:59:05 -0700393
394 // this gives us a smooth step across approximately one fragment
egdaniel4ca2e602015-11-18 08:01:26 -0800395 fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
jvanverthfa38a302014-10-06 05:59:05 -0700396 }
egdaniel4ca2e602015-11-18 08:01:26 -0800397 fragBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
jvanverthfa38a302014-10-06 05:59:05 -0700398
egdaniel4ca2e602015-11-18 08:01:26 -0800399 fragBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverthfa38a302014-10-06 05:59:05 -0700400 }
401
egdaniel018fb622015-10-28 07:26:40 -0700402 void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc) override {
reede4ef1ca2015-02-17 18:38:38 -0800403 SkASSERT(fTextureSizeUni.isValid());
jvanverthfa38a302014-10-06 05:59:05 -0700404
joshualitt87f48d92014-12-04 10:41:40 -0800405 GrTexture* texture = proc.texture(0);
halcanary9d524f22016-03-29 09:03:52 -0700406 if (texture->width() != fTextureSize.width() ||
jvanverthfa38a302014-10-06 05:59:05 -0700407 texture->height() != fTextureSize.height()) {
408 fTextureSize = SkISize::Make(texture->width(), texture->height());
reede4ef1ca2015-02-17 18:38:38 -0800409 pdman.set2f(fTextureSizeUni,
410 SkIntToScalar(fTextureSize.width()),
411 SkIntToScalar(fTextureSize.height()));
jvanverthfa38a302014-10-06 05:59:05 -0700412 }
joshualitt9b989322014-12-15 14:16:27 -0800413
joshualitte578a952015-05-14 10:09:13 -0700414 const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>();
joshualitt5559ca22015-05-21 15:50:36 -0700415
416 if (!dfpgp.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dfpgp.viewMatrix())) {
417 fViewMatrix = dfpgp.viewMatrix();
egdaniel018fb622015-10-28 07:26:40 -0700418 float viewMatrix[3 * 3];
egdaniel64c47282015-11-13 06:54:19 -0800419 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
joshualitt5559ca22015-05-21 15:50:36 -0700420 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
421 }
jvanverthfa38a302014-10-06 05:59:05 -0700422 }
423
robertphillips46d36f02015-01-18 08:14:14 -0800424 static inline void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700425 const GrGLSLCaps&,
jvanverthfa38a302014-10-06 05:59:05 -0700426 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700427 const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>();
jvanverthfa38a302014-10-06 05:59:05 -0700428
joshualitt8fc6c2d2014-12-22 15:27:05 -0800429 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700430 key |= dfTexEffect.colorIgnored() << 16;
joshualitte578a952015-05-14 10:09:13 -0700431 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800432 b->add32(key);
jvanverthfa38a302014-10-06 05:59:05 -0700433 }
434
435private:
reede4ef1ca2015-02-17 18:38:38 -0800436 UniformHandle fTextureSizeUni;
joshualitt5559ca22015-05-21 15:50:36 -0700437 UniformHandle fViewMatrixUniform;
438 SkMatrix fViewMatrix;
joshualitt9b989322014-12-15 14:16:27 -0800439 SkISize fTextureSize;
jvanverthfa38a302014-10-06 05:59:05 -0700440
egdaniele659a582015-11-13 09:55:43 -0800441 typedef GrGLSLGeometryProcessor INHERITED;
jvanverthfa38a302014-10-06 05:59:05 -0700442};
443
444///////////////////////////////////////////////////////////////////////////////
445
jvanverth502286d2015-04-08 12:37:51 -0700446GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(
joshualitt2e3b3e32014-12-09 13:31:14 -0800447 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800448 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800449 GrTexture* texture,
450 const GrTextureParams& params,
joshualittb8c241a2015-05-19 08:23:30 -0700451 uint32_t flags,
452 bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700453 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700454 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800455 , fTextureAccess(texture, params)
jvanverthfa38a302014-10-06 05:59:05 -0700456 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
halcanary96fcdcc2015-08-27 07:41:13 -0700457 , fInColor(nullptr)
joshualittb8c241a2015-05-19 08:23:30 -0700458 , fUsesLocalCoords(usesLocalCoords) {
jvanverthfa38a302014-10-06 05:59:05 -0700459 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth502286d2015-04-08 12:37:51 -0700460 this->initClassID<GrDistanceFieldPathGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700461 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
462 kHigh_GrSLPrecision));
joshualitt53f26aa2015-12-10 07:29:54 -0800463 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800464 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
joshualittb8c241a2015-05-19 08:23:30 -0700465 kVec2f_GrVertexAttribType));
jvanverthfa38a302014-10-06 05:59:05 -0700466 this->addTextureAccess(&fTextureAccess);
467}
468
egdaniel57d3b032015-11-13 11:57:27 -0800469void GrDistanceFieldPathGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps,
470 GrProcessorKeyBuilder* b) const {
joshualitt465283c2015-09-11 08:19:35 -0700471 GrGLDistanceFieldPathGeoProc::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800472}
473
egdaniel57d3b032015-11-13 11:57:27 -0800474GrGLSLPrimitiveProcessor* GrDistanceFieldPathGeoProc::createGLSLInstance(const GrGLSLCaps&) const {
joshualitt465283c2015-09-11 08:19:35 -0700475 return new GrGLDistanceFieldPathGeoProc();
jvanverthfa38a302014-10-06 05:59:05 -0700476}
477
478///////////////////////////////////////////////////////////////////////////////
479
jvanverth502286d2015-04-08 12:37:51 -0700480GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc);
jvanverthfa38a302014-10-06 05:59:05 -0700481
bsalomonc21b09e2015-08-28 18:46:56 -0700482const GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700483 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
484 : GrProcessorUnitTest::kAlphaTextureIdx;
jvanverthfa38a302014-10-06 05:59:05 -0700485 static const SkShader::TileMode kTileModes[] = {
486 SkShader::kClamp_TileMode,
487 SkShader::kRepeat_TileMode,
488 SkShader::kMirror_TileMode,
489 };
490 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700491 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
492 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
jvanverthfa38a302014-10-06 05:59:05 -0700493 };
joshualitt0067ff52015-07-08 14:26:19 -0700494 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode
495 : GrTextureParams::kNone_FilterMode);
jvanverthfa38a302014-10-06 05:59:05 -0700496
jvanverthcf371bb2016-03-10 11:10:43 -0800497 uint32_t flags = 0;
498 flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
499 if (flags & kSimilarity_DistanceFieldEffectFlag) {
500 flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
501 }
502
joshualitt0067ff52015-07-08 14:26:19 -0700503 return GrDistanceFieldPathGeoProc::Create(GrRandomColor(d->fRandom),
504 GrTest::TestMatrix(d->fRandom),
505 d->fTextures[texIdx],
jvanverth502286d2015-04-08 12:37:51 -0700506 params,
jvanverthcf371bb2016-03-10 11:10:43 -0800507 flags,
508 d->fRandom->nextBool());
jvanverthfa38a302014-10-06 05:59:05 -0700509}
510
511///////////////////////////////////////////////////////////////////////////////
512
egdaniele659a582015-11-13 09:55:43 -0800513class GrGLDistanceFieldLCDTextGeoProc : public GrGLSLGeometryProcessor {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000514public:
joshualitt465283c2015-09-11 08:19:35 -0700515 GrGLDistanceFieldLCDTextGeoProc()
joshualitt53f26aa2015-12-10 07:29:54 -0800516 : fViewMatrix(SkMatrix::InvalidMatrix()) {
jvanverth502286d2015-04-08 12:37:51 -0700517 fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f);
jvanverth21deace2015-04-01 12:43:48 -0700518 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000519
mtklein36352bf2015-03-25 18:17:31 -0700520 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
jvanverth502286d2015-04-08 12:37:51 -0700521 const GrDistanceFieldLCDTextGeoProc& dfTexEffect =
522 args.fGP.cast<GrDistanceFieldLCDTextGeoProc>();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000523
egdaniel4ca2e602015-11-18 08:01:26 -0800524 GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
egdaniel0eafe792015-11-20 14:01:22 -0800525 GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
egdaniel7ea439b2015-12-03 09:20:44 -0800526 GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
joshualittabb52a12015-01-13 15:02:10 -0800527
528 // emit attributes
egdaniel0eafe792015-11-20 14:01:22 -0800529 varyingHandler->emitAttributes(dfTexEffect);
egdaniel4ca2e602015-11-18 08:01:26 -0800530
cdalton85285412016-02-18 12:37:07 -0800531 GrGLSLPPFragmentBuilder* fragBuilder = args.fFragBuilder;
joshualittabb52a12015-01-13 15:02:10 -0800532
joshualitt9b989322014-12-15 14:16:27 -0800533 // setup pass through color
joshualittb8c241a2015-05-19 08:23:30 -0700534 if (!dfTexEffect.colorIgnored()) {
joshualitt53f26aa2015-12-10 07:29:54 -0800535 varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
joshualittb8c241a2015-05-19 08:23:30 -0700536 }
joshualitt9b989322014-12-15 14:16:27 -0800537
joshualittabb52a12015-01-13 15:02:10 -0800538 // Setup position
egdaniel7ea439b2015-12-03 09:20:44 -0800539 this->setupPosition(vertBuilder,
540 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800541 gpArgs,
542 dfTexEffect.inPosition()->fName,
543 dfTexEffect.viewMatrix(),
joshualitt5559ca22015-05-21 15:50:36 -0700544 &fViewMatrixUniform);
joshualitt4973d9d2014-11-08 09:24:25 -0800545
joshualittabb52a12015-01-13 15:02:10 -0800546 // emit transforms
egdaniel7ea439b2015-12-03 09:20:44 -0800547 this->emitTransforms(vertBuilder,
egdaniel0eafe792015-11-20 14:01:22 -0800548 varyingHandler,
egdaniel7ea439b2015-12-03 09:20:44 -0800549 uniformHandler,
egdaniel4ca2e602015-11-18 08:01:26 -0800550 gpArgs->fPositionVar,
551 dfTexEffect.inPosition()->fName,
552 args.fTransformsIn,
553 args.fTransformsOut);
joshualittabb52a12015-01-13 15:02:10 -0800554
jvanverthbb4a1cf2015-04-07 09:06:00 -0700555 // set up varyings
jvanverthcf371bb2016-03-10 11:10:43 -0800556 bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
557 kUniformScale_DistanceFieldEffectMask;
558 bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
egdaniel8dcdedc2015-11-11 06:27:20 -0800559 GrGLSLVertToFrag recipScale(kFloat_GrSLType);
jvanverth7023a002016-02-22 11:25:32 -0800560 GrGLSLVertToFrag uv(kVec2f_GrSLType);
561 varyingHandler->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision);
562 vertBuilder->codeAppendf("%s = %s;", uv.vsOut(), dfTexEffect.inTextureCoords()->fName);
jvanverthbb4a1cf2015-04-07 09:06:00 -0700563
jvanverthcf371bb2016-03-10 11:10:43 -0800564 // compute numbers to be hardcoded to convert texture coordinates from float to int
joshualitt922c8b12015-08-07 09:55:23 -0700565 SkASSERT(dfTexEffect.numTextures() == 1);
566 GrTexture* atlas = dfTexEffect.textureAccess(0).getTexture();
joshualitt7375d6b2015-08-07 13:36:44 -0700567 SkASSERT(atlas && SkIsPow2(atlas->width()) && SkIsPow2(atlas->height()));
joshualitt922c8b12015-08-07 09:55:23 -0700568
jvanverth7023a002016-02-22 11:25:32 -0800569 GrGLSLVertToFrag st(kVec2f_GrSLType);
570 varyingHandler->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision);
571 vertBuilder->codeAppendf("%s = vec2(%d, %d) * %s;", st.vsOut(),
572 atlas->width(), atlas->height(),
egdaniel4ca2e602015-11-18 08:01:26 -0800573 dfTexEffect.inTextureCoords()->fName);
jvanverthbb4a1cf2015-04-07 09:06:00 -0700574
575 // add frag shader code
joshualitt30ba4362014-08-21 20:18:45 -0700576
egdaniel4ca2e602015-11-18 08:01:26 -0800577 SkAssertResult(fragBuilder->enableFeature(
egdaniel2d721d32015-11-11 13:06:05 -0800578 GrGLSLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
joshualitt30ba4362014-08-21 20:18:45 -0700579
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000580 // create LCD offset adjusted by inverse of transform
jvanverthfdf7ccc2015-01-27 08:19:33 -0800581 // Use highp to work around aliasing issues
egdaniela2e3e0f2015-11-19 07:23:45 -0800582 fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800583 kHigh_GrSLPrecision));
584 fragBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn());
egdaniela2e3e0f2015-11-19 07:23:45 -0800585 fragBuilder->codeAppend(GrGLSLShaderVar::PrecisionString(args.fGLSLCaps,
egdaniel4ca2e602015-11-18 08:01:26 -0800586 kHigh_GrSLPrecision));
joshualitt922c8b12015-08-07 09:55:23 -0700587
588 SkScalar lcdDelta = 1.0f / (3.0f * atlas->width());
jvanverth5a105ff2015-02-18 11:36:35 -0800589 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
egdaniel4ca2e602015-11-18 08:01:26 -0800590 fragBuilder->codeAppendf("float delta = -%.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
jvanverth5a105ff2015-02-18 11:36:35 -0800591 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800592 fragBuilder->codeAppendf("float delta = %.*f;\n", SK_FLT_DECIMAL_DIG, lcdDelta);
jvanverth5a105ff2015-02-18 11:36:35 -0800593 }
jvanverth78f07182014-07-30 06:17:59 -0700594 if (isUniformScale) {
jvanverthcf371bb2016-03-10 11:10:43 -0800595 fragBuilder->codeAppendf("float st_grad_len = abs(dFdy(%s.y));", st.fsIn());
596 fragBuilder->codeAppend("vec2 offset = vec2(st_grad_len*delta, 0.0);");
597 } else if (isSimilarity) {
598 // For a similarity matrix with rotation, the gradient will not be aligned
599 // with the texel coordinate axes, so we need to calculate it.
600 // We use dFdy because of a Mali 400 bug, and rotate -90 degrees to
601 // get the gradient in the x direction.
602 fragBuilder->codeAppendf("vec2 st_grad = dFdy(%s);", st.fsIn());
603 fragBuilder->codeAppend("float st_grad_len = length(st_grad);");
604 fragBuilder->codeAppend("vec2 offset = delta*vec2(st_grad.y, -st_grad.x);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000605 } else {
egdaniel4ca2e602015-11-18 08:01:26 -0800606 fragBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn());
jvanverthbb4a1cf2015-04-07 09:06:00 -0700607
egdaniel4ca2e602015-11-18 08:01:26 -0800608 fragBuilder->codeAppend("vec2 Jdx = dFdx(st);");
609 fragBuilder->codeAppend("vec2 Jdy = dFdy(st);");
610 fragBuilder->codeAppend("vec2 offset = delta*Jdx;");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000611 }
612
613 // green is distance to uv center
egdaniel4ca2e602015-11-18 08:01:26 -0800614 fragBuilder->codeAppend("\tvec4 texColor = ");
615 fragBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
616 fragBuilder->codeAppend(";\n");
617 fragBuilder->codeAppend("\tvec3 distance;\n");
618 fragBuilder->codeAppend("\tdistance.y = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000619 // red is distance to left offset
egdaniel4ca2e602015-11-18 08:01:26 -0800620 fragBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
621 fragBuilder->codeAppend("\ttexColor = ");
622 fragBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
623 fragBuilder->codeAppend(";\n");
624 fragBuilder->codeAppend("\tdistance.x = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000625 // blue is distance to right offset
egdaniel4ca2e602015-11-18 08:01:26 -0800626 fragBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
627 fragBuilder->codeAppend("\ttexColor = ");
628 fragBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
629 fragBuilder->codeAppend(";\n");
630 fragBuilder->codeAppend("\tdistance.z = texColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700631
egdaniel4ca2e602015-11-18 08:01:26 -0800632 fragBuilder->codeAppend("\tdistance = "
jvanverthada68ef2014-11-03 14:00:24 -0800633 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
jvanverth2d2a68c2014-06-10 06:42:56 -0700634
jvanverth21deace2015-04-01 12:43:48 -0700635 // adjust width based on gamma
halcanary96fcdcc2015-08-27 07:41:13 -0700636 const char* distanceAdjustUniName = nullptr;
cdalton5e58cee2016-02-11 12:49:47 -0800637 fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag,
egdaniel7ea439b2015-12-03 09:20:44 -0800638 kVec3f_GrSLType, kDefault_GrSLPrecision,
639 "DistanceAdjust", &distanceAdjustUniName);
egdaniel4ca2e602015-11-18 08:01:26 -0800640 fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
jvanverth21deace2015-04-01 12:43:48 -0700641
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000642 // To be strictly correct, we should compute the anti-aliasing factor separately
643 // for each color component. However, this is only important when using perspective
644 // transformations, and even then using a single factor seems like a reasonable
645 // trade-off between quality and speed.
egdaniel4ca2e602015-11-18 08:01:26 -0800646 fragBuilder->codeAppend("float afwidth;");
jvanverthcf371bb2016-03-10 11:10:43 -0800647 if (isSimilarity) {
halcanary9d524f22016-03-29 09:03:52 -0700648 // For similarity transform (uniform scale-only is a subset of this), we adjust for the
649 // effect of the transformation on the distance by using the length of the gradient of
jvanverthcf371bb2016-03-10 11:10:43 -0800650 // the texture coordinates. We use st coordinates to ensure we're mapping 1:1 from texel
651 // space to pixel space.
jvanverth354eba52015-03-16 11:32:49 -0700652
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000653 // this gives us a smooth step across approximately one fragment
jvanverthcf371bb2016-03-10 11:10:43 -0800654 fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*st_grad_len;");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000655 } else {
jvanverth354eba52015-03-16 11:32:49 -0700656 // For general transforms, to determine the amount of correction we multiply a unit
657 // vector pointing along the SDF gradient direction by the Jacobian of the st coords
658 // (which is the inverse transform for this fragment) and take the length of the result.
egdaniel4ca2e602015-11-18 08:01:26 -0800659 fragBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));");
jvanverthd68a5502015-03-16 12:58:43 -0700660 // the length of the gradient may be 0, so we need to check for this
661 // this also compensates for the Adreno, which likes to drop tiles on division by 0
egdaniel4ca2e602015-11-18 08:01:26 -0800662 fragBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);");
663 fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
664 fragBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);");
665 fragBuilder->codeAppend("} else {");
666 fragBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);");
667 fragBuilder->codeAppend("}");
668 fragBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
669 fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000670
671 // this gives us a smooth step across approximately one fragment
egdaniel4ca2e602015-11-18 08:01:26 -0800672 fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000673 }
674
egdaniel4ca2e602015-11-18 08:01:26 -0800675 fragBuilder->codeAppend(
jvanverth21deace2015-04-01 12:43:48 -0700676 "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);");
egdaniel27b63352015-09-15 13:13:50 -0700677 // set alpha to be max of rgb coverage
egdaniel4ca2e602015-11-18 08:01:26 -0800678 fragBuilder->codeAppend("val.a = max(max(val.r, val.g), val.b);");
jvanverth2d2a68c2014-06-10 06:42:56 -0700679
egdaniel4ca2e602015-11-18 08:01:26 -0800680 fragBuilder->codeAppendf("%s = val;", args.fOutputCoverage);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000681 }
682
egdaniel018fb622015-10-28 07:26:40 -0700683 void setData(const GrGLSLProgramDataManager& pdman,
joshualitt465283c2015-09-11 08:19:35 -0700684 const GrPrimitiveProcessor& processor) override {
jvanverth21deace2015-04-01 12:43:48 -0700685 SkASSERT(fDistanceAdjustUni.isValid());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000686
joshualitt5559ca22015-05-21 15:50:36 -0700687 const GrDistanceFieldLCDTextGeoProc& dflcd = processor.cast<GrDistanceFieldLCDTextGeoProc>();
688 GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.getDistanceAdjust();
jvanverth21deace2015-04-01 12:43:48 -0700689 if (wa != fDistanceAdjust) {
690 pdman.set3f(fDistanceAdjustUni,
691 wa.fR,
692 wa.fG,
693 wa.fB);
694 fDistanceAdjust = wa;
jvanverth2d2a68c2014-06-10 06:42:56 -0700695 }
joshualitt9b989322014-12-15 14:16:27 -0800696
joshualitt5559ca22015-05-21 15:50:36 -0700697 if (!dflcd.viewMatrix().isIdentity() && !fViewMatrix.cheapEqualTo(dflcd.viewMatrix())) {
698 fViewMatrix = dflcd.viewMatrix();
egdaniel018fb622015-10-28 07:26:40 -0700699 float viewMatrix[3 * 3];
egdaniel64c47282015-11-13 06:54:19 -0800700 GrGLSLGetMatrix<3>(viewMatrix, fViewMatrix);
joshualitt5559ca22015-05-21 15:50:36 -0700701 pdman.setMatrix3f(fViewMatrixUniform, viewMatrix);
702 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000703 }
704
robertphillips46d36f02015-01-18 08:14:14 -0800705 static inline void GenKey(const GrGeometryProcessor& gp,
jvanverthcfc18862015-04-28 08:48:20 -0700706 const GrGLSLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700707 GrProcessorKeyBuilder* b) {
jvanverth502286d2015-04-08 12:37:51 -0700708 const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000709
joshualitt8fc6c2d2014-12-22 15:27:05 -0800710 uint32_t key = dfTexEffect.getFlags();
joshualittb8c241a2015-05-19 08:23:30 -0700711 key |= dfTexEffect.colorIgnored() << 16;
joshualitte578a952015-05-14 10:09:13 -0700712 key |= ComputePosKey(dfTexEffect.viewMatrix()) << 25;
joshualitt8fc6c2d2014-12-22 15:27:05 -0800713 b->add32(key);
joshualitt922c8b12015-08-07 09:55:23 -0700714
715 // Currently we hardcode numbers to convert atlas coordinates to normalized floating point
716 SkASSERT(gp.numTextures() == 1);
717 GrTexture* atlas = gp.textureAccess(0).getTexture();
718 SkASSERT(atlas);
719 b->add32(atlas->width());
720 b->add32(atlas->height());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000721 }
722
723private:
joshualitt5559ca22015-05-21 15:50:36 -0700724 SkMatrix fViewMatrix;
joshualitt5559ca22015-05-21 15:50:36 -0700725 UniformHandle fViewMatrixUniform;
jvanverth21deace2015-04-01 12:43:48 -0700726 UniformHandle fColorUniform;
jvanverth502286d2015-04-08 12:37:51 -0700727 GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust;
jvanverth21deace2015-04-01 12:43:48 -0700728 UniformHandle fDistanceAdjustUni;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000729
egdaniele659a582015-11-13 09:55:43 -0800730 typedef GrGLSLGeometryProcessor INHERITED;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000731};
732
733///////////////////////////////////////////////////////////////////////////////
734
jvanverth502286d2015-04-08 12:37:51 -0700735GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(
joshualitt8059eb92014-12-29 15:10:07 -0800736 GrColor color, const SkMatrix& viewMatrix,
jvanverth2d2a68c2014-06-10 06:42:56 -0700737 GrTexture* texture, const GrTextureParams& params,
jvanverth21deace2015-04-01 12:43:48 -0700738 DistanceAdjust distanceAdjust,
joshualittb8c241a2015-05-19 08:23:30 -0700739 uint32_t flags, bool usesLocalCoords)
joshualitte3ababe2015-05-15 07:56:07 -0700740 : fColor(color)
joshualitte578a952015-05-14 10:09:13 -0700741 , fViewMatrix(viewMatrix)
joshualitt2e3b3e32014-12-09 13:31:14 -0800742 , fTextureAccess(texture, params)
jvanverth21deace2015-04-01 12:43:48 -0700743 , fDistanceAdjust(distanceAdjust)
joshualittb8c241a2015-05-19 08:23:30 -0700744 , fFlags(flags & kLCD_DistanceFieldEffectMask)
745 , fUsesLocalCoords(usesLocalCoords) {
jvanverth78f07182014-07-30 06:17:59 -0700746 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
jvanverth502286d2015-04-08 12:37:51 -0700747 this->initClassID<GrDistanceFieldLCDTextGeoProc>();
senorblancof2539d52015-05-20 14:03:42 -0700748 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType,
749 kHigh_GrSLPrecision));
joshualitt53f26aa2015-12-10 07:29:54 -0800750 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType));
joshualitt71c92602015-01-14 08:12:47 -0800751 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords",
jvanverth7023a002016-02-22 11:25:32 -0800752 kVec2us_GrVertexAttribType,
753 kHigh_GrSLPrecision));
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000754 this->addTextureAccess(&fTextureAccess);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000755}
756
egdaniel57d3b032015-11-13 11:57:27 -0800757void GrDistanceFieldLCDTextGeoProc::getGLSLProcessorKey(const GrGLSLCaps& caps,
758 GrProcessorKeyBuilder* b) const {
joshualitt465283c2015-09-11 08:19:35 -0700759 GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, caps, b);
joshualitteb2a6762014-12-04 11:35:33 -0800760}
761
egdaniel57d3b032015-11-13 11:57:27 -0800762GrGLSLPrimitiveProcessor* GrDistanceFieldLCDTextGeoProc::createGLSLInstance(const GrGLSLCaps&) const {
joshualitt465283c2015-09-11 08:19:35 -0700763 return new GrGLDistanceFieldLCDTextGeoProc();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000764}
765
766///////////////////////////////////////////////////////////////////////////////
767
jvanverth502286d2015-04-08 12:37:51 -0700768GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000769
bsalomonc21b09e2015-08-28 18:46:56 -0700770const GrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) {
joshualitt0067ff52015-07-08 14:26:19 -0700771 int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
772 GrProcessorUnitTest::kAlphaTextureIdx;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000773 static const SkShader::TileMode kTileModes[] = {
774 SkShader::kClamp_TileMode,
775 SkShader::kRepeat_TileMode,
776 SkShader::kMirror_TileMode,
777 };
778 SkShader::TileMode tileModes[] = {
joshualitt0067ff52015-07-08 14:26:19 -0700779 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
780 kTileModes[d->fRandom->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000781 };
joshualitt0067ff52015-07-08 14:26:19 -0700782 GrTextureParams params(tileModes, d->fRandom->nextBool() ? GrTextureParams::kBilerp_FilterMode :
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000783 GrTextureParams::kNone_FilterMode);
jvanverth21deace2015-04-01 12:43:48 -0700784 DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
jvanverth78f07182014-07-30 06:17:59 -0700785 uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
jvanverthcf371bb2016-03-10 11:10:43 -0800786 flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
787 if (flags & kSimilarity_DistanceFieldEffectFlag) {
788 flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
789 }
joshualitt0067ff52015-07-08 14:26:19 -0700790 flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
791 return GrDistanceFieldLCDTextGeoProc::Create(GrRandomColor(d->fRandom),
792 GrTest::TestMatrix(d->fRandom),
793 d->fTextures[texIdx], params,
jvanverth502286d2015-04-08 12:37:51 -0700794 wa,
joshualittb8c241a2015-05-19 08:23:30 -0700795 flags,
joshualitt0067ff52015-07-08 14:26:19 -0700796 d->fRandom->nextBool());
jvanverth@google.comd830d132013-11-11 20:54:09 +0000797}