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/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"
17 #include "SkDistanceFieldGen.h"
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"
25 #define SK_DistanceFieldLCDFactor "0.05"
26 #define SK_DistanceFieldNonLCDFactor "0.05"
29 // Assuming a radius of the diagonal of the fragment, hence a factor of sqrt(2)/2
30 #define SK_DistanceFieldAAFactor "0.7071"
32 class GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor {
34 GrGLDistanceFieldTextureEffect(const GrBackendProcessorFactory& factory,
37 , fTextureSize(SkISize::Make(-1,-1))
38 #ifdef SK_GAMMA_APPLY_TO_A8
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());
54 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
55 SkAssertResult(fsBuilder->enableFeature(
56 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
59 const char* vsCoordName;
60 const char* fsCoordNamePtr;
61 builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
62 fsCoordName = fsCoordNamePtr;
64 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
65 vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
67 const char* textureSizeUniName = NULL;
68 fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
69 kVec2f_GrSLType, "TextureSize",
72 fsBuilder->codeAppend("\tvec4 texColor = ");
73 fsBuilder->appendTextureLookup(samplers[0],
76 fsBuilder->codeAppend(";\n");
77 fsBuilder->codeAppend("\tfloat distance = "
78 SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ")"
79 "+ " SK_DistanceFieldNonLCDFactor ";\n");
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");
91 fsBuilder->codeAppend("\tvec2 Jdx = dFdx(st);\n");
92 fsBuilder->codeAppend("\tvec2 Jdy = dFdy(st);\n");
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");
104 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
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");
109 // this gives us a smooth step across approximately one fragment
110 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
112 fsBuilder->codeAppend("\tfloat val = smoothstep(-afwidth, afwidth, distance);\n");
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",
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");
129 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
130 (GrGLSLExpr4(inputColor) * GrGLSLExpr1("val")).c_str());
133 virtual void setData(const GrGLProgramDataManager& pdman,
134 const GrProcessor& effect) SK_OVERRIDE {
135 SkASSERT(fTextureSizeUni.isValid());
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()));
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;
156 static inline void GenKey(const GrProcessor& processor, const GrGLCaps&,
157 GrProcessorKeyBuilder* b) {
158 const GrDistanceFieldTextureEffect& dfTexEffect =
159 processor.cast<GrDistanceFieldTextureEffect>();
161 b->add32(dfTexEffect.getFlags());
165 GrGLProgramDataManager::UniformHandle fTextureSizeUni;
166 SkISize fTextureSize;
167 GrGLProgramDataManager::UniformHandle fLuminanceUni;
170 typedef GrGLGeometryProcessor INHERITED;
173 ///////////////////////////////////////////////////////////////////////////////
175 GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrTexture* texture,
176 const GrTextureParams& params,
177 #ifdef SK_GAMMA_APPLY_TO_A8
179 const GrTextureParams& gammaParams,
183 : fTextureAccess(texture, params)
184 #ifdef SK_GAMMA_APPLY_TO_A8
185 , fGammaTextureAccess(gamma, gammaParams)
186 , fLuminance(luminance)
188 , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
189 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
191 GrShaderVar::kAttribute_TypeModifier))) {
192 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
193 this->addTextureAccess(&fTextureAccess);
194 #ifdef SK_GAMMA_APPLY_TO_A8
195 this->addTextureAccess(&fGammaTextureAccess);
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 &&
206 fFlags == cte.fFlags;
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;
219 const GrBackendGeometryProcessorFactory& GrDistanceFieldTextureEffect::getFactory() const {
220 return GrTBackendGeometryProcessorFactory<GrDistanceFieldTextureEffect>::getInstance();
223 ///////////////////////////////////////////////////////////////////////////////
225 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect);
227 GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random,
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;
237 static const SkShader::TileMode kTileModes[] = {
238 SkShader::kClamp_TileMode,
239 SkShader::kRepeat_TileMode,
240 SkShader::kMirror_TileMode,
242 SkShader::TileMode tileModes[] = {
243 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
244 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
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);
253 return GrDistanceFieldTextureEffect::Create(textures[texIdx], params,
254 #ifdef SK_GAMMA_APPLY_TO_A8
255 textures[texIdx2], params2,
259 kSimilarity_DistanceFieldEffectFlag : 0);
262 ///////////////////////////////////////////////////////////////////////////////
264 class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor {
266 GrGLDistanceFieldLCDTextureEffect(const GrBackendProcessorFactory& factory,
268 : INHERITED (factory)
269 , fTextureSize(SkISize::Make(-1,-1))
270 , fTextColor(GrColor_ILLEGAL) {}
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());
283 SkString fsCoordName;
284 const char* vsCoordName;
285 const char* fsCoordNamePtr;
286 builder->addVarying(kVec2f_GrSLType, "textureCoords", &vsCoordName, &fsCoordNamePtr);
287 fsCoordName = fsCoordNamePtr;
289 GrGLVertexShaderBuilder* vsBuilder = builder->getVertexShaderBuilder();
290 vsBuilder->codeAppendf("\t%s = %s;\n", vsCoordName, dfTexEffect.inTextureCoords().c_str());
292 const char* textureSizeUniName = NULL;
293 // width, height, 1/(3*width)
294 fTextureSizeUni = builder->addUniform(GrGLProgramBuilder::kFragment_Visibility,
295 kVec3f_GrSLType, "TextureSize",
296 &textureSizeUniName);
298 GrGLProcessorFragmentShaderBuilder* fsBuilder = builder->getFragmentShaderBuilder();
300 SkAssertResult(fsBuilder->enableFeature(
301 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature));
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);
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);
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");
335 fsBuilder->codeAppend("\tdistance = "
336 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"))"
337 "+ vec3(" SK_DistanceFieldLCDFactor ");\n");
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.
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");
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");
362 fsBuilder->codeAppend("\tuv_grad = normalize(uv);\n");
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");
367 // this gives us a smooth step across approximately one fragment
368 fsBuilder->codeAppend("\tafwidth = " SK_DistanceFieldAAFactor "*length(grad);\n");
371 fsBuilder->codeAppend("\tvec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);\n");
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",
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");
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");
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");
398 fsBuilder->codeAppendf("\t%s = %s;\n", outputColor,
399 (GrGLSLExpr4(inputColor) * GrGLSLExpr4("val")).c_str());
402 virtual void setData(const GrGLProgramDataManager& pdman,
403 const GrProcessor& processor) SK_OVERRIDE {
404 SkASSERT(fTextureSizeUni.isValid());
405 SkASSERT(fTextColorUni.isValid());
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) {
417 pdman.set3f(fTextureSizeUni,
418 SkIntToScalar(fTextureSize.width()),
419 SkIntToScalar(fTextureSize.height()),
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;
434 static inline void GenKey(const GrProcessor& processor, const GrGLCaps&,
435 GrProcessorKeyBuilder* b) {
436 const GrDistanceFieldLCDTextureEffect& dfTexEffect =
437 processor.cast<GrDistanceFieldLCDTextureEffect>();
439 b->add32(dfTexEffect.getFlags());
443 GrGLProgramDataManager::UniformHandle fTextureSizeUni;
444 SkISize fTextureSize;
445 GrGLProgramDataManager::UniformHandle fTextColorUni;
448 typedef GrGLGeometryProcessor INHERITED;
451 ///////////////////////////////////////////////////////////////////////////////
453 GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect(
454 GrTexture* texture, const GrTextureParams& params,
455 GrTexture* gamma, const GrTextureParams& gParams,
458 : fTextureAccess(texture, params)
459 , fGammaTextureAccess(gamma, gParams)
460 , fTextColor(textColor)
461 , fFlags(flags & kLCD_DistanceFieldEffectMask)
462 , fInTextureCoords(this->addVertexAttrib(GrShaderVar("inTextureCoords",
464 GrShaderVar::kAttribute_TypeModifier))) {
465 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
467 this->addTextureAccess(&fTextureAccess);
468 this->addTextureAccess(&fGammaTextureAccess);
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);
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;
489 const GrBackendGeometryProcessorFactory& GrDistanceFieldLCDTextureEffect::getFactory() const {
490 return GrTBackendGeometryProcessorFactory<GrDistanceFieldLCDTextureEffect>::getInstance();
493 ///////////////////////////////////////////////////////////////////////////////
495 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect);
497 GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random,
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,
510 SkShader::TileMode tileModes[] = {
511 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
512 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))],
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,