GrDistanceFieldGeoProc.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931
  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. #include "include/gpu/GrTexture.h"
  8. #include "src/core/SkDistanceFieldGen.h"
  9. #include "src/gpu/GrCaps.h"
  10. #include "src/gpu/GrShaderCaps.h"
  11. #include "src/gpu/effects/GrAtlasedShaderHelpers.h"
  12. #include "src/gpu/effects/GrDistanceFieldGeoProc.h"
  13. #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
  14. #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
  15. #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
  16. #include "src/gpu/glsl/GrGLSLUniformHandler.h"
  17. #include "src/gpu/glsl/GrGLSLUtil.h"
  18. #include "src/gpu/glsl/GrGLSLVarying.h"
  19. #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
  20. // Assuming a radius of a little less than the diagonal of the fragment
  21. #define SK_DistanceFieldAAFactor "0.65"
  22. class GrGLDistanceFieldA8TextGeoProc : public GrGLSLGeometryProcessor {
  23. public:
  24. GrGLDistanceFieldA8TextGeoProc() = default;
  25. void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
  26. const GrDistanceFieldA8TextGeoProc& dfTexEffect =
  27. args.fGP.cast<GrDistanceFieldA8TextGeoProc>();
  28. GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
  29. GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
  30. GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
  31. GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
  32. // emit attributes
  33. varyingHandler->emitAttributes(dfTexEffect);
  34. const char* atlasSizeInvName;
  35. fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
  36. kFloat2_GrSLType,
  37. "AtlasSizeInv",
  38. &atlasSizeInvName);
  39. #ifdef SK_GAMMA_APPLY_TO_A8
  40. // adjust based on gamma
  41. const char* distanceAdjustUniName = nullptr;
  42. // width, height, 1/(3*width)
  43. fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf_GrSLType,
  44. "DistanceAdjust", &distanceAdjustUniName);
  45. #endif
  46. // Setup pass through color
  47. varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
  48. // Setup position
  49. gpArgs->fPositionVar = dfTexEffect.inPosition().asShaderVar();
  50. // emit transforms
  51. this->emitTransforms(vertBuilder,
  52. varyingHandler,
  53. uniformHandler,
  54. dfTexEffect.inPosition().asShaderVar(),
  55. dfTexEffect.localMatrix(),
  56. args.fFPCoordTransformHandler);
  57. // add varyings
  58. GrGLSLVarying uv(kFloat2_GrSLType);
  59. GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
  60. GrGLSLVarying texIdx(texIdxType);
  61. GrGLSLVarying st(kFloat2_GrSLType);
  62. append_index_uv_varyings(args, dfTexEffect.inTextureCoords().name(), atlasSizeInvName, &uv,
  63. &texIdx, &st);
  64. bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
  65. kUniformScale_DistanceFieldEffectMask;
  66. bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
  67. bool isGammaCorrect =
  68. SkToBool(dfTexEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag);
  69. bool isAliased =
  70. SkToBool(dfTexEffect.getFlags() & kAliased_DistanceFieldEffectFlag);
  71. // Use highp to work around aliasing issues
  72. fragBuilder->codeAppendf("float2 uv = %s;\n", uv.fsIn());
  73. fragBuilder->codeAppend("half4 texColor;");
  74. append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(),
  75. texIdx, "uv", "texColor");
  76. fragBuilder->codeAppend("half distance = "
  77. SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
  78. #ifdef SK_GAMMA_APPLY_TO_A8
  79. // adjust width based on gamma
  80. fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
  81. #endif
  82. fragBuilder->codeAppend("half afwidth;");
  83. if (isUniformScale) {
  84. // For uniform scale, we adjust for the effect of the transformation on the distance
  85. // by using the length of the gradient of the t coordinate in the y direction.
  86. // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space.
  87. // this gives us a smooth step across approximately one fragment
  88. #ifdef SK_VULKAN
  89. fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor
  90. "*half(dFdx(%s.x)));", st.fsIn());
  91. #else
  92. // We use the y gradient because there is a bug in the Mali 400 in the x direction.
  93. fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor
  94. "*half(dFdy(%s.y)));", st.fsIn());
  95. #endif
  96. } else if (isSimilarity) {
  97. // For similarity transform, we adjust the effect of the transformation on the distance
  98. // by using the length of the gradient of the texture coordinates. We use st coordinates
  99. // to ensure we're mapping 1:1 from texel space to pixel space.
  100. // We use the y gradient because there is a bug in the Mali 400 in the x direction.
  101. // this gives us a smooth step across approximately one fragment
  102. #ifdef SK_VULKAN
  103. fragBuilder->codeAppendf("half st_grad_len = length(half2(dFdx(%s)));", st.fsIn());
  104. #else
  105. // We use the y gradient because there is a bug in the Mali 400 in the x direction.
  106. fragBuilder->codeAppendf("half st_grad_len = length(half2(dFdy(%s)));", st.fsIn());
  107. #endif
  108. fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);");
  109. } else {
  110. // For general transforms, to determine the amount of correction we multiply a unit
  111. // vector pointing along the SDF gradient direction by the Jacobian of the st coords
  112. // (which is the inverse transform for this fragment) and take the length of the result.
  113. fragBuilder->codeAppend("half2 dist_grad = half2(float2(dFdx(distance), "
  114. "dFdy(distance)));");
  115. // the length of the gradient may be 0, so we need to check for this
  116. // this also compensates for the Adreno, which likes to drop tiles on division by 0
  117. fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);");
  118. fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
  119. fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);");
  120. fragBuilder->codeAppend("} else {");
  121. fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));");
  122. fragBuilder->codeAppend("}");
  123. fragBuilder->codeAppendf("half2 Jdx = half2(dFdx(%s));", st.fsIn());
  124. fragBuilder->codeAppendf("half2 Jdy = half2(dFdy(%s));", st.fsIn());
  125. fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
  126. fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
  127. // this gives us a smooth step across approximately one fragment
  128. fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
  129. }
  130. if (isAliased) {
  131. fragBuilder->codeAppend("half val = distance > 0 ? 1.0 : 0.0;");
  132. } else if (isGammaCorrect) {
  133. // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
  134. // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want
  135. // distance mapped linearly to coverage, so use a linear step:
  136. fragBuilder->codeAppend(
  137. "half val = saturate((distance + afwidth) / (2.0 * afwidth));");
  138. } else {
  139. fragBuilder->codeAppend("half val = smoothstep(-afwidth, afwidth, distance);");
  140. }
  141. fragBuilder->codeAppendf("%s = half4(val);", args.fOutputCoverage);
  142. }
  143. void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
  144. FPCoordTransformIter&& transformIter) override {
  145. const GrDistanceFieldA8TextGeoProc& dfa8gp = proc.cast<GrDistanceFieldA8TextGeoProc>();
  146. #ifdef SK_GAMMA_APPLY_TO_A8
  147. float distanceAdjust = dfa8gp.getDistanceAdjust();
  148. if (distanceAdjust != fDistanceAdjust) {
  149. fDistanceAdjust = distanceAdjust;
  150. pdman.set1f(fDistanceAdjustUni, distanceAdjust);
  151. }
  152. #endif
  153. const SkISize& atlasSize = dfa8gp.atlasSize();
  154. SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
  155. if (fAtlasSize != atlasSize) {
  156. pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
  157. fAtlasSize = atlasSize;
  158. }
  159. this->setTransformDataHelper(dfa8gp.localMatrix(), pdman, &transformIter);
  160. }
  161. static inline void GenKey(const GrGeometryProcessor& gp,
  162. const GrShaderCaps&,
  163. GrProcessorKeyBuilder* b) {
  164. const GrDistanceFieldA8TextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldA8TextGeoProc>();
  165. uint32_t key = dfTexEffect.getFlags();
  166. b->add32(key);
  167. b->add32(dfTexEffect.numTextureSamplers());
  168. }
  169. private:
  170. #ifdef SK_GAMMA_APPLY_TO_A8
  171. float fDistanceAdjust = -1.f;
  172. UniformHandle fDistanceAdjustUni;
  173. #endif
  174. SkISize fAtlasSize = {0, 0};
  175. UniformHandle fAtlasSizeInvUniform;
  176. typedef GrGLSLGeometryProcessor INHERITED;
  177. };
  178. ///////////////////////////////////////////////////////////////////////////////
  179. GrDistanceFieldA8TextGeoProc::GrDistanceFieldA8TextGeoProc(const GrShaderCaps& caps,
  180. const sk_sp<GrTextureProxy>* proxies,
  181. int numProxies,
  182. const GrSamplerState& params,
  183. #ifdef SK_GAMMA_APPLY_TO_A8
  184. float distanceAdjust,
  185. #endif
  186. uint32_t flags,
  187. const SkMatrix& localMatrix)
  188. : INHERITED(kGrDistanceFieldA8TextGeoProc_ClassID)
  189. , fLocalMatrix(localMatrix)
  190. , fFlags(flags & kNonLCD_DistanceFieldEffectMask)
  191. #ifdef SK_GAMMA_APPLY_TO_A8
  192. , fDistanceAdjust(distanceAdjust)
  193. #endif
  194. {
  195. SkASSERT(numProxies <= kMaxTextures);
  196. SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
  197. if (flags & kPerspective_DistanceFieldEffectFlag) {
  198. fInPosition = {"inPosition", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
  199. } else {
  200. fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
  201. }
  202. fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType };
  203. fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
  204. caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
  205. this->setVertexAttributes(&fInPosition, 3);
  206. if (numProxies) {
  207. fAtlasSize = proxies[0]->isize();
  208. }
  209. for (int i = 0; i < numProxies; ++i) {
  210. SkASSERT(proxies[i]);
  211. SkASSERT(proxies[i]->isize() == fAtlasSize);
  212. fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params,
  213. proxies[i]->textureSwizzle());
  214. }
  215. this->setTextureSamplerCnt(numProxies);
  216. }
  217. void GrDistanceFieldA8TextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
  218. int numProxies,
  219. const GrSamplerState& params) {
  220. SkASSERT(numProxies <= kMaxTextures);
  221. if (!fTextureSamplers[0].isInitialized()) {
  222. fAtlasSize = proxies[0]->isize();
  223. }
  224. for (int i = 0; i < numProxies; ++i) {
  225. SkASSERT(proxies[i]);
  226. SkASSERT(proxies[i]->isize() == fAtlasSize);
  227. if (!fTextureSamplers[i].isInitialized()) {
  228. fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params,
  229. proxies[i]->textureSwizzle());
  230. }
  231. }
  232. this->setTextureSamplerCnt(numProxies);
  233. }
  234. void GrDistanceFieldA8TextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
  235. GrProcessorKeyBuilder* b) const {
  236. GrGLDistanceFieldA8TextGeoProc::GenKey(*this, caps, b);
  237. }
  238. GrGLSLPrimitiveProcessor*
  239. GrDistanceFieldA8TextGeoProc::createGLSLInstance(const GrShaderCaps&) const {
  240. return new GrGLDistanceFieldA8TextGeoProc();
  241. }
  242. ///////////////////////////////////////////////////////////////////////////////
  243. GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldA8TextGeoProc);
  244. #if GR_TEST_UTILS
  245. sk_sp<GrGeometryProcessor> GrDistanceFieldA8TextGeoProc::TestCreate(GrProcessorTestData* d) {
  246. int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
  247. : GrProcessorUnitTest::kAlphaTextureIdx;
  248. sk_sp<GrTextureProxy> proxies[kMaxTextures] = {
  249. d->textureProxy(texIdx),
  250. nullptr,
  251. nullptr,
  252. nullptr
  253. };
  254. GrSamplerState::WrapMode wrapModes[2];
  255. GrTest::TestWrapModes(d->fRandom, wrapModes);
  256. GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
  257. ? GrSamplerState::Filter::kBilerp
  258. : GrSamplerState::Filter::kNearest);
  259. uint32_t flags = 0;
  260. flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
  261. if (flags & kSimilarity_DistanceFieldEffectFlag) {
  262. flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
  263. }
  264. SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
  265. #ifdef SK_GAMMA_APPLY_TO_A8
  266. float lum = d->fRandom->nextF();
  267. #endif
  268. return GrDistanceFieldA8TextGeoProc::Make(*d->caps()->shaderCaps(),
  269. proxies, 1,
  270. samplerState,
  271. #ifdef SK_GAMMA_APPLY_TO_A8
  272. lum,
  273. #endif
  274. flags, localMatrix);
  275. }
  276. #endif
  277. ///////////////////////////////////////////////////////////////////////////////
  278. class GrGLDistanceFieldPathGeoProc : public GrGLSLGeometryProcessor {
  279. public:
  280. GrGLDistanceFieldPathGeoProc()
  281. : fMatrix(SkMatrix::InvalidMatrix())
  282. , fAtlasSize({0,0}) {
  283. }
  284. void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
  285. const GrDistanceFieldPathGeoProc& dfPathEffect =
  286. args.fGP.cast<GrDistanceFieldPathGeoProc>();
  287. GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
  288. GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
  289. GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
  290. GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
  291. // emit attributes
  292. varyingHandler->emitAttributes(dfPathEffect);
  293. const char* atlasSizeInvName;
  294. fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
  295. kFloat2_GrSLType,
  296. "AtlasSizeInv",
  297. &atlasSizeInvName);
  298. GrGLSLVarying uv(kFloat2_GrSLType);
  299. GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
  300. GrGLSLVarying texIdx(texIdxType);
  301. GrGLSLVarying st(kFloat2_GrSLType);
  302. append_index_uv_varyings(args, dfPathEffect.inTextureCoords().name(), atlasSizeInvName, &uv,
  303. &texIdx, &st);
  304. // setup pass through color
  305. varyingHandler->addPassThroughAttribute(dfPathEffect.inColor(), args.fOutputColor);
  306. if (dfPathEffect.matrix().hasPerspective()) {
  307. // Setup position
  308. this->writeOutputPosition(vertBuilder,
  309. uniformHandler,
  310. gpArgs,
  311. dfPathEffect.inPosition().name(),
  312. dfPathEffect.matrix(),
  313. &fMatrixUniform);
  314. // emit transforms
  315. this->emitTransforms(vertBuilder,
  316. varyingHandler,
  317. uniformHandler,
  318. dfPathEffect.inPosition().asShaderVar(),
  319. args.fFPCoordTransformHandler);
  320. } else {
  321. // Setup position
  322. this->writeOutputPosition(vertBuilder, gpArgs, dfPathEffect.inPosition().name());
  323. // emit transforms
  324. this->emitTransforms(vertBuilder,
  325. varyingHandler,
  326. uniformHandler,
  327. dfPathEffect.inPosition().asShaderVar(),
  328. dfPathEffect.matrix(),
  329. args.fFPCoordTransformHandler);
  330. }
  331. // Use highp to work around aliasing issues
  332. fragBuilder->codeAppendf("float2 uv = %s;", uv.fsIn());
  333. fragBuilder->codeAppend("half4 texColor;");
  334. append_multitexture_lookup(args, dfPathEffect.numTextureSamplers(), texIdx, "uv",
  335. "texColor");
  336. fragBuilder->codeAppend("half distance = "
  337. SK_DistanceFieldMultiplier "*(texColor.r - " SK_DistanceFieldThreshold ");");
  338. fragBuilder->codeAppend("half afwidth;");
  339. bool isUniformScale = (dfPathEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
  340. kUniformScale_DistanceFieldEffectMask;
  341. bool isSimilarity = SkToBool(dfPathEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
  342. bool isGammaCorrect =
  343. SkToBool(dfPathEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag);
  344. if (isUniformScale) {
  345. // For uniform scale, we adjust for the effect of the transformation on the distance
  346. // by using the length of the gradient of the t coordinate in the y direction.
  347. // We use st coordinates to ensure we're mapping 1:1 from texel space to pixel space.
  348. // this gives us a smooth step across approximately one fragment
  349. #ifdef SK_VULKAN
  350. fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor
  351. "*half(dFdx(%s.x)));", st.fsIn());
  352. #else
  353. // We use the y gradient because there is a bug in the Mali 400 in the x direction.
  354. fragBuilder->codeAppendf("afwidth = abs(" SK_DistanceFieldAAFactor
  355. "*half(dFdy(%s.y)));", st.fsIn());
  356. #endif
  357. } else if (isSimilarity) {
  358. // For similarity transform, we adjust the effect of the transformation on the distance
  359. // by using the length of the gradient of the texture coordinates. We use st coordinates
  360. // to ensure we're mapping 1:1 from texel space to pixel space.
  361. // this gives us a smooth step across approximately one fragment
  362. #ifdef SK_VULKAN
  363. fragBuilder->codeAppendf("half st_grad_len = half(length(dFdx(%s)));", st.fsIn());
  364. #else
  365. // We use the y gradient because there is a bug in the Mali 400 in the x direction.
  366. fragBuilder->codeAppendf("half st_grad_len = half(length(dFdy(%s)));", st.fsIn());
  367. #endif
  368. fragBuilder->codeAppend("afwidth = abs(" SK_DistanceFieldAAFactor "*st_grad_len);");
  369. } else {
  370. // For general transforms, to determine the amount of correction we multiply a unit
  371. // vector pointing along the SDF gradient direction by the Jacobian of the st coords
  372. // (which is the inverse transform for this fragment) and take the length of the result.
  373. fragBuilder->codeAppend("half2 dist_grad = half2(dFdx(distance), "
  374. "dFdy(distance));");
  375. // the length of the gradient may be 0, so we need to check for this
  376. // this also compensates for the Adreno, which likes to drop tiles on division by 0
  377. fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);");
  378. fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
  379. fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);");
  380. fragBuilder->codeAppend("} else {");
  381. fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));");
  382. fragBuilder->codeAppend("}");
  383. fragBuilder->codeAppendf("half2 Jdx = half2(dFdx(%s));", st.fsIn());
  384. fragBuilder->codeAppendf("half2 Jdy = half2(dFdy(%s));", st.fsIn());
  385. fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
  386. fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
  387. // this gives us a smooth step across approximately one fragment
  388. fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
  389. }
  390. // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
  391. // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance
  392. // mapped linearly to coverage, so use a linear step:
  393. if (isGammaCorrect) {
  394. fragBuilder->codeAppend(
  395. "half val = saturate((distance + afwidth) / (2.0 * afwidth));");
  396. } else {
  397. fragBuilder->codeAppend("half val = smoothstep(-afwidth, afwidth, distance);");
  398. }
  399. fragBuilder->codeAppendf("%s = half4(val);", args.fOutputCoverage);
  400. }
  401. void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& proc,
  402. FPCoordTransformIter&& transformIter) override {
  403. const GrDistanceFieldPathGeoProc& dfpgp = proc.cast<GrDistanceFieldPathGeoProc>();
  404. if (dfpgp.matrix().hasPerspective() && !fMatrix.cheapEqualTo(dfpgp.matrix())) {
  405. fMatrix = dfpgp.matrix();
  406. float matrix[3 * 3];
  407. GrGLSLGetMatrix<3>(matrix, fMatrix);
  408. pdman.setMatrix3f(fMatrixUniform, matrix);
  409. }
  410. const SkISize& atlasSize = dfpgp.atlasSize();
  411. SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
  412. if (fAtlasSize != atlasSize) {
  413. pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
  414. fAtlasSize = atlasSize;
  415. }
  416. if (dfpgp.matrix().hasPerspective()) {
  417. this->setTransformDataHelper(SkMatrix::I(), pdman, &transformIter);
  418. } else {
  419. this->setTransformDataHelper(dfpgp.matrix(), pdman, &transformIter);
  420. }
  421. }
  422. static inline void GenKey(const GrGeometryProcessor& gp,
  423. const GrShaderCaps&,
  424. GrProcessorKeyBuilder* b) {
  425. const GrDistanceFieldPathGeoProc& dfTexEffect = gp.cast<GrDistanceFieldPathGeoProc>();
  426. uint32_t key = dfTexEffect.getFlags();
  427. key |= ComputePosKey(dfTexEffect.matrix()) << 16;
  428. b->add32(key);
  429. b->add32(dfTexEffect.matrix().hasPerspective());
  430. b->add32(dfTexEffect.numTextureSamplers());
  431. }
  432. private:
  433. SkMatrix fMatrix; // view matrix if perspective, local matrix otherwise
  434. UniformHandle fMatrixUniform;
  435. SkISize fAtlasSize;
  436. UniformHandle fAtlasSizeInvUniform;
  437. typedef GrGLSLGeometryProcessor INHERITED;
  438. };
  439. ///////////////////////////////////////////////////////////////////////////////
  440. GrDistanceFieldPathGeoProc::GrDistanceFieldPathGeoProc(const GrShaderCaps& caps,
  441. const SkMatrix& matrix,
  442. bool wideColor,
  443. const sk_sp<GrTextureProxy>* proxies,
  444. int numProxies,
  445. const GrSamplerState& params,
  446. uint32_t flags)
  447. : INHERITED(kGrDistanceFieldPathGeoProc_ClassID)
  448. , fMatrix(matrix)
  449. , fFlags(flags & kNonLCD_DistanceFieldEffectMask) {
  450. SkASSERT(numProxies <= kMaxTextures);
  451. SkASSERT(!(flags & ~kNonLCD_DistanceFieldEffectMask));
  452. fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
  453. fInColor = MakeColorAttribute("inColor", wideColor);
  454. fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
  455. caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
  456. this->setVertexAttributes(&fInPosition, 3);
  457. if (numProxies) {
  458. fAtlasSize = proxies[0]->isize();
  459. }
  460. for (int i = 0; i < numProxies; ++i) {
  461. SkASSERT(proxies[i]);
  462. SkASSERT(proxies[i]->isize() == fAtlasSize);
  463. fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params,
  464. proxies[i]->textureSwizzle());
  465. }
  466. this->setTextureSamplerCnt(numProxies);
  467. }
  468. void GrDistanceFieldPathGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
  469. int numProxies,
  470. const GrSamplerState& params) {
  471. SkASSERT(numProxies <= kMaxTextures);
  472. if (!fTextureSamplers[0].isInitialized()) {
  473. fAtlasSize = proxies[0]->isize();
  474. }
  475. for (int i = 0; i < numProxies; ++i) {
  476. SkASSERT(proxies[i]);
  477. SkASSERT(proxies[i]->isize() == fAtlasSize);
  478. if (!fTextureSamplers[i].isInitialized()) {
  479. fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params,
  480. proxies[i]->textureSwizzle());
  481. }
  482. }
  483. this->setTextureSamplerCnt(numProxies);
  484. }
  485. void GrDistanceFieldPathGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
  486. GrProcessorKeyBuilder* b) const {
  487. GrGLDistanceFieldPathGeoProc::GenKey(*this, caps, b);
  488. }
  489. GrGLSLPrimitiveProcessor*
  490. GrDistanceFieldPathGeoProc::createGLSLInstance(const GrShaderCaps&) const {
  491. return new GrGLDistanceFieldPathGeoProc();
  492. }
  493. ///////////////////////////////////////////////////////////////////////////////
  494. GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldPathGeoProc);
  495. #if GR_TEST_UTILS
  496. sk_sp<GrGeometryProcessor> GrDistanceFieldPathGeoProc::TestCreate(GrProcessorTestData* d) {
  497. int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx
  498. : GrProcessorUnitTest::kAlphaTextureIdx;
  499. sk_sp<GrTextureProxy> proxies[kMaxTextures] = {
  500. d->textureProxy(texIdx),
  501. nullptr,
  502. nullptr,
  503. nullptr
  504. };
  505. GrSamplerState::WrapMode wrapModes[2];
  506. GrTest::TestWrapModes(d->fRandom, wrapModes);
  507. GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
  508. ? GrSamplerState::Filter::kBilerp
  509. : GrSamplerState::Filter::kNearest);
  510. uint32_t flags = 0;
  511. flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
  512. if (flags & kSimilarity_DistanceFieldEffectFlag) {
  513. flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
  514. }
  515. return GrDistanceFieldPathGeoProc::Make(*d->caps()->shaderCaps(),
  516. GrTest::TestMatrix(d->fRandom),
  517. d->fRandom->nextBool(),
  518. proxies, 1,
  519. samplerState,
  520. flags);
  521. }
  522. #endif
  523. ///////////////////////////////////////////////////////////////////////////////
  524. class GrGLDistanceFieldLCDTextGeoProc : public GrGLSLGeometryProcessor {
  525. public:
  526. GrGLDistanceFieldLCDTextGeoProc() : fAtlasSize({0, 0}) {
  527. fDistanceAdjust = GrDistanceFieldLCDTextGeoProc::DistanceAdjust::Make(1.0f, 1.0f, 1.0f);
  528. }
  529. void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override{
  530. const GrDistanceFieldLCDTextGeoProc& dfTexEffect =
  531. args.fGP.cast<GrDistanceFieldLCDTextGeoProc>();
  532. GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
  533. GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
  534. GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
  535. // emit attributes
  536. varyingHandler->emitAttributes(dfTexEffect);
  537. const char* atlasSizeInvName;
  538. fAtlasSizeInvUniform = uniformHandler->addUniform(kVertex_GrShaderFlag,
  539. kFloat2_GrSLType,
  540. "AtlasSizeInv",
  541. &atlasSizeInvName);
  542. GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
  543. // setup pass through color
  544. varyingHandler->addPassThroughAttribute(dfTexEffect.inColor(), args.fOutputColor);
  545. // Setup position
  546. gpArgs->fPositionVar = dfTexEffect.inPosition().asShaderVar();
  547. // emit transforms
  548. this->emitTransforms(vertBuilder,
  549. varyingHandler,
  550. uniformHandler,
  551. dfTexEffect.inPosition().asShaderVar(),
  552. dfTexEffect.localMatrix(),
  553. args.fFPCoordTransformHandler);
  554. // set up varyings
  555. GrGLSLVarying uv(kFloat2_GrSLType);
  556. GrSLType texIdxType = args.fShaderCaps->integerSupport() ? kInt_GrSLType : kFloat_GrSLType;
  557. GrGLSLVarying texIdx(texIdxType);
  558. GrGLSLVarying st(kFloat2_GrSLType);
  559. append_index_uv_varyings(args, dfTexEffect.inTextureCoords().name(), atlasSizeInvName, &uv,
  560. &texIdx, &st);
  561. GrGLSLVarying delta(kFloat_GrSLType);
  562. varyingHandler->addVarying("Delta", &delta);
  563. if (dfTexEffect.getFlags() & kBGR_DistanceFieldEffectFlag) {
  564. vertBuilder->codeAppendf("%s = -%s.x/3.0;", delta.vsOut(), atlasSizeInvName);
  565. } else {
  566. vertBuilder->codeAppendf("%s = %s.x/3.0;", delta.vsOut(), atlasSizeInvName);
  567. }
  568. // add frag shader code
  569. bool isUniformScale = (dfTexEffect.getFlags() & kUniformScale_DistanceFieldEffectMask) ==
  570. kUniformScale_DistanceFieldEffectMask;
  571. bool isSimilarity = SkToBool(dfTexEffect.getFlags() & kSimilarity_DistanceFieldEffectFlag);
  572. bool isGammaCorrect =
  573. SkToBool(dfTexEffect.getFlags() & kGammaCorrect_DistanceFieldEffectFlag);
  574. // create LCD offset adjusted by inverse of transform
  575. // Use highp to work around aliasing issues
  576. fragBuilder->codeAppendf("float2 uv = %s;\n", uv.fsIn());
  577. if (isUniformScale) {
  578. #ifdef SK_VULKAN
  579. fragBuilder->codeAppendf("half st_grad_len = half(abs(dFdx(%s.x)));", st.fsIn());
  580. #else
  581. // We use the y gradient because there is a bug in the Mali 400 in the x direction.
  582. fragBuilder->codeAppendf("half st_grad_len = half(abs(dFdy(%s.y)));", st.fsIn());
  583. #endif
  584. fragBuilder->codeAppendf("half2 offset = half2(half(st_grad_len*%s), 0.0);",
  585. delta.fsIn());
  586. } else if (isSimilarity) {
  587. // For a similarity matrix with rotation, the gradient will not be aligned
  588. // with the texel coordinate axes, so we need to calculate it.
  589. #ifdef SK_VULKAN
  590. fragBuilder->codeAppendf("half2 st_grad = half2(dFdx(%s));", st.fsIn());
  591. fragBuilder->codeAppendf("half2 offset = half(%s)*st_grad;", delta.fsIn());
  592. #else
  593. // We use dFdy because of a Mali 400 bug, and rotate -90 degrees to
  594. // get the gradient in the x direction.
  595. fragBuilder->codeAppendf("half2 st_grad = half2(dFdy(%s));", st.fsIn());
  596. fragBuilder->codeAppendf("half2 offset = half2(%s*float2(st_grad.y, -st_grad.x));",
  597. delta.fsIn());
  598. #endif
  599. fragBuilder->codeAppend("half st_grad_len = length(st_grad);");
  600. } else {
  601. fragBuilder->codeAppendf("half2 st = half2(%s);\n", st.fsIn());
  602. fragBuilder->codeAppend("half2 Jdx = half2(dFdx(st));");
  603. fragBuilder->codeAppend("half2 Jdy = half2(dFdy(st));");
  604. fragBuilder->codeAppendf("half2 offset = half2(half(%s))*Jdx;", delta.fsIn());
  605. }
  606. // sample the texture by index
  607. fragBuilder->codeAppend("half4 texColor;");
  608. append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(),
  609. texIdx, "uv", "texColor");
  610. // green is distance to uv center
  611. fragBuilder->codeAppend("half3 distance;");
  612. fragBuilder->codeAppend("distance.y = texColor.r;");
  613. // red is distance to left offset
  614. fragBuilder->codeAppend("half2 uv_adjusted = half2(uv) - offset;");
  615. append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(),
  616. texIdx, "uv_adjusted", "texColor");
  617. fragBuilder->codeAppend("distance.x = texColor.r;");
  618. // blue is distance to right offset
  619. fragBuilder->codeAppend("uv_adjusted = half2(uv) + offset;");
  620. append_multitexture_lookup(args, dfTexEffect.numTextureSamplers(),
  621. texIdx, "uv_adjusted", "texColor");
  622. fragBuilder->codeAppend("distance.z = texColor.r;");
  623. fragBuilder->codeAppend("distance = "
  624. "half3(" SK_DistanceFieldMultiplier ")*(distance - half3(" SK_DistanceFieldThreshold"));");
  625. // adjust width based on gamma
  626. const char* distanceAdjustUniName = nullptr;
  627. fDistanceAdjustUni = uniformHandler->addUniform(kFragment_GrShaderFlag, kHalf3_GrSLType,
  628. "DistanceAdjust", &distanceAdjustUniName);
  629. fragBuilder->codeAppendf("distance -= %s;", distanceAdjustUniName);
  630. // To be strictly correct, we should compute the anti-aliasing factor separately
  631. // for each color component. However, this is only important when using perspective
  632. // transformations, and even then using a single factor seems like a reasonable
  633. // trade-off between quality and speed.
  634. fragBuilder->codeAppend("half afwidth;");
  635. if (isSimilarity) {
  636. // For similarity transform (uniform scale-only is a subset of this), we adjust for the
  637. // effect of the transformation on the distance by using the length of the gradient of
  638. // the texture coordinates. We use st coordinates to ensure we're mapping 1:1 from texel
  639. // space to pixel space.
  640. // this gives us a smooth step across approximately one fragment
  641. fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*st_grad_len;");
  642. } else {
  643. // For general transforms, to determine the amount of correction we multiply a unit
  644. // vector pointing along the SDF gradient direction by the Jacobian of the st coords
  645. // (which is the inverse transform for this fragment) and take the length of the result.
  646. fragBuilder->codeAppend("half2 dist_grad = half2(half(dFdx(distance.r)), "
  647. "half(dFdy(distance.r)));");
  648. // the length of the gradient may be 0, so we need to check for this
  649. // this also compensates for the Adreno, which likes to drop tiles on division by 0
  650. fragBuilder->codeAppend("half dg_len2 = dot(dist_grad, dist_grad);");
  651. fragBuilder->codeAppend("if (dg_len2 < 0.0001) {");
  652. fragBuilder->codeAppend("dist_grad = half2(0.7071, 0.7071);");
  653. fragBuilder->codeAppend("} else {");
  654. fragBuilder->codeAppend("dist_grad = dist_grad*half(inversesqrt(dg_len2));");
  655. fragBuilder->codeAppend("}");
  656. fragBuilder->codeAppend("half2 grad = half2(dist_grad.x*Jdx.x + dist_grad.y*Jdy.x,");
  657. fragBuilder->codeAppend(" dist_grad.x*Jdx.y + dist_grad.y*Jdy.y);");
  658. // this gives us a smooth step across approximately one fragment
  659. fragBuilder->codeAppend("afwidth = " SK_DistanceFieldAAFactor "*length(grad);");
  660. }
  661. // The smoothstep falloff compensates for the non-linear sRGB response curve. If we are
  662. // doing gamma-correct rendering (to an sRGB or F16 buffer), then we actually want distance
  663. // mapped linearly to coverage, so use a linear step:
  664. if (isGammaCorrect) {
  665. fragBuilder->codeAppendf("%s = "
  666. "half4(saturate((distance + half3(afwidth)) / half3(2.0 * afwidth)), 1.0);",
  667. args.fOutputCoverage);
  668. } else {
  669. fragBuilder->codeAppendf(
  670. "%s = half4(smoothstep(half3(-afwidth), half3(afwidth), distance), 1.0);",
  671. args.fOutputCoverage);
  672. }
  673. }
  674. void setData(const GrGLSLProgramDataManager& pdman, const GrPrimitiveProcessor& processor,
  675. FPCoordTransformIter&& transformIter) override {
  676. SkASSERT(fDistanceAdjustUni.isValid());
  677. const GrDistanceFieldLCDTextGeoProc& dflcd = processor.cast<GrDistanceFieldLCDTextGeoProc>();
  678. GrDistanceFieldLCDTextGeoProc::DistanceAdjust wa = dflcd.getDistanceAdjust();
  679. if (wa != fDistanceAdjust) {
  680. pdman.set3f(fDistanceAdjustUni,
  681. wa.fR,
  682. wa.fG,
  683. wa.fB);
  684. fDistanceAdjust = wa;
  685. }
  686. const SkISize& atlasSize = dflcd.atlasSize();
  687. SkASSERT(SkIsPow2(atlasSize.fWidth) && SkIsPow2(atlasSize.fHeight));
  688. if (fAtlasSize != atlasSize) {
  689. pdman.set2f(fAtlasSizeInvUniform, 1.0f / atlasSize.fWidth, 1.0f / atlasSize.fHeight);
  690. fAtlasSize = atlasSize;
  691. }
  692. this->setTransformDataHelper(dflcd.localMatrix(), pdman, &transformIter);
  693. }
  694. static inline void GenKey(const GrGeometryProcessor& gp,
  695. const GrShaderCaps&,
  696. GrProcessorKeyBuilder* b) {
  697. const GrDistanceFieldLCDTextGeoProc& dfTexEffect = gp.cast<GrDistanceFieldLCDTextGeoProc>();
  698. uint32_t key = dfTexEffect.getFlags();
  699. b->add32(key);
  700. b->add32(dfTexEffect.numTextureSamplers());
  701. }
  702. private:
  703. GrDistanceFieldLCDTextGeoProc::DistanceAdjust fDistanceAdjust;
  704. UniformHandle fDistanceAdjustUni;
  705. SkISize fAtlasSize;
  706. UniformHandle fAtlasSizeInvUniform;
  707. typedef GrGLSLGeometryProcessor INHERITED;
  708. };
  709. ///////////////////////////////////////////////////////////////////////////////
  710. GrDistanceFieldLCDTextGeoProc::GrDistanceFieldLCDTextGeoProc(const GrShaderCaps& caps,
  711. const sk_sp<GrTextureProxy>* proxies,
  712. int numProxies,
  713. const GrSamplerState& params,
  714. DistanceAdjust distanceAdjust,
  715. uint32_t flags,
  716. const SkMatrix& localMatrix)
  717. : INHERITED(kGrDistanceFieldLCDTextGeoProc_ClassID)
  718. , fLocalMatrix(localMatrix)
  719. , fDistanceAdjust(distanceAdjust)
  720. , fFlags(flags & kLCD_DistanceFieldEffectMask) {
  721. SkASSERT(numProxies <= kMaxTextures);
  722. SkASSERT(!(flags & ~kLCD_DistanceFieldEffectMask) && (flags & kUseLCD_DistanceFieldEffectFlag));
  723. if (fFlags & kPerspective_DistanceFieldEffectFlag) {
  724. fInPosition = {"inPosition", kFloat3_GrVertexAttribType, kFloat3_GrSLType};
  725. } else {
  726. fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
  727. }
  728. fInColor = {"inColor", kUByte4_norm_GrVertexAttribType, kHalf4_GrSLType};
  729. fInTextureCoords = {"inTextureCoords", kUShort2_GrVertexAttribType,
  730. caps.integerSupport() ? kUShort2_GrSLType : kFloat2_GrSLType};
  731. this->setVertexAttributes(&fInPosition, 3);
  732. if (numProxies) {
  733. fAtlasSize = proxies[0]->isize();
  734. }
  735. for (int i = 0; i < numProxies; ++i) {
  736. SkASSERT(proxies[i]);
  737. SkASSERT(proxies[i]->isize() == fAtlasSize);
  738. fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params,
  739. proxies[i]->textureSwizzle());
  740. }
  741. this->setTextureSamplerCnt(numProxies);
  742. }
  743. void GrDistanceFieldLCDTextGeoProc::addNewProxies(const sk_sp<GrTextureProxy>* proxies,
  744. int numProxies,
  745. const GrSamplerState& params) {
  746. SkASSERT(numProxies <= kMaxTextures);
  747. if (!fTextureSamplers[0].isInitialized()) {
  748. fAtlasSize = proxies[0]->isize();
  749. }
  750. for (int i = 0; i < numProxies; ++i) {
  751. SkASSERT(proxies[i]);
  752. SkASSERT(proxies[i]->isize() == fAtlasSize);
  753. if (!fTextureSamplers[i].isInitialized()) {
  754. fTextureSamplers[i].reset(proxies[i]->textureType(), proxies[i]->config(), params,
  755. proxies[i]->textureSwizzle());
  756. }
  757. }
  758. this->setTextureSamplerCnt(numProxies);
  759. }
  760. void GrDistanceFieldLCDTextGeoProc::getGLSLProcessorKey(const GrShaderCaps& caps,
  761. GrProcessorKeyBuilder* b) const {
  762. GrGLDistanceFieldLCDTextGeoProc::GenKey(*this, caps, b);
  763. }
  764. GrGLSLPrimitiveProcessor* GrDistanceFieldLCDTextGeoProc::createGLSLInstance(const GrShaderCaps&) const {
  765. return new GrGLDistanceFieldLCDTextGeoProc();
  766. }
  767. ///////////////////////////////////////////////////////////////////////////////
  768. GR_DEFINE_GEOMETRY_PROCESSOR_TEST(GrDistanceFieldLCDTextGeoProc);
  769. #if GR_TEST_UTILS
  770. sk_sp<GrGeometryProcessor> GrDistanceFieldLCDTextGeoProc::TestCreate(GrProcessorTestData* d) {
  771. int texIdx = d->fRandom->nextBool() ? GrProcessorUnitTest::kSkiaPMTextureIdx :
  772. GrProcessorUnitTest::kAlphaTextureIdx;
  773. sk_sp<GrTextureProxy> proxies[kMaxTextures] = {
  774. d->textureProxy(texIdx),
  775. nullptr,
  776. nullptr,
  777. nullptr
  778. };
  779. GrSamplerState::WrapMode wrapModes[2];
  780. GrTest::TestWrapModes(d->fRandom, wrapModes);
  781. GrSamplerState samplerState(wrapModes, d->fRandom->nextBool()
  782. ? GrSamplerState::Filter::kBilerp
  783. : GrSamplerState::Filter::kNearest);
  784. DistanceAdjust wa = { 0.0f, 0.1f, -0.1f };
  785. uint32_t flags = kUseLCD_DistanceFieldEffectFlag;
  786. flags |= d->fRandom->nextBool() ? kSimilarity_DistanceFieldEffectFlag : 0;
  787. if (flags & kSimilarity_DistanceFieldEffectFlag) {
  788. flags |= d->fRandom->nextBool() ? kScaleOnly_DistanceFieldEffectFlag : 0;
  789. }
  790. flags |= d->fRandom->nextBool() ? kBGR_DistanceFieldEffectFlag : 0;
  791. SkMatrix localMatrix = GrTest::TestMatrix(d->fRandom);
  792. return GrDistanceFieldLCDTextGeoProc::Make(*d->caps()->shaderCaps(), proxies, 1, samplerState,
  793. wa, flags, localMatrix);
  794. }
  795. #endif