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/GrGLEffect.h" 10#include "gl/GrGLSL.h" 11#include "gl/GrGLTexture.h" 12#include "gl/GrGLVertexEffect.h" 13#include "GrTBackendEffectFactory.h" 14#include "GrTexture.h" 15 16#include "SkDistanceFieldGen.h" 17 18// To get optical sizes people don't complain about when we blit correctly, 19// we need to slightly bold each glyph. On the Mac, we need a larger bold value. 20#if defined(SK_BUILD_FOR_MAC) 21#define SK_DistanceFieldLCDFactor "0.33" 22#define SK_DistanceFieldNonLCDFactor "0.25" 23#else 24#define SK_DistanceFieldLCDFactor "0.05" 25#define SK_DistanceFieldNonLCDFactor "0.05" 26#endif 27 28// Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2 29#define SK_DistanceFieldAAFactor "0.7071" 30 31class GrGLDistanceFieldTextureEffect : public GrGLVertexEffect { 32public: 33 GrGLDistanceFieldTextureEffect(const GrBackendEffectFactory& factory, 34 const GrDrawEffect& drawEffect) 35 : INHERITED (factory) 36 , fTextureSize(SkISize::Make(-1,-1)) {} 37 38 virtual void emitCode(GrGLFullShaderBuilder* builder, 39 const GrDrawEffect& drawEffect, 40 EffectKey key, 41 const char* outputColor, 42 const char* inputColor, 43 const TransformedCoordsArray&, 44 const TextureSamplerArray& samplers) SK_OVERRIDE { 45 SkASSERT(1 == drawEffect.castEffect<GrDistanceFieldTextureEffect>().numVertexAttribs()); 46 47 SkAssertResult(builder->enableFeature(GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); 48 const GrDistanceFieldTextureEffect& dfTexEffect = 49 drawEffect.castEffect<GrDistanceFieldTextureEffect>(); 50 51 SkString fsCoordName; 52 const char* vsCoordName; 53 const char* fsCoordNamePtr; 54 builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr); 55 fsCoordName = fsCoordNamePtr; 56 57 const char* attrName0 = 58 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str(); 59 builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attrName0); 60 61 const char* textureSizeUniName = NULL; 62 fTextureSizeUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 63 kVec2f_GrSLType, "TextureSize", 64 &textureSizeUniName); 65 66 builder->fsCodeAppend("\tvec4 texColor = "); 67 builder->fsAppendTextureLookup(samplers[0], 68 fsCoordName.c_str(), 69 kVec2f_GrSLType); 70 builder->fsCodeAppend(";\n"); 71 builder->fsCodeAppend("\tfloat distance = " 72 SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ")" 73 "+ " SK_DistanceFieldNonLCDFactor ";\n"); 74 75 // we adjust for the effect of the transformation on the distance by using 76 // the length of the gradient of the texture coordinates. We use st coordinates 77 // to ensure we're mapping 1:1 from texel space to pixel space. 78 builder->fsCodeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str()); 79 builder->fsCodeAppendf("\tvec2 st = uv*%s;\n", textureSizeUniName); 80 builder->fsCodeAppend("\tfloat afwidth;\n"); 81 if (dfTexEffect.isSimilarity()) { 82 // this gives us a smooth step across approximately one fragment 83 builder->fsCodeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dFdx(st.x);\n"); 84 } else { 85 builder->fsCodeAppend("\tvec2 Jdx = dFdx(st);\n"); 86 builder->fsCodeAppend("\tvec2 Jdy = dFdy(st);\n"); 87 88 builder->fsCodeAppend("\tvec2 uv_grad;\n"); 89 if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) { 90 // this is to compensate for the Adreno, which likes to drop tiles on division by 0 91 builder->fsCodeAppend("\tfloat uv_len2 = dot(uv, uv);\n"); 92 builder->fsCodeAppend("\tif (uv_len2 < 0.0001) {\n"); 93 builder->fsCodeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n"); 94 builder->fsCodeAppend("\t} else {\n"); 95 builder->fsCodeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n"); 96 builder->fsCodeAppend("\t}\n"); 97 } else { 98 builder->fsCodeAppend("\tuv_grad = normalize(uv);\n"); 99 } 100 builder->fsCodeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n"); 101 builder->fsCodeAppend("\t uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n"); 102 103 // this gives us a smooth step across approximately one fragment 104 builder->fsCodeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n"); 105 } 106 builder->fsCodeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n"); 107 108#ifdef SK_GAMMA_APPLY_TO_A8 109 // adjust based on gamma 110 const char* luminanceUniName = NULL; 111 // width, height, 1/(3*width) 112 fLuminanceUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 113 kFloat_GrSLType, "Luminance", 114 &luminanceUniName); 115 116 builder->fsCodeAppendf("\tuv = vec2(val, %s);\n", luminanceUniName); 117 builder->fsCodeAppend("\tvec4 gammaColor = "); 118 builder->fsAppendTextureLookup(samplers[1], "uv", kVec2f_GrSLType); 119 builder->fsCodeAppend(";\n"); 120 builder->fsCodeAppend("\tval = gammaColor.r;\n"); 121#endif 122 123 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, 124 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str()); 125 } 126 127 virtual void setData(const GrGLUniformManager& uman, 128 const GrDrawEffect& drawEffect) SK_OVERRIDE { 129 SkASSERT(fTextureSizeUni.isValid()); 130 131 GrTexture* texture = drawEffect.effect()->get()->texture(0); 132 if (texture->width() != fTextureSize.width() || 133 texture->height() != fTextureSize.height()) { 134 fTextureSize = SkISize::Make(texture->width(), texture->height()); 135 uman.set2f(fTextureSizeUni, 136 SkIntToScalar(fTextureSize.width()), 137 SkIntToScalar(fTextureSize.height())); 138 } 139#ifdef SK_GAMMA_APPLY_TO_A8 140 const GrDistanceFieldTextureEffect& dfTexEffect = 141 drawEffect.castEffect<GrDistanceFieldTextureEffect>(); 142 float luminance = dfTexEffect.getLuminance(); 143 if (luminance != fLuminance) { 144 uman.set1f(fLuminanceUni, luminance); 145 fLuminance = luminance; 146 } 147#endif 148 } 149 150 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 151 const GrDistanceFieldTextureEffect& dfTexEffect = 152 drawEffect.castEffect<GrDistanceFieldTextureEffect>(); 153 154 return dfTexEffect.isSimilarity() ? 0x1 : 0x0; 155 } 156 157private: 158 GrGLUniformManager::UniformHandle fTextureSizeUni; 159 SkISize fTextureSize; 160 GrGLUniformManager::UniformHandle fLuminanceUni; 161 float fLuminance; 162 163 typedef GrGLVertexEffect INHERITED; 164}; 165 166/////////////////////////////////////////////////////////////////////////////// 167 168GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture, 169 const GrTextureParams& params, 170#ifdef SK_GAMMA_APPLY_TO_A8 171 GrTexture* gamma, 172 const GrTextureParams& gammaParams, 173 float luminance, 174#endif 175 bool similarity) 176 : fTextureAccess(texture, params) 177#ifdef SK_GAMMA_APPLY_TO_A8 178 , fGammaTextureAccess(gamma, gammaParams) 179 , fLuminance(luminance) 180#endif 181 , fIsSimilarity(similarity) { 182 this->addTextureAccess(&fTextureAccess); 183#ifdef SK_GAMMA_APPLY_TO_A8 184 this->addTextureAccess(&fGammaTextureAccess); 185#endif 186 this->addVertexAttrib(kVec2f_GrSLType); 187} 188 189bool GrDistanceFieldTextureEffect::onIsEqual(const GrEffect& other) const { 190 const GrDistanceFieldTextureEffect& cte = CastEffect<GrDistanceFieldTextureEffect>(other); 191 return fTextureAccess == cte.fTextureAccess; 192} 193 194void GrDistanceFieldTextureEffect::getConstantColorComponents(GrColor* color, 195 uint32_t* validFlags) const { 196 if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) && 197 GrPixelConfigIsOpaque(this->texture(0)->config())) { 198 *validFlags = kA_GrColorComponentFlag; 199 } else { 200 *validFlags = 0; 201 } 202} 203 204const GrBackendEffectFactory& GrDistanceFieldTextureEffect::getFactory() const { 205 return GrTBackendEffectFactory<GrDistanceFieldTextureEffect>::getInstance(); 206} 207 208/////////////////////////////////////////////////////////////////////////////// 209 210GR_DEFINE_EFFECT_TEST(GrDistanceFieldTextureEffect); 211 212GrEffectRef* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random, 213 GrContext*, 214 const GrDrawTargetCaps&, 215 GrTexture* textures[]) { 216 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : 217 GrEffectUnitTest::kAlphaTextureIdx; 218#ifdef SK_GAMMA_APPLY_TO_A8 219 int texIdx2 = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : 220 GrEffectUnitTest::kAlphaTextureIdx; 221#endif 222 static const SkShader::TileMode kTileModes[] = { 223 SkShader::kClamp_TileMode, 224 SkShader::kRepeat_TileMode, 225 SkShader::kMirror_TileMode, 226 }; 227 SkShader::TileMode tileModes[] = { 228 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 229 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 230 }; 231 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : 232 GrTextureParams::kNone_FilterMode); 233#ifdef SK_GAMMA_APPLY_TO_A8 234 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : 235 GrTextureParams::kNone_FilterMode); 236#endif 237 238 return GrDistanceFieldTextureEffect::Create(textures[texIdx], params, 239#ifdef SK_GAMMA_APPLY_TO_A8 240 textures[texIdx2], params2, 241 random->nextF(), 242#endif 243 random->nextBool()); 244} 245 246/////////////////////////////////////////////////////////////////////////////// 247 248class GrGLDistanceFieldLCDTextureEffect : public GrGLVertexEffect { 249public: 250 GrGLDistanceFieldLCDTextureEffect(const GrBackendEffectFactory& factory, 251 const GrDrawEffect& drawEffect) 252 : INHERITED (factory) 253 , fTextureSize(SkISize::Make(-1,-1)) {} 254 255 virtual void emitCode(GrGLFullShaderBuilder* builder, 256 const GrDrawEffect& drawEffect, 257 EffectKey key, 258 const char* outputColor, 259 const char* inputColor, 260 const TransformedCoordsArray&, 261 const TextureSamplerArray& samplers) SK_OVERRIDE { 262 SkASSERT(1 == drawEffect.castEffect<GrDistanceFieldLCDTextureEffect>().numVertexAttribs()); 263 264 SkAssertResult(builder->enableFeature(GrGLShaderBuilder::kStandardDerivatives_GLSLFeature)); 265 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 266 drawEffect.castEffect<GrDistanceFieldLCDTextureEffect>(); 267 268 SkString fsCoordName; 269 const char* vsCoordName; 270 const char* fsCoordNamePtr; 271 builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr); 272 fsCoordName = fsCoordNamePtr; 273 274 const char* attrName0 = 275 builder->getEffectAttributeName(drawEffect.getVertexAttribIndices()[0])->c_str(); 276 builder->vsCodeAppendf("\t%s = %s;\n", vsCoordName, attrName0); 277 278 const char* textureSizeUniName = NULL; 279 // width, height, 1/(3*width) 280 fTextureSizeUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 281 kVec3f_GrSLType, "TextureSize", 282 &textureSizeUniName); 283 284 // create LCD offset adjusted by inverse of transform 285 builder->fsCodeAppendf("\tvec2 uv = %s;\n", fsCoordName.c_str()); 286 builder->fsCodeAppendf("\tvec2 st = uv*%s.xy;\n", textureSizeUniName); 287 if (dfTexEffect.isUniformScale()) { 288 builder->fsCodeAppend("\tfloat dx = dFdx(st.x);\n"); 289 builder->fsCodeAppendf("\tvec2 offset = vec2(dx*%s.z, 0.0);\n", textureSizeUniName); 290 } else { 291 builder->fsCodeAppend("\tvec2 Jdx = dFdx(st);\n"); 292 builder->fsCodeAppend("\tvec2 Jdy = dFdy(st);\n"); 293 builder->fsCodeAppendf("\tvec2 offset = %s.z*Jdx;\n", textureSizeUniName); 294 } 295 296 // green is distance to uv center 297 builder->fsCodeAppend("\tvec4 texColor = "); 298 builder->fsAppendTextureLookup(samplers[0], "uv", kVec2f_GrSLType); 299 builder->fsCodeAppend(";\n"); 300 builder->fsCodeAppend("\tvec3 distance;\n"); 301 builder->fsCodeAppend("\tdistance.y = texColor.r;\n"); 302 // red is distance to left offset 303 builder->fsCodeAppend("\tvec2 uv_adjusted = uv - offset;\n"); 304 builder->fsCodeAppend("\ttexColor = "); 305 builder->fsAppendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType); 306 builder->fsCodeAppend(";\n"); 307 builder->fsCodeAppend("\tdistance.x = texColor.r;\n"); 308 // blue is distance to right offset 309 builder->fsCodeAppend("\tuv_adjusted = uv + offset;\n"); 310 builder->fsCodeAppend("\ttexColor = "); 311 builder->fsAppendTextureLookup(samplers[0], "uv_adjusted", kVec2f_GrSLType); 312 builder->fsCodeAppend(";\n"); 313 builder->fsCodeAppend("\tdistance.z = texColor.r;\n"); 314 315 builder->fsCodeAppend("\tdistance = " 316 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"))" 317 "+ vec3(" SK_DistanceFieldLCDFactor ");\n"); 318 319 // we adjust for the effect of the transformation on the distance by using 320 // the length of the gradient of the texture coordinates. We use st coordinates 321 // to ensure we're mapping 1:1 from texel space to pixel space. 322 323 // To be strictly correct, we should compute the anti-aliasing factor separately 324 // for each color component. However, this is only important when using perspective 325 // transformations, and even then using a single factor seems like a reasonable 326 // trade-off between quality and speed. 327 builder->fsCodeAppend("\tfloat afwidth;\n"); 328 if (dfTexEffect.isUniformScale()) { 329 // this gives us a smooth step across approximately one fragment 330 builder->fsCodeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*dx;\n"); 331 } else { 332 builder->fsCodeAppend("\tvec2 uv_grad;\n"); 333 if (builder->ctxInfo().caps()->dropsTileOnZeroDivide()) { 334 // this is to compensate for the Adreno, which likes to drop tiles on division by 0 335 builder->fsCodeAppend("\tfloat uv_len2 = dot(uv, uv);\n"); 336 builder->fsCodeAppend("\tif (uv_len2 < 0.0001) {\n"); 337 builder->fsCodeAppend("\t\tuv_grad = vec2(0.7071, 0.7071);\n"); 338 builder->fsCodeAppend("\t} else {\n"); 339 builder->fsCodeAppend("\t\tuv_grad = uv*inversesqrt(uv_len2);\n"); 340 builder->fsCodeAppend("\t}\n"); 341 } else { 342 builder->fsCodeAppend("\tuv_grad = normalize(uv);\n"); 343 } 344 builder->fsCodeAppend("\tvec2 grad = vec2(uv_grad.x*Jdx.x + uv_grad.y*Jdy.x,\n"); 345 builder->fsCodeAppend("\t uv_grad.x*Jdx.y + uv_grad.y*Jdy.y);\n"); 346 347 // this gives us a smooth step across approximately one fragment 348 builder->fsCodeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n"); 349 } 350 351 builder->fsCodeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n"); 352 353 // adjust based on gamma 354 const char* textColorUniName = NULL; 355 // width, height, 1/(3*width) 356 fTextColorUni = builder->addUniform(GrGLShaderBuilder::kFragment_Visibility, 357 kVec3f_GrSLType, "TextColor", 358 &textColorUniName); 359 360 builder->fsCodeAppendf("\tuv = vec2(val.x, %s.x);\n", textColorUniName); 361 builder->fsCodeAppend("\tvec4 gammaColor = "); 362 builder->fsAppendTextureLookup(samplers[1], "uv", kVec2f_GrSLType); 363 builder->fsCodeAppend(";\n"); 364 builder->fsCodeAppend("\tval.x = gammaColor.r;\n"); 365 366 builder->fsCodeAppendf("\tuv = vec2(val.y, %s.y);\n", textColorUniName); 367 builder->fsCodeAppend("\tgammaColor = "); 368 builder->fsAppendTextureLookup(samplers[1], "uv", kVec2f_GrSLType); 369 builder->fsCodeAppend(";\n"); 370 builder->fsCodeAppend("\tval.y = gammaColor.r;\n"); 371 372 builder->fsCodeAppendf("\tuv = vec2(val.z, %s.z);\n", textColorUniName); 373 builder->fsCodeAppend("\tgammaColor = "); 374 builder->fsAppendTextureLookup(samplers[1], "uv", kVec2f_GrSLType); 375 builder->fsCodeAppend(";\n"); 376 builder->fsCodeAppend("\tval.z = gammaColor.r;\n"); 377 378 builder->fsCodeAppendf("\t%s = %s;\n", outputColor, 379 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("val")).c_str()); 380 } 381 382 virtual void setData(const GrGLUniformManager& uman, 383 const GrDrawEffect& drawEffect) SK_OVERRIDE { 384 SkASSERT(fTextureSizeUni.isValid()); 385 SkASSERT(fTextColorUni.isValid()); 386 387 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 388 drawEffect.castEffect<GrDistanceFieldLCDTextureEffect>(); 389 GrTexture* texture = drawEffect.effect()->get()->texture(0); 390 if (texture->width() != fTextureSize.width() || 391 texture->height() != fTextureSize.height()) { 392 fTextureSize = SkISize::Make(texture->width(), texture->height()); 393 float delta = 1.0f/(3.0f*texture->width()); 394 if (dfTexEffect.useBGR()) { 395 delta = -delta; 396 } 397 uman.set3f(fTextureSizeUni, 398 SkIntToScalar(fTextureSize.width()), 399 SkIntToScalar(fTextureSize.height()), 400 delta); 401 } 402 403 GrColor textColor = dfTexEffect.getTextColor(); 404 if (textColor != fTextColor) { 405 static const float ONE_OVER_255 = 1.f / 255.f; 406 uman.set3f(fTextColorUni, 407 GrColorUnpackR(textColor) * ONE_OVER_255, 408 GrColorUnpackG(textColor) * ONE_OVER_255, 409 GrColorUnpackB(textColor) * ONE_OVER_255); 410 fTextColor = textColor; 411 } 412 } 413 414 static inline EffectKey GenKey(const GrDrawEffect& drawEffect, const GrGLCaps&) { 415 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 416 drawEffect.castEffect<GrDistanceFieldLCDTextureEffect>(); 417 418 return dfTexEffect.isUniformScale() ? 0x01 : 0x00;; 419 } 420 421private: 422 GrGLUniformManager::UniformHandle fTextureSizeUni; 423 SkISize fTextureSize; 424 GrGLUniformManager::UniformHandle fTextColorUni; 425 SkColor fTextColor; 426 427 typedef GrGLVertexEffect INHERITED; 428}; 429 430/////////////////////////////////////////////////////////////////////////////// 431 432GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect( 433 GrTexture* texture, const GrTextureParams& params, 434 GrTexture* gamma, const GrTextureParams& gParams, 435 SkColor textColor, 436 bool uniformScale, bool useBGR) 437 : fTextureAccess(texture, params) 438 , fGammaTextureAccess(gamma, gParams) 439 , fTextColor(textColor) 440 , fUniformScale(uniformScale) 441 , fUseBGR(useBGR) { 442 this->addTextureAccess(&fTextureAccess); 443 this->addTextureAccess(&fGammaTextureAccess); 444 this->addVertexAttrib(kVec2f_GrSLType); 445} 446 447bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrEffect& other) const { 448 const GrDistanceFieldLCDTextureEffect& cte = 449 CastEffect<GrDistanceFieldLCDTextureEffect>(other); 450 return (fTextureAccess == cte.fTextureAccess && fGammaTextureAccess == cte.fGammaTextureAccess); 451} 452 453void GrDistanceFieldLCDTextureEffect::getConstantColorComponents(GrColor* color, 454 uint32_t* validFlags) const { 455 if ((*validFlags & kA_GrColorComponentFlag) && 0xFF == GrColorUnpackA(*color) && 456 GrPixelConfigIsOpaque(this->texture(0)->config())) { 457 *validFlags = kA_GrColorComponentFlag; 458 } else { 459 *validFlags = 0; 460 } 461} 462 463const GrBackendEffectFactory& GrDistanceFieldLCDTextureEffect::getFactory() const { 464 return GrTBackendEffectFactory<GrDistanceFieldLCDTextureEffect>::getInstance(); 465} 466 467/////////////////////////////////////////////////////////////////////////////// 468 469GR_DEFINE_EFFECT_TEST(GrDistanceFieldLCDTextureEffect); 470 471GrEffectRef* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random, 472 GrContext*, 473 const GrDrawTargetCaps&, 474 GrTexture* textures[]) { 475 int texIdx = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : 476 GrEffectUnitTest::kAlphaTextureIdx; 477 int texIdx2 = random->nextBool() ? GrEffectUnitTest::kSkiaPMTextureIdx : 478 GrEffectUnitTest::kAlphaTextureIdx; 479 static const SkShader::TileMode kTileModes[] = { 480 SkShader::kClamp_TileMode, 481 SkShader::kRepeat_TileMode, 482 SkShader::kMirror_TileMode, 483 }; 484 SkShader::TileMode tileModes[] = { 485 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 486 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 487 }; 488 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : 489 GrTextureParams::kNone_FilterMode); 490 GrTextureParams params2(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : 491 GrTextureParams::kNone_FilterMode); 492 GrColor textColor = GrColorPackRGBA(random->nextULessThan(256), 493 random->nextULessThan(256), 494 random->nextULessThan(256), 495 random->nextULessThan(256)); 496 return GrDistanceFieldLCDTextureEffect::Create(textures[texIdx], params, 497 textures[texIdx2], params2, 498 textColor, 499 random->nextBool(), random->nextBool()); 500} 501