blob: ab765257197dceb9d5d5e240fa392565c70aecef [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"
joshualitt408d6122014-09-17 07:00:35 -07009#include "gl/builders/GrGLFullProgramBuilder.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000010#include "gl/GrGLEffect.h"
11#include "gl/GrGLSL.h"
12#include "gl/GrGLTexture.h"
joshualitt249af152014-09-15 11:41:13 -070013#include "gl/GrGLGeometryProcessor.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000014#include "GrTBackendEffectFactory.h"
15#include "GrTexture.h"
16
commit-bot@chromium.org762cd802014-04-14 22:05:07 +000017#include "SkDistanceFieldGen.h"
jvanverth@google.comd830d132013-11-11 20:54:09 +000018
jvanverth2d2a68c2014-06-10 06:42:56 -070019// To get optical sizes people don't complain about when we blit correctly,
20// we need to slightly bold each glyph. On the Mac, we need a larger bold value.
21#if defined(SK_BUILD_FOR_MAC)
22#define SK_DistanceFieldLCDFactor "0.33"
23#define SK_DistanceFieldNonLCDFactor "0.25"
24#else
25#define SK_DistanceFieldLCDFactor "0.05"
26#define SK_DistanceFieldNonLCDFactor "0.05"
27#endif
28
29// Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2
30#define SK_DistanceFieldAAFactor "0.7071"
31
joshualitt249af152014-09-15 11:41:13 -070032class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
jvanverth@google.comd830d132013-11-11 20:54:09 +000033public:
skia.committer@gmail.coma3b53272014-02-15 03:02:15 +000034 GrGLDistanceFieldTextureEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -070035 const GrEffect& effect)
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000036 : INHERITED (factory)
jvanverth9564ce62014-09-16 05:45:19 -070037 , fTextureSize(SkISize::Make(-1,-1))
38#ifdef SK_GAMMA_APPLY_TO_A8
39 , fLuminance(-1.0f)
40#endif
41 {}
jvanverth@google.comd830d132013-11-11 20:54:09 +000042
joshualitt30ba4362014-08-21 20:18:45 -070043 virtual void emitCode(GrGLFullProgramBuilder* builder,
joshualitt49586be2014-09-16 08:21:41 -070044 const GrEffect& effect,
bsalomon63e99f72014-07-21 08:03:14 -070045 const GrEffectKey& key,
jvanverth@google.comd830d132013-11-11 20:54:09 +000046 const char* outputColor,
47 const char* inputColor,
48 const TransformedCoordsArray&,
49 const TextureSamplerArray& samplers) SK_OVERRIDE {
joshualitt249af152014-09-15 11:41:13 -070050 const GrDistanceFieldTextureEffect& dfTexEffect =
joshualitt49586be2014-09-16 08:21:41 -070051 effect.cast<GrDistanceFieldTextureEffect>();
joshualitt249af152014-09-15 11:41:13 -070052 SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
jvanverth@google.comd830d132013-11-11 20:54:09 +000053
joshualitt30ba4362014-08-21 20:18:45 -070054 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
55 SkAssertResult(fsBuilder->enableFeature(
56 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
jvanverth@google.comd830d132013-11-11 20:54:09 +000057
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000058 SkString fsCoordName;
59 const char* vsCoordName;
60 const char* fsCoordNamePtr;
61 builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
62 fsCoordName = fsCoordNamePtr;
63
joshualitt30ba4362014-08-21 20:18:45 -070064 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
joshualitt249af152014-09-15 11:41:13 -070065 vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000066
67 const char* textureSizeUniName = NULL;
joshualitt30ba4362014-08-21 20:18:45 -070068 fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000069 kVec2f_GrSLType, "TextureSize",
70 &textureSizeUniName);
jvanverth@google.comd830d132013-11-11 20:54:09 +000071
joshualitt30ba4362014-08-21 20:18:45 -070072 fsBuilder->codeAppend("\tvec4 texColor = ");
73 fsBuilder->appendTextureLookup(samplers[0],
jvanverth@google.comd830d132013-11-11 20:54:09 +000074 fsCoordName.c_str(),
75 kVec2f_GrSLType);
joshualitt30ba4362014-08-21 20:18:45 -070076 fsBuilder->codeAppend(";\n");
77 fsBuilder->codeAppend("\tfloat distance = "
jvanverth2d2a68c2014-06-10 06:42:56 -070078 SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ")"
79 "+ " SK_DistanceFieldNonLCDFactor ";\n");
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000080
81 // we adjust for the effect of the transformation on the distance by using
82 // the length of the gradient of the texture coordinates. We use st coordinates
83 // to ensure we're mapping 1:1 from texel space to pixel space.
joshualitt30ba4362014-08-21 20:18:45 -070084 fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
85 fsBuilder->codeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName);
86 fsBuilder->codeAppend("\tfloat afwidth;\n");
jvanverth78f07182014-07-30 06:17:59 -070087 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
commit-bot@chromium.org4362a382014-03-26 19:49:03 +000088 // this gives us a smooth step across approximately one fragment
joshualitt30ba4362014-08-21 20:18:45 -070089 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dFdx(st.x);\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +000090 } else {
joshualitt30ba4362014-08-21 20:18:45 -070091 fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
92 fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +000093
joshualitt30ba4362014-08-21 20:18:45 -070094 fsBuilder->codeAppend("\tvec2 uv_grad;\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +000095 if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) {
96 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
joshualitt30ba4362014-08-21 20:18:45 -070097 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
98 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
99 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
100 fsBuilder->codeAppend("\t} else {\n");
101 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
102 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000103 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700104 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000105 }
joshualitt30ba4362014-08-21 20:18:45 -0700106 fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
107 fsBuilder->codeAppend("\t uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000108
109 // this gives us a smooth step across approximately one fragment
joshualitt30ba4362014-08-21 20:18:45 -0700110 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000111 }
joshualitt30ba4362014-08-21 20:18:45 -0700112 fsBuilder->codeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n");
jvanverth@google.comd830d132013-11-11 20:54:09 +0000113
jvanverth2d2a68c2014-06-10 06:42:56 -0700114#ifdef SK_GAMMA_APPLY_TO_A8
115 // adjust based on gamma
116 const char* luminanceUniName = NULL;
117 // width, height, 1/(3*width)
joshualitt30ba4362014-08-21 20:18:45 -0700118 fLuminanceUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
jvanverth2d2a68c2014-06-10 06:42:56 -0700119 kFloat_GrSLType, "Luminance",
120 &luminanceUniName);
121
joshualitt30ba4362014-08-21 20:18:45 -0700122 fsBuilder->codeAppendf("\tuv = vec2(val, %s);\n", luminanceUniName);
123 fsBuilder->codeAppend("\tvec4 gammaColor = ");
124 fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
125 fsBuilder->codeAppend(";\n");
126 fsBuilder->codeAppend("\tval = gammaColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700127#endif
128
joshualitt30ba4362014-08-21 20:18:45 -0700129 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
jvanverth@google.comd830d132013-11-11 20:54:09 +0000130 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str());
131 }
132
kkinnunen7510b222014-07-30 00:04:16 -0700133 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -0700134 const GrEffect& effect) SK_OVERRIDE {
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000135 SkASSERT(fTextureSizeUni.isValid());
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000136
joshualitt49586be2014-09-16 08:21:41 -0700137 GrTexture* texture = effect.texture(0);
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000138 if (texture->width() != fTextureSize.width() ||
139 texture->height() != fTextureSize.height()) {
140 fTextureSize = SkISize::Make(texture->width(), texture->height());
kkinnunen7510b222014-07-30 00:04:16 -0700141 pdman.set2f(fTextureSizeUni,
142 SkIntToScalar(fTextureSize.width()),
143 SkIntToScalar(fTextureSize.height()));
commit-bot@chromium.org66beaf02014-03-26 18:21:55 +0000144 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700145#ifdef SK_GAMMA_APPLY_TO_A8
146 const GrDistanceFieldTextureEffect& dfTexEffect =
joshualitt49586be2014-09-16 08:21:41 -0700147 effect.cast<GrDistanceFieldTextureEffect>();
jvanverth2d2a68c2014-06-10 06:42:56 -0700148 float luminance = dfTexEffect.getLuminance();
149 if (luminance != fLuminance) {
kkinnunen7510b222014-07-30 00:04:16 -0700150 pdman.set1f(fLuminanceUni, luminance);
jvanverth2d2a68c2014-06-10 06:42:56 -0700151 fLuminance = luminance;
152 }
153#endif
commit-bot@chromium.org8fe2ee12014-03-26 18:03:05 +0000154 }
155
joshualitt49586be2014-09-16 08:21:41 -0700156 static inline void GenKey(const GrEffect& effect, const GrGLCaps&,
bsalomon63e99f72014-07-21 08:03:14 -0700157 GrEffectKeyBuilder* b) {
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000158 const GrDistanceFieldTextureEffect& dfTexEffect =
joshualitt49586be2014-09-16 08:21:41 -0700159 effect.cast<GrDistanceFieldTextureEffect>();
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000160
jvanverth78f07182014-07-30 06:17:59 -0700161 b->add32(dfTexEffect.getFlags());
commit-bot@chromium.org4362a382014-03-26 19:49:03 +0000162 }
163
jvanverth@google.comd830d132013-11-11 20:54:09 +0000164private:
kkinnunen7510b222014-07-30 00:04:16 -0700165 GrGLProgramDataManager::UniformHandle fTextureSizeUni;
166 SkISize fTextureSize;
167 GrGLProgramDataManager::UniformHandle fLuminanceUni;
168 float fLuminance;
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000169
joshualitt249af152014-09-15 11:41:13 -0700170 typedef GrGLGeometryProcessor INHERITED;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000171};
172
173///////////////////////////////////////////////////////////////////////////////
174
175GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture,
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000176 const GrTextureParams& params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700177#ifdef SK_GAMMA_APPLY_TO_A8
178 GrTexture* gamma,
179 const GrTextureParams& gammaParams,
180 float luminance,
181#endif
jvanverth78f07182014-07-30 06:17:59 -0700182 uint32_t flags)
commit-bot@chromium.org6c89c342014-02-14 21:48:29 +0000183 : fTextureAccess(texture, params)
jvanverth2d2a68c2014-06-10 06:42:56 -0700184#ifdef SK_GAMMA_APPLY_TO_A8
185 , fGammaTextureAccess(gamma, gammaParams)
186 , fLuminance(luminance)
187#endif
joshualitt249af152014-09-15 11:41:13 -0700188 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
189 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
190 kVec2f_GrSLType,
191 GrShaderVar::kAttribute_TypeModifier))) {
jvanverth78f07182014-07-30 06:17:59 -0700192 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
jvanverth@google.comd830d132013-11-11 20:54:09 +0000193 this->addTextureAccess(&fTextureAccess);
jvanverth2d2a68c2014-06-10 06:42:56 -0700194#ifdef SK_GAMMA_APPLY_TO_A8
195 this->addTextureAccess(&fGammaTextureAccess);
196#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000197}
198
199bool GrDistanceFieldTextureEffect::onIsEqual(const GrEffect& other) const {
joshualitt49586be2014-09-16 08:21:41 -0700200 const GrDistanceFieldTextureEffect& cte = other.cast<GrDistanceFieldTextureEffect>();
jvanverth78f07182014-07-30 06:17:59 -0700201 return fTextureAccess == cte.fTextureAccess &&
202#ifdef SK_GAMMA_APPLY_TO_A8
203 fGammaTextureAccess == cte.fGammaTextureAccess &&
204 fLuminance == cte.fLuminance &&
205#endif
206 fFlags == cte.fFlags;
jvanverth@google.comd830d132013-11-11 20:54:09 +0000207}
208
209void GrDistanceFieldTextureEffect::getConstantColorComponents(GrColor* color,
210 uint32_t* validFlags) const {
211 if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) &&
212 GrPixelConfigIsOpaque(this->texture(0)->config())) {
213 *validFlags = kA_GrColorComponentFlag;
214 } else {
215 *validFlags = 0;
216 }
217}
218
219const GrBackendEffectFactory& GrDistanceFieldTextureEffect::getFactory() const {
220 return GrTBackendEffectFactory<GrDistanceFieldTextureEffect>::getInstance();
221}
222
223///////////////////////////////////////////////////////////////////////////////
224
225GR_DEFINE_EFFECT_TEST(GrDistanceFieldTextureEffect);
226
bsalomon83d081a2014-07-08 09:56:10 -0700227GrEffect* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
228 GrContext*,
229 const GrDrawTargetCaps&,
230 GrTexture* textures[]) {
jvanverth@google.comd830d132013-11-11 20:54:09 +0000231 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
232 GrEffectUnitTest::kAlphaTextureIdx;
jvanverth2d2a68c2014-06-10 06:42:56 -0700233#ifdef SK_GAMMA_APPLY_TO_A8
234 int texIdx2 = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
235 GrEffectUnitTest::kAlphaTextureIdx;
236#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000237 static const SkShader::TileMode kTileModes[] = {
238 SkShader::kClamp_TileMode,
239 SkShader::kRepeat_TileMode,
240 SkShader::kMirror_TileMode,
241 };
242 SkShader::TileMode tileModes[] = {
243 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
244 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
245 };
246 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
247 GrTextureParams::kNone_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700248#ifdef SK_GAMMA_APPLY_TO_A8
249 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
250 GrTextureParams::kNone_FilterMode);
251#endif
jvanverth@google.comd830d132013-11-11 20:54:09 +0000252
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000253 return GrDistanceFieldTextureEffect::Create(textures[texIdx], params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700254#ifdef SK_GAMMA_APPLY_TO_A8
255 textures[texIdx2], params2,
256 random->nextF(),
257#endif
jvanverth78f07182014-07-30 06:17:59 -0700258 random->nextBool() ?
259 kSimilarity_DistanceFieldEffectFlag : 0);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000260}
261
262///////////////////////////////////////////////////////////////////////////////
263
joshualitt249af152014-09-15 11:41:13 -0700264class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000265public:
266 GrGLDistanceFieldLCDTextureEffect(const GrBackendEffectFactory& factory,
joshualitt49586be2014-09-16 08:21:41 -0700267 const GrEffect& effect)
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000268 : INHERITED (factory)
jvanverth9564ce62014-09-16 05:45:19 -0700269 , fTextureSize(SkISize::Make(-1,-1))
270 , fTextColor(GrColor_ILLEGAL) {}
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000271
joshualitt30ba4362014-08-21 20:18:45 -0700272 virtual void emitCode(GrGLFullProgramBuilder* builder,
joshualitt49586be2014-09-16 08:21:41 -0700273 const GrEffect& effect,
bsalomon63e99f72014-07-21 08:03:14 -0700274 const GrEffectKey& key,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000275 const char* outputColor,
276 const char* inputColor,
277 const TransformedCoordsArray&,
278 const TextureSamplerArray& samplers) SK_OVERRIDE {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000279 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
joshualitt49586be2014-09-16 08:21:41 -0700280 effect.cast<GrDistanceFieldLCDTextureEffect>();
joshualitt249af152014-09-15 11:41:13 -0700281 SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000282
283 SkString fsCoordName;
284 const char* vsCoordName;
285 const char* fsCoordNamePtr;
286 builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
287 fsCoordName = fsCoordNamePtr;
288
joshualitt30ba4362014-08-21 20:18:45 -0700289 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
joshualitt249af152014-09-15 11:41:13 -0700290 vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000291
292 const char* textureSizeUniName = NULL;
293 // width, height, 1/(3*width)
joshualitt30ba4362014-08-21 20:18:45 -0700294 fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000295 kVec3f_GrSLType, "TextureSize",
296 &textureSizeUniName);
297
joshualitt30ba4362014-08-21 20:18:45 -0700298 GrGLFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
299
300 SkAssertResult(fsBuilder->enableFeature(
301 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
302
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000303 // create LCD offset adjusted by inverse of transform
joshualitt30ba4362014-08-21 20:18:45 -0700304 fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str());
305 fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
jvanverth78f07182014-07-30 06:17:59 -0700306 bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
307 if (isUniformScale) {
joshualitt30ba4362014-08-21 20:18:45 -0700308 fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n");
309 fsBuilder->codeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000310 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700311 fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
312 fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
313 fsBuilder->codeAppendf("\tvec2 offset = %s.z*Jdx;\n", textureSizeUniName);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000314 }
315
316 // green is distance to uv center
joshualitt30ba4362014-08-21 20:18:45 -0700317 fsBuilder->codeAppend("\tvec4 texColor = ");
318 fsBuilder->appendTextureLookup(samplers[0], "uv", kVec2f_GrSLType);
319 fsBuilder->codeAppend(";\n");
320 fsBuilder->codeAppend("\tvec3 distance;\n");
321 fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000322 // red is distance to left offset
joshualitt30ba4362014-08-21 20:18:45 -0700323 fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
324 fsBuilder->codeAppend("\ttexColor = ");
325 fsBuilder->appendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
326 fsBuilder->codeAppend(";\n");
327 fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000328 // blue is distance to right offset
joshualitt30ba4362014-08-21 20:18:45 -0700329 fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
330 fsBuilder->codeAppend("\ttexColor = ");
331 fsBuilder->appendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType);
332 fsBuilder->codeAppend(";\n");
333 fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700334
joshualitt30ba4362014-08-21 20:18:45 -0700335 fsBuilder->codeAppend("\tdistance = "
jvanverth2d2a68c2014-06-10 06:42:56 -0700336 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"))"
337 "+ vec3(" SK_DistanceFieldLCDFactor ");\n");
338
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000339 // we adjust for the effect of the transformation on the distance by using
340 // the length of the gradient of the texture coordinates. We use st coordinates
341 // to ensure we're mapping 1:1 from texel space to pixel space.
342
343 // To be strictly correct, we should compute the anti-aliasing factor separately
344 // for each color component. However, this is only important when using perspective
345 // transformations, and even then using a single factor seems like a reasonable
346 // trade-off between quality and speed.
joshualitt30ba4362014-08-21 20:18:45 -0700347 fsBuilder->codeAppend("\tfloat afwidth;\n");
jvanverth78f07182014-07-30 06:17:59 -0700348 if (isUniformScale) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000349 // this gives us a smooth step across approximately one fragment
joshualitt30ba4362014-08-21 20:18:45 -0700350 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dx;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000351 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700352 fsBuilder->codeAppend("\tvec2 uv_grad;\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000353 if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) {
354 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
joshualitt30ba4362014-08-21 20:18:45 -0700355 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
356 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
357 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
358 fsBuilder->codeAppend("\t} else {\n");
359 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
360 fsBuilder->codeAppend("\t}\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000361 } else {
joshualitt30ba4362014-08-21 20:18:45 -0700362 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000363 }
joshualitt30ba4362014-08-21 20:18:45 -0700364 fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
365 fsBuilder->codeAppend("\t uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000366
367 // this gives us a smooth step across approximately one fragment
joshualitt30ba4362014-08-21 20:18:45 -0700368 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000369 }
370
joshualitt30ba4362014-08-21 20:18:45 -0700371 fsBuilder->codeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n");
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000372
jvanverth2d2a68c2014-06-10 06:42:56 -0700373 // adjust based on gamma
374 const char* textColorUniName = NULL;
375 // width, height, 1/(3*width)
joshualitt30ba4362014-08-21 20:18:45 -0700376 fTextColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
jvanverth2d2a68c2014-06-10 06:42:56 -0700377 kVec3f_GrSLType, "TextColor",
378 &textColorUniName);
379
joshualitt30ba4362014-08-21 20:18:45 -0700380 fsBuilder->codeAppendf("\tuv = vec2(val.x, %s.x);\n", textColorUniName);
381 fsBuilder->codeAppend("\tvec4 gammaColor = ");
382 fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
383 fsBuilder->codeAppend(";\n");
384 fsBuilder->codeAppend("\tval.x = gammaColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700385
joshualitt30ba4362014-08-21 20:18:45 -0700386 fsBuilder->codeAppendf("\tuv = vec2(val.y, %s.y);\n", textColorUniName);
387 fsBuilder->codeAppend("\tgammaColor = ");
388 fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
389 fsBuilder->codeAppend(";\n");
390 fsBuilder->codeAppend("\tval.y = gammaColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700391
joshualitt30ba4362014-08-21 20:18:45 -0700392 fsBuilder->codeAppendf("\tuv = vec2(val.z, %s.z);\n", textColorUniName);
393 fsBuilder->codeAppend("\tgammaColor = ");
394 fsBuilder->appendTextureLookup(samplers[1], "uv", kVec2f_GrSLType);
395 fsBuilder->codeAppend(";\n");
396 fsBuilder->codeAppend("\tval.z = gammaColor.r;\n");
jvanverth2d2a68c2014-06-10 06:42:56 -0700397
joshualitt30ba4362014-08-21 20:18:45 -0700398 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000399 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("val")).c_str());
400 }
401
kkinnunen7510b222014-07-30 00:04:16 -0700402 virtual void setData(const GrGLProgramDataManager& pdman,
joshualitt49586be2014-09-16 08:21:41 -0700403 const GrEffect& effect) SK_OVERRIDE {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000404 SkASSERT(fTextureSizeUni.isValid());
jvanverth2d2a68c2014-06-10 06:42:56 -0700405 SkASSERT(fTextColorUni.isValid());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000406
jvanverth2d2a68c2014-06-10 06:42:56 -0700407 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
joshualitt49586be2014-09-16 08:21:41 -0700408 effect.cast<GrDistanceFieldLCDTextureEffect>();
409 GrTexture* texture = effect.texture(0);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000410 if (texture->width() != fTextureSize.width() ||
411 texture->height() != fTextureSize.height()) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000412 fTextureSize = SkISize::Make(texture->width(), texture->height());
413 float delta = 1.0f/(3.0f*texture->width());
jvanverth78f07182014-07-30 06:17:59 -0700414 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000415 delta = -delta;
416 }
kkinnunen7510b222014-07-30 00:04:16 -0700417 pdman.set3f(fTextureSizeUni,
418 SkIntToScalar(fTextureSize.width()),
419 SkIntToScalar(fTextureSize.height()),
420 delta);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000421 }
jvanverth2d2a68c2014-06-10 06:42:56 -0700422
423 GrColor textColor = dfTexEffect.getTextColor();
424 if (textColor != fTextColor) {
425 static const float ONE_OVER_255 = 1.f / 255.f;
kkinnunen7510b222014-07-30 00:04:16 -0700426 pdman.set3f(fTextColorUni,
427 GrColorUnpackR(textColor) * ONE_OVER_255,
428 GrColorUnpackG(textColor) * ONE_OVER_255,
429 GrColorUnpackB(textColor) * ONE_OVER_255);
jvanverth2d2a68c2014-06-10 06:42:56 -0700430 fTextColor = textColor;
431 }
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000432 }
433
joshualitt49586be2014-09-16 08:21:41 -0700434 static inline void GenKey(const GrEffect& effect, const GrGLCaps&,
bsalomon63e99f72014-07-21 08:03:14 -0700435 GrEffectKeyBuilder* b) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000436 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
joshualitt49586be2014-09-16 08:21:41 -0700437 effect.cast<GrDistanceFieldLCDTextureEffect>();
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000438
jvanverth78f07182014-07-30 06:17:59 -0700439 b->add32(dfTexEffect.getFlags());
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000440 }
441
442private:
kkinnunen7510b222014-07-30 00:04:16 -0700443 GrGLProgramDataManager::UniformHandle fTextureSizeUni;
444 SkISize fTextureSize;
445 GrGLProgramDataManager::UniformHandle fTextColorUni;
446 SkColor fTextColor;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000447
joshualitt249af152014-09-15 11:41:13 -0700448 typedef GrGLGeometryProcessor INHERITED;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000449};
450
451///////////////////////////////////////////////////////////////////////////////
452
jvanverth2d2a68c2014-06-10 06:42:56 -0700453GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect(
454 GrTexture* texture, const GrTextureParams& params,
455 GrTexture* gamma, const GrTextureParams& gParams,
456 SkColor textColor,
jvanverth78f07182014-07-30 06:17:59 -0700457 uint32_t flags)
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000458 : fTextureAccess(texture, params)
jvanverth2d2a68c2014-06-10 06:42:56 -0700459 , fGammaTextureAccess(gamma, gParams)
460 , fTextColor(textColor)
joshualitt249af152014-09-15 11:41:13 -0700461 , fFlags(flags & kLCD_DistanceFieldEffectMask)
462 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
463 kVec2f_GrSLType,
464 GrShaderVar::kAttribute_TypeModifier))) {
jvanverth78f07182014-07-30 06:17:59 -0700465 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
466
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000467 this->addTextureAccess(&fTextureAccess);
jvanverth2d2a68c2014-06-10 06:42:56 -0700468 this->addTextureAccess(&fGammaTextureAccess);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000469}
470
471bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrEffect& other) const {
joshualitt49586be2014-09-16 08:21:41 -0700472 const GrDistanceFieldLCDTextureEffect& cte = other.cast<GrDistanceFieldLCDTextureEffect>();
jvanverth78f07182014-07-30 06:17:59 -0700473 return (fTextureAccess == cte.fTextureAccess &&
474 fGammaTextureAccess == cte.fGammaTextureAccess &&
475 fTextColor == cte.fTextColor &&
476 fFlags == cte.fFlags);
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000477}
478
479void GrDistanceFieldLCDTextureEffect::getConstantColorComponents(GrColor* color,
480 uint32_t* validFlags) const {
481 if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) &&
482 GrPixelConfigIsOpaque(this->texture(0)->config())) {
483 *validFlags = kA_GrColorComponentFlag;
484 } else {
485 *validFlags = 0;
486 }
487}
488
489const GrBackendEffectFactory& GrDistanceFieldLCDTextureEffect::getFactory() const {
490 return GrTBackendEffectFactory<GrDistanceFieldLCDTextureEffect>::getInstance();
491}
492
493///////////////////////////////////////////////////////////////////////////////
494
495GR_DEFINE_EFFECT_TEST(GrDistanceFieldLCDTextureEffect);
496
bsalomon83d081a2014-07-08 09:56:10 -0700497GrEffect* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random,
498 GrContext*,
499 const GrDrawTargetCaps&,
500 GrTexture* textures[]) {
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000501 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
jvanverth2d2a68c2014-06-10 06:42:56 -0700502 GrEffectUnitTest::kAlphaTextureIdx;
503 int texIdx2 = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx :
504 GrEffectUnitTest::kAlphaTextureIdx;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000505 static const SkShader::TileMode kTileModes[] = {
506 SkShader::kClamp_TileMode,
507 SkShader::kRepeat_TileMode,
508 SkShader::kMirror_TileMode,
509 };
510 SkShader::TileMode tileModes[] = {
511 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
512 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
513 };
514 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
515 GrTextureParams::kNone_FilterMode);
jvanverth2d2a68c2014-06-10 06:42:56 -0700516 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
517 GrTextureParams::kNone_FilterMode);
518 GrColor textColor = GrColorPackRGBA(random->nextULessThan(256),
519 random->nextULessThan(256),
520 random->nextULessThan(256),
521 random->nextULessThan(256));
jvanverth78f07182014-07-30 06:17:59 -0700522 uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
523 flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
524 flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
commit-bot@chromium.org609ced42014-04-03 18:25:48 +0000525 return GrDistanceFieldLCDTextureEffect::Create(textures[texIdx], params,
jvanverth2d2a68c2014-06-10 06:42:56 -0700526 textures[texIdx2], params2,
527 textColor,
jvanverth78f07182014-07-30 06:17:59 -0700528 flags);
jvanverth@google.comd830d132013-11-11 20:54:09 +0000529}