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 |