1 /* 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" 9 #include "gl/builders/GrGLFullProgramBuilder.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" 16 17 #include "SkDistanceFieldGen.h" 18 19 // 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 32 class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor { 33 public: 34 GrGLDistanceFieldTextureEffect(const GrBackendProcessorFactory& factory, 35 const GrProcessor&) 36 : INHERITED (factory) 37 , fTextureSize(SkISize::Make(-1,-1)) 38 #ifdef SK_GAMMA_APPLY_TO_A8 39 , fLuminance(-1.0f) 40 #endif 41 {} 42 43 virtual void emitCode(GrGLFullProgramBuilder* builder, 44 const GrGeometryProcessor& geometryProcessor, 45 const GrProcessorKey& key, 46 const char* outputColor, 47 const char* inputColor, 48 const TransformedCoordsArray&, 49 const TextureSamplerArray& samplers) SK_OVERRIDE { 50 const GrDistanceFieldTextureEffect& dfTexEffect = 51 geometryProcessor.cast<GrDistanceFieldTextureEffect>(); 52 SkASSERT(1 == dfTexEffect.getVertexAttribs().count()); 53 54 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 55 SkAssertResult(fsBuilder->enableFeature( 56 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); 57 58 SkString fsCoordName; 59 const char* vsCoordName; 60 const char* fsCoordNamePtr; 61 builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr); 62 fsCoordName = fsCoordNamePtr; 63 64 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder(); 65 vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str()); 66 67 const char* textureSizeUniName = NULL; 68 fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 69 kVec2f_GrSLType, "TextureSize", 70 &textureSizeUniName); 71 72 fsBuilder->codeAppend("\tvec4 texColor = "); 73 fsBuilder->appendTextureLookup(samplers[0], 74 fsCoordName.c_str(), 75 kVec2f_GrSLType); 76 fsBuilder->codeAppend(";\n"); 77 fsBuilder->codeAppend("\tfloat distance = " 78 SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ")" 79 "+ " SK_DistanceFieldNonLCDFactor ";\n"); 80 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. 84 fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str()); 85 fsBuilder->codeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName); 86 fsBuilder->codeAppend("\tfloat afwidth;\n"); 87 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) { 88 // this gives us a smooth step across approximately one fragment 89 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dFdx(st.x);\n"); 90 } else { 91 fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n"); 92 fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n"); 93 94 fsBuilder->codeAppend("\tvec2 uv_grad;\n"); 95 if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) { 96 // this is to compensate for the Adreno, which likes to drop tiles on division by 0 97 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"); 103 } else { 104 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n"); 105 } 106 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"); 108 109 // this gives us a smooth step across approximately one fragment 110 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n"); 111 } 112 fsBuilder->codeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n"); 113 114 #ifdef SK_GAMMA_APPLY_TO_A8 115 // adjust based on gamma 116 const char* luminanceUniName = NULL; 117 // width, height, 1/(3*width) 118 fLuminanceUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 119 kFloat_GrSLType, "Luminance", 120 &luminanceUniName); 121 122 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"); 127 #endif 128 129 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor, 130 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str()); 131 } 132 133 virtual void setData(const GrGLProgramDataManager& pdman, 134 const GrProcessor& effect) SK_OVERRIDE { 135 SkASSERT(fTextureSizeUni.isValid()); 136 137 GrTexture* texture = effect.texture(0); 138 if (texture->width() != fTextureSize.width() || 139 texture->height() != fTextureSize.height()) { 140 fTextureSize = SkISize::Make(texture->width(), texture->height()); 141 pdman.set2f(fTextureSizeUni, 142 SkIntToScalar(fTextureSize.width()), 143 SkIntToScalar(fTextureSize.height())); 144 } 145 #ifdef SK_GAMMA_APPLY_TO_A8 146 const GrDistanceFieldTextureEffect& dfTexEffect = 147 effect.cast<GrDistanceFieldTextureEffect>(); 148 float luminance = dfTexEffect.getLuminance(); 149 if (luminance != fLuminance) { 150 pdman.set1f(fLuminanceUni, luminance); 151 fLuminance = luminance; 152 } 153 #endif 154 } 155 156 static inline void GenKey(const GrProcessor& processor, const GrGLCaps&, 157 GrProcessorKeyBuilder* b) { 158 const GrDistanceFieldTextureEffect& dfTexEffect = 159 processor.cast<GrDistanceFieldTextureEffect>(); 160 161 b->add32(dfTexEffect.getFlags()); 162 } 163 164 private: 165 GrGLProgramDataManager::UniformHandle fTextureSizeUni; 166 SkISize fTextureSize; 167 GrGLProgramDataManager::UniformHandle fLuminanceUni; 168 float fLuminance; 169 170 typedef GrGLGeometryProcessor INHERITED; 171 }; 172 173 /////////////////////////////////////////////////////////////////////////////// 174 175 GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture, 176 const GrTextureParams& params, 177 #ifdef SK_GAMMA_APPLY_TO_A8 178 GrTexture* gamma, 179 const GrTextureParams& gammaParams, 180 float luminance, 181 #endif 182 uint32_t flags) 183 : fTextureAccess(texture, params) 184 #ifdef SK_GAMMA_APPLY_TO_A8 185 , fGammaTextureAccess(gamma, gammaParams) 186 , fLuminance(luminance) 187 #endif 188 , fFlags(flags & kNonLCD_DistanceFieldEffectMask) 189 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords", 190 kVec2f_GrSLType, 191 GrShaderVar::kAttribute_TypeModifier))) { 192 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask)); 193 this->addTextureAccess(&fTextureAccess); 194 #ifdef SK_GAMMA_APPLY_TO_A8 195 this->addTextureAccess(&fGammaTextureAccess); 196 #endif 197 } 198 199 bool GrDistanceFieldTextureEffect::onIsEqual(const GrProcessor& other) const { 200 const GrDistanceFieldTextureEffect& cte = other.cast<GrDistanceFieldTextureEffect>(); 201 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; 207 } 208 209 void 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 219 const GrBackendGeometryProcessorFactory& GrDistanceFieldTextureEffect::getFactory() const { 220 return GrTBackendGeometryProcessorFactory<GrDistanceFieldTextureEffect>::getInstance(); 221 } 222 223 /////////////////////////////////////////////////////////////////////////////// 224 225 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect); 226 227 GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random, 228 GrContext*, 229 const GrDrawTargetCaps&, 230 GrTexture* textures[]) { 231 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : 232 GrProcessorUnitTest::kAlphaTextureIdx; 233 #ifdef SK_GAMMA_APPLY_TO_A8 234 int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : 235 GrProcessorUnitTest::kAlphaTextureIdx; 236 #endif 237 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); 248 #ifdef SK_GAMMA_APPLY_TO_A8 249 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : 250 GrTextureParams::kNone_FilterMode); 251 #endif 252 253 return GrDistanceFieldTextureEffect::Create(textures[texIdx], params, 254 #ifdef SK_GAMMA_APPLY_TO_A8 255 textures[texIdx2], params2, 256 random->nextF(), 257 #endif 258 random->nextBool() ? 259 kSimilarity_DistanceFieldEffectFlag : 0); 260 } 261 262 /////////////////////////////////////////////////////////////////////////////// 263 264 class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor { 265 public: 266 GrGLDistanceFieldLCDTextureEffect(const GrBackendProcessorFactory& factory, 267 const GrProcessor&) 268 : INHERITED (factory) 269 , fTextureSize(SkISize::Make(-1,-1)) 270 , fTextColor(GrColor_ILLEGAL) {} 271 272 virtual void emitCode(GrGLFullProgramBuilder* builder, 273 const GrGeometryProcessor& geometryProcessor, 274 const GrProcessorKey& key, 275 const char* outputColor, 276 const char* inputColor, 277 const TransformedCoordsArray&, 278 const TextureSamplerArray& samplers) SK_OVERRIDE { 279 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 280 geometryProcessor.cast<GrDistanceFieldLCDTextureEffect>(); 281 SkASSERT(1 == dfTexEffect.getVertexAttribs().count()); 282 283 SkString fsCoordName; 284 const char* vsCoordName; 285 const char* fsCoordNamePtr; 286 builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr); 287 fsCoordName = fsCoordNamePtr; 288 289 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder(); 290 vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str()); 291 292 const char* textureSizeUniName = NULL; 293 // width, height, 1/(3*width) 294 fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 295 kVec3f_GrSLType, "TextureSize", 296 &textureSizeUniName); 297 298 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder(); 299 300 SkAssertResult(fsBuilder->enableFeature( 301 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); 302 303 // create LCD offset adjusted by inverse of transform 304 fsBuilder->codeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str()); 305 fsBuilder->codeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName); 306 bool isUniformScale = !!(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask); 307 if (isUniformScale) { 308 fsBuilder->codeAppend("\tfloat dx = dFdx(st.x);\n"); 309 fsBuilder->codeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName); 310 } else { 311 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); 314 } 315 316 // green is distance to uv center 317 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"); 322 // red is distance to left offset 323 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"); 328 // blue is distance to right offset 329 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"); 334 335 fsBuilder->codeAppend("\tdistance = " 336 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"))" 337 "+ vec3(" SK_DistanceFieldLCDFactor ");\n"); 338 339 // 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. 347 fsBuilder->codeAppend("\tfloat afwidth;\n"); 348 if (isUniformScale) { 349 // this gives us a smooth step across approximately one fragment 350 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dx;\n"); 351 } else { 352 fsBuilder->codeAppend("\tvec2 uv_grad;\n"); 353 if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) { 354 // this is to compensate for the Adreno, which likes to drop tiles on division by 0 355 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"); 361 } else { 362 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n"); 363 } 364 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"); 366 367 // this gives us a smooth step across approximately one fragment 368 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n"); 369 } 370 371 fsBuilder->codeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n"); 372 373 // adjust based on gamma 374 const char* textColorUniName = NULL; 375 // width, height, 1/(3*width) 376 fTextColorUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility, 377 kVec3f_GrSLType, "TextColor", 378 &textColorUniName); 379 380 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"); 385 386 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"); 391 392 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"); 397 398 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor, 399 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("val")).c_str()); 400 } 401 402 virtual void setData(const GrGLProgramDataManager& pdman, 403 const GrProcessor& processor) SK_OVERRIDE { 404 SkASSERT(fTextureSizeUni.isValid()); 405 SkASSERT(fTextColorUni.isValid()); 406 407 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 408 processor.cast<GrDistanceFieldLCDTextureEffect>(); 409 GrTexture* texture = processor.texture(0); 410 if (texture->width() != fTextureSize.width() || 411 texture->height() != fTextureSize.height()) { 412 fTextureSize = SkISize::Make(texture->width(), texture->height()); 413 float delta = 1.0f/(3.0f*texture->width()); 414 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) { 415 delta = -delta; 416 } 417 pdman.set3f(fTextureSizeUni, 418 SkIntToScalar(fTextureSize.width()), 419 SkIntToScalar(fTextureSize.height()), 420 delta); 421 } 422 423 GrColor textColor = dfTexEffect.getTextColor(); 424 if (textColor != fTextColor) { 425 static const float ONE_OVER_255 = 1.f / 255.f; 426 pdman.set3f(fTextColorUni, 427 GrColorUnpackR(textColor) * ONE_OVER_255, 428 GrColorUnpackG(textColor) * ONE_OVER_255, 429 GrColorUnpackB(textColor) * ONE_OVER_255); 430 fTextColor = textColor; 431 } 432 } 433 434 static inline void GenKey(const GrProcessor& processor, const GrGLCaps&, 435 GrProcessorKeyBuilder* b) { 436 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 437 processor.cast<GrDistanceFieldLCDTextureEffect>(); 438 439 b->add32(dfTexEffect.getFlags()); 440 } 441 442 private: 443 GrGLProgramDataManager::UniformHandle fTextureSizeUni; 444 SkISize fTextureSize; 445 GrGLProgramDataManager::UniformHandle fTextColorUni; 446 SkColor fTextColor; 447 448 typedef GrGLGeometryProcessor INHERITED; 449 }; 450 451 /////////////////////////////////////////////////////////////////////////////// 452 453 GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect( 454 GrTexture* texture, const GrTextureParams& params, 455 GrTexture* gamma, const GrTextureParams& gParams, 456 SkColor textColor, 457 uint32_t flags) 458 : fTextureAccess(texture, params) 459 , fGammaTextureAccess(gamma, gParams) 460 , fTextColor(textColor) 461 , fFlags(flags & kLCD_DistanceFieldEffectMask) 462 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords", 463 kVec2f_GrSLType, 464 GrShaderVar::kAttribute_TypeModifier))) { 465 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag)); 466 467 this->addTextureAccess(&fTextureAccess); 468 this->addTextureAccess(&fGammaTextureAccess); 469 } 470 471 bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrProcessor& other) const { 472 const GrDistanceFieldLCDTextureEffect& cte = other.cast<GrDistanceFieldLCDTextureEffect>(); 473 return (fTextureAccess == cte.fTextureAccess && 474 fGammaTextureAccess == cte.fGammaTextureAccess && 475 fTextColor == cte.fTextColor && 476 fFlags == cte.fFlags); 477 } 478 479 void 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 489 const GrBackendGeometryProcessorFactory& GrDistanceFieldLCDTextureEffect::getFactory() const { 490 return GrTBackendGeometryProcessorFactory<GrDistanceFieldLCDTextureEffect>::getInstance(); 491 } 492 493 /////////////////////////////////////////////////////////////////////////////// 494 495 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect); 496 497 GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random, 498 GrContext*, 499 const GrDrawTargetCaps&, 500 GrTexture* textures[]) { 501 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : 502 GrProcessorUnitTest::kAlphaTextureIdx; 503 int texIdx2 = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : 504 GrProcessorUnitTest::kAlphaTextureIdx; 505 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); 516 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)); 522 uint32_t flags = kUseLCD_DistanceFieldEffectFlag; 523 flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0; 524 flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0; 525 return GrDistanceFieldLCDTextureEffect::Create(textures[texIdx], params, 526 textures[texIdx2], params2, 527 textColor, 528 flags); 529 } 530