GrDistanceFieldGeoProc.cpp revision bb4a1cf0e66c98c723f04f473a3221b2a4d8ece1
16255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt/* 26255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt * Copyright 2013 Google Inc. 36255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt * 46255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt * Use of this source code is governed by a BSD-style license that can be 56255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt * found in the LICENSE file. 66255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt */ 76255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt 86255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "GrDistanceFieldTextureEffect.h" 96255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "GrFontAtlasSizes.h" 106255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "GrInvariantOutput.h" 116255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "GrTexture.h" 126255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt 136255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "SkDistanceFieldGen.h" 146255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt 156255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/GrGLProcessor.h" 166255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/GrGLSL.h" 176255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/GrGLTexture.h" 186255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/GrGLGeometryProcessor.h" 196255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#include "gl/builders/GrGLProgramBuilder.h" 206255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt 216255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt// Assuming a radius of a little less than the diagonal of the fragment 226255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt#define SK_DistanceFieldAAFactor "0.65" 236255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt 246255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholtstruct DistanceFieldBatchTracker { 256255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt GrGPInput fInputColorType; 266255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt GrColor fColor; 276255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt bool fUsesLocalCoords; 286255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt}; 296255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt 306255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholtclass GrGLDistanceFieldTextureEffect : public GrGLGeometryProcessor { 31bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholtpublic: 32bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt GrGLDistanceFieldTextureEffect(const GrGeometryProcessor&, 33bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt const GrBatchTracker&) 346255a1f4c6425aa311c90e9dc7fca41c34e8dc2bEric Anholt : fColor(GrColor_ILLEGAL) 35bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt#ifdef SK_GAMMA_APPLY_TO_A8 36bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt , fDistanceAdjust(-1.0f) 37bdd9b1f3ffa2a195d983816adfeca20480256119Eric Anholt#endif 3849a5d5c4f5bf6e8d6ba344e8496d1d1fa0b4586dEric Anholt {} 39b145e903694fa932ab1e0d955e889555193ab604Eric Anholt 40 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ 41 const GrDistanceFieldTextureEffect& dfTexEffect = 42 args.fGP.cast<GrDistanceFieldTextureEffect>(); 43 const DistanceFieldBatchTracker& local = args.fBT.cast<DistanceFieldBatchTracker>(); 44 GrGLGPBuilder* pb = args.fPB; 45 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 46 SkAssertResult(fsBuilder->enableFeature( 47 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); 48 49 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); 50 51 // emit attributes 52 vsBuilder->emitAttributes(dfTexEffect); 53 54#ifdef SK_GAMMA_APPLY_TO_A8 55 // adjust based on gamma 56 const char* distanceAdjustUniName = NULL; 57 // width, height, 1/(3*width) 58 fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, 59 kFloat_GrSLType, kDefault_GrSLPrecision, 60 "DistanceAdjust", &distanceAdjustUniName); 61#endif 62 63 // Setup pass through color 64 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, 65 dfTexEffect.inColor(), &fColorUniform); 66 67 // Setup position 68 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix()); 69 70 // emit transforms 71 const SkMatrix& localMatrix = dfTexEffect.localMatrix(); 72 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, 73 localMatrix, args.fTransformsIn, args.fTransformsOut); 74 75 // add varyings 76 GrGLVertToFrag recipScale(kFloat_GrSLType); 77 GrGLVertToFrag st(kVec2f_GrSLType); 78 bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag); 79 const char* viewMatrixName = this->uViewM(); 80 // view matrix name is NULL if identity matrix 81 bool useInverseScale = !localMatrix.isIdentity() && viewMatrixName; 82 if (isSimilarity && useInverseScale) { 83 args.fPB->addVarying("RecipScale", &recipScale, kHigh_GrSLPrecision); 84 vsBuilder->codeAppendf("vec2 tx = vec2(%s[0][0], %s[1][0]);", 85 viewMatrixName, viewMatrixName); 86 vsBuilder->codeAppend("float tx2 = dot(tx, tx);"); 87 vsBuilder->codeAppendf("%s = inversesqrt(tx2);", recipScale.vsOut()); 88 } else { 89 args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); 90 vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); 91 } 92 93 GrGLVertToFrag uv(kVec2f_GrSLType); 94 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); 95 // this is only used with text, so our texture bounds always match the glyph atlas 96 vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", " 97 GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(), 98 dfTexEffect.inTextureCoords()->fName); 99 100 // Use highp to work around aliasing issues 101 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, 102 pb->ctxInfo().standard())); 103 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); 104 105 fsBuilder->codeAppend("\tfloat texColor = "); 106 fsBuilder->appendTextureLookup(args.fSamplers[0], 107 "uv", 108 kVec2f_GrSLType); 109 fsBuilder->codeAppend(".r;\n"); 110 fsBuilder->codeAppend("\tfloat distance = " 111 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");"); 112#ifdef SK_GAMMA_APPLY_TO_A8 113 // adjust width based on gamma 114 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); 115#endif 116 117 fsBuilder->codeAppend("float afwidth;"); 118 if (isSimilarity) { 119 // For uniform scale, we adjust for the effect of the transformation on the distance 120 // either by using the inverse scale in the view matrix, or (if there is no view matrix) 121 // by using the length of the gradient of the texture coordinates. We use st coordinates 122 // with the latter to ensure we're mapping 1:1 from texel space to pixel space. 123 124 // this gives us a smooth step across approximately one fragment 125 if (useInverseScale) { 126 fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*%s);", 127 recipScale.fsIn()); 128 } else { 129 fsBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(%s.x));", 130 st.fsIn()); 131 } 132 } else { 133 // For general transforms, to determine the amount of correction we multiply a unit 134 // vector pointing along the SDF gradient direction by the Jacobian of the st coords 135 // (which is the inverse transform for this fragment) and take the length of the result. 136 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));"); 137 // the length of the gradient may be 0, so we need to check for this 138 // this also compensates for the Adreno, which likes to drop tiles on division by 0 139 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); 140 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {"); 141 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); 142 fsBuilder->codeAppend("} else {"); 143 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); 144 fsBuilder->codeAppend("}"); 145 146 fsBuilder->codeAppendf("vec2 Jdx = dFdx(%s);", st.fsIn()); 147 fsBuilder->codeAppendf("vec2 Jdy = dFdy(%s);", st.fsIn()); 148 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); 149 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); 150 151 // this gives us a smooth step across approximately one fragment 152 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); 153 } 154 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);"); 155 156 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); 157 } 158 159 virtual void setData(const GrGLProgramDataManager& pdman, 160 const GrPrimitiveProcessor& proc, 161 const GrBatchTracker& bt) override { 162#ifdef SK_GAMMA_APPLY_TO_A8 163 const GrDistanceFieldTextureEffect& dfTexEffect = 164 proc.cast<GrDistanceFieldTextureEffect>(); 165 float distanceAdjust = dfTexEffect.getDistanceAdjust(); 166 if (distanceAdjust != fDistanceAdjust) { 167 pdman.set1f(fDistanceAdjustUni, distanceAdjust); 168 fDistanceAdjust = distanceAdjust; 169 } 170#endif 171 172 this->setUniformViewMatrix(pdman, proc.viewMatrix()); 173 174 const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>(); 175 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { 176 GrGLfloat c[4]; 177 GrColorToRGBAFloat(local.fColor, c); 178 pdman.set4fv(fColorUniform, 1, c); 179 fColor = local.fColor; 180 } 181 } 182 183 static inline void GenKey(const GrGeometryProcessor& gp, 184 const GrBatchTracker& bt, 185 const GrGLCaps&, 186 GrProcessorKeyBuilder* b) { 187 const GrDistanceFieldTextureEffect& dfTexEffect = gp.cast<GrDistanceFieldTextureEffect>(); 188 const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTracker>(); 189 uint32_t key = dfTexEffect.getFlags(); 190 key |= local.fInputColorType << 16; 191 key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0; 192 key |= ComputePosKey(gp.viewMatrix()) << 25; 193 key |= (!gp.viewMatrix().isIdentity() && !gp.localMatrix().isIdentity()) ? 0x1 << 27 : 0x0; 194 b->add32(key); 195 } 196 197private: 198 GrColor fColor; 199 UniformHandle fColorUniform; 200#ifdef SK_GAMMA_APPLY_TO_A8 201 float fDistanceAdjust; 202 UniformHandle fDistanceAdjustUni; 203#endif 204 205 typedef GrGLGeometryProcessor INHERITED; 206}; 207 208/////////////////////////////////////////////////////////////////////////////// 209 210GrDistanceFieldTextureEffect::GrDistanceFieldTextureEffect(GrColor color, 211 const SkMatrix& viewMatrix, 212 const SkMatrix& localMatrix, 213 GrTexture* texture, 214 const GrTextureParams& params, 215#ifdef SK_GAMMA_APPLY_TO_A8 216 float distanceAdjust, 217#endif 218 uint32_t flags, bool opaqueVertexColors) 219 : INHERITED(color, viewMatrix, localMatrix, opaqueVertexColors) 220 , fTextureAccess(texture, params) 221#ifdef SK_GAMMA_APPLY_TO_A8 222 , fDistanceAdjust(distanceAdjust) 223#endif 224 , fFlags(flags & kNonLCD_DistanceFieldEffectMask) 225 , fInColor(NULL) { 226 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask)); 227 this->initClassID<GrDistanceFieldTextureEffect>(); 228 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType)); 229 if (flags & kColorAttr_DistanceFieldEffectFlag) { 230 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType)); 231 this->setHasVertexColor(); 232 } 233 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", 234 kVec2s_GrVertexAttribType)); 235 this->addTextureAccess(&fTextureAccess); 236} 237 238bool GrDistanceFieldTextureEffect::onIsEqual(const GrGeometryProcessor& other) const { 239 const GrDistanceFieldTextureEffect& cte = other.cast<GrDistanceFieldTextureEffect>(); 240 return 241#ifdef SK_GAMMA_APPLY_TO_A8 242 fDistanceAdjust == cte.fDistanceAdjust && 243#endif 244 fFlags == cte.fFlags; 245} 246 247void GrDistanceFieldTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) const { 248 out->setUnknownSingleComponent(); 249} 250 251void GrDistanceFieldTextureEffect::getGLProcessorKey(const GrBatchTracker& bt, 252 const GrGLCaps& caps, 253 GrProcessorKeyBuilder* b) const { 254 GrGLDistanceFieldTextureEffect::GenKey(*this, bt, caps, b); 255} 256 257GrGLPrimitiveProcessor* 258GrDistanceFieldTextureEffect::createGLInstance(const GrBatchTracker& bt, 259 const GrGLCaps&) const { 260 return SkNEW_ARGS(GrGLDistanceFieldTextureEffect, (*this, bt)); 261} 262 263void GrDistanceFieldTextureEffect::initBatchTracker(GrBatchTracker* bt, 264 const GrPipelineInfo& init) const { 265 DistanceFieldBatchTracker* local = bt->cast<DistanceFieldBatchTracker>(); 266 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, 267 SkToBool(fInColor)); 268 local->fUsesLocalCoords = init.fUsesLocalCoords; 269} 270 271bool GrDistanceFieldTextureEffect::onCanMakeEqual(const GrBatchTracker& m, 272 const GrGeometryProcessor& that, 273 const GrBatchTracker& t) const { 274 const DistanceFieldBatchTracker& mine = m.cast<DistanceFieldBatchTracker>(); 275 const DistanceFieldBatchTracker& theirs = t.cast<DistanceFieldBatchTracker>(); 276 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords, 277 that, theirs.fUsesLocalCoords) && 278 CanCombineOutput(mine.fInputColorType, mine.fColor, 279 theirs.fInputColorType, theirs.fColor); 280} 281 282/////////////////////////////////////////////////////////////////////////////// 283 284GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldTextureEffect); 285 286GrGeometryProcessor* GrDistanceFieldTextureEffect::TestCreate(SkRandom* random, 287 GrContext*, 288 const GrDrawTargetCaps&, 289 GrTexture* textures[]) { 290 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : 291 GrProcessorUnitTest::kAlphaTextureIdx; 292 static const SkShader::TileMode kTileModes[] = { 293 SkShader::kClamp_TileMode, 294 SkShader::kRepeat_TileMode, 295 SkShader::kMirror_TileMode, 296 }; 297 SkShader::TileMode tileModes[] = { 298 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 299 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 300 }; 301 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : 302 GrTextureParams::kNone_FilterMode); 303 304 return GrDistanceFieldTextureEffect::Create(GrRandomColor(random), 305 GrProcessorUnitTest::TestMatrix(random), 306 GrProcessorUnitTest::TestMatrix(random), 307 textures[texIdx], params, 308#ifdef SK_GAMMA_APPLY_TO_A8 309 random->nextF(), 310#endif 311 random->nextBool() ? 312 kSimilarity_DistanceFieldEffectFlag : 0, 313 random->nextBool()); 314} 315 316/////////////////////////////////////////////////////////////////////////////// 317 318struct DistanceFieldNoGammaBatchTracker { 319 GrGPInput fInputColorType; 320 GrColor fColor; 321 bool fUsesLocalCoords; 322}; 323 324class GrGLDistanceFieldNoGammaTextureEffect : public GrGLGeometryProcessor { 325public: 326 GrGLDistanceFieldNoGammaTextureEffect(const GrGeometryProcessor&, 327 const GrBatchTracker&) 328 : fColor(GrColor_ILLEGAL), fTextureSize(SkISize::Make(-1, -1)) {} 329 330 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ 331 const GrDistanceFieldNoGammaTextureEffect& dfTexEffect = 332 args.fGP.cast<GrDistanceFieldNoGammaTextureEffect>(); 333 334 const DistanceFieldNoGammaBatchTracker& local = 335 args.fBT.cast<DistanceFieldNoGammaBatchTracker>(); 336 GrGLGPBuilder* pb = args.fPB; 337 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 338 SkAssertResult(fsBuilder->enableFeature( 339 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); 340 341 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); 342 343 // emit attributes 344 vsBuilder->emitAttributes(dfTexEffect); 345 346 GrGLVertToFrag v(kVec2f_GrSLType); 347 args.fPB->addVarying("TextureCoords", &v, kHigh_GrSLPrecision); 348 349 // setup pass through color 350 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, 351 dfTexEffect.inColor(), &fColorUniform); 352 353 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoords()->fName); 354 355 // Setup position 356 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix()); 357 358 // emit transforms 359 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, 360 dfTexEffect.localMatrix(), args.fTransformsIn, args.fTransformsOut); 361 362 const char* textureSizeUniName = NULL; 363 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, 364 kVec2f_GrSLType, kDefault_GrSLPrecision, 365 "TextureSize", &textureSizeUniName); 366 367 // Use highp to work around aliasing issues 368 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, 369 pb->ctxInfo().standard())); 370 fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn()); 371 372 fsBuilder->codeAppend("float texColor = "); 373 fsBuilder->appendTextureLookup(args.fSamplers[0], 374 "uv", 375 kVec2f_GrSLType); 376 fsBuilder->codeAppend(".r;"); 377 fsBuilder->codeAppend("float distance = " 378 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold ");"); 379 380 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, 381 pb->ctxInfo().standard())); 382 fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName); 383 fsBuilder->codeAppend("float afwidth;"); 384 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) { 385 // For uniform scale, we adjust for the effect of the transformation on the distance 386 // by using the length of the gradient of the texture coordinates. We use st coordinates 387 // to ensure we're mapping 1:1 from texel space to pixel space. 388 389 // this gives us a smooth step across approximately one fragment 390 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dFdx(st.x));"); 391 } else { 392 // For general transforms, to determine the amount of correction we multiply a unit 393 // vector pointing along the SDF gradient direction by the Jacobian of the st coords 394 // (which is the inverse transform for this fragment) and take the length of the result. 395 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(distance));"); 396 // the length of the gradient may be 0, so we need to check for this 397 // this also compensates for the Adreno, which likes to drop tiles on division by 0 398 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); 399 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {"); 400 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); 401 fsBuilder->codeAppend("} else {"); 402 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); 403 fsBuilder->codeAppend("}"); 404 405 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);"); 406 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);"); 407 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); 408 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); 409 410 // this gives us a smooth step across approximately one fragment 411 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); 412 } 413 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distance);"); 414 415 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); 416 } 417 418 virtual void setData(const GrGLProgramDataManager& pdman, 419 const GrPrimitiveProcessor& proc, 420 const GrBatchTracker& bt) override { 421 SkASSERT(fTextureSizeUni.isValid()); 422 423 GrTexture* texture = proc.texture(0); 424 if (texture->width() != fTextureSize.width() || 425 texture->height() != fTextureSize.height()) { 426 fTextureSize = SkISize::Make(texture->width(), texture->height()); 427 pdman.set2f(fTextureSizeUni, 428 SkIntToScalar(fTextureSize.width()), 429 SkIntToScalar(fTextureSize.height())); 430 } 431 432 this->setUniformViewMatrix(pdman, proc.viewMatrix()); 433 434 const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>(); 435 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { 436 GrGLfloat c[4]; 437 GrColorToRGBAFloat(local.fColor, c); 438 pdman.set4fv(fColorUniform, 1, c); 439 fColor = local.fColor; 440 } 441 } 442 443 static inline void GenKey(const GrGeometryProcessor& gp, 444 const GrBatchTracker& bt, 445 const GrGLCaps&, 446 GrProcessorKeyBuilder* b) { 447 const GrDistanceFieldNoGammaTextureEffect& dfTexEffect = 448 gp.cast<GrDistanceFieldNoGammaTextureEffect>(); 449 450 const DistanceFieldNoGammaBatchTracker& local = bt.cast<DistanceFieldNoGammaBatchTracker>(); 451 uint32_t key = dfTexEffect.getFlags(); 452 key |= local.fInputColorType << 16; 453 key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0; 454 key |= ComputePosKey(gp.viewMatrix()) << 25; 455 b->add32(key); 456 } 457 458private: 459 UniformHandle fColorUniform; 460 UniformHandle fTextureSizeUni; 461 GrColor fColor; 462 SkISize fTextureSize; 463 464 typedef GrGLGeometryProcessor INHERITED; 465}; 466 467/////////////////////////////////////////////////////////////////////////////// 468 469GrDistanceFieldNoGammaTextureEffect::GrDistanceFieldNoGammaTextureEffect( 470 GrColor color, 471 const SkMatrix& viewMatrix, 472 GrTexture* texture, 473 const GrTextureParams& params, 474 uint32_t flags, 475 bool opaqueVertexColors) 476 : INHERITED(color, viewMatrix, SkMatrix::I(), opaqueVertexColors) 477 , fTextureAccess(texture, params) 478 , fFlags(flags & kNonLCD_DistanceFieldEffectMask) 479 , fInColor(NULL) { 480 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask)); 481 this->initClassID<GrDistanceFieldNoGammaTextureEffect>(); 482 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType)); 483 if (flags & kColorAttr_DistanceFieldEffectFlag) { 484 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexAttribType)); 485 this->setHasVertexColor(); 486 } 487 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", 488 kVec2f_GrVertexAttribType)); 489 this->addTextureAccess(&fTextureAccess); 490} 491 492bool GrDistanceFieldNoGammaTextureEffect::onIsEqual(const GrGeometryProcessor& other) const { 493 const GrDistanceFieldNoGammaTextureEffect& cte = 494 other.cast<GrDistanceFieldNoGammaTextureEffect>(); 495 return fFlags == cte.fFlags; 496} 497 498void GrDistanceFieldNoGammaTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) 499 const { 500 out->setUnknownSingleComponent(); 501} 502 503void GrDistanceFieldNoGammaTextureEffect::getGLProcessorKey(const GrBatchTracker& bt, 504 const GrGLCaps& caps, 505 GrProcessorKeyBuilder* b) const { 506 GrGLDistanceFieldNoGammaTextureEffect::GenKey(*this, bt, caps, b); 507} 508 509GrGLPrimitiveProcessor* 510GrDistanceFieldNoGammaTextureEffect::createGLInstance(const GrBatchTracker& bt, 511 const GrGLCaps&) const { 512 return SkNEW_ARGS(GrGLDistanceFieldNoGammaTextureEffect, (*this, bt)); 513} 514 515void GrDistanceFieldNoGammaTextureEffect::initBatchTracker(GrBatchTracker* bt, 516 const GrPipelineInfo& init) const { 517 DistanceFieldNoGammaBatchTracker* local = bt->cast<DistanceFieldNoGammaBatchTracker>(); 518 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, 519 SkToBool(fInColor)); 520 local->fUsesLocalCoords = init.fUsesLocalCoords; 521} 522 523bool GrDistanceFieldNoGammaTextureEffect::onCanMakeEqual(const GrBatchTracker& m, 524 const GrGeometryProcessor& that, 525 const GrBatchTracker& t) const { 526 const DistanceFieldNoGammaBatchTracker& mine = m.cast<DistanceFieldNoGammaBatchTracker>(); 527 const DistanceFieldNoGammaBatchTracker& theirs = t.cast<DistanceFieldNoGammaBatchTracker>(); 528 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords, 529 that, theirs.fUsesLocalCoords) && 530 CanCombineOutput(mine.fInputColorType, mine.fColor, 531 theirs.fInputColorType, theirs.fColor); 532} 533 534/////////////////////////////////////////////////////////////////////////////// 535 536GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldNoGammaTextureEffect); 537 538GrGeometryProcessor* GrDistanceFieldNoGammaTextureEffect::TestCreate(SkRandom* random, 539 GrContext*, 540 const GrDrawTargetCaps&, 541 GrTexture* textures[]) { 542 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx 543 : GrProcessorUnitTest::kAlphaTextureIdx; 544 static const SkShader::TileMode kTileModes[] = { 545 SkShader::kClamp_TileMode, 546 SkShader::kRepeat_TileMode, 547 SkShader::kMirror_TileMode, 548 }; 549 SkShader::TileMode tileModes[] = { 550 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 551 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 552 }; 553 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode 554 : GrTextureParams::kNone_FilterMode); 555 556 return GrDistanceFieldNoGammaTextureEffect::Create(GrRandomColor(random), 557 GrProcessorUnitTest::TestMatrix(random), 558 textures[texIdx], 559 params, 560 random->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0, random->nextBool()); 561} 562 563/////////////////////////////////////////////////////////////////////////////// 564 565struct DistanceFieldLCDBatchTracker { 566 GrGPInput fInputColorType; 567 GrColor fColor; 568 bool fUsesLocalCoords; 569}; 570 571class GrGLDistanceFieldLCDTextureEffect : public GrGLGeometryProcessor { 572public: 573 GrGLDistanceFieldLCDTextureEffect(const GrGeometryProcessor&, 574 const GrBatchTracker&) 575 : fColor(GrColor_ILLEGAL) { 576 fDistanceAdjust = GrDistanceFieldLCDTextureEffect::DistanceAdjust::Make(1.0f, 1.0f, 1.0f); 577 } 578 579 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ 580 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 581 args.fGP.cast<GrDistanceFieldLCDTextureEffect>(); 582 const DistanceFieldLCDBatchTracker& local = args.fBT.cast<DistanceFieldLCDBatchTracker>(); 583 GrGLGPBuilder* pb = args.fPB; 584 585 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); 586 587 // emit attributes 588 vsBuilder->emitAttributes(dfTexEffect); 589 590 // setup pass through color 591 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor, NULL, 592 &fColorUniform); 593 594 // Setup position 595 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEffect.viewMatrix()); 596 597 // emit transforms 598 const SkMatrix& localMatrix = dfTexEffect.localMatrix(); 599 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosition()->fName, 600 localMatrix, args.fTransformsIn, args.fTransformsOut); 601 602 // set up varyings 603 bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask); 604 GrGLVertToFrag recipScale(kFloat_GrSLType); 605 GrGLVertToFrag st(kVec2f_GrSLType); 606 const char* viewMatrixName = this->uViewM(); 607 // view matrix name is NULL if identity matrix 608 bool useInverseScale = !localMatrix.isIdentity() && viewMatrixName; 609 if (isUniformScale && useInverseScale) { 610 args.fPB->addVarying("RecipScale", &recipScale, kHigh_GrSLPrecision); 611 vsBuilder->codeAppendf("vec2 tx = vec2(%s[0][0], %s[1][0]);", 612 viewMatrixName, viewMatrixName); 613 vsBuilder->codeAppend("float tx2 = dot(tx, tx);"); 614 vsBuilder->codeAppendf("%s = inversesqrt(tx2);", recipScale.vsOut()); 615 } else { 616 args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); 617 vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTextureCoords()->fName); 618 } 619 620 GrGLVertToFrag uv(kVec2f_GrSLType); 621 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); 622 // this is only used with text, so our texture bounds always match the glyph atlas 623 vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", " 624 GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(), 625 dfTexEffect.inTextureCoords()->fName); 626 627 // add frag shader code 628 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); 629 630 SkAssertResult(fsBuilder->enableFeature( 631 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); 632 633 // create LCD offset adjusted by inverse of transform 634 // Use highp to work around aliasing issues 635 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, 636 pb->ctxInfo().standard())); 637 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); 638 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision, 639 pb->ctxInfo().standard())); 640 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) { 641 fsBuilder->codeAppend("float delta = -" GR_FONT_ATLAS_LCD_DELTA ";\n"); 642 } else { 643 fsBuilder->codeAppend("float delta = " GR_FONT_ATLAS_LCD_DELTA ";\n"); 644 } 645 if (isUniformScale) { 646 if (useInverseScale) { 647 fsBuilder->codeAppendf("float dx = %s;", recipScale.fsIn()); 648 } else { 649 fsBuilder->codeAppendf("float dx = dFdx(%s.x);", st.fsIn()); 650 } 651 fsBuilder->codeAppend("vec2 offset = vec2(dx*delta, 0.0);"); 652 } else { 653 fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn()); 654 655 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);"); 656 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);"); 657 fsBuilder->codeAppend("vec2 offset = delta*Jdx;"); 658 } 659 660 // green is distance to uv center 661 fsBuilder->codeAppend("\tvec4 texColor = "); 662 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType); 663 fsBuilder->codeAppend(";\n"); 664 fsBuilder->codeAppend("\tvec3 distance;\n"); 665 fsBuilder->codeAppend("\tdistance.y = texColor.r;\n"); 666 // red is distance to left offset 667 fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n"); 668 fsBuilder->codeAppend("\ttexColor = "); 669 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType); 670 fsBuilder->codeAppend(";\n"); 671 fsBuilder->codeAppend("\tdistance.x = texColor.r;\n"); 672 // blue is distance to right offset 673 fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n"); 674 fsBuilder->codeAppend("\ttexColor = "); 675 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_GrSLType); 676 fsBuilder->codeAppend(";\n"); 677 fsBuilder->codeAppend("\tdistance.z = texColor.r;\n"); 678 679 fsBuilder->codeAppend("\tdistance = " 680 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceFieldThreshold"));"); 681 682 // adjust width based on gamma 683 const char* distanceAdjustUniName = NULL; 684 fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Visibility, 685 kVec3f_GrSLType, kDefault_GrSLPrecision, 686 "DistanceAdjust", &distanceAdjustUniName); 687 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); 688 689 // To be strictly correct, we should compute the anti-aliasing factor separately 690 // for each color component. However, this is only important when using perspective 691 // transformations, and even then using a single factor seems like a reasonable 692 // trade-off between quality and speed. 693 fsBuilder->codeAppend("float afwidth;"); 694 if (isUniformScale) { 695 // For uniform scale, we adjust for the effect of the transformation on the distance 696 // by using the length of the gradient of the texture coordinates. We use st coordinates 697 // to ensure we're mapping 1:1 from texel space to pixel space. 698 699 // this gives us a smooth step across approximately one fragment 700 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dx);"); 701 } else { 702 // For general transforms, to determine the amount of correction we multiply a unit 703 // vector pointing along the SDF gradient direction by the Jacobian of the st coords 704 // (which is the inverse transform for this fragment) and take the length of the result. 705 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(distance.r));"); 706 // the length of the gradient may be 0, so we need to check for this 707 // this also compensates for the Adreno, which likes to drop tiles on division by 0 708 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); 709 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {"); 710 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); 711 fsBuilder->codeAppend("} else {"); 712 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);"); 713 fsBuilder->codeAppend("}"); 714 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,"); 715 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);"); 716 717 // this gives us a smooth step across approximately one fragment 718 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);"); 719 } 720 721 fsBuilder->codeAppend( 722 "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth), distance), 1.0);"); 723 724 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); 725 } 726 727 virtual void setData(const GrGLProgramDataManager& pdman, 728 const GrPrimitiveProcessor& processor, 729 const GrBatchTracker& bt) override { 730 SkASSERT(fDistanceAdjustUni.isValid()); 731 732 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 733 processor.cast<GrDistanceFieldLCDTextureEffect>(); 734 GrDistanceFieldLCDTextureEffect::DistanceAdjust wa = dfTexEffect.getDistanceAdjust(); 735 if (wa != fDistanceAdjust) { 736 pdman.set3f(fDistanceAdjustUni, 737 wa.fR, 738 wa.fG, 739 wa.fB); 740 fDistanceAdjust = wa; 741 } 742 743 this->setUniformViewMatrix(pdman, processor.viewMatrix()); 744 745 const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>(); 746 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColor) { 747 GrGLfloat c[4]; 748 GrColorToRGBAFloat(local.fColor, c); 749 pdman.set4fv(fColorUniform, 1, c); 750 fColor = local.fColor; 751 } 752 } 753 754 static inline void GenKey(const GrGeometryProcessor& gp, 755 const GrBatchTracker& bt, 756 const GrGLCaps&, 757 GrProcessorKeyBuilder* b) { 758 const GrDistanceFieldLCDTextureEffect& dfTexEffect = 759 gp.cast<GrDistanceFieldLCDTextureEffect>(); 760 761 const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatchTracker>(); 762 uint32_t key = dfTexEffect.getFlags(); 763 key |= local.fInputColorType << 16; 764 key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1 << 24: 0x0; 765 key |= ComputePosKey(gp.viewMatrix()) << 25; 766 key |= (!gp.viewMatrix().isIdentity() && !gp.localMatrix().isIdentity()) ? 0x1 << 27 : 0x0; 767 b->add32(key); 768 } 769 770private: 771 GrColor fColor; 772 UniformHandle fColorUniform; 773 GrDistanceFieldLCDTextureEffect::DistanceAdjust fDistanceAdjust; 774 UniformHandle fDistanceAdjustUni; 775 776 typedef GrGLGeometryProcessor INHERITED; 777}; 778 779/////////////////////////////////////////////////////////////////////////////// 780 781GrDistanceFieldLCDTextureEffect::GrDistanceFieldLCDTextureEffect( 782 GrColor color, const SkMatrix& viewMatrix, 783 const SkMatrix& localMatrix, 784 GrTexture* texture, const GrTextureParams& params, 785 DistanceAdjust distanceAdjust, 786 uint32_t flags) 787 : INHERITED(color, viewMatrix, localMatrix) 788 , fTextureAccess(texture, params) 789 , fDistanceAdjust(distanceAdjust) 790 , fFlags(flags & kLCD_DistanceFieldEffectMask){ 791 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag)); 792 this->initClassID<GrDistanceFieldLCDTextureEffect>(); 793 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertexAttribType)); 794 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", 795 kVec2s_GrVertexAttribType)); 796 this->addTextureAccess(&fTextureAccess); 797} 798 799bool GrDistanceFieldLCDTextureEffect::onIsEqual(const GrGeometryProcessor& other) const { 800 const GrDistanceFieldLCDTextureEffect& cte = other.cast<GrDistanceFieldLCDTextureEffect>(); 801 return (fDistanceAdjust == cte.fDistanceAdjust && 802 fFlags == cte.fFlags); 803} 804 805void GrDistanceFieldLCDTextureEffect::onGetInvariantOutputCoverage(GrInitInvariantOutput* out) 806 const { 807 out->setUnknownFourComponents(); 808 out->setUsingLCDCoverage(); 809} 810 811void GrDistanceFieldLCDTextureEffect::getGLProcessorKey(const GrBatchTracker& bt, 812 const GrGLCaps& caps, 813 GrProcessorKeyBuilder* b) const { 814 GrGLDistanceFieldLCDTextureEffect::GenKey(*this, bt, caps, b); 815} 816 817GrGLPrimitiveProcessor* 818GrDistanceFieldLCDTextureEffect::createGLInstance(const GrBatchTracker& bt, 819 const GrGLCaps&) const { 820 return SkNEW_ARGS(GrGLDistanceFieldLCDTextureEffect, (*this, bt)); 821} 822 823void GrDistanceFieldLCDTextureEffect::initBatchTracker(GrBatchTracker* bt, 824 const GrPipelineInfo& init) const { 825 DistanceFieldLCDBatchTracker* local = bt->cast<DistanceFieldLCDBatchTracker>(); 826 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), init, false); 827 local->fUsesLocalCoords = init.fUsesLocalCoords; 828} 829 830bool GrDistanceFieldLCDTextureEffect::onCanMakeEqual(const GrBatchTracker& m, 831 const GrGeometryProcessor& that, 832 const GrBatchTracker& t) const { 833 const DistanceFieldLCDBatchTracker& mine = m.cast<DistanceFieldLCDBatchTracker>(); 834 const DistanceFieldLCDBatchTracker& theirs = t.cast<DistanceFieldLCDBatchTracker>(); 835 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords, 836 that, theirs.fUsesLocalCoords) && 837 CanCombineOutput(mine.fInputColorType, mine.fColor, 838 theirs.fInputColorType, theirs.fColor); 839} 840 841/////////////////////////////////////////////////////////////////////////////// 842 843GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextureEffect); 844 845GrGeometryProcessor* GrDistanceFieldLCDTextureEffect::TestCreate(SkRandom* random, 846 GrContext*, 847 const GrDrawTargetCaps&, 848 GrTexture* textures[]) { 849 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : 850 GrProcessorUnitTest::kAlphaTextureIdx; 851 static const SkShader::TileMode kTileModes[] = { 852 SkShader::kClamp_TileMode, 853 SkShader::kRepeat_TileMode, 854 SkShader::kMirror_TileMode, 855 }; 856 SkShader::TileMode tileModes[] = { 857 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 858 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], 859 }; 860 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBilerp_FilterMode : 861 GrTextureParams::kNone_FilterMode); 862 DistanceAdjust wa = { 0.0f, 0.1f, -0.1f }; 863 uint32_t flags = kUseLCD_DistanceFieldEffectFlag; 864 flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0; 865 flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0; 866 return GrDistanceFieldLCDTextureEffect::Create(GrRandomColor(random), 867 GrProcessorUnitTest::TestMatrix(random), 868 GrProcessorUnitTest::TestMatrix(random), 869 textures[texIdx], params, 870 wa, 871 flags); 872} 873