| OLD | NEW |
| (Empty) |
| 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 "GrFontAtlasSizes.h" | |
| 10 #include "GrInvariantOutput.h" | |
| 11 #include "GrTexture.h" | |
| 12 | |
| 13 #include "SkDistanceFieldGen.h" | |
| 14 | |
| 15 #include "gl/GrGLProcessor.h" | |
| 16 #include "gl/GrGLSL.h" | |
| 17 #include "gl/GrGLTexture.h" | |
| 18 #include "gl/GrGLGeometryProcessor.h" | |
| 19 #include "gl/builders/GrGLProgramBuilder.h" | |
| 20 | |
| 21 // Assuming a radius of a little less than the diagonal of the fragment | |
| 22 #define SK_DistanceFieldAAFactor "0.65" | |
| 23 | |
| 24 struct DistanceFieldBatchTracker { | |
| 25 GrGPInput fInputColorType; | |
| 26 GrColor fColor; | |
| 27 bool fUsesLocalCoords; | |
| 28 }; | |
| 29 | |
| 30 class GrGLDistanceFieldA8TextGeoProc : public GrGLGeometryProcessor { | |
| 31 public: | |
| 32 GrGLDistanceFieldA8TextGeoProc(const GrGeometryProcessor&, | |
| 33 const GrBatchTracker&) | |
| 34 : fColor(GrColor_ILLEGAL) | |
| 35 #ifdef SK_GAMMA_APPLY_TO_A8 | |
| 36 , fDistanceAdjust(-1.0f) | |
| 37 #endif | |
| 38 {} | |
| 39 | |
| 40 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ | |
| 41 const GrDistanceFieldA8TextGeoProc& dfTexEffect = | |
| 42 args.fGP.cast<GrDistanceFieldA8TextGeoProc>(); | |
| 43 const DistanceFieldBatchTracker& local = args.fBT.cast<DistanceFieldBatc
hTracker>(); | |
| 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, dfTexEf
fect.viewMatrix()); | |
| 69 | |
| 70 // emit transforms | |
| 71 const SkMatrix& localMatrix = dfTexEffect.localMatrix(); | |
| 72 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosit
ion()->fName, | |
| 73 localMatrix, args.fTransformsIn, args.fTransformsOu
t); | |
| 74 | |
| 75 // add varyings | |
| 76 GrGLVertToFrag recipScale(kFloat_GrSLType); | |
| 77 GrGLVertToFrag st(kVec2f_GrSLType); | |
| 78 bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_Distan
ceFieldEffectFlag); | |
| 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.inTexture
Coords()->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 g
lyph 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().stand
ard())); | |
| 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_DistanceFie
ldThreshold ");"); | |
| 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 ther
e is no view matrix) | |
| 121 // by using the length of the gradient of the texture coordinates. W
e use st coordinates | |
| 122 // with the latter to ensure we're mapping 1:1 from texel space to p
ixel 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 l
ength of the result. | |
| 136 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(di
stance));"); | |
| 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 o
n 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_gra
d.y*Jdy.x,"); | |
| 149 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_gra
d.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, distanc
e);"); | |
| 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 GrDistanceFieldA8TextGeoProc& dfTexEffect = proc.cast<GrDistanceFi
eldA8TextGeoProc>(); | |
| 164 float distanceAdjust = dfTexEffect.getDistanceAdjust(); | |
| 165 if (distanceAdjust != fDistanceAdjust) { | |
| 166 pdman.set1f(fDistanceAdjustUni, distanceAdjust); | |
| 167 fDistanceAdjust = distanceAdjust; | |
| 168 } | |
| 169 #endif | |
| 170 | |
| 171 this->setUniformViewMatrix(pdman, proc.viewMatrix()); | |
| 172 | |
| 173 const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTrack
er>(); | |
| 174 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColo
r) { | |
| 175 GrGLfloat c[4]; | |
| 176 GrColorToRGBAFloat(local.fColor, c); | |
| 177 pdman.set4fv(fColorUniform, 1, c); | |
| 178 fColor = local.fColor; | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 static inline void GenKey(const GrGeometryProcessor& gp, | |
| 183 const GrBatchTracker& bt, | |
| 184 const GrGLCaps&, | |
| 185 GrProcessorKeyBuilder* b) { | |
| 186 const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFiel
dA8TextGeoProc>(); | |
| 187 const DistanceFieldBatchTracker& local = bt.cast<DistanceFieldBatchTrack
er>(); | |
| 188 uint32_t key = dfTexEffect.getFlags(); | |
| 189 key |= local.fInputColorType << 16; | |
| 190 key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1
<< 24: 0x0; | |
| 191 key |= ComputePosKey(gp.viewMatrix()) << 25; | |
| 192 key |= (!gp.viewMatrix().isIdentity() && !gp.localMatrix().isIdentity())
? 0x1 << 27 : 0x0; | |
| 193 b->add32(key); | |
| 194 } | |
| 195 | |
| 196 private: | |
| 197 GrColor fColor; | |
| 198 UniformHandle fColorUniform; | |
| 199 #ifdef SK_GAMMA_APPLY_TO_A8 | |
| 200 float fDistanceAdjust; | |
| 201 UniformHandle fDistanceAdjustUni; | |
| 202 #endif | |
| 203 | |
| 204 typedef GrGLGeometryProcessor INHERITED; | |
| 205 }; | |
| 206 | |
| 207 /////////////////////////////////////////////////////////////////////////////// | |
| 208 | |
| 209 GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(GrColor color, | |
| 210 const SkMatrix& viewM
atrix, | |
| 211 const SkMatrix& local
Matrix, | |
| 212 GrTexture* texture, | |
| 213 const GrTextureParams
& params, | |
| 214 #ifdef SK_GAMMA_APPLY_TO_A8 | |
| 215 float distanceAdjust, | |
| 216 #endif | |
| 217 uint32_t flags, bool
opaqueVertexColors) | |
| 218 : INHERITED(color, viewMatrix, localMatrix, opaqueVertexColors) | |
| 219 , fTextureAccess(texture, params) | |
| 220 #ifdef SK_GAMMA_APPLY_TO_A8 | |
| 221 , fDistanceAdjust(distanceAdjust) | |
| 222 #endif | |
| 223 , fFlags(flags & kNonLCD_DistanceFieldEffectMask) | |
| 224 , fInColor(NULL) { | |
| 225 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask)); | |
| 226 this->initClassID<GrDistanceFieldA8TextGeoProc>(); | |
| 227 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertex
AttribType)); | |
| 228 if (flags & kColorAttr_DistanceFieldEffectFlag) { | |
| 229 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexA
ttribType)); | |
| 230 this->setHasVertexColor(); | |
| 231 } | |
| 232 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", | |
| 233 kVec2s_GrVertexAttribT
ype)); | |
| 234 this->addTextureAccess(&fTextureAccess); | |
| 235 } | |
| 236 | |
| 237 bool GrDistanceFieldA8TextGeoProc::onIsEqual(const GrGeometryProcessor& other) c
onst { | |
| 238 const GrDistanceFieldA8TextGeoProc& cte = other.cast<GrDistanceFieldA8TextGe
oProc>(); | |
| 239 return | |
| 240 #ifdef SK_GAMMA_APPLY_TO_A8 | |
| 241 fDistanceAdjust == cte.fDistanceAdjust && | |
| 242 #endif | |
| 243 fFlags == cte.fFlags; | |
| 244 } | |
| 245 | |
| 246 void GrDistanceFieldA8TextGeoProc::onGetInvariantOutputCoverage(GrInitInvariantO
utput* out) const { | |
| 247 out->setUnknownSingleComponent(); | |
| 248 } | |
| 249 | |
| 250 void GrDistanceFieldA8TextGeoProc::getGLProcessorKey(const GrBatchTracker& bt, | |
| 251 const GrGLCaps& caps, | |
| 252 GrProcessorKeyBuilder* b) c
onst { | |
| 253 GrGLDistanceFieldA8TextGeoProc::GenKey(*this, bt, caps, b); | |
| 254 } | |
| 255 | |
| 256 GrGLPrimitiveProcessor* | |
| 257 GrDistanceFieldA8TextGeoProc::createGLInstance(const GrBatchTracker& bt, | |
| 258 const GrGLCaps&) const { | |
| 259 return SkNEW_ARGS(GrGLDistanceFieldA8TextGeoProc, (*this, bt)); | |
| 260 } | |
| 261 | |
| 262 void GrDistanceFieldA8TextGeoProc::initBatchTracker(GrBatchTracker* bt, | |
| 263 const GrPipelineInfo& init)
const { | |
| 264 DistanceFieldBatchTracker* local = bt->cast<DistanceFieldBatchTracker>(); | |
| 265 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), in
it, | |
| 266 SkToBool(fInColor)); | |
| 267 local->fUsesLocalCoords = init.fUsesLocalCoords; | |
| 268 } | |
| 269 | |
| 270 bool GrDistanceFieldA8TextGeoProc::onCanMakeEqual(const GrBatchTracker& m, | |
| 271 const GrGeometryProcessor& tha
t, | |
| 272 const GrBatchTracker& t) const
{ | |
| 273 const DistanceFieldBatchTracker& mine = m.cast<DistanceFieldBatchTracker>(); | |
| 274 const DistanceFieldBatchTracker& theirs = t.cast<DistanceFieldBatchTracker>(
); | |
| 275 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords, | |
| 276 that, theirs.fUsesLocalCoords) && | |
| 277 CanCombineOutput(mine.fInputColorType, mine.fColor, | |
| 278 theirs.fInputColorType, theirs.fColor); | |
| 279 } | |
| 280 | |
| 281 /////////////////////////////////////////////////////////////////////////////// | |
| 282 | |
| 283 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc); | |
| 284 | |
| 285 GrGeometryProcessor* GrDistanceFieldA8TextGeoProc::TestCreate(SkRandom* random, | |
| 286 GrContext*, | |
| 287 const GrDrawTarget
Caps&, | |
| 288 GrTexture* texture
s[]) { | |
| 289 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : | |
| 290 GrProcessorUnitTest::kAlphaTextureIdx; | |
| 291 static const SkShader::TileMode kTileModes[] = { | |
| 292 SkShader::kClamp_TileMode, | |
| 293 SkShader::kRepeat_TileMode, | |
| 294 SkShader::kMirror_TileMode, | |
| 295 }; | |
| 296 SkShader::TileMode tileModes[] = { | |
| 297 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], | |
| 298 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], | |
| 299 }; | |
| 300 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBil
erp_FilterMode : | |
| 301 GrTextureParams::kNon
e_FilterMode); | |
| 302 | |
| 303 return GrDistanceFieldA8TextGeoProc::Create(GrRandomColor(random), | |
| 304 GrProcessorUnitTest::TestMatrix(
random), | |
| 305 GrProcessorUnitTest::TestMatrix(
random), | |
| 306 textures[texIdx], params, | |
| 307 #ifdef SK_GAMMA_APPLY_TO_A8 | |
| 308 random->nextF(), | |
| 309 #endif | |
| 310 random->nextBool() ? | |
| 311 kSimilarity_DistanceFieldEff
ectFlag : 0, | |
| 312 random->nextBool()); | |
| 313 } | |
| 314 | |
| 315 /////////////////////////////////////////////////////////////////////////////// | |
| 316 | |
| 317 struct DistanceFieldPathBatchTracker { | |
| 318 GrGPInput fInputColorType; | |
| 319 GrColor fColor; | |
| 320 bool fUsesLocalCoords; | |
| 321 }; | |
| 322 | |
| 323 class GrGLDistanceFieldPathGeoProc : public GrGLGeometryProcessor { | |
| 324 public: | |
| 325 GrGLDistanceFieldPathGeoProc(const GrGeometryProcessor&, | |
| 326 const GrBatchTracker&) | |
| 327 : fColor(GrColor_ILLEGAL), fTextureSize(SkISize::Make(-1, -1)) {} | |
| 328 | |
| 329 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ | |
| 330 const GrDistanceFieldPathGeoProc& dfTexEffect = args.fGP.cast<GrDistance
FieldPathGeoProc>(); | |
| 331 | |
| 332 const DistanceFieldPathBatchTracker& local = args.fBT.cast<DistanceField
PathBatchTracker>(); | |
| 333 GrGLGPBuilder* pb = args.fPB; | |
| 334 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); | |
| 335 SkAssertResult(fsBuilder->enableFeature( | |
| 336 GrGLFragmentShaderBuilder::kStandardDerivat
ives_GLSLFeature)); | |
| 337 | |
| 338 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); | |
| 339 | |
| 340 // emit attributes | |
| 341 vsBuilder->emitAttributes(dfTexEffect); | |
| 342 | |
| 343 GrGLVertToFrag v(kVec2f_GrSLType); | |
| 344 args.fPB->addVarying("TextureCoords", &v, kHigh_GrSLPrecision); | |
| 345 | |
| 346 // setup pass through color | |
| 347 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor
, | |
| 348 dfTexEffect.inColor(), &fColorUniform); | |
| 349 | |
| 350 vsBuilder->codeAppendf("%s = %s;", v.vsOut(), dfTexEffect.inTextureCoord
s()->fName); | |
| 351 | |
| 352 // Setup position | |
| 353 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEf
fect.viewMatrix()); | |
| 354 | |
| 355 // emit transforms | |
| 356 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosit
ion()->fName, | |
| 357 dfTexEffect.localMatrix(), args.fTransformsIn, args
.fTransformsOut); | |
| 358 | |
| 359 const char* textureSizeUniName = NULL; | |
| 360 fTextureSizeUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_Vis
ibility, | |
| 361 kVec2f_GrSLType, kDefault_GrSLPrec
ision, | |
| 362 "TextureSize", &textureSizeUniName
); | |
| 363 | |
| 364 // Use highp to work around aliasing issues | |
| 365 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision
, | |
| 366 pb->ctxInfo().stand
ard())); | |
| 367 fsBuilder->codeAppendf("vec2 uv = %s;", v.fsIn()); | |
| 368 | |
| 369 fsBuilder->codeAppend("float texColor = "); | |
| 370 fsBuilder->appendTextureLookup(args.fSamplers[0], | |
| 371 "uv", | |
| 372 kVec2f_GrSLType); | |
| 373 fsBuilder->codeAppend(".r;"); | |
| 374 fsBuilder->codeAppend("float distance = " | |
| 375 SK_DistanceFieldMultiplier "*(texColor - " SK_DistanceFieldThreshold
");"); | |
| 376 | |
| 377 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision
, | |
| 378 pb->ctxInfo().stand
ard())); | |
| 379 fsBuilder->codeAppendf("vec2 st = uv*%s;", textureSizeUniName); | |
| 380 fsBuilder->codeAppend("float afwidth;"); | |
| 381 if (dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag) { | |
| 382 // For uniform scale, we adjust for the effect of the transformation
on the distance | |
| 383 // by using the length of the gradient of the texture coordinates. W
e use st coordinates | |
| 384 // to ensure we're mapping 1:1 from texel space to pixel space. | |
| 385 | |
| 386 // this gives us a smooth step across approximately one fragment | |
| 387 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dF
dx(st.x));"); | |
| 388 } else { | |
| 389 // For general transforms, to determine the amount of correction we
multiply a unit | |
| 390 // vector pointing along the SDF gradient direction by the Jacobian
of the st coords | |
| 391 // (which is the inverse transform for this fragment) and take the l
ength of the result. | |
| 392 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance), dFdy(di
stance));"); | |
| 393 // the length of the gradient may be 0, so we need to check for this | |
| 394 // this also compensates for the Adreno, which likes to drop tiles o
n division by 0 | |
| 395 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); | |
| 396 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {"); | |
| 397 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); | |
| 398 fsBuilder->codeAppend("} else {"); | |
| 399 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);")
; | |
| 400 fsBuilder->codeAppend("}"); | |
| 401 | |
| 402 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);"); | |
| 403 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);"); | |
| 404 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_gra
d.y*Jdy.x,"); | |
| 405 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_gra
d.y*Jdy.y);"); | |
| 406 | |
| 407 // this gives us a smooth step across approximately one fragment | |
| 408 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length
(grad);"); | |
| 409 } | |
| 410 fsBuilder->codeAppend("float val = smoothstep(-afwidth, afwidth, distanc
e);"); | |
| 411 | |
| 412 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); | |
| 413 } | |
| 414 | |
| 415 virtual void setData(const GrGLProgramDataManager& pdman, | |
| 416 const GrPrimitiveProcessor& proc, | |
| 417 const GrBatchTracker& bt) override { | |
| 418 SkASSERT(fTextureSizeUni.isValid()); | |
| 419 | |
| 420 GrTexture* texture = proc.texture(0); | |
| 421 if (texture->width() != fTextureSize.width() || | |
| 422 texture->height() != fTextureSize.height()) { | |
| 423 fTextureSize = SkISize::Make(texture->width(), texture->height()); | |
| 424 pdman.set2f(fTextureSizeUni, | |
| 425 SkIntToScalar(fTextureSize.width()), | |
| 426 SkIntToScalar(fTextureSize.height())); | |
| 427 } | |
| 428 | |
| 429 this->setUniformViewMatrix(pdman, proc.viewMatrix()); | |
| 430 | |
| 431 const DistanceFieldPathBatchTracker& local = bt.cast<DistanceFieldPathBa
tchTracker>(); | |
| 432 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColo
r) { | |
| 433 GrGLfloat c[4]; | |
| 434 GrColorToRGBAFloat(local.fColor, c); | |
| 435 pdman.set4fv(fColorUniform, 1, c); | |
| 436 fColor = local.fColor; | |
| 437 } | |
| 438 } | |
| 439 | |
| 440 static inline void GenKey(const GrGeometryProcessor& gp, | |
| 441 const GrBatchTracker& bt, | |
| 442 const GrGLCaps&, | |
| 443 GrProcessorKeyBuilder* b) { | |
| 444 const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldP
athGeoProc>(); | |
| 445 | |
| 446 const DistanceFieldPathBatchTracker& local = bt.cast<DistanceFieldPathBa
tchTracker>(); | |
| 447 uint32_t key = dfTexEffect.getFlags(); | |
| 448 key |= local.fInputColorType << 16; | |
| 449 key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1
<< 24: 0x0; | |
| 450 key |= ComputePosKey(gp.viewMatrix()) << 25; | |
| 451 b->add32(key); | |
| 452 } | |
| 453 | |
| 454 private: | |
| 455 UniformHandle fColorUniform; | |
| 456 UniformHandle fTextureSizeUni; | |
| 457 GrColor fColor; | |
| 458 SkISize fTextureSize; | |
| 459 | |
| 460 typedef GrGLGeometryProcessor INHERITED; | |
| 461 }; | |
| 462 | |
| 463 /////////////////////////////////////////////////////////////////////////////// | |
| 464 | |
| 465 GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc( | |
| 466 GrColor color, | |
| 467 const SkMatrix& viewMatrix, | |
| 468 GrTexture* texture, | |
| 469 const GrTextureParams& params, | |
| 470 uint32_t flags, | |
| 471 bool opaqueVertexColors) | |
| 472 : INHERITED(color, viewMatrix, SkMatrix::I(), opaqueVertexColors) | |
| 473 , fTextureAccess(texture, params) | |
| 474 , fFlags(flags & kNonLCD_DistanceFieldEffectMask) | |
| 475 , fInColor(NULL) { | |
| 476 SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask)); | |
| 477 this->initClassID<GrDistanceFieldPathGeoProc>(); | |
| 478 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertex
AttribType)); | |
| 479 if (flags & kColorAttr_DistanceFieldEffectFlag) { | |
| 480 fInColor = &this->addVertexAttrib(Attribute("inColor", kVec4ub_GrVertexA
ttribType)); | |
| 481 this->setHasVertexColor(); | |
| 482 } | |
| 483 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", | |
| 484 kVec2f_GrVertexAttribT
ype)); | |
| 485 this->addTextureAccess(&fTextureAccess); | |
| 486 } | |
| 487 | |
| 488 bool GrDistanceFieldPathGeoProc::onIsEqual(const GrGeometryProcessor& other) con
st { | |
| 489 const GrDistanceFieldPathGeoProc& cte = other.cast<GrDistanceFieldPathGeoPro
c>(); | |
| 490 return fFlags == cte.fFlags; | |
| 491 } | |
| 492 | |
| 493 void GrDistanceFieldPathGeoProc::onGetInvariantOutputCoverage(GrInitInvariantOut
put* out) const { | |
| 494 out->setUnknownSingleComponent(); | |
| 495 } | |
| 496 | |
| 497 void GrDistanceFieldPathGeoProc::getGLProcessorKey(const GrBatchTracker& bt, | |
| 498 const GrGLCaps& caps, | |
| 499 GrProcessorKeyBuilder* b) con
st { | |
| 500 GrGLDistanceFieldPathGeoProc::GenKey(*this, bt, caps, b); | |
| 501 } | |
| 502 | |
| 503 GrGLPrimitiveProcessor* | |
| 504 GrDistanceFieldPathGeoProc::createGLInstance(const GrBatchTracker& bt, const GrG
LCaps&) const { | |
| 505 return SkNEW_ARGS(GrGLDistanceFieldPathGeoProc, (*this, bt)); | |
| 506 } | |
| 507 | |
| 508 void GrDistanceFieldPathGeoProc::initBatchTracker(GrBatchTracker* bt, | |
| 509 const GrPipelineInfo& init) co
nst { | |
| 510 DistanceFieldPathBatchTracker* local = bt->cast<DistanceFieldPathBatchTracke
r>(); | |
| 511 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), in
it, | |
| 512 SkToBool(fInColor)); | |
| 513 local->fUsesLocalCoords = init.fUsesLocalCoords; | |
| 514 } | |
| 515 | |
| 516 bool GrDistanceFieldPathGeoProc::onCanMakeEqual(const GrBatchTracker& m, | |
| 517 const GrGeometryProcessor& that, | |
| 518 const GrBatchTracker& t) const { | |
| 519 const DistanceFieldPathBatchTracker& mine = m.cast<DistanceFieldPathBatchTra
cker>(); | |
| 520 const DistanceFieldPathBatchTracker& theirs = t.cast<DistanceFieldPathBatchT
racker>(); | |
| 521 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords, | |
| 522 that, theirs.fUsesLocalCoords) && | |
| 523 CanCombineOutput(mine.fInputColorType, mine.fColor, | |
| 524 theirs.fInputColorType, theirs.fColor); | |
| 525 } | |
| 526 | |
| 527 /////////////////////////////////////////////////////////////////////////////// | |
| 528 | |
| 529 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc); | |
| 530 | |
| 531 GrGeometryProcessor* GrDistanceFieldPathGeoProc::TestCreate(SkRandom* random, | |
| 532 GrContext*, | |
| 533 const GrDrawTargetCa
ps&, | |
| 534 GrTexture* textures[
]) { | |
| 535 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx | |
| 536 : GrProcessorUnitTest::kAlphaTextureIdx; | |
| 537 static const SkShader::TileMode kTileModes[] = { | |
| 538 SkShader::kClamp_TileMode, | |
| 539 SkShader::kRepeat_TileMode, | |
| 540 SkShader::kMirror_TileMode, | |
| 541 }; | |
| 542 SkShader::TileMode tileModes[] = { | |
| 543 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], | |
| 544 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], | |
| 545 }; | |
| 546 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBil
erp_FilterMode | |
| 547 : GrTextureParams::kNon
e_FilterMode); | |
| 548 | |
| 549 return GrDistanceFieldPathGeoProc::Create(GrRandomColor(random), | |
| 550 GrProcessorUnitTest::TestMatrix(ra
ndom), | |
| 551 textures[texIdx], | |
| 552 params, | |
| 553 random->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0, random->ne
xtBool()); | |
| 554 } | |
| 555 | |
| 556 /////////////////////////////////////////////////////////////////////////////// | |
| 557 | |
| 558 struct DistanceFieldLCDBatchTracker { | |
| 559 GrGPInput fInputColorType; | |
| 560 GrColor fColor; | |
| 561 bool fUsesLocalCoords; | |
| 562 }; | |
| 563 | |
| 564 class GrGLDistanceFieldLCDTextGeoProc : public GrGLGeometryProcessor { | |
| 565 public: | |
| 566 GrGLDistanceFieldLCDTextGeoProc(const GrGeometryProcessor&, const GrBatchTra
cker&) | |
| 567 : fColor(GrColor_ILLEGAL) { | |
| 568 fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.
0f, 1.0f, 1.0f); | |
| 569 } | |
| 570 | |
| 571 void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{ | |
| 572 const GrDistanceFieldLCDTextGeoProc& dfTexEffect = | |
| 573 args.fGP.cast<GrDistanceFieldLCDTextGeoProc>(); | |
| 574 const DistanceFieldLCDBatchTracker& local = args.fBT.cast<DistanceFieldL
CDBatchTracker>(); | |
| 575 GrGLGPBuilder* pb = args.fPB; | |
| 576 | |
| 577 GrGLVertexBuilder* vsBuilder = args.fPB->getVertexShaderBuilder(); | |
| 578 | |
| 579 // emit attributes | |
| 580 vsBuilder->emitAttributes(dfTexEffect); | |
| 581 | |
| 582 // setup pass through color | |
| 583 this->setupColorPassThrough(pb, local.fInputColorType, args.fOutputColor
, NULL, | |
| 584 &fColorUniform); | |
| 585 | |
| 586 // Setup position | |
| 587 this->setupPosition(pb, gpArgs, dfTexEffect.inPosition()->fName, dfTexEf
fect.viewMatrix()); | |
| 588 | |
| 589 // emit transforms | |
| 590 const SkMatrix& localMatrix = dfTexEffect.localMatrix(); | |
| 591 this->emitTransforms(args.fPB, gpArgs->fPositionVar, dfTexEffect.inPosit
ion()->fName, | |
| 592 localMatrix, args.fTransformsIn, args.fTransformsOu
t); | |
| 593 | |
| 594 // set up varyings | |
| 595 bool isUniformScale = SkToBool(dfTexEffect.getFlags() & kUniformScale_Di
stanceFieldEffectMask); | |
| 596 GrGLVertToFrag recipScale(kFloat_GrSLType); | |
| 597 GrGLVertToFrag st(kVec2f_GrSLType); | |
| 598 const char* viewMatrixName = this->uViewM(); | |
| 599 // view matrix name is NULL if identity matrix | |
| 600 bool useInverseScale = !localMatrix.isIdentity() && viewMatrixName; | |
| 601 if (isUniformScale && useInverseScale) { | |
| 602 args.fPB->addVarying("RecipScale", &recipScale, kHigh_GrSLPrecision)
; | |
| 603 vsBuilder->codeAppendf("vec2 tx = vec2(%s[0][0], %s[1][0]);", | |
| 604 viewMatrixName, viewMatrixName); | |
| 605 vsBuilder->codeAppend("float tx2 = dot(tx, tx);"); | |
| 606 vsBuilder->codeAppendf("%s = inversesqrt(tx2);", recipScale.vsOut())
; | |
| 607 } else { | |
| 608 args.fPB->addVarying("IntTextureCoords", &st, kHigh_GrSLPrecision); | |
| 609 vsBuilder->codeAppendf("%s = %s;", st.vsOut(), dfTexEffect.inTexture
Coords()->fName); | |
| 610 } | |
| 611 | |
| 612 GrGLVertToFrag uv(kVec2f_GrSLType); | |
| 613 args.fPB->addVarying("TextureCoords", &uv, kHigh_GrSLPrecision); | |
| 614 // this is only used with text, so our texture bounds always match the g
lyph atlas | |
| 615 vsBuilder->codeAppendf("%s = vec2(" GR_FONT_ATLAS_A8_RECIP_WIDTH ", " | |
| 616 GR_FONT_ATLAS_RECIP_HEIGHT ")*%s;", uv.vsOut(), | |
| 617 dfTexEffect.inTextureCoords()->fName); | |
| 618 | |
| 619 // add frag shader code | |
| 620 GrGLGPFragmentBuilder* fsBuilder = args.fPB->getFragmentShaderBuilder(); | |
| 621 | |
| 622 SkAssertResult(fsBuilder->enableFeature( | |
| 623 GrGLFragmentShaderBuilder::kStandardDerivatives_GLSLFeature)); | |
| 624 | |
| 625 // create LCD offset adjusted by inverse of transform | |
| 626 // Use highp to work around aliasing issues | |
| 627 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision
, | |
| 628 pb->ctxInfo().stand
ard())); | |
| 629 fsBuilder->codeAppendf("vec2 uv = %s;\n", uv.fsIn()); | |
| 630 fsBuilder->codeAppend(GrGLShaderVar::PrecisionString(kHigh_GrSLPrecision
, | |
| 631 pb->ctxInfo().stand
ard())); | |
| 632 if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) { | |
| 633 fsBuilder->codeAppend("float delta = -" GR_FONT_ATLAS_LCD_DELTA ";\n
"); | |
| 634 } else { | |
| 635 fsBuilder->codeAppend("float delta = " GR_FONT_ATLAS_LCD_DELTA ";\n"
); | |
| 636 } | |
| 637 if (isUniformScale) { | |
| 638 if (useInverseScale) { | |
| 639 fsBuilder->codeAppendf("float dx = %s;", recipScale.fsIn()); | |
| 640 } else { | |
| 641 fsBuilder->codeAppendf("float dx = dFdx(%s.x);", st.fsIn()); | |
| 642 } | |
| 643 fsBuilder->codeAppend("vec2 offset = vec2(dx*delta, 0.0);"); | |
| 644 } else { | |
| 645 fsBuilder->codeAppendf("vec2 st = %s;\n", st.fsIn()); | |
| 646 | |
| 647 fsBuilder->codeAppend("vec2 Jdx = dFdx(st);"); | |
| 648 fsBuilder->codeAppend("vec2 Jdy = dFdy(st);"); | |
| 649 fsBuilder->codeAppend("vec2 offset = delta*Jdx;"); | |
| 650 } | |
| 651 | |
| 652 // green is distance to uv center | |
| 653 fsBuilder->codeAppend("\tvec4 texColor = "); | |
| 654 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv", kVec2f_GrSLType)
; | |
| 655 fsBuilder->codeAppend(";\n"); | |
| 656 fsBuilder->codeAppend("\tvec3 distance;\n"); | |
| 657 fsBuilder->codeAppend("\tdistance.y = texColor.r;\n"); | |
| 658 // red is distance to left offset | |
| 659 fsBuilder->codeAppend("\tvec2 uv_adjusted = uv - offset;\n"); | |
| 660 fsBuilder->codeAppend("\ttexColor = "); | |
| 661 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_
GrSLType); | |
| 662 fsBuilder->codeAppend(";\n"); | |
| 663 fsBuilder->codeAppend("\tdistance.x = texColor.r;\n"); | |
| 664 // blue is distance to right offset | |
| 665 fsBuilder->codeAppend("\tuv_adjusted = uv + offset;\n"); | |
| 666 fsBuilder->codeAppend("\ttexColor = "); | |
| 667 fsBuilder->appendTextureLookup(args.fSamplers[0], "uv_adjusted", kVec2f_
GrSLType); | |
| 668 fsBuilder->codeAppend(";\n"); | |
| 669 fsBuilder->codeAppend("\tdistance.z = texColor.r;\n"); | |
| 670 | |
| 671 fsBuilder->codeAppend("\tdistance = " | |
| 672 "vec3(" SK_DistanceFieldMultiplier ")*(distance - vec3(" SK_DistanceF
ieldThreshold"));"); | |
| 673 | |
| 674 // adjust width based on gamma | |
| 675 const char* distanceAdjustUniName = NULL; | |
| 676 fDistanceAdjustUni = args.fPB->addUniform(GrGLProgramBuilder::kFragment_
Visibility, | |
| 677 kVec3f_GrSLType, kDefault_GrSLPrecision, | |
| 678 "DistanceAdjust", &distanceAdjustUniName); | |
| 679 fsBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName); | |
| 680 | |
| 681 // To be strictly correct, we should compute the anti-aliasing factor se
parately | |
| 682 // for each color component. However, this is only important when using
perspective | |
| 683 // transformations, and even then using a single factor seems like a rea
sonable | |
| 684 // trade-off between quality and speed. | |
| 685 fsBuilder->codeAppend("float afwidth;"); | |
| 686 if (isUniformScale) { | |
| 687 // For uniform scale, we adjust for the effect of the transformation
on the distance | |
| 688 // by using the length of the gradient of the texture coordinates. W
e use st coordinates | |
| 689 // to ensure we're mapping 1:1 from texel space to pixel space. | |
| 690 | |
| 691 // this gives us a smooth step across approximately one fragment | |
| 692 fsBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*dx
);"); | |
| 693 } else { | |
| 694 // For general transforms, to determine the amount of correction we
multiply a unit | |
| 695 // vector pointing along the SDF gradient direction by the Jacobian
of the st coords | |
| 696 // (which is the inverse transform for this fragment) and take the l
ength of the result. | |
| 697 fsBuilder->codeAppend("vec2 dist_grad = vec2(dFdx(distance.r), dFdy(
distance.r));"); | |
| 698 // the length of the gradient may be 0, so we need to check for this | |
| 699 // this also compensates for the Adreno, which likes to drop tiles o
n division by 0 | |
| 700 fsBuilder->codeAppend("float dg_len2 = dot(dist_grad, dist_grad);"); | |
| 701 fsBuilder->codeAppend("if (dg_len2 < 0.0001) {"); | |
| 702 fsBuilder->codeAppend("dist_grad = vec2(0.7071, 0.7071);"); | |
| 703 fsBuilder->codeAppend("} else {"); | |
| 704 fsBuilder->codeAppend("dist_grad = dist_grad*inversesqrt(dg_len2);")
; | |
| 705 fsBuilder->codeAppend("}"); | |
| 706 fsBuilder->codeAppend("vec2 grad = vec2(dist_grad.x*Jdx.x + dist_gra
d.y*Jdy.x,"); | |
| 707 fsBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_gra
d.y*Jdy.y);"); | |
| 708 | |
| 709 // this gives us a smooth step across approximately one fragment | |
| 710 fsBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length
(grad);"); | |
| 711 } | |
| 712 | |
| 713 fsBuilder->codeAppend( | |
| 714 "vec4 val = vec4(smoothstep(vec3(-afwidth), vec3(afwidth),
distance), 1.0);"); | |
| 715 | |
| 716 fsBuilder->codeAppendf("%s = vec4(val);", args.fOutputCoverage); | |
| 717 } | |
| 718 | |
| 719 virtual void setData(const GrGLProgramDataManager& pdman, | |
| 720 const GrPrimitiveProcessor& processor, | |
| 721 const GrBatchTracker& bt) override { | |
| 722 SkASSERT(fDistanceAdjustUni.isValid()); | |
| 723 | |
| 724 const GrDistanceFieldLCDTextGeoProc& dfTexEffect = | |
| 725 processor.cast<GrDistanceFieldLCDTextGeoProc>(); | |
| 726 GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dfTexEffect.getDistan
ceAdjust(); | |
| 727 if (wa != fDistanceAdjust) { | |
| 728 pdman.set3f(fDistanceAdjustUni, | |
| 729 wa.fR, | |
| 730 wa.fG, | |
| 731 wa.fB); | |
| 732 fDistanceAdjust = wa; | |
| 733 } | |
| 734 | |
| 735 this->setUniformViewMatrix(pdman, processor.viewMatrix()); | |
| 736 | |
| 737 const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatc
hTracker>(); | |
| 738 if (kUniform_GrGPInput == local.fInputColorType && local.fColor != fColo
r) { | |
| 739 GrGLfloat c[4]; | |
| 740 GrColorToRGBAFloat(local.fColor, c); | |
| 741 pdman.set4fv(fColorUniform, 1, c); | |
| 742 fColor = local.fColor; | |
| 743 } | |
| 744 } | |
| 745 | |
| 746 static inline void GenKey(const GrGeometryProcessor& gp, | |
| 747 const GrBatchTracker& bt, | |
| 748 const GrGLCaps&, | |
| 749 GrProcessorKeyBuilder* b) { | |
| 750 const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFie
ldLCDTextGeoProc>(); | |
| 751 | |
| 752 const DistanceFieldLCDBatchTracker& local = bt.cast<DistanceFieldLCDBatc
hTracker>(); | |
| 753 uint32_t key = dfTexEffect.getFlags(); | |
| 754 key |= local.fInputColorType << 16; | |
| 755 key |= local.fUsesLocalCoords && gp.localMatrix().hasPerspective() ? 0x1
<< 24: 0x0; | |
| 756 key |= ComputePosKey(gp.viewMatrix()) << 25; | |
| 757 key |= (!gp.viewMatrix().isIdentity() && !gp.localMatrix().isIdentity())
? 0x1 << 27 : 0x0; | |
| 758 b->add32(key); | |
| 759 } | |
| 760 | |
| 761 private: | |
| 762 GrColor fColor; | |
| 763 UniformHandle fColorUniform; | |
| 764 GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust; | |
| 765 UniformHandle fDistanceAdjustUni; | |
| 766 | |
| 767 typedef GrGLGeometryProcessor INHERITED; | |
| 768 }; | |
| 769 | |
| 770 /////////////////////////////////////////////////////////////////////////////// | |
| 771 | |
| 772 GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc( | |
| 773 GrColor color, const SkMatrix&
viewMatrix, | |
| 774 const SkMatrix& localMatrix, | |
| 775 GrTexture* texture, const GrTe
xtureParams& params, | |
| 776 DistanceAdjust distanceAdjust, | |
| 777 uint32_t flags) | |
| 778 : INHERITED(color, viewMatrix, localMatrix) | |
| 779 , fTextureAccess(texture, params) | |
| 780 , fDistanceAdjust(distanceAdjust) | |
| 781 , fFlags(flags & kLCD_DistanceFieldEffectMask){ | |
| 782 SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_Distan
ceFieldEffectFlag)); | |
| 783 this->initClassID<GrDistanceFieldLCDTextGeoProc>(); | |
| 784 fInPosition = &this->addVertexAttrib(Attribute("inPosition", kVec2f_GrVertex
AttribType)); | |
| 785 fInTextureCoords = &this->addVertexAttrib(Attribute("inTextureCoords", | |
| 786 kVec2s_GrVertexAttribT
ype)); | |
| 787 this->addTextureAccess(&fTextureAccess); | |
| 788 } | |
| 789 | |
| 790 bool GrDistanceFieldLCDTextGeoProc::onIsEqual(const GrGeometryProcessor& other)
const { | |
| 791 const GrDistanceFieldLCDTextGeoProc& cte = other.cast<GrDistanceFieldLCDText
GeoProc>(); | |
| 792 return (fDistanceAdjust == cte.fDistanceAdjust && | |
| 793 fFlags == cte.fFlags); | |
| 794 } | |
| 795 | |
| 796 void GrDistanceFieldLCDTextGeoProc::onGetInvariantOutputCoverage(GrInitInvariant
Output* out) const { | |
| 797 out->setUnknownFourComponents(); | |
| 798 out->setUsingLCDCoverage(); | |
| 799 } | |
| 800 | |
| 801 void GrDistanceFieldLCDTextGeoProc::getGLProcessorKey(const GrBatchTracker& bt, | |
| 802 const GrGLCaps& caps, | |
| 803 GrProcessorKeyBuilder* b)
const { | |
| 804 GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, bt, caps, b); | |
| 805 } | |
| 806 | |
| 807 GrGLPrimitiveProcessor* | |
| 808 GrDistanceFieldLCDTextGeoProc::createGLInstance(const GrBatchTracker& bt, | |
| 809 const GrGLCaps&) const { | |
| 810 return SkNEW_ARGS(GrGLDistanceFieldLCDTextGeoProc, (*this, bt)); | |
| 811 } | |
| 812 | |
| 813 void GrDistanceFieldLCDTextGeoProc::initBatchTracker(GrBatchTracker* bt, | |
| 814 const GrPipelineInfo& init)
const { | |
| 815 DistanceFieldLCDBatchTracker* local = bt->cast<DistanceFieldLCDBatchTracker>
(); | |
| 816 local->fInputColorType = GetColorInputType(&local->fColor, this->color(), in
it, false); | |
| 817 local->fUsesLocalCoords = init.fUsesLocalCoords; | |
| 818 } | |
| 819 | |
| 820 bool GrDistanceFieldLCDTextGeoProc::onCanMakeEqual(const GrBatchTracker& m, | |
| 821 const GrGeometryProcessor& th
at, | |
| 822 const GrBatchTracker& t) cons
t { | |
| 823 const DistanceFieldLCDBatchTracker& mine = m.cast<DistanceFieldLCDBatchTrack
er>(); | |
| 824 const DistanceFieldLCDBatchTracker& theirs = t.cast<DistanceFieldLCDBatchTra
cker>(); | |
| 825 return CanCombineLocalMatrices(*this, mine.fUsesLocalCoords, | |
| 826 that, theirs.fUsesLocalCoords) && | |
| 827 CanCombineOutput(mine.fInputColorType, mine.fColor, | |
| 828 theirs.fInputColorType, theirs.fColor); | |
| 829 } | |
| 830 | |
| 831 /////////////////////////////////////////////////////////////////////////////// | |
| 832 | |
| 833 GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc); | |
| 834 | |
| 835 GrGeometryProcessor* GrDistanceFieldLCDTextGeoProc::TestCreate(SkRandom* random, | |
| 836 GrContext*, | |
| 837 const GrDrawTar
getCaps&, | |
| 838 GrTexture* text
ures[]) { | |
| 839 int texIdx = random->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx : | |
| 840 GrProcessorUnitTest::kAlphaTextureIdx; | |
| 841 static const SkShader::TileMode kTileModes[] = { | |
| 842 SkShader::kClamp_TileMode, | |
| 843 SkShader::kRepeat_TileMode, | |
| 844 SkShader::kMirror_TileMode, | |
| 845 }; | |
| 846 SkShader::TileMode tileModes[] = { | |
| 847 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], | |
| 848 kTileModes[random->nextULessThan(SK_ARRAY_COUNT(kTileModes))], | |
| 849 }; | |
| 850 GrTextureParams params(tileModes, random->nextBool() ? GrTextureParams::kBil
erp_FilterMode : | |
| 851 GrTextureParams::kNone_FilterMode); | |
| 852 DistanceAdjust wa = { 0.0f, 0.1f, -0.1f }; | |
| 853 uint32_t flags = kUseLCD_DistanceFieldEffectFlag; | |
| 854 flags |= random->nextBool() ? kUniformScale_DistanceFieldEffectMask : 0; | |
| 855 flags |= random->nextBool() ? kBGR_DistanceFieldEffectFlag : 0; | |
| 856 return GrDistanceFieldLCDTextGeoProc::Create(GrRandomColor(random), | |
| 857 GrProcessorUnitTest::TestMatrix
(random), | |
| 858 GrProcessorUnitTest::TestMatrix
(random), | |
| 859 textures[texIdx], params, | |
| 860 wa, | |
| 861 flags); | |
| 862 } | |
| OLD | NEW |