Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: src/gpu/effects/GrDistanceFieldTextureEffect.cpp

Issue 1073473005: Rename DistanceFieldTextureEffect.{cpp,h} (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 5 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/gpu/effects/GrDistanceFieldTextureEffect.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 }
OLDNEW
« no previous file with comments | « src/gpu/effects/GrDistanceFieldTextureEffect.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698