2 * Copyright 2013 Google Inc.
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
8 #include "GrDistanceFieldTextureEffect.h"
9 #include "gl/builders/GrGLProgramBuilder.h"
10 #include "gl/GrGLProcessor.h"
11 #include "gl/GrGLSL.h"
12 #include "gl/GrGLTexture.h"
13 #include "gl/GrGLGeometryProcessor.h"
14 #include "GrTBackendProcessorFactory.h"
15 #include "GrTexture.h"
17 #include "SkDistanceFieldGen.h"
19 // Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2
20 #define SK_DistanceFieldAAFactor "0.7071"
22 class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
24 GrGLDistanceFieldTextureEffect(const GrBackendProcessorFactory& factory,
27 , fTextureSize(SkISize::Make(-1,-1))
28 #ifdef SK_GAMMA_APPLY_TO_A8
33 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
34 const GrDistanceFieldTextureEffect& dfTexEffect =
35 args.fGP.cast<GrDistanceFieldTextureEffect>();
36 SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
38 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
39 SkAssertResult(fsBuilder->enableFeature(
40 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
42 GrGLVertToFrag v(kVec2f_GrSLType);
43 args.fPB->addVarying("TextureCoords", &v);
45 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
46 vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
48 const char* textureSizeUniName = NULL;
49 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
50 kVec2f_GrSLType, "TextureSize",
53 fsBuilder->codeAppend("\tvec4 texColor = ");
54 fsBuilder->appendTextureLookup(args.fSamplers[0],
57 fsBuilder->codeAppend(";\n");
58 fsBuilder->codeAppend("\tfloat distance = "
59 SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
61 // we adjust for the effect of the transformation on the distance by using
62 // the length of the gradient of the texture coordinates. We use st coordinates
63 // to ensure we're mapping 1:1 from texel space to pixel space.
64 fsBuilder->codeAppendf("\tvec2 uv = %s;\n", v.fsIn());
65 fsBuilder->codeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName);
66 fsBuilder->codeAppend("\tfloat afwidth;\n");
67 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
68 // this gives us a smooth step across approximately one fragment
69 fsBuilder->codeAppend("\tafwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));\n");
71 fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
72 fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
74 fsBuilder->codeAppend("\tvec2 uv_grad;\n");
75 if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
76 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
77 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
78 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
79 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
80 fsBuilder->codeAppend("\t} else {\n");
81 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
82 fsBuilder->codeAppend("\t}\n");
84 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
86 fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
87 fsBuilder->codeAppend("\t uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
89 // this gives us a smooth step across approximately one fragment
90 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
92 fsBuilder->codeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n");
94 #ifdef SK_GAMMA_APPLY_TO_A8
95 // adjust based on gamma
96 const char* luminanceUniName = NULL;
97 // width, height, 1/(3*width)
98 fLuminanceUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
99 kFloat_GrSLType, "Luminance",
102 fsBuilder->codeAppendf("\tuv = vec2(val, %s);\n", luminanceUniName);
103 fsBuilder->codeAppend("\tvec4 gammaColor = ");
104 fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
105 fsBuilder->codeAppend(";\n");
106 fsBuilder->codeAppend("\tval = gammaColor.r;\n");
109 fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
110 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("val")).c_str());
113 virtual void setData(const GrGLProgramDataManager& pdman,
114 const GrProcessor& effect) SK_OVERRIDE {
115 SkASSERT(fTextureSizeUni.isValid());
117 GrTexture* texture = effect.texture(0);
118 if (texture->width() != fTextureSize.width() ||
119 texture->height() != fTextureSize.height()) {
120 fTextureSize = SkISize::Make(texture->width(), texture->height());
121 pdman.set2f(fTextureSizeUni,
122 SkIntToScalar(fTextureSize.width()),
123 SkIntToScalar(fTextureSize.height()));
125 #ifdef SK_GAMMA_APPLY_TO_A8
126 const GrDistanceFieldTextureEffect& dfTexEffect =
127 effect.cast<GrDistanceFieldTextureEffect>();
128 float luminance = dfTexEffect.getLuminance();
129 if (luminance != fLuminance) {
130 pdman.set1f(fLuminanceUni, luminance);
131 fLuminance = luminance;
136 static inline void GenKey(const GrProcessor& processor, const GrGLCaps&,
137 GrProcessorKeyBuilder* b) {
138 const GrDistanceFieldTextureEffect& dfTexEffect =
139 processor.cast<GrDistanceFieldTextureEffect>();
141 b->add32(dfTexEffect.getFlags());
145 GrGLProgramDataManager::UniformHandle fTextureSizeUni;
146 SkISize fTextureSize;
147 GrGLProgramDataManager::UniformHandle fLuminanceUni;
150 typedef GrGLGeometryProcessor INHERITED;
153 ///////////////////////////////////////////////////////////////////////////////
155 GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture,
156 const GrTextureParams& params,
157 #ifdef SK_GAMMA_APPLY_TO_A8
159 const GrTextureParams& gammaParams,
163 : fTextureAccess(texture, params)
164 #ifdef SK_GAMMA_APPLY_TO_A8
165 , fGammaTextureAccess(gamma, gammaParams)
166 , fLuminance(luminance)
168 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
169 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
171 GrShaderVar::kAttribute_TypeModifier))) {
172 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
173 this->addTextureAccess(&fTextureAccess);
174 #ifdef SK_GAMMA_APPLY_TO_A8
175 this->addTextureAccess(&fGammaTextureAccess);
179 bool GrDistanceFieldTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
180 const GrDistanceFieldTextureEffect& cte = other.cast<GrDistanceFieldTextureEffect>();
182 #ifdef SK_GAMMA_APPLY_TO_A8
183 fLuminance == cte.fLuminance &&
185 fFlags == cte.fFlags;
188 void GrDistanceFieldTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
189 inout->mulByUnknownAlpha();
192 const GrBackendGeometryProcessorFactory& GrDistanceFieldTextureEffect::getFactory() const {
193 return GrTBackendGeometryProcessorFactory<GrDistanceFieldTextureEffect>::getInstance();
196 ///////////////////////////////////////////////////////////////////////////////
198 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect);
200 GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
202 const GrDrawTargetCaps&,
203 GrTexture* textures[]) {
204 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
205 GrProcessorUnitTest::kAlphaTextureIdx;
206 #ifdef SK_GAMMA_APPLY_TO_A8
207 int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
208 GrProcessorUnitTest::kAlphaTextureIdx;
210 static const SkShader::TileMode kTileModes[] = {
211 SkShader::kClamp_TileMode,
212 SkShader::kRepeat_TileMode,
213 SkShader::kMirror_TileMode,
215 SkShader::TileMode tileModes[] = {
216 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
217 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
219 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
220 GrTextureParams::kNone_FilterMode);
221 #ifdef SK_GAMMA_APPLY_TO_A8
222 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
223 GrTextureParams::kNone_FilterMode);
226 return GrDistanceFieldTextureEffect::Create(textures[texIdx], params,
227 #ifdef SK_GAMMA_APPLY_TO_A8
228 textures[texIdx2], params2,
232 kSimilarity_DistanceFieldEffectFlag : 0);
235 ///////////////////////////////////////////////////////////////////////////////
237 class GrGLDistanceFieldNoGammaTextureEffect : public GrGLGeometryProcessor {
239 GrGLDistanceFieldNoGammaTextureEffect(const GrBackendProcessorFactory& factory,
240 const GrProcessor& effect)
242 , fTextureSize(SkISize::Make(-1, -1)) {}
244 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
245 const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
246 args.fGP.cast<GrDistanceFieldNoGammaTextureEffect>();
247 SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
249 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
250 SkAssertResult(fsBuilder->enableFeature(
251 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
253 GrGLVertToFrag v(kVec2f_GrSLType);
254 args.fPB->addVarying("TextureCoords", &v);
256 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
257 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
259 const char* textureSizeUniName = NULL;
260 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
261 kVec2f_GrSLType, "TextureSize",
262 &textureSizeUniName);
264 fsBuilder->codeAppend("vec4 texColor = ");
265 fsBuilder->appendTextureLookup(args.fSamplers[0],
268 fsBuilder->codeAppend(";");
269 fsBuilder->codeAppend("float distance = "
270 SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
272 // we adjust for the effect of the transformation on the distance by using
273 // the length of the gradient of the texture coordinates. We use st coordinates
274 // to ensure we're mapping 1:1 from texel space to pixel space.
275 fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn());
276 fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName);
277 fsBuilder->codeAppend("float afwidth;");
278 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) {
279 // this gives us a smooth step across approximately one fragment
280 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));");
282 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);");
283 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);");
285 fsBuilder->codeAppend("vec2 uv_grad;");
286 if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
287 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
288 fsBuilder->codeAppend("float uv_len2 = dot(uv, uv);");
289 fsBuilder->codeAppend("if (uv_len2 < 0.0001) {");
290 fsBuilder->codeAppend("uv_grad = vec2(0.7071, 0.7071);");
291 fsBuilder->codeAppend("} else {");
292 fsBuilder->codeAppend("uv_grad = uv*inversesqrt(uv_len2);");
293 fsBuilder->codeAppend("}");
295 fsBuilder->codeAppend("uv_grad = normalize(uv);");
297 fsBuilder->codeAppend("vec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,");
298 fsBuilder->codeAppend(" uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);");
300 // this gives us a smooth step across approximately one fragment
301 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
303 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);");
305 fsBuilder->codeAppendf("%s = %s;", args.fOutput,
306 (GrGLSLExpr4(args.fInput) * GrGLSLExpr1("val")).c_str());
309 virtual void setData(const GrGLProgramDataManager& pdman,
310 const GrProcessor& effect) SK_OVERRIDE {
311 SkASSERT(fTextureSizeUni.isValid());
313 GrTexture* texture = effect.texture(0);
314 if (texture->width() != fTextureSize.width() ||
315 texture->height() != fTextureSize.height()) {
316 fTextureSize = SkISize::Make(texture->width(), texture->height());
317 pdman.set2f(fTextureSizeUni,
318 SkIntToScalar(fTextureSize.width()),
319 SkIntToScalar(fTextureSize.height()));
323 static inline void GenKey(const GrProcessor& effect, const GrGLCaps&,
324 GrProcessorKeyBuilder* b) {
325 const GrDistanceFieldNoGammaTextureEffect& dfTexEffect =
326 effect.cast<GrDistanceFieldNoGammaTextureEffect>();
328 b->add32(dfTexEffect.getFlags());
332 GrGLProgramDataManager::UniformHandle fTextureSizeUni;
333 SkISize fTextureSize;
335 typedef GrGLGeometryProcessor INHERITED;
338 ///////////////////////////////////////////////////////////////////////////////
340 GrDistanceFieldNoGammaTextureEffect::GrDistanceFieldNoGammaTextureEffect(GrTexture* texture,
341 const GrTextureParams& params,
343 : fTextureAccess(texture, params)
344 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
345 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
347 GrShaderVar::kAttribute_TypeModifier))) {
348 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
349 this->addTextureAccess(&fTextureAccess);
352 bool GrDistanceFieldNoGammaTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
353 const GrDistanceFieldNoGammaTextureEffect& cte =
354 other.cast<GrDistanceFieldNoGammaTextureEffect>();
355 return fFlags == cte.fFlags;
358 void GrDistanceFieldNoGammaTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
359 inout->mulByUnknownAlpha();
362 const GrBackendGeometryProcessorFactory& GrDistanceFieldNoGammaTextureEffect::getFactory() const {
363 return GrTBackendGeometryProcessorFactory<GrDistanceFieldNoGammaTextureEffect>::getInstance();
366 ///////////////////////////////////////////////////////////////////////////////
368 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldNoGammaTextureEffect);
370 GrGeometryProcessor* GrDistanceFieldNoGammaTextureEffect::TestCreate(SkRandom* random,
372 const GrDrawTargetCaps&,
373 GrTexture* textures[]) {
374 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
375 : GrProcessorUnitTest::kAlphaTextureIdx;
376 static const SkShader::TileMode kTileModes[] = {
377 SkShader::kClamp_TileMode,
378 SkShader::kRepeat_TileMode,
379 SkShader::kMirror_TileMode,
381 SkShader::TileMode tileModes[] = {
382 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
383 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
385 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode
386 : GrTextureParams::kNone_FilterMode);
388 return GrDistanceFieldNoGammaTextureEffect::Create(textures[texIdx], params,
389 random->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0);
392 ///////////////////////////////////////////////////////////////////////////////
394 class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
396 GrGLDistanceFieldLCDTextureEffect(const GrBackendProcessorFactory& factory,
398 : INHERITED (factory)
399 , fTextureSize(SkISize::Make(-1,-1))
400 , fTextColor(GrColor_ILLEGAL) {}
402 virtual void emitCode(const EmitArgs& args) SK_OVERRIDE {
403 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
404 args.fGP.cast<GrDistanceFieldLCDTextureEffect>();
405 SkASSERT(1 == dfTexEffect.getVertexAttribs().count());
407 GrGLVertToFrag v(kVec2f_GrSLType);
408 args.fPB->addVarying("TextureCoords", &v);
410 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder();
411 vsBuilder->codeAppendf("\t%s = %s;\n", v.vsOut(), dfTexEffect.inTextureCoords().c_str());
413 const char* textureSizeUniName = NULL;
414 // width, height, 1/(3*width)
415 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
416 kVec3f_GrSLType, "TextureSize",
417 &textureSizeUniName);
419 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder();
421 SkAssertResult(fsBuilder->enableFeature(
422 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
424 // create LCD offset adjusted by inverse of transform
425 fsBuilder->codeAppendf("\tvec2 uv = %s;\n", v.fsIn());
426 fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName);
427 bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask);
428 if (isUniformScale) {
429 fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n");
430 fsBuilder->codeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName);
432 fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
433 fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
434 fsBuilder->codeAppendf("\tvec2 offset = %s.z*Jdx;\n", textureSizeUniName);
437 // green is distance to uv center
438 fsBuilder->codeAppend("\tvec4 texColor = ");
439 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType);
440 fsBuilder->codeAppend(";\n");
441 fsBuilder->codeAppend("\tvec3 distance;\n");
442 fsBuilder->codeAppend("\tdistance.y = texColor.r;\n");
443 // red is distance to left offset
444 fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n");
445 fsBuilder->codeAppend("\ttexColor = ");
446 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
447 fsBuilder->codeAppend(";\n");
448 fsBuilder->codeAppend("\tdistance.x = texColor.r;\n");
449 // blue is distance to right offset
450 fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n");
451 fsBuilder->codeAppend("\ttexColor = ");
452 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType);
453 fsBuilder->codeAppend(";\n");
454 fsBuilder->codeAppend("\tdistance.z = texColor.r;\n");
456 fsBuilder->codeAppend("\tdistance = "
457 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));");
459 // we adjust for the effect of the transformation on the distance by using
460 // the length of the gradient of the texture coordinates. We use st coordinates
461 // to ensure we're mapping 1:1 from texel space to pixel space.
463 // To be strictly correct, we should compute the anti-aliasing factor separately
464 // for each color component. However, this is only important when using perspective
465 // transformations, and even then using a single factor seems like a reasonable
466 // trade-off between quality and speed.
467 fsBuilder->codeAppend("\tfloat afwidth;\n");
468 if (isUniformScale) {
469 // this gives us a smooth step across approximately one fragment
470 fsBuilder->codeAppend("\tafwidth = abs(" SK_DistanceFieldAAFactor "*dx);\n");
472 fsBuilder->codeAppend("\tvec2 uv_grad;\n");
473 if (args.fPB->ctxInfo().caps()->dropsTileOnZeroDivide()) {
474 // this is to compensate for the Adreno, which likes to drop tiles on division by 0
475 fsBuilder->codeAppend("\tfloat uv_len2 = dot(uv, uv);\n");
476 fsBuilder->codeAppend("\tif (uv_len2 < 0.0001) {\n");
477 fsBuilder->codeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n");
478 fsBuilder->codeAppend("\t} else {\n");
479 fsBuilder->codeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n");
480 fsBuilder->codeAppend("\t}\n");
482 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
484 fsBuilder->codeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n");
485 fsBuilder->codeAppend("\t uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n");
487 // this gives us a smooth step across approximately one fragment
488 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
491 fsBuilder->codeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n");
493 // adjust based on gamma
494 const char* textColorUniName = NULL;
495 // width, height, 1/(3*width)
496 fTextColorUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility,
497 kVec3f_GrSLType, "TextColor",
500 fsBuilder->codeAppendf("\tuv = vec2(val.x, %s.x);\n", textColorUniName);
501 fsBuilder->codeAppend("\tvec4 gammaColor = ");
502 fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
503 fsBuilder->codeAppend(";\n");
504 fsBuilder->codeAppend("\tval.x = gammaColor.r;\n");
506 fsBuilder->codeAppendf("\tuv = vec2(val.y, %s.y);\n", textColorUniName);
507 fsBuilder->codeAppend("\tgammaColor = ");
508 fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
509 fsBuilder->codeAppend(";\n");
510 fsBuilder->codeAppend("\tval.y = gammaColor.r;\n");
512 fsBuilder->codeAppendf("\tuv = vec2(val.z, %s.z);\n", textColorUniName);
513 fsBuilder->codeAppend("\tgammaColor = ");
514 fsBuilder->appendTextureLookup(args.fSamplers[1], "uv", kVec2f_GrSLType);
515 fsBuilder->codeAppend(";\n");
516 fsBuilder->codeAppend("\tval.z = gammaColor.r;\n");
518 fsBuilder->codeAppendf("\t%s = %s;\n", args.fOutput,
519 (GrGLSLExpr4(args.fInput) * GrGLSLExpr4("val")).c_str());
522 virtual void setData(const GrGLProgramDataManager& pdman,
523 const GrProcessor& processor) SK_OVERRIDE {
524 SkASSERT(fTextureSizeUni.isValid());
525 SkASSERT(fTextColorUni.isValid());
527 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
528 processor.cast<GrDistanceFieldLCDTextureEffect>();
529 GrTexture* texture = processor.texture(0);
530 if (texture->width() != fTextureSize.width() ||
531 texture->height() != fTextureSize.height()) {
532 fTextureSize = SkISize::Make(texture->width(), texture->height());
533 float delta = 1.0f/(3.0f*texture->width());
534 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
537 pdman.set3f(fTextureSizeUni,
538 SkIntToScalar(fTextureSize.width()),
539 SkIntToScalar(fTextureSize.height()),
543 GrColor textColor = dfTexEffect.getTextColor();
544 if (textColor != fTextColor) {
545 static const float ONE_OVER_255 = 1.f / 255.f;
546 pdman.set3f(fTextColorUni,
547 GrColorUnpackR(textColor) * ONE_OVER_255,
548 GrColorUnpackG(textColor) * ONE_OVER_255,
549 GrColorUnpackB(textColor) * ONE_OVER_255);
550 fTextColor = textColor;
554 static inline void GenKey(const GrProcessor& processor, const GrGLCaps&,
555 GrProcessorKeyBuilder* b) {
556 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
557 processor.cast<GrDistanceFieldLCDTextureEffect>();
559 b->add32(dfTexEffect.getFlags());
563 GrGLProgramDataManager::UniformHandle fTextureSizeUni;
564 SkISize fTextureSize;
565 GrGLProgramDataManager::UniformHandle fTextColorUni;
568 typedef GrGLGeometryProcessor INHERITED;
571 ///////////////////////////////////////////////////////////////////////////////
573 GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect(
574 GrTexture* texture, const GrTextureParams& params,
575 GrTexture* gamma, const GrTextureParams& gParams,
578 : fTextureAccess(texture, params)
579 , fGammaTextureAccess(gamma, gParams)
580 , fTextColor(textColor)
581 , fFlags(flags & kLCD_DistanceFieldEffectMask)
582 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
584 GrShaderVar::kAttribute_TypeModifier))) {
585 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
587 this->addTextureAccess(&fTextureAccess);
588 this->addTextureAccess(&fGammaTextureAccess);
591 bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrGeometryProcessor& other) const {
592 const GrDistanceFieldLCDTextureEffect& cte = other.cast<GrDistanceFieldLCDTextureEffect>();
593 return (fTextColor == cte.fTextColor &&
594 fFlags == cte.fFlags);
597 void GrDistanceFieldLCDTextureEffect::onComputeInvariantOutput(InvariantOutput* inout) const {
598 inout->mulByUnknownColor();
601 const GrBackendGeometryProcessorFactory& GrDistanceFieldLCDTextureEffect::getFactory() const {
602 return GrTBackendGeometryProcessorFactory<GrDistanceFieldLCDTextureEffect>::getInstance();
605 ///////////////////////////////////////////////////////////////////////////////
607 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect);
609 GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random,
611 const GrDrawTargetCaps&,
612 GrTexture* textures[]) {
613 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
614 GrProcessorUnitTest::kAlphaTextureIdx;
615 int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
616 GrProcessorUnitTest::kAlphaTextureIdx;
617 static const SkShader::TileMode kTileModes[] = {
618 SkShader::kClamp_TileMode,
619 SkShader::kRepeat_TileMode,
620 SkShader::kMirror_TileMode,
622 SkShader::TileMode tileModes[] = {
623 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
624 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
626 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
627 GrTextureParams::kNone_FilterMode);
628 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode :
629 GrTextureParams::kNone_FilterMode);
630 GrColor textColor = GrColorPackRGBA(random->nextULessThan(256),
631 random->nextULessThan(256),
632 random->nextULessThan(256),
633 random->nextULessThan(256));
634 uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
635 flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0;
636 flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
637 return GrDistanceFieldLCDTextureEffect::Create(textures[texIdx], params,
638 textures[texIdx2], params2,