blob: cdb6ff75e138ec6d249239b67872f3a4f8920dad [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
8#include "GrDistanceFieldTextureEffect.h"
egdaniel605dd0f2014-11-12 08:35:25 -08009#include "GrInvariantOutput.h"
joshualitteb2a6762014-12-04 11:35:33 -080010#include "GrTexture.h"
11#include "SkDistanceFieldGen.h"
joshualittb0a8a372014-09-23 09:50:21 -070012#include "gl/GrGLProcessor.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000013#include "gl/GrGLSL.h"
14#include "gl/GrGLTexture.h"
joshualitt249af152014-09-15 11:41:13 -070015#include "gl/GrGLGeometryProcessor.h"
joshualitteb2a6762014-12-04 11:35:33 -080016#include "gl/builders/GrGLProgramBuilder.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000017
jvanverth2d2a68c2014-06-10 06:42:56 -070018// Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2
19#define SK_DistanceFieldAAFactor "0.7071"
20
joshualitt9b989322014-12-15 14:16:27 -080021struct DistanceFieldBatchTracker {
22 GrGPInput fInputColorType;
23 GrColor fColor;
joshualitt290c09b2014-12-19 13:45:20 -080024 bool fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -080025};
26
joshualitt249af152014-09-15 11:41:13 -070027class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
jvanverth@google.comd830d132013-11-11 20:54:09 +000028public:
joshualitteb2a6762014-12-04 11:35:33 -080029 GrGLDistanceFieldTextureEffect(const GrGeometryProcessor&,
joshualitt87f48d92014-12-04 10:41:40 -080030 const GrBatchTracker&)
joshualitt9b989322014-12-15 14:16:27 -080031 : fColor(GrColor_ILLEGAL)
32 , fTextureSize(SkISize::Make(-1,-1))
jvanverth9564ce62014-09-16 05:45:19 -070033#ifdef SK_GAMMA_APPLY_TO_A8
34 , fLuminance(-1.0f)
35#endif
36 {}
jvanverth@google.comd830d132013-11-11 20:54:09 +000037
mtklein72c9faa2015-01-09 10:06:39 -080038 void emitCode(const EmitArgs& args) SK_OVERRIDE {
joshualitt249af152014-09-15 11:41:13 -070039 const GrDistanceFieldTextureEffect& dfTexEffect =
joshualittc369e7c2014-10-22 10:56:26 -070040 args.fGP.cast<GrDistanceFieldTextureEffect>();
joshualitt9b989322014-12-15 14:16:27 -080041 const DistanceFieldBatchTracker& local = args.fBT.cast<DistanceFieldBatchTracker>();
42 GrGLGPBuilder* pb = args.fPB;
joshualittc369e7c2014-10-22 10:56:26 -070043 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -070044 SkAssertResult(fsBuilder->enableFeature(
45 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
jvanverth@google.comd830d132013-11-11 20:54:09 +000046
joshualitt2dd1ae02014-12-03 06:24:10 -080047 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualitt74077b92014-10-24 11:26:03 -070048 GrGLVertToFrag v(kVec2f_GrSLType);
49 args.fPB->addVarying("TextureCoords", &v);
joshualitt2dd1ae02014-12-03 06:24:10 -080050 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000051
joshualitt9b989322014-12-15 14:16:27 -080052 // Setup pass through color
53 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor,
54 dfTexEffect.inColor(), &fColorUniform);
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000055
joshualittee2af952014-12-30 09:04:15 -080056 // setup uniform viewMatrix
57 this->addUniformViewMatrix(pb);
58
joshualitt4973d9d2014-11-08 09:24:25 -080059 // setup position varying
60 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPosition(),
joshualittee2af952014-12-30 09:04:15 -080061 this->uViewM(), dfTexEffect.inPosition()->fName);
joshualitt2dd1ae02014-12-03 06:24:10 -080062
63 // setup output coords
64 vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(),
65 dfTexEffect.inPosition()->fName);
66 vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(),
67 dfTexEffect.inPosition()->fName);
joshualitt4973d9d2014-11-08 09:24:25 -080068
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000069 const char* textureSizeUniName = NULL;
joshualittc369e7c2014-10-22 10:56:26 -070070 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -080071 kVec2f_GrSLType, kDefault_GrSLPrecision,
72 "TextureSize", &textureSizeUniName);
jvanverth@google.comd830d132013-11-11 20:54:09 +000073
joshualitt30ba4362014-08-21 20:18:45 -070074 fsBuilder->codeAppend("\tvec4 texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -070075 fsBuilder->appendTextureLookup(args.fSamplers[0],
joshualitt74077b92014-10-24 11:26:03 -070076 v.fsIn(),
jvanverth@google.comd830d132013-11-11 20:54:09 +000077 kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -070078 fsBuilder->codeAppend(";\n");
79 fsBuilder->codeAppend("\tfloat distance = "
jvanverthada68ef2014-11-03 14:00:24 -080080 SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000081
82 // we adjust for the effect of the transformation on the distance by using
83 // the length of the gradient of the texture coordinates. We use st coordinates
84 // to ensure we're mapping 1:1 from texel space to pixel space.
joshualitt74077b92014-10-24 11:26:03 -070085 fsBuilder->codeAppendf("\tvec2 uv = %s;\n", v.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -070086 fsBuilder->codeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName);
87 fsBuilder->codeAppend("\tfloat afwidth;\n");
jvanverth78f07182014-07-30 06:17:59 -070088 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
commit-bot@chromium.org4362a382014-03-26 19:49:03 +000089 // this gives us a smooth step across approximately one fragment
jvanverthfa38a302014-10-06 05:59:05 -070090 fsBuilder->codeAppend("\tafwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +000091 } else {
joshualitt30ba4362014-08-21 20:18:45 -070092 fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
93 fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000094
joshualitt30ba4362014-08-21 20:18:45 -070095 fsBuilder->codeAppend("\tvec2 uv_grad;\n");
joshualittc369e7c2014-10-22 10:56:26 -070096 if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
commit-bot@chromium.org4362a382014-03-26 19:49:03 +000097 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
joshualitt30ba4362014-08-21 20:18:45 -070098 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
99 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
100 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
101 fsBuilder->codeAppend("\t} else {\n");
102 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
103 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000104 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700105 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000106 }
joshualitt30ba4362014-08-21 20:18:45 -0700107 fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
108 fsBuilder->codeAppend("\t uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000109
110 // this gives us a smooth step across approximately one fragment
joshualitt30ba4362014-08-21 20:18:45 -0700111 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000112 }
joshualitt30ba4362014-08-21 20:18:45 -0700113 fsBuilder->codeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n");
jvanverth@google.comd830d132013-11-11 20:54:09 +0000114
jvanverth2d2a68c2014-06-10 06:42:56 -0700115#ifdef SK_GAMMA_APPLY_TO_A8
116 // adjust based on gamma
117 const char* luminanceUniName = NULL;
118 // width, height, 1/(3*width)
joshualittc369e7c2014-10-22 10:56:26 -0700119 fLuminanceUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800120 kFloat_GrSLType, kDefault_GrSLPrecision,
121 "Luminance", &luminanceUniName);
jvanverth2d2a68c2014-06-10 06:42:56 -0700122
joshualitt30ba4362014-08-21 20:18:45 -0700123 fsBuilder->codeAppendf("\tuv = vec2(val, %s);\n", luminanceUniName);
124 fsBuilder->codeAppend("\tvec4 gammaColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700125 fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700126 fsBuilder->codeAppend(";\n");
127 fsBuilder->codeAppend("\tval = gammaColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700128#endif
129
joshualitt2dd1ae02014-12-03 06:24:10 -0800130 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000131 }
132
kkinnunen7510b222014-07-30 00:04:16 -0700133 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800134 const GrPrimitiveProcessor& proc,
135 const GrBatchTracker& bt) SK_OVERRIDE {
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000136 SkASSERT(fTextureSizeUni.isValid());
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000137
joshualitt87f48d92014-12-04 10:41:40 -0800138 GrTexture* texture = proc.texture(0);
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000139 if (texture->width() != fTextureSize.width() ||
140 texture->height() != fTextureSize.height()) {
141 fTextureSize = SkISize::Make(texture->width(), texture->height());
kkinnunen7510b222014-07-30 00:04:16 -0700142 pdman.set2f(fTextureSizeUni,
143 SkIntToScalar(fTextureSize.width()),
144 SkIntToScalar(fTextureSize.height()));
commit-bot@chromium.org66beaf02014-03-26 18:21:55 +0000145 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700146#ifdef SK_GAMMA_APPLY_TO_A8
147 const GrDistanceFieldTextureEffect& dfTexEffect =
joshualitt87f48d92014-12-04 10:41:40 -0800148 proc.cast<GrDistanceFieldTextureEffect>();
jvanverth2d2a68c2014-06-10 06:42:56 -0700149 float luminance = dfTexEffect.getLuminance();
150 if (luminance != fLuminance) {
kkinnunen7510b222014-07-30 00:04:16 -0700151 pdman.set1f(fLuminanceUni, luminance);
jvanverth2d2a68c2014-06-10 06:42:56 -0700152 fLuminance = luminance;
153 }
154#endif
joshualitt9b989322014-12-15 14:16:27 -0800155
joshualittee2af952014-12-30 09:04:15 -0800156 this->setUniformViewMatrix(pdman, proc.viewMatrix());
157
joshualitt9b989322014-12-15 14:16:27 -0800158 const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
159 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
160 GrGLfloat c[4];
161 GrColorToRGBAFloat(local.fColor, c);
162 pdman.set4fv(fColorUniform, 1, c);
163 fColor = local.fColor;
164 }
commit-bot@chromium.org8fe2ee12014-03-26 18:03:05 +0000165 }
166
joshualitt87f48d92014-12-04 10:41:40 -0800167 static inline void GenKey(const GrGeometryProcessor& processor,
joshualitt9b989322014-12-15 14:16:27 -0800168 const GrBatchTracker& bt,
joshualitt87f48d92014-12-04 10:41:40 -0800169 const GrGLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700170 GrProcessorKeyBuilder* b) {
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000171 const GrDistanceFieldTextureEffect& dfTexEffect =
joshualittb0a8a372014-09-23 09:50:21 -0700172 processor.cast<GrDistanceFieldTextureEffect>();
joshualitt9b989322014-12-15 14:16:27 -0800173 const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800174 uint32_t key = dfTexEffect.getFlags();
175 key |= local.fInputColorType << 16;
176 key |= local.fUsesLocalCoords && processor.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
177 b->add32(key);
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000178 }
179
jvanverth@google.comd830d132013-11-11 20:54:09 +0000180private:
joshualitt9b989322014-12-15 14:16:27 -0800181 GrColor fColor;
182 UniformHandle fColorUniform;
183 UniformHandle fTextureSizeUni;
184 SkISize fTextureSize;
185 UniformHandle fLuminanceUni;
186 float fLuminance;
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000187
joshualitt249af152014-09-15 11:41:13 -0700188 typedef GrGLGeometryProcessor INHERITED;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000189};
190
191///////////////////////////////////////////////////////////////////////////////
192
joshualitt2e3b3e32014-12-09 13:31:14 -0800193GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800194 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800195 GrTexture* texture,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000196 const GrTextureParams& params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700197#ifdef SK_GAMMA_APPLY_TO_A8
198 GrTexture* gamma,
199 const GrTextureParams& gammaParams,
200 float luminance,
201#endif
joshualitt56995b52014-12-11 15:44:02 -0800202 uint32_t flags, bool opaqueVertexColors)
joshualitt8059eb92014-12-29 15:10:07 -0800203 : INHERITED(color, viewMatrix, SkMatrix::I(), opaqueVertexColors)
joshualitt2e3b3e32014-12-09 13:31:14 -0800204 , fTextureAccess(texture, params)
jvanverth2d2a68c2014-06-10 06:42:56 -0700205#ifdef SK_GAMMA_APPLY_TO_A8
206 , fGammaTextureAccess(gamma, gammaParams)
207 , fLuminance(luminance)
208#endif
joshualitt249af152014-09-15 11:41:13 -0700209 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
joshualitt2dd1ae02014-12-03 06:24:10 -0800210 , fInColor(NULL) {
jvanverth78f07182014-07-30 06:17:59 -0700211 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
joshualitteb2a6762014-12-04 11:35:33 -0800212 this->initClassID<GrDistanceFieldTextureEffect>();
joshualitt2dd1ae02014-12-03 06:24:10 -0800213 fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
214 if (flags & kColorAttr_DistanceFieldEffectFlag) {
215 fInColor = &this->addVertexAttrib(GrAttribute("inColor", kVec4ub_GrVertexAttribType));
216 this->setHasVertexColor();
217 }
218 fInTextureCoords = &this->addVertexAttrib(GrAttribute("inTextureCoords",
219 kVec2f_GrVertexAttribType));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000220 this->addTextureAccess(&fTextureAccess);
jvanverth2d2a68c2014-06-10 06:42:56 -0700221#ifdef SK_GAMMA_APPLY_TO_A8
222 this->addTextureAccess(&fGammaTextureAccess);
223#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000224}
225
bsalomon0e08fc12014-10-15 08:19:04 -0700226bool GrDistanceFieldTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
joshualitt49586be2014-09-16 08:21:41 -0700227 const GrDistanceFieldTextureEffect& cte = other.cast<GrDistanceFieldTextureEffect>();
bsalomon420d7e92014-10-16 09:18:09 -0700228 return
jvanverth78f07182014-07-30 06:17:59 -0700229#ifdef SK_GAMMA_APPLY_TO_A8
jvanverth78f07182014-07-30 06:17:59 -0700230 fLuminance == cte.fLuminance &&
231#endif
232 fFlags == cte.fFlags;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000233}
234
joshualitt56995b52014-12-11 15:44:02 -0800235void GrDistanceFieldTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
236 out->setUnknownSingleComponent();
jvanverth@google.comd830d132013-11-11 20:54:09 +0000237}
238
joshualitteb2a6762014-12-04 11:35:33 -0800239void GrDistanceFieldTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
240 const GrGLCaps& caps,
241 GrProcessorKeyBuilder* b) const {
242 GrGLDistanceFieldTextureEffect::GenKey(*this, bt, caps, b);
243}
244
245GrGLGeometryProcessor*
246GrDistanceFieldTextureEffect::createGLInstance(const GrBatchTracker& bt) const {
247 return SkNEW_ARGS(GrGLDistanceFieldTextureEffect, (*this, bt));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000248}
249
joshualitt9b989322014-12-15 14:16:27 -0800250void GrDistanceFieldTextureEffect::initBatchTracker(GrBatchTracker* bt, const InitBT& init) const {
251 DistanceFieldBatchTracker* local = bt->cast<DistanceFieldBatchTracker>();
252 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
253 SkToBool(fInColor));
joshualitt290c09b2014-12-19 13:45:20 -0800254 local->fUsesLocalCoords = init.fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800255}
256
257bool GrDistanceFieldTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
joshualitt290c09b2014-12-19 13:45:20 -0800258 const GrGeometryProcessor& that,
joshualitt9b989322014-12-15 14:16:27 -0800259 const GrBatchTracker& t) const {
260 const DistanceFieldBatchTracker& mine = m.cast<DistanceFieldBatchTracker>();
261 const DistanceFieldBatchTracker& theirs = t.cast<DistanceFieldBatchTracker>();
joshualitt290c09b2014-12-19 13:45:20 -0800262 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
263 that, theirs.fUsesLocalCoords) &&
264 CanCombineOutput(mine.fInputColorType, mine.fColor,
joshualitt9b989322014-12-15 14:16:27 -0800265 theirs.fInputColorType, theirs.fColor);
266}
267
jvanverth@google.comd830d132013-11-11 20:54:09 +0000268///////////////////////////////////////////////////////////////////////////////
269
joshualittb0a8a372014-09-23 09:50:21 -0700270GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000271
joshualittb0a8a372014-09-23 09:50:21 -0700272GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
273 GrContext*,
274 const GrDrawTargetCaps&,
275 GrTexture* textures[]) {
276 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
277 GrProcessorUnitTest::kAlphaTextureIdx;
jvanverth2d2a68c2014-06-10 06:42:56 -0700278#ifdef SK_GAMMA_APPLY_TO_A8
joshualittb0a8a372014-09-23 09:50:21 -0700279 int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
280 GrProcessorUnitTest::kAlphaTextureIdx;
jvanverth2d2a68c2014-06-10 06:42:56 -0700281#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000282 static const SkShader::TileMode kTileModes[] = {
283 SkShader::kClamp_TileMode,
284 SkShader::kRepeat_TileMode,
285 SkShader::kMirror_TileMode,
286 };
287 SkShader::TileMode tileModes[] = {
288 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
289 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
290 };
291 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
292 GrTextureParams::kNone_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700293#ifdef SK_GAMMA_APPLY_TO_A8
294 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
295 GrTextureParams::kNone_FilterMode);
296#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000297
joshualitt8059eb92014-12-29 15:10:07 -0800298 return GrDistanceFieldTextureEffect::Create(GrRandomColor(random),
299 GrProcessorUnitTest::TestMatrix(random),
300 textures[texIdx], params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700301#ifdef SK_GAMMA_APPLY_TO_A8
302 textures[texIdx2], params2,
303 random->nextF(),
304#endif
jvanverth78f07182014-07-30 06:17:59 -0700305 random->nextBool() ?
joshualitt56995b52014-12-11 15:44:02 -0800306 kSimilarity_DistanceFieldEffectFlag : 0,
307 random->nextBool());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000308}
309
310///////////////////////////////////////////////////////////////////////////////
311
joshualitt9b989322014-12-15 14:16:27 -0800312struct DistanceFieldNoGammaBatchTracker {
313 GrGPInput fInputColorType;
314 GrColor fColor;
joshualitt290c09b2014-12-19 13:45:20 -0800315 bool fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800316};
317
jvanverthfa38a302014-10-06 05:59:05 -0700318class GrGLDistanceFieldNoGammaTextureEffect : public GrGLGeometryProcessor {
319public:
joshualitteb2a6762014-12-04 11:35:33 -0800320 GrGLDistanceFieldNoGammaTextureEffect(const GrGeometryProcessor&,
joshualitt87f48d92014-12-04 10:41:40 -0800321 const GrBatchTracker&)
joshualitt9b989322014-12-15 14:16:27 -0800322 : fColor(GrColor_ILLEGAL), fTextureSize(SkISize::Make(-1, -1)) {}
jvanverthfa38a302014-10-06 05:59:05 -0700323
mtklein72c9faa2015-01-09 10:06:39 -0800324 void emitCode(const EmitArgs& args) SK_OVERRIDE {
jvanverthfa38a302014-10-06 05:59:05 -0700325 const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
joshualittc369e7c2014-10-22 10:56:26 -0700326 args.fGP.cast<GrDistanceFieldNoGammaTextureEffect>();
jvanverthfa38a302014-10-06 05:59:05 -0700327
joshualitt9b989322014-12-15 14:16:27 -0800328 const DistanceFieldNoGammaBatchTracker& local =
329 args.fBT.cast<DistanceFieldNoGammaBatchTracker>();
330 GrGLGPBuilder* pb = args.fPB;
joshualittc369e7c2014-10-22 10:56:26 -0700331 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
jvanverthfa38a302014-10-06 05:59:05 -0700332 SkAssertResult(fsBuilder->enableFeature(
333 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
334
joshualitt2dd1ae02014-12-03 06:24:10 -0800335 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualitt74077b92014-10-24 11:26:03 -0700336 GrGLVertToFrag v(kVec2f_GrSLType);
337 args.fPB->addVarying("TextureCoords", &v);
jvanverthfa38a302014-10-06 05:59:05 -0700338
joshualitt9b989322014-12-15 14:16:27 -0800339 // setup pass through color
340 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor,
341 dfTexEffect.inColor(), &fColorUniform);
joshualitt2dd1ae02014-12-03 06:24:10 -0800342
343 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
344
345 // setup coord outputs
346 vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(),
347 dfTexEffect.inPosition()->fName);
348 vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(),
349 dfTexEffect.inPosition()->fName);
jvanverthfa38a302014-10-06 05:59:05 -0700350
joshualittee2af952014-12-30 09:04:15 -0800351 // setup uniform viewMatrix
352 this->addUniformViewMatrix(pb);
353
joshualitt4973d9d2014-11-08 09:24:25 -0800354 // setup position varying
355 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPosition(),
joshualittee2af952014-12-30 09:04:15 -0800356 this->uViewM(), dfTexEffect.inPosition()->fName);
joshualitt4973d9d2014-11-08 09:24:25 -0800357
jvanverthfa38a302014-10-06 05:59:05 -0700358 const char* textureSizeUniName = NULL;
joshualittc369e7c2014-10-22 10:56:26 -0700359 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800360 kVec2f_GrSLType, kDefault_GrSLPrecision,
361 "TextureSize", &textureSizeUniName);
jvanverthfa38a302014-10-06 05:59:05 -0700362
363 fsBuilder->codeAppend("vec4 texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700364 fsBuilder->appendTextureLookup(args.fSamplers[0],
joshualitt74077b92014-10-24 11:26:03 -0700365 v.fsIn(),
jvanverthfa38a302014-10-06 05:59:05 -0700366 kVec2f_GrSLType);
367 fsBuilder->codeAppend(";");
368 fsBuilder->codeAppend("float distance = "
369 SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
370
371 // we adjust for the effect of the transformation on the distance by using
372 // the length of the gradient of the texture coordinates. We use st coordinates
373 // to ensure we're mapping 1:1 from texel space to pixel space.
joshualitt74077b92014-10-24 11:26:03 -0700374 fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
jvanverthfa38a302014-10-06 05:59:05 -0700375 fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
376 fsBuilder->codeAppend("float afwidth;");
377 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
378 // this gives us a smooth step across approximately one fragment
379 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));");
380 } else {
381 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
382 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
383
384 fsBuilder->codeAppend("vec2 uv_grad;");
joshualittc369e7c2014-10-22 10:56:26 -0700385 if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
jvanverthfa38a302014-10-06 05:59:05 -0700386 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
387 fsBuilder->codeAppend("float uv_len2 = dot(uv, uv);");
388 fsBuilder->codeAppend("if (uv_len2 < 0.0001) {");
389 fsBuilder->codeAppend("uv_grad = vec2(0.7071, 0.7071);");
390 fsBuilder->codeAppend("} else {");
391 fsBuilder->codeAppend("uv_grad = uv*inversesqrt(uv_len2);");
392 fsBuilder->codeAppend("}");
393 } else {
394 fsBuilder->codeAppend("uv_grad = normalize(uv);");
395 }
396 fsBuilder->codeAppend("vec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,");
397 fsBuilder->codeAppend(" uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);");
398
399 // this gives us a smooth step across approximately one fragment
400 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
401 }
402 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
403
joshualitt2dd1ae02014-12-03 06:24:10 -0800404 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
jvanverthfa38a302014-10-06 05:59:05 -0700405 }
406
407 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800408 const GrPrimitiveProcessor& proc,
409 const GrBatchTracker& bt) SK_OVERRIDE {
jvanverthfa38a302014-10-06 05:59:05 -0700410 SkASSERT(fTextureSizeUni.isValid());
411
joshualitt87f48d92014-12-04 10:41:40 -0800412 GrTexture* texture = proc.texture(0);
jvanverthfa38a302014-10-06 05:59:05 -0700413 if (texture->width() != fTextureSize.width() ||
414 texture->height() != fTextureSize.height()) {
415 fTextureSize = SkISize::Make(texture->width(), texture->height());
416 pdman.set2f(fTextureSizeUni,
417 SkIntToScalar(fTextureSize.width()),
418 SkIntToScalar(fTextureSize.height()));
419 }
joshualitt9b989322014-12-15 14:16:27 -0800420
joshualittee2af952014-12-30 09:04:15 -0800421 this->setUniformViewMatrix(pdman, proc.viewMatrix());
422
joshualitt9b989322014-12-15 14:16:27 -0800423 const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>();
424 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
425 GrGLfloat c[4];
426 GrColorToRGBAFloat(local.fColor, c);
427 pdman.set4fv(fColorUniform, 1, c);
428 fColor = local.fColor;
429 }
jvanverthfa38a302014-10-06 05:59:05 -0700430 }
431
joshualitt87f48d92014-12-04 10:41:40 -0800432 static inline void GenKey(const GrGeometryProcessor& proc,
joshualitt9b989322014-12-15 14:16:27 -0800433 const GrBatchTracker& bt,
joshualitt87f48d92014-12-04 10:41:40 -0800434 const GrGLCaps&,
jvanverthfa38a302014-10-06 05:59:05 -0700435 GrProcessorKeyBuilder* b) {
436 const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
joshualitt87f48d92014-12-04 10:41:40 -0800437 proc.cast<GrDistanceFieldNoGammaTextureEffect>();
jvanverthfa38a302014-10-06 05:59:05 -0700438
joshualitt9b989322014-12-15 14:16:27 -0800439 const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800440 uint32_t key = dfTexEffect.getFlags();
441 key |= local.fInputColorType << 16;
442 key |= local.fUsesLocalCoords && proc.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
443 b->add32(key);
jvanverthfa38a302014-10-06 05:59:05 -0700444 }
445
446private:
joshualitt9b989322014-12-15 14:16:27 -0800447 UniformHandle fColorUniform;
448 UniformHandle fTextureSizeUni;
449 GrColor fColor;
450 SkISize fTextureSize;
jvanverthfa38a302014-10-06 05:59:05 -0700451
452 typedef GrGLGeometryProcessor INHERITED;
453};
454
455///////////////////////////////////////////////////////////////////////////////
456
joshualitt2e3b3e32014-12-09 13:31:14 -0800457GrDistanceFieldNoGammaTextureEffect::GrDistanceFieldNoGammaTextureEffect(
458 GrColor color,
joshualitt8059eb92014-12-29 15:10:07 -0800459 const SkMatrix& viewMatrix,
joshualitt2e3b3e32014-12-09 13:31:14 -0800460 GrTexture* texture,
461 const GrTextureParams& params,
joshualitt56995b52014-12-11 15:44:02 -0800462 uint32_t flags,
463 bool opaqueVertexColors)
joshualitt8059eb92014-12-29 15:10:07 -0800464 : INHERITED(color, viewMatrix, SkMatrix::I(), opaqueVertexColors)
joshualitt2e3b3e32014-12-09 13:31:14 -0800465 , fTextureAccess(texture, params)
jvanverthfa38a302014-10-06 05:59:05 -0700466 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
joshualitt2dd1ae02014-12-03 06:24:10 -0800467 , fInColor(NULL) {
jvanverthfa38a302014-10-06 05:59:05 -0700468 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
joshualitteb2a6762014-12-04 11:35:33 -0800469 this->initClassID<GrDistanceFieldNoGammaTextureEffect>();
joshualitt2dd1ae02014-12-03 06:24:10 -0800470 fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
471 if (flags & kColorAttr_DistanceFieldEffectFlag) {
472 fInColor = &this->addVertexAttrib(GrAttribute("inColor", kVec4ub_GrVertexAttribType));
473 this->setHasVertexColor();
474 }
475 fInTextureCoords = &this->addVertexAttrib(GrAttribute("inTextureCoords",
476 kVec2f_GrVertexAttribType));
jvanverthfa38a302014-10-06 05:59:05 -0700477 this->addTextureAccess(&fTextureAccess);
478}
479
bsalomon0e08fc12014-10-15 08:19:04 -0700480bool GrDistanceFieldNoGammaTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
jvanverthfa38a302014-10-06 05:59:05 -0700481 const GrDistanceFieldNoGammaTextureEffect& cte =
482 other.cast<GrDistanceFieldNoGammaTextureEffect>();
bsalomon420d7e92014-10-16 09:18:09 -0700483 return fFlags == cte.fFlags;
jvanverthfa38a302014-10-06 05:59:05 -0700484}
485
joshualitt56995b52014-12-11 15:44:02 -0800486void GrDistanceFieldNoGammaTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const{
487 out->setUnknownSingleComponent();
jvanverthfa38a302014-10-06 05:59:05 -0700488}
489
joshualitteb2a6762014-12-04 11:35:33 -0800490void GrDistanceFieldNoGammaTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
491 const GrGLCaps& caps,
492 GrProcessorKeyBuilder* b) const {
493 GrGLDistanceFieldNoGammaTextureEffect::GenKey(*this, bt, caps, b);
494}
495
496GrGLGeometryProcessor*
497GrDistanceFieldNoGammaTextureEffect::createGLInstance(const GrBatchTracker& bt) const {
498 return SkNEW_ARGS(GrGLDistanceFieldNoGammaTextureEffect, (*this, bt));
jvanverthfa38a302014-10-06 05:59:05 -0700499}
500
joshualitt9b989322014-12-15 14:16:27 -0800501void GrDistanceFieldNoGammaTextureEffect::initBatchTracker(GrBatchTracker* bt,
502 const InitBT& init) const {
503 DistanceFieldNoGammaBatchTracker* local = bt->cast<DistanceFieldNoGammaBatchTracker>();
504 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init,
505 SkToBool(fInColor));
joshualitt290c09b2014-12-19 13:45:20 -0800506 local->fUsesLocalCoords = init.fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800507}
508
509bool GrDistanceFieldNoGammaTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
joshualitt290c09b2014-12-19 13:45:20 -0800510 const GrGeometryProcessor& that,
joshualitt9b989322014-12-15 14:16:27 -0800511 const GrBatchTracker& t) const {
512 const DistanceFieldNoGammaBatchTracker& mine = m.cast<DistanceFieldNoGammaBatchTracker>();
513 const DistanceFieldNoGammaBatchTracker& theirs = t.cast<DistanceFieldNoGammaBatchTracker>();
joshualitt290c09b2014-12-19 13:45:20 -0800514 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
515 that, theirs.fUsesLocalCoords) &&
516 CanCombineOutput(mine.fInputColorType, mine.fColor,
joshualitt9b989322014-12-15 14:16:27 -0800517 theirs.fInputColorType, theirs.fColor);
518}
519
jvanverthfa38a302014-10-06 05:59:05 -0700520///////////////////////////////////////////////////////////////////////////////
521
522GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldNoGammaTextureEffect);
523
524GrGeometryProcessor* GrDistanceFieldNoGammaTextureEffect::TestCreate(SkRandom* random,
525 GrContext*,
526 const GrDrawTargetCaps&,
527 GrTexture* textures[]) {
528 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
529 : GrProcessorUnitTest::kAlphaTextureIdx;
530 static const SkShader::TileMode kTileModes[] = {
531 SkShader::kClamp_TileMode,
532 SkShader::kRepeat_TileMode,
533 SkShader::kMirror_TileMode,
534 };
535 SkShader::TileMode tileModes[] = {
536 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
537 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
538 };
539 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode
540 : GrTextureParams::kNone_FilterMode);
541
joshualitt8059eb92014-12-29 15:10:07 -0800542 return GrDistanceFieldNoGammaTextureEffect::Create(GrRandomColor(random),
543 GrProcessorUnitTest::TestMatrix(random),
544 textures[texIdx],
joshualitt2e3b3e32014-12-09 13:31:14 -0800545 params,
joshualitt56995b52014-12-11 15:44:02 -0800546 random->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0, random->nextBool());
jvanverthfa38a302014-10-06 05:59:05 -0700547}
548
549///////////////////////////////////////////////////////////////////////////////
550
joshualitt9b989322014-12-15 14:16:27 -0800551struct DistanceFieldLCDBatchTracker {
552 GrGPInput fInputColorType;
553 GrColor fColor;
joshualitt290c09b2014-12-19 13:45:20 -0800554 bool fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800555};
556
joshualitt249af152014-09-15 11:41:13 -0700557class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000558public:
joshualitteb2a6762014-12-04 11:35:33 -0800559 GrGLDistanceFieldLCDTextureEffect(const GrGeometryProcessor&,
joshualitt87f48d92014-12-04 10:41:40 -0800560 const GrBatchTracker&)
joshualitt9b989322014-12-15 14:16:27 -0800561 : fColor(GrColor_ILLEGAL)
562 , fTextureSize(SkISize::Make(-1,-1))
jvanverth9564ce62014-09-16 05:45:19 -0700563 , fTextColor(GrColor_ILLEGAL) {}
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000564
mtklein72c9faa2015-01-09 10:06:39 -0800565 void emitCode(const EmitArgs& args) SK_OVERRIDE {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000566 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
joshualittc369e7c2014-10-22 10:56:26 -0700567 args.fGP.cast<GrDistanceFieldLCDTextureEffect>();
joshualitt9b989322014-12-15 14:16:27 -0800568 const DistanceFieldLCDBatchTracker& local = args.fBT.cast<DistanceFieldLCDBatchTracker>();
569 GrGLGPBuilder* pb = args.fPB;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000570
joshualittc369e7c2014-10-22 10:56:26 -0700571 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
joshualitt2dd1ae02014-12-03 06:24:10 -0800572 GrGLVertToFrag v(kVec2f_GrSLType);
573 args.fPB->addVarying("TextureCoords", &v);
574 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName);
575
joshualitt9b989322014-12-15 14:16:27 -0800576 // setup pass through color
577 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL,
578 &fColorUniform);
579
joshualitt2dd1ae02014-12-03 06:24:10 -0800580 // setup coord outputs
581 vsBuilder->codeAppendf("%s = %s;", vsBuilder->positionCoords(),
582 dfTexEffect.inPosition()->fName);
583 vsBuilder->codeAppendf("%s = %s;", vsBuilder->localCoords(),
584 dfTexEffect.inPosition()->fName);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000585
joshualittee2af952014-12-30 09:04:15 -0800586 // setup uniform viewMatrix
587 this->addUniformViewMatrix(pb);
588
joshualitt4973d9d2014-11-08 09:24:25 -0800589 // setup position varying
joshualittee2af952014-12-30 09:04:15 -0800590 vsBuilder->codeAppendf("%s = %s * vec3(%s, 1);", vsBuilder->glPosition(), this->uViewM(),
591 dfTexEffect.inPosition()->fName);
joshualitt4973d9d2014-11-08 09:24:25 -0800592
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000593 const char* textureSizeUniName = NULL;
594 // width, height, 1/(3*width)
joshualittc369e7c2014-10-22 10:56:26 -0700595 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800596 kVec3f_GrSLType, kDefault_GrSLPrecision,
597 "TextureSize", &textureSizeUniName);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000598
joshualittc369e7c2014-10-22 10:56:26 -0700599 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
joshualitt30ba4362014-08-21 20:18:45 -0700600
601 SkAssertResult(fsBuilder->enableFeature(
602 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
603
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000604 // create LCD offset adjusted by inverse of transform
joshualitt74077b92014-10-24 11:26:03 -0700605 fsBuilder->codeAppendf("\tvec2 uv = %s;\n", v.fsIn());
joshualitt30ba4362014-08-21 20:18:45 -0700606 fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
jvanverth78f07182014-07-30 06:17:59 -0700607 bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
608 if (isUniformScale) {
joshualitt30ba4362014-08-21 20:18:45 -0700609 fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n");
610 fsBuilder->codeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000611 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700612 fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
613 fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
614 fsBuilder->codeAppendf("\tvec2 offset = %s.z*Jdx;\n", textureSizeUniName);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000615 }
616
617 // green is distance to uv center
joshualitt30ba4362014-08-21 20:18:45 -0700618 fsBuilder->codeAppend("\tvec4 texColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700619 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700620 fsBuilder->codeAppend(";\n");
621 fsBuilder->codeAppend("\tvec3 distance;\n");
622 fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000623 // red is distance to left offset
joshualitt30ba4362014-08-21 20:18:45 -0700624 fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
625 fsBuilder->codeAppend("\ttexColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700626 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700627 fsBuilder->codeAppend(";\n");
628 fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000629 // blue is distance to right offset
joshualitt30ba4362014-08-21 20:18:45 -0700630 fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
631 fsBuilder->codeAppend("\ttexColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700632 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700633 fsBuilder->codeAppend(";\n");
634 fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700635
joshualitt30ba4362014-08-21 20:18:45 -0700636 fsBuilder->codeAppend("\tdistance = "
jvanverthada68ef2014-11-03 14:00:24 -0800637 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
jvanverth2d2a68c2014-06-10 06:42:56 -0700638
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000639 // we adjust for the effect of the transformation on the distance by using
640 // the length of the gradient of the texture coordinates. We use st coordinates
641 // to ensure we're mapping 1:1 from texel space to pixel space.
642
643 // To be strictly correct, we should compute the anti-aliasing factor separately
644 // for each color component. However, this is only important when using perspective
645 // transformations, and even then using a single factor seems like a reasonable
646 // trade-off between quality and speed.
joshualitt30ba4362014-08-21 20:18:45 -0700647 fsBuilder->codeAppend("\tfloat afwidth;\n");
jvanverth78f07182014-07-30 06:17:59 -0700648 if (isUniformScale) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000649 // this gives us a smooth step across approximately one fragment
jvanverthfa38a302014-10-06 05:59:05 -0700650 fsBuilder->codeAppend("\tafwidth = abs(" SK_DistanceFieldAAFactor "*dx);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000651 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700652 fsBuilder->codeAppend("\tvec2 uv_grad;\n");
joshualittc369e7c2014-10-22 10:56:26 -0700653 if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000654 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
joshualitt30ba4362014-08-21 20:18:45 -0700655 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
656 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
657 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
658 fsBuilder->codeAppend("\t} else {\n");
659 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
660 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000661 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700662 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000663 }
joshualitt30ba4362014-08-21 20:18:45 -0700664 fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
665 fsBuilder->codeAppend("\t uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000666
667 // this gives us a smooth step across approximately one fragment
joshualitt30ba4362014-08-21 20:18:45 -0700668 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000669 }
670
joshualitt30ba4362014-08-21 20:18:45 -0700671 fsBuilder->codeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000672
jvanverth2d2a68c2014-06-10 06:42:56 -0700673 // adjust based on gamma
674 const char* textColorUniName = NULL;
675 // width, height, 1/(3*width)
joshualittc369e7c2014-10-22 10:56:26 -0700676 fTextColorUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
bsalomon422f56f2014-12-09 10:18:12 -0800677 kVec3f_GrSLType, kDefault_GrSLPrecision,
678 "TextColor", &textColorUniName);
jvanverth2d2a68c2014-06-10 06:42:56 -0700679
joshualitt30ba4362014-08-21 20:18:45 -0700680 fsBuilder->codeAppendf("\tuv = vec2(val.x, %s.x);\n", textColorUniName);
681 fsBuilder->codeAppend("\tvec4 gammaColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700682 fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700683 fsBuilder->codeAppend(";\n");
684 fsBuilder->codeAppend("\tval.x = gammaColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700685
joshualitt30ba4362014-08-21 20:18:45 -0700686 fsBuilder->codeAppendf("\tuv = vec2(val.y, %s.y);\n", textColorUniName);
687 fsBuilder->codeAppend("\tgammaColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700688 fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700689 fsBuilder->codeAppend(";\n");
690 fsBuilder->codeAppend("\tval.y = gammaColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700691
joshualitt30ba4362014-08-21 20:18:45 -0700692 fsBuilder->codeAppendf("\tuv = vec2(val.z, %s.z);\n", textColorUniName);
693 fsBuilder->codeAppend("\tgammaColor = ");
joshualittc369e7c2014-10-22 10:56:26 -0700694 fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -0700695 fsBuilder->codeAppend(";\n");
696 fsBuilder->codeAppend("\tval.z = gammaColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700697
joshualitt2dd1ae02014-12-03 06:24:10 -0800698 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000699 }
700
kkinnunen7510b222014-07-30 00:04:16 -0700701 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt9b989322014-12-15 14:16:27 -0800702 const GrPrimitiveProcessor& processor,
703 const GrBatchTracker& bt) SK_OVERRIDE {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000704 SkASSERT(fTextureSizeUni.isValid());
jvanverth2d2a68c2014-06-10 06:42:56 -0700705 SkASSERT(fTextColorUni.isValid());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000706
jvanverth2d2a68c2014-06-10 06:42:56 -0700707 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
joshualittb0a8a372014-09-23 09:50:21 -0700708 processor.cast<GrDistanceFieldLCDTextureEffect>();
709 GrTexture* texture = processor.texture(0);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000710 if (texture->width() != fTextureSize.width() ||
711 texture->height() != fTextureSize.height()) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000712 fTextureSize = SkISize::Make(texture->width(), texture->height());
713 float delta = 1.0f/(3.0f*texture->width());
jvanverth78f07182014-07-30 06:17:59 -0700714 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000715 delta = -delta;
716 }
kkinnunen7510b222014-07-30 00:04:16 -0700717 pdman.set3f(fTextureSizeUni,
718 SkIntToScalar(fTextureSize.width()),
719 SkIntToScalar(fTextureSize.height()),
720 delta);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000721 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700722
723 GrColor textColor = dfTexEffect.getTextColor();
724 if (textColor != fTextColor) {
725 static const float ONE_OVER_255 = 1.f / 255.f;
kkinnunen7510b222014-07-30 00:04:16 -0700726 pdman.set3f(fTextColorUni,
727 GrColorUnpackR(textColor) * ONE_OVER_255,
728 GrColorUnpackG(textColor) * ONE_OVER_255,
729 GrColorUnpackB(textColor) * ONE_OVER_255);
jvanverth2d2a68c2014-06-10 06:42:56 -0700730 fTextColor = textColor;
731 }
joshualitt9b989322014-12-15 14:16:27 -0800732
joshualittee2af952014-12-30 09:04:15 -0800733 this->setUniformViewMatrix(pdman, processor.viewMatrix());
734
joshualitt9b989322014-12-15 14:16:27 -0800735 const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
736 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) {
737 GrGLfloat c[4];
738 GrColorToRGBAFloat(local.fColor, c);
739 pdman.set4fv(fColorUniform, 1, c);
740 fColor = local.fColor;
741 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000742 }
743
joshualitt87f48d92014-12-04 10:41:40 -0800744 static inline void GenKey(const GrGeometryProcessor& processor,
joshualitt9b989322014-12-15 14:16:27 -0800745 const GrBatchTracker& bt,
joshualitt87f48d92014-12-04 10:41:40 -0800746 const GrGLCaps&,
joshualittb0a8a372014-09-23 09:50:21 -0700747 GrProcessorKeyBuilder* b) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000748 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
joshualittb0a8a372014-09-23 09:50:21 -0700749 processor.cast<GrDistanceFieldLCDTextureEffect>();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000750
joshualitt9b989322014-12-15 14:16:27 -0800751 const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>();
joshualitt8fc6c2d2014-12-22 15:27:05 -0800752 uint32_t key = dfTexEffect.getFlags();
753 key |= local.fInputColorType << 16;
754 key |= local.fUsesLocalCoords && processor.localMatrix().hasPerspective() ? 0x1 << 24: 0x0;
755 b->add32(key);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000756 }
757
758private:
joshualitt9b989322014-12-15 14:16:27 -0800759 GrColor fColor;
760 UniformHandle fColorUniform;
761 UniformHandle fTextureSizeUni;
762 SkISize fTextureSize;
763 UniformHandle fTextColorUni;
764 SkColor fTextColor;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000765
joshualitt249af152014-09-15 11:41:13 -0700766 typedef GrGLGeometryProcessor INHERITED;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000767};
768
769///////////////////////////////////////////////////////////////////////////////
770
jvanverth2d2a68c2014-06-10 06:42:56 -0700771GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect(
joshualitt8059eb92014-12-29 15:10:07 -0800772 GrColor color, const SkMatrix& viewMatrix,
jvanverth2d2a68c2014-06-10 06:42:56 -0700773 GrTexture* texture, const GrTextureParams& params,
774 GrTexture* gamma, const GrTextureParams& gParams,
775 SkColor textColor,
jvanverth78f07182014-07-30 06:17:59 -0700776 uint32_t flags)
joshualitt8059eb92014-12-29 15:10:07 -0800777 : INHERITED(color, viewMatrix, SkMatrix::I())
joshualitt2e3b3e32014-12-09 13:31:14 -0800778 , fTextureAccess(texture, params)
jvanverth2d2a68c2014-06-10 06:42:56 -0700779 , fGammaTextureAccess(gamma, gParams)
780 , fTextColor(textColor)
joshualitt2dd1ae02014-12-03 06:24:10 -0800781 , fFlags(flags & kLCD_DistanceFieldEffectMask){
jvanverth78f07182014-07-30 06:17:59 -0700782 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
joshualitteb2a6762014-12-04 11:35:33 -0800783 this->initClassID<GrDistanceFieldLCDTextureEffect>();
joshualitt2dd1ae02014-12-03 06:24:10 -0800784 fInPosition = &this->addVertexAttrib(GrAttribute("inPosition", kVec2f_GrVertexAttribType));
785 fInTextureCoords = &this->addVertexAttrib(GrAttribute("inTextureCoords",
786 kVec2f_GrVertexAttribType));
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000787 this->addTextureAccess(&fTextureAccess);
jvanverth2d2a68c2014-06-10 06:42:56 -0700788 this->addTextureAccess(&fGammaTextureAccess);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000789}
790
bsalomon0e08fc12014-10-15 08:19:04 -0700791bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
joshualitt49586be2014-09-16 08:21:41 -0700792 const GrDistanceFieldLCDTextureEffect& cte = other.cast<GrDistanceFieldLCDTextureEffect>();
bsalomon420d7e92014-10-16 09:18:09 -0700793 return (fTextColor == cte.fTextColor &&
jvanverth78f07182014-07-30 06:17:59 -0700794 fFlags == cte.fFlags);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000795}
796
joshualitt56995b52014-12-11 15:44:02 -0800797void GrDistanceFieldLCDTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const {
798 out->setUnknownFourComponents();
799 out->setUsingLCDCoverage();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000800}
801
joshualitteb2a6762014-12-04 11:35:33 -0800802void GrDistanceFieldLCDTextureEffect::getGLProcessorKey(const GrBatchTracker& bt,
803 const GrGLCaps& caps,
804 GrProcessorKeyBuilder* b) const {
805 GrGLDistanceFieldLCDTextureEffect::GenKey(*this, bt, caps, b);
806}
807
808GrGLGeometryProcessor*
809GrDistanceFieldLCDTextureEffect::createGLInstance(const GrBatchTracker& bt) const {
810 return SkNEW_ARGS(GrGLDistanceFieldLCDTextureEffect, (*this, bt));
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000811}
812
joshualitt9b989322014-12-15 14:16:27 -0800813void GrDistanceFieldLCDTextureEffect::initBatchTracker(GrBatchTracker* bt,
814 const InitBT& init) const {
815 DistanceFieldLCDBatchTracker* local = bt->cast<DistanceFieldLCDBatchTracker>();
816 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false);
joshualitt290c09b2014-12-19 13:45:20 -0800817 local->fUsesLocalCoords = init.fUsesLocalCoords;
joshualitt9b989322014-12-15 14:16:27 -0800818}
819
820bool GrDistanceFieldLCDTextureEffect::onCanMakeEqual(const GrBatchTracker& m,
joshualitt290c09b2014-12-19 13:45:20 -0800821 const GrGeometryProcessor& that,
joshualitt9b989322014-12-15 14:16:27 -0800822 const GrBatchTracker& t) const {
823 const DistanceFieldLCDBatchTracker& mine = m.cast<DistanceFieldLCDBatchTracker>();
824 const DistanceFieldLCDBatchTracker& theirs = t.cast<DistanceFieldLCDBatchTracker>();
joshualitt290c09b2014-12-19 13:45:20 -0800825 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords,
826 that, theirs.fUsesLocalCoords) &&
827 CanCombineOutput(mine.fInputColorType, mine.fColor,
joshualitt9b989322014-12-15 14:16:27 -0800828 theirs.fInputColorType, theirs.fColor);
829}
830
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000831///////////////////////////////////////////////////////////////////////////////
832
joshualittb0a8a372014-09-23 09:50:21 -0700833GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000834
joshualittb0a8a372014-09-23 09:50:21 -0700835GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random,
836 GrContext*,
837 const GrDrawTargetCaps&,
838 GrTexture* textures[]) {
839 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
840 GrProcessorUnitTest::kAlphaTextureIdx;
841 int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
842 GrProcessorUnitTest::kAlphaTextureIdx;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000843 static const SkShader::TileMode kTileModes[] = {
844 SkShader::kClamp_TileMode,
845 SkShader::kRepeat_TileMode,
846 SkShader::kMirror_TileMode,
847 };
848 SkShader::TileMode tileModes[] = {
849 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
850 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
851 };
852 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
853 GrTextureParams::kNone_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700854 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
855 GrTextureParams::kNone_FilterMode);
856 GrColor textColor = GrColorPackRGBA(random->nextULessThan(256),
857 random->nextULessThan(256),
858 random->nextULessThan(256),
859 random->nextULessThan(256));
jvanverth78f07182014-07-30 06:17:59 -0700860 uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
861 flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
862 flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
joshualitt8059eb92014-12-29 15:10:07 -0800863 return GrDistanceFieldLCDTextureEffect::Create(GrRandomColor(random),
864 GrProcessorUnitTest::TestMatrix(random),
865 textures[texIdx], params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700866 textures[texIdx2], params2,
867 textColor,
jvanverth78f07182014-07-30 06:17:59 -0700868 flags);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000869}