GrAAConvexPathRenderer.cpp 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863
  1. /*
  2. * Copyright 2012 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/core/SkString.h"
  8. #include "include/core/SkTypes.h"
  9. #include "src/core/SkGeometry.h"
  10. #include "src/core/SkPathPriv.h"
  11. #include "src/core/SkPointPriv.h"
  12. #include "src/gpu/GrAuditTrail.h"
  13. #include "src/gpu/GrCaps.h"
  14. #include "src/gpu/GrDrawOpTest.h"
  15. #include "src/gpu/GrGeometryProcessor.h"
  16. #include "src/gpu/GrProcessor.h"
  17. #include "src/gpu/GrRenderTargetContext.h"
  18. #include "src/gpu/GrVertexWriter.h"
  19. #include "src/gpu/geometry/GrPathUtils.h"
  20. #include "src/gpu/geometry/GrShape.h"
  21. #include "src/gpu/glsl/GrGLSLFragmentShaderBuilder.h"
  22. #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
  23. #include "src/gpu/glsl/GrGLSLProgramDataManager.h"
  24. #include "src/gpu/glsl/GrGLSLUniformHandler.h"
  25. #include "src/gpu/glsl/GrGLSLVarying.h"
  26. #include "src/gpu/glsl/GrGLSLVertexGeoBuilder.h"
  27. #include "src/gpu/ops/GrAAConvexPathRenderer.h"
  28. #include "src/gpu/ops/GrMeshDrawOp.h"
  29. #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
  30. GrAAConvexPathRenderer::GrAAConvexPathRenderer() {
  31. }
  32. struct Segment {
  33. enum {
  34. // These enum values are assumed in member functions below.
  35. kLine = 0,
  36. kQuad = 1,
  37. } fType;
  38. // line uses one pt, quad uses 2 pts
  39. SkPoint fPts[2];
  40. // normal to edge ending at each pt
  41. SkVector fNorms[2];
  42. // is the corner where the previous segment meets this segment
  43. // sharp. If so, fMid is a normalized bisector facing outward.
  44. SkVector fMid;
  45. int countPoints() {
  46. GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
  47. return fType + 1;
  48. }
  49. const SkPoint& endPt() const {
  50. GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
  51. return fPts[fType];
  52. }
  53. const SkPoint& endNorm() const {
  54. GR_STATIC_ASSERT(0 == kLine && 1 == kQuad);
  55. return fNorms[fType];
  56. }
  57. };
  58. typedef SkTArray<Segment, true> SegmentArray;
  59. static bool center_of_mass(const SegmentArray& segments, SkPoint* c) {
  60. SkScalar area = 0;
  61. SkPoint center = {0, 0};
  62. int count = segments.count();
  63. SkPoint p0 = {0, 0};
  64. if (count > 2) {
  65. // We translate the polygon so that the first point is at the origin.
  66. // This avoids some precision issues with small area polygons far away
  67. // from the origin.
  68. p0 = segments[0].endPt();
  69. SkPoint pi;
  70. SkPoint pj;
  71. // the first and last iteration of the below loop would compute
  72. // zeros since the starting / ending point is (0,0). So instead we start
  73. // at i=1 and make the last iteration i=count-2.
  74. pj = segments[1].endPt() - p0;
  75. for (int i = 1; i < count - 1; ++i) {
  76. pi = pj;
  77. pj = segments[i + 1].endPt() - p0;
  78. SkScalar t = SkPoint::CrossProduct(pi, pj);
  79. area += t;
  80. center.fX += (pi.fX + pj.fX) * t;
  81. center.fY += (pi.fY + pj.fY) * t;
  82. }
  83. }
  84. // If the poly has no area then we instead return the average of
  85. // its points.
  86. if (SkScalarNearlyZero(area)) {
  87. SkPoint avg;
  88. avg.set(0, 0);
  89. for (int i = 0; i < count; ++i) {
  90. const SkPoint& pt = segments[i].endPt();
  91. avg.fX += pt.fX;
  92. avg.fY += pt.fY;
  93. }
  94. SkScalar denom = SK_Scalar1 / count;
  95. avg.scale(denom);
  96. *c = avg;
  97. } else {
  98. area *= 3;
  99. area = SkScalarInvert(area);
  100. center.scale(area);
  101. // undo the translate of p0 to the origin.
  102. *c = center + p0;
  103. }
  104. return !SkScalarIsNaN(c->fX) && !SkScalarIsNaN(c->fY) && c->isFinite();
  105. }
  106. static bool compute_vectors(SegmentArray* segments,
  107. SkPoint* fanPt,
  108. SkPathPriv::FirstDirection dir,
  109. int* vCount,
  110. int* iCount) {
  111. if (!center_of_mass(*segments, fanPt)) {
  112. return false;
  113. }
  114. int count = segments->count();
  115. // Make the normals point towards the outside
  116. SkPointPriv::Side normSide;
  117. if (dir == SkPathPriv::kCCW_FirstDirection) {
  118. normSide = SkPointPriv::kRight_Side;
  119. } else {
  120. normSide = SkPointPriv::kLeft_Side;
  121. }
  122. int64_t vCount64 = 0;
  123. int64_t iCount64 = 0;
  124. // compute normals at all points
  125. for (int a = 0; a < count; ++a) {
  126. Segment& sega = (*segments)[a];
  127. int b = (a + 1) % count;
  128. Segment& segb = (*segments)[b];
  129. const SkPoint* prevPt = &sega.endPt();
  130. int n = segb.countPoints();
  131. for (int p = 0; p < n; ++p) {
  132. segb.fNorms[p] = segb.fPts[p] - *prevPt;
  133. segb.fNorms[p].normalize();
  134. segb.fNorms[p] = SkPointPriv::MakeOrthog(segb.fNorms[p], normSide);
  135. prevPt = &segb.fPts[p];
  136. }
  137. if (Segment::kLine == segb.fType) {
  138. vCount64 += 5;
  139. iCount64 += 9;
  140. } else {
  141. vCount64 += 6;
  142. iCount64 += 12;
  143. }
  144. }
  145. // compute mid-vectors where segments meet. TODO: Detect shallow corners
  146. // and leave out the wedges and close gaps by stitching segments together.
  147. for (int a = 0; a < count; ++a) {
  148. const Segment& sega = (*segments)[a];
  149. int b = (a + 1) % count;
  150. Segment& segb = (*segments)[b];
  151. segb.fMid = segb.fNorms[0] + sega.endNorm();
  152. segb.fMid.normalize();
  153. // corner wedges
  154. vCount64 += 4;
  155. iCount64 += 6;
  156. }
  157. if (vCount64 > SK_MaxS32 || iCount64 > SK_MaxS32) {
  158. return false;
  159. }
  160. *vCount = vCount64;
  161. *iCount = iCount64;
  162. return true;
  163. }
  164. struct DegenerateTestData {
  165. DegenerateTestData() { fStage = kInitial; }
  166. bool isDegenerate() const { return kNonDegenerate != fStage; }
  167. enum {
  168. kInitial,
  169. kPoint,
  170. kLine,
  171. kNonDegenerate
  172. } fStage;
  173. SkPoint fFirstPoint;
  174. SkVector fLineNormal;
  175. SkScalar fLineC;
  176. };
  177. static const SkScalar kClose = (SK_Scalar1 / 16);
  178. static const SkScalar kCloseSqd = kClose * kClose;
  179. static void update_degenerate_test(DegenerateTestData* data, const SkPoint& pt) {
  180. switch (data->fStage) {
  181. case DegenerateTestData::kInitial:
  182. data->fFirstPoint = pt;
  183. data->fStage = DegenerateTestData::kPoint;
  184. break;
  185. case DegenerateTestData::kPoint:
  186. if (SkPointPriv::DistanceToSqd(pt, data->fFirstPoint) > kCloseSqd) {
  187. data->fLineNormal = pt - data->fFirstPoint;
  188. data->fLineNormal.normalize();
  189. data->fLineNormal = SkPointPriv::MakeOrthog(data->fLineNormal);
  190. data->fLineC = -data->fLineNormal.dot(data->fFirstPoint);
  191. data->fStage = DegenerateTestData::kLine;
  192. }
  193. break;
  194. case DegenerateTestData::kLine:
  195. if (SkScalarAbs(data->fLineNormal.dot(pt) + data->fLineC) > kClose) {
  196. data->fStage = DegenerateTestData::kNonDegenerate;
  197. }
  198. case DegenerateTestData::kNonDegenerate:
  199. break;
  200. default:
  201. SK_ABORT("Unexpected degenerate test stage.");
  202. }
  203. }
  204. static inline bool get_direction(const SkPath& path, const SkMatrix& m,
  205. SkPathPriv::FirstDirection* dir) {
  206. if (!SkPathPriv::CheapComputeFirstDirection(path, dir)) {
  207. return false;
  208. }
  209. // check whether m reverses the orientation
  210. SkASSERT(!m.hasPerspective());
  211. SkScalar det2x2 = m.get(SkMatrix::kMScaleX) * m.get(SkMatrix::kMScaleY) -
  212. m.get(SkMatrix::kMSkewX) * m.get(SkMatrix::kMSkewY);
  213. if (det2x2 < 0) {
  214. *dir = SkPathPriv::OppositeFirstDirection(*dir);
  215. }
  216. return true;
  217. }
  218. static inline void add_line_to_segment(const SkPoint& pt,
  219. SegmentArray* segments) {
  220. segments->push_back();
  221. segments->back().fType = Segment::kLine;
  222. segments->back().fPts[0] = pt;
  223. }
  224. static inline void add_quad_segment(const SkPoint pts[3],
  225. SegmentArray* segments) {
  226. if (SkPointPriv::DistanceToLineSegmentBetweenSqd(pts[1], pts[0], pts[2]) < kCloseSqd) {
  227. if (pts[0] != pts[2]) {
  228. add_line_to_segment(pts[2], segments);
  229. }
  230. } else {
  231. segments->push_back();
  232. segments->back().fType = Segment::kQuad;
  233. segments->back().fPts[0] = pts[1];
  234. segments->back().fPts[1] = pts[2];
  235. }
  236. }
  237. static inline void add_cubic_segments(const SkPoint pts[4],
  238. SkPathPriv::FirstDirection dir,
  239. SegmentArray* segments) {
  240. SkSTArray<15, SkPoint, true> quads;
  241. GrPathUtils::convertCubicToQuadsConstrainToTangents(pts, SK_Scalar1, dir, &quads);
  242. int count = quads.count();
  243. for (int q = 0; q < count; q += 3) {
  244. add_quad_segment(&quads[q], segments);
  245. }
  246. }
  247. static bool get_segments(const SkPath& path,
  248. const SkMatrix& m,
  249. SegmentArray* segments,
  250. SkPoint* fanPt,
  251. int* vCount,
  252. int* iCount) {
  253. SkPath::Iter iter(path, true);
  254. // This renderer over-emphasizes very thin path regions. We use the distance
  255. // to the path from the sample to compute coverage. Every pixel intersected
  256. // by the path will be hit and the maximum distance is sqrt(2)/2. We don't
  257. // notice that the sample may be close to a very thin area of the path and
  258. // thus should be very light. This is particularly egregious for degenerate
  259. // line paths. We detect paths that are very close to a line (zero area) and
  260. // draw nothing.
  261. DegenerateTestData degenerateData;
  262. SkPathPriv::FirstDirection dir;
  263. // get_direction can fail for some degenerate paths.
  264. if (!get_direction(path, m, &dir)) {
  265. return false;
  266. }
  267. for (;;) {
  268. SkPoint pts[4];
  269. SkPath::Verb verb = iter.next(pts, true, true);
  270. switch (verb) {
  271. case SkPath::kMove_Verb:
  272. m.mapPoints(pts, 1);
  273. update_degenerate_test(&degenerateData, pts[0]);
  274. break;
  275. case SkPath::kLine_Verb: {
  276. m.mapPoints(&pts[1], 1);
  277. update_degenerate_test(&degenerateData, pts[1]);
  278. add_line_to_segment(pts[1], segments);
  279. break;
  280. }
  281. case SkPath::kQuad_Verb:
  282. m.mapPoints(pts, 3);
  283. update_degenerate_test(&degenerateData, pts[1]);
  284. update_degenerate_test(&degenerateData, pts[2]);
  285. add_quad_segment(pts, segments);
  286. break;
  287. case SkPath::kConic_Verb: {
  288. m.mapPoints(pts, 3);
  289. SkScalar weight = iter.conicWeight();
  290. SkAutoConicToQuads converter;
  291. const SkPoint* quadPts = converter.computeQuads(pts, weight, 0.25f);
  292. for (int i = 0; i < converter.countQuads(); ++i) {
  293. update_degenerate_test(&degenerateData, quadPts[2*i + 1]);
  294. update_degenerate_test(&degenerateData, quadPts[2*i + 2]);
  295. add_quad_segment(quadPts + 2*i, segments);
  296. }
  297. break;
  298. }
  299. case SkPath::kCubic_Verb: {
  300. m.mapPoints(pts, 4);
  301. update_degenerate_test(&degenerateData, pts[1]);
  302. update_degenerate_test(&degenerateData, pts[2]);
  303. update_degenerate_test(&degenerateData, pts[3]);
  304. add_cubic_segments(pts, dir, segments);
  305. break;
  306. }
  307. case SkPath::kDone_Verb:
  308. if (degenerateData.isDegenerate()) {
  309. return false;
  310. } else {
  311. return compute_vectors(segments, fanPt, dir, vCount, iCount);
  312. }
  313. default:
  314. break;
  315. }
  316. }
  317. }
  318. struct Draw {
  319. Draw() : fVertexCnt(0), fIndexCnt(0) {}
  320. int fVertexCnt;
  321. int fIndexCnt;
  322. };
  323. typedef SkTArray<Draw, true> DrawArray;
  324. static void create_vertices(const SegmentArray& segments,
  325. const SkPoint& fanPt,
  326. const GrVertexColor& color,
  327. DrawArray* draws,
  328. GrVertexWriter& verts,
  329. uint16_t* idxs,
  330. size_t vertexStride) {
  331. Draw* draw = &draws->push_back();
  332. // alias just to make vert/index assignments easier to read.
  333. int* v = &draw->fVertexCnt;
  334. int* i = &draw->fIndexCnt;
  335. const size_t uvOffset = sizeof(SkPoint) + color.size();
  336. int count = segments.count();
  337. for (int a = 0; a < count; ++a) {
  338. const Segment& sega = segments[a];
  339. int b = (a + 1) % count;
  340. const Segment& segb = segments[b];
  341. // Check whether adding the verts for this segment to the current draw would cause index
  342. // values to overflow.
  343. int vCount = 4;
  344. if (Segment::kLine == segb.fType) {
  345. vCount += 5;
  346. } else {
  347. vCount += 6;
  348. }
  349. if (draw->fVertexCnt + vCount > (1 << 16)) {
  350. idxs += *i;
  351. draw = &draws->push_back();
  352. v = &draw->fVertexCnt;
  353. i = &draw->fIndexCnt;
  354. }
  355. const SkScalar negOneDists[2] = { -SK_Scalar1, -SK_Scalar1 };
  356. // FIXME: These tris are inset in the 1 unit arc around the corner
  357. SkPoint p0 = sega.endPt();
  358. // Position, Color, UV, D0, D1
  359. verts.write(p0, color, SkPoint{0, 0}, negOneDists);
  360. verts.write(p0 + sega.endNorm(), color, SkPoint{0, -SK_Scalar1}, negOneDists);
  361. verts.write(p0 + segb.fMid, color, SkPoint{0, -SK_Scalar1}, negOneDists);
  362. verts.write(p0 + segb.fNorms[0], color, SkPoint{0, -SK_Scalar1}, negOneDists);
  363. idxs[*i + 0] = *v + 0;
  364. idxs[*i + 1] = *v + 2;
  365. idxs[*i + 2] = *v + 1;
  366. idxs[*i + 3] = *v + 0;
  367. idxs[*i + 4] = *v + 3;
  368. idxs[*i + 5] = *v + 2;
  369. *v += 4;
  370. *i += 6;
  371. if (Segment::kLine == segb.fType) {
  372. // we draw the line edge as a degenerate quad (u is 0, v is the
  373. // signed distance to the edge)
  374. SkPoint v1Pos = sega.endPt();
  375. SkPoint v2Pos = segb.fPts[0];
  376. SkScalar dist = SkPointPriv::DistanceToLineBetween(fanPt, v1Pos, v2Pos);
  377. verts.write(fanPt, color, SkPoint{0, dist}, negOneDists);
  378. verts.write(v1Pos, color, SkPoint{0, 0}, negOneDists);
  379. verts.write(v2Pos, color, SkPoint{0, 0}, negOneDists);
  380. verts.write(v1Pos + segb.fNorms[0], color, SkPoint{0, -SK_Scalar1}, negOneDists);
  381. verts.write(v2Pos + segb.fNorms[0], color, SkPoint{0, -SK_Scalar1}, negOneDists);
  382. idxs[*i + 0] = *v + 3;
  383. idxs[*i + 1] = *v + 1;
  384. idxs[*i + 2] = *v + 2;
  385. idxs[*i + 3] = *v + 4;
  386. idxs[*i + 4] = *v + 3;
  387. idxs[*i + 5] = *v + 2;
  388. *i += 6;
  389. // Draw the interior fan if it exists.
  390. // TODO: Detect and combine colinear segments. This will ensure we catch every case
  391. // with no interior, and that the resulting shared edge uses the same endpoints.
  392. if (count >= 3) {
  393. idxs[*i + 0] = *v + 0;
  394. idxs[*i + 1] = *v + 2;
  395. idxs[*i + 2] = *v + 1;
  396. *i += 3;
  397. }
  398. *v += 5;
  399. } else {
  400. void* quadVertsBegin = verts.fPtr;
  401. SkPoint qpts[] = {sega.endPt(), segb.fPts[0], segb.fPts[1]};
  402. SkScalar c0 = segb.fNorms[0].dot(qpts[0]);
  403. SkScalar c1 = segb.fNorms[1].dot(qpts[2]);
  404. GrVertexWriter::Skip<SkPoint> skipUVs;
  405. verts.write(fanPt,
  406. color, skipUVs,
  407. -segb.fNorms[0].dot(fanPt) + c0,
  408. -segb.fNorms[1].dot(fanPt) + c1);
  409. verts.write(qpts[0],
  410. color, skipUVs,
  411. 0.0f,
  412. -segb.fNorms[1].dot(qpts[0]) + c1);
  413. verts.write(qpts[2],
  414. color, skipUVs,
  415. -segb.fNorms[0].dot(qpts[2]) + c0,
  416. 0.0f);
  417. verts.write(qpts[0] + segb.fNorms[0],
  418. color, skipUVs,
  419. -SK_ScalarMax/100,
  420. -SK_ScalarMax/100);
  421. verts.write(qpts[2] + segb.fNorms[1],
  422. color, skipUVs,
  423. -SK_ScalarMax/100,
  424. -SK_ScalarMax/100);
  425. SkVector midVec = segb.fNorms[0] + segb.fNorms[1];
  426. midVec.normalize();
  427. verts.write(qpts[1] + midVec,
  428. color, skipUVs,
  429. -SK_ScalarMax/100,
  430. -SK_ScalarMax/100);
  431. GrPathUtils::QuadUVMatrix toUV(qpts);
  432. toUV.apply(quadVertsBegin, 6, vertexStride, uvOffset);
  433. idxs[*i + 0] = *v + 3;
  434. idxs[*i + 1] = *v + 1;
  435. idxs[*i + 2] = *v + 2;
  436. idxs[*i + 3] = *v + 4;
  437. idxs[*i + 4] = *v + 3;
  438. idxs[*i + 5] = *v + 2;
  439. idxs[*i + 6] = *v + 5;
  440. idxs[*i + 7] = *v + 3;
  441. idxs[*i + 8] = *v + 4;
  442. *i += 9;
  443. // Draw the interior fan if it exists.
  444. // TODO: Detect and combine colinear segments. This will ensure we catch every case
  445. // with no interior, and that the resulting shared edge uses the same endpoints.
  446. if (count >= 3) {
  447. idxs[*i + 0] = *v + 0;
  448. idxs[*i + 1] = *v + 2;
  449. idxs[*i + 2] = *v + 1;
  450. *i += 3;
  451. }
  452. *v += 6;
  453. }
  454. }
  455. }
  456. ///////////////////////////////////////////////////////////////////////////////
  457. /*
  458. * Quadratic specified by 0=u^2-v canonical coords. u and v are the first
  459. * two components of the vertex attribute. Coverage is based on signed
  460. * distance with negative being inside, positive outside. The edge is specified in
  461. * window space (y-down). If either the third or fourth component of the interpolated
  462. * vertex coord is > 0 then the pixel is considered outside the edge. This is used to
  463. * attempt to trim to a portion of the infinite quad.
  464. * Requires shader derivative instruction support.
  465. */
  466. class QuadEdgeEffect : public GrGeometryProcessor {
  467. public:
  468. static sk_sp<GrGeometryProcessor> Make(const SkMatrix& localMatrix, bool usesLocalCoords,
  469. bool wideColor) {
  470. return sk_sp<GrGeometryProcessor>(
  471. new QuadEdgeEffect(localMatrix, usesLocalCoords, wideColor));
  472. }
  473. ~QuadEdgeEffect() override {}
  474. const char* name() const override { return "QuadEdge"; }
  475. class GLSLProcessor : public GrGLSLGeometryProcessor {
  476. public:
  477. GLSLProcessor() {}
  478. void onEmitCode(EmitArgs& args, GrGPArgs* gpArgs) override {
  479. const QuadEdgeEffect& qe = args.fGP.cast<QuadEdgeEffect>();
  480. GrGLSLVertexBuilder* vertBuilder = args.fVertBuilder;
  481. GrGLSLVaryingHandler* varyingHandler = args.fVaryingHandler;
  482. GrGLSLUniformHandler* uniformHandler = args.fUniformHandler;
  483. // emit attributes
  484. varyingHandler->emitAttributes(qe);
  485. GrGLSLVarying v(kHalf4_GrSLType);
  486. varyingHandler->addVarying("QuadEdge", &v);
  487. vertBuilder->codeAppendf("%s = %s;", v.vsOut(), qe.fInQuadEdge.name());
  488. // Setup pass through color
  489. varyingHandler->addPassThroughAttribute(qe.fInColor, args.fOutputColor);
  490. GrGLSLFPFragmentBuilder* fragBuilder = args.fFragBuilder;
  491. // Setup position
  492. this->writeOutputPosition(vertBuilder, gpArgs, qe.fInPosition.name());
  493. // emit transforms
  494. this->emitTransforms(vertBuilder,
  495. varyingHandler,
  496. uniformHandler,
  497. qe.fInPosition.asShaderVar(),
  498. qe.fLocalMatrix,
  499. args.fFPCoordTransformHandler);
  500. fragBuilder->codeAppendf("half edgeAlpha;");
  501. // keep the derivative instructions outside the conditional
  502. fragBuilder->codeAppendf("half2 duvdx = half2(dFdx(%s.xy));", v.fsIn());
  503. fragBuilder->codeAppendf("half2 duvdy = half2(dFdy(%s.xy));", v.fsIn());
  504. fragBuilder->codeAppendf("if (%s.z > 0.0 && %s.w > 0.0) {", v.fsIn(), v.fsIn());
  505. // today we know z and w are in device space. We could use derivatives
  506. fragBuilder->codeAppendf("edgeAlpha = min(min(%s.z, %s.w) + 0.5, 1.0);", v.fsIn(),
  507. v.fsIn());
  508. fragBuilder->codeAppendf ("} else {");
  509. fragBuilder->codeAppendf("half2 gF = half2(2.0*%s.x*duvdx.x - duvdx.y,"
  510. " 2.0*%s.x*duvdy.x - duvdy.y);",
  511. v.fsIn(), v.fsIn());
  512. fragBuilder->codeAppendf("edgeAlpha = (%s.x*%s.x - %s.y);", v.fsIn(), v.fsIn(),
  513. v.fsIn());
  514. fragBuilder->codeAppendf("edgeAlpha = "
  515. "saturate(0.5 - edgeAlpha / length(gF));}");
  516. fragBuilder->codeAppendf("%s = half4(edgeAlpha);", args.fOutputCoverage);
  517. }
  518. static inline void GenKey(const GrGeometryProcessor& gp,
  519. const GrShaderCaps&,
  520. GrProcessorKeyBuilder* b) {
  521. const QuadEdgeEffect& qee = gp.cast<QuadEdgeEffect>();
  522. b->add32(SkToBool(qee.fUsesLocalCoords && qee.fLocalMatrix.hasPerspective()));
  523. }
  524. void setData(const GrGLSLProgramDataManager& pdman,
  525. const GrPrimitiveProcessor& gp,
  526. FPCoordTransformIter&& transformIter) override {
  527. const QuadEdgeEffect& qe = gp.cast<QuadEdgeEffect>();
  528. this->setTransformDataHelper(qe.fLocalMatrix, pdman, &transformIter);
  529. }
  530. private:
  531. typedef GrGLSLGeometryProcessor INHERITED;
  532. };
  533. void getGLSLProcessorKey(const GrShaderCaps& caps, GrProcessorKeyBuilder* b) const override {
  534. GLSLProcessor::GenKey(*this, caps, b);
  535. }
  536. GrGLSLPrimitiveProcessor* createGLSLInstance(const GrShaderCaps&) const override {
  537. return new GLSLProcessor();
  538. }
  539. private:
  540. QuadEdgeEffect(const SkMatrix& localMatrix, bool usesLocalCoords, bool wideColor)
  541. : INHERITED(kQuadEdgeEffect_ClassID)
  542. , fLocalMatrix(localMatrix)
  543. , fUsesLocalCoords(usesLocalCoords) {
  544. fInPosition = {"inPosition", kFloat2_GrVertexAttribType, kFloat2_GrSLType};
  545. fInColor = MakeColorAttribute("inColor", wideColor);
  546. fInQuadEdge = {"inQuadEdge", kFloat4_GrVertexAttribType, kHalf4_GrSLType};
  547. this->setVertexAttributes(&fInPosition, 3);
  548. }
  549. Attribute fInPosition;
  550. Attribute fInColor;
  551. Attribute fInQuadEdge;
  552. SkMatrix fLocalMatrix;
  553. bool fUsesLocalCoords;
  554. GR_DECLARE_GEOMETRY_PROCESSOR_TEST
  555. typedef GrGeometryProcessor INHERITED;
  556. };
  557. GR_DEFINE_GEOMETRY_PROCESSOR_TEST(QuadEdgeEffect);
  558. #if GR_TEST_UTILS
  559. sk_sp<GrGeometryProcessor> QuadEdgeEffect::TestCreate(GrProcessorTestData* d) {
  560. // Doesn't work without derivative instructions.
  561. return d->caps()->shaderCaps()->shaderDerivativeSupport()
  562. ? QuadEdgeEffect::Make(GrTest::TestMatrix(d->fRandom), d->fRandom->nextBool(),
  563. d->fRandom->nextBool())
  564. : nullptr;
  565. }
  566. #endif
  567. ///////////////////////////////////////////////////////////////////////////////
  568. GrPathRenderer::CanDrawPath
  569. GrAAConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
  570. if (args.fCaps->shaderCaps()->shaderDerivativeSupport() &&
  571. (GrAAType::kCoverage == args.fAAType) && args.fShape->style().isSimpleFill() &&
  572. !args.fShape->inverseFilled() && args.fShape->knownToBeConvex()) {
  573. return CanDrawPath::kYes;
  574. }
  575. return CanDrawPath::kNo;
  576. }
  577. namespace {
  578. class AAConvexPathOp final : public GrMeshDrawOp {
  579. private:
  580. using Helper = GrSimpleMeshDrawOpHelperWithStencil;
  581. public:
  582. DEFINE_OP_CLASS_ID
  583. static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
  584. GrPaint&& paint,
  585. const SkMatrix& viewMatrix,
  586. const SkPath& path,
  587. const GrUserStencilSettings* stencilSettings) {
  588. return Helper::FactoryHelper<AAConvexPathOp>(context, std::move(paint), viewMatrix, path,
  589. stencilSettings);
  590. }
  591. AAConvexPathOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color,
  592. const SkMatrix& viewMatrix, const SkPath& path,
  593. const GrUserStencilSettings* stencilSettings)
  594. : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencilSettings) {
  595. fPaths.emplace_back(PathData{viewMatrix, path, color});
  596. this->setTransformedBounds(path.getBounds(), viewMatrix, HasAABloat::kYes, IsZeroArea::kNo);
  597. }
  598. const char* name() const override { return "AAConvexPathOp"; }
  599. void visitProxies(const VisitProxyFunc& func) const override {
  600. fHelper.visitProxies(func);
  601. }
  602. #ifdef SK_DEBUG
  603. SkString dumpInfo() const override {
  604. SkString string;
  605. string.appendf("Count: %d\n", fPaths.count());
  606. string += fHelper.dumpInfo();
  607. string += INHERITED::dumpInfo();
  608. return string;
  609. }
  610. #endif
  611. FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
  612. GrProcessorSet::Analysis finalize(
  613. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  614. GrClampType clampType) override {
  615. return fHelper.finalizeProcessors(
  616. caps, clip, hasMixedSampledCoverage, clampType,
  617. GrProcessorAnalysisCoverage::kSingleChannel, &fPaths.back().fColor, &fWideColor);
  618. }
  619. private:
  620. void onPrepareDraws(Target* target) override {
  621. int instanceCount = fPaths.count();
  622. SkMatrix invert;
  623. if (fHelper.usesLocalCoords() && !fPaths.back().fViewMatrix.invert(&invert)) {
  624. return;
  625. }
  626. // Setup GrGeometryProcessor
  627. sk_sp<GrGeometryProcessor> quadProcessor(
  628. QuadEdgeEffect::Make(invert, fHelper.usesLocalCoords(), fWideColor));
  629. const size_t kVertexStride = quadProcessor->vertexStride();
  630. // TODO generate all segments for all paths and use one vertex buffer
  631. for (int i = 0; i < instanceCount; i++) {
  632. const PathData& args = fPaths[i];
  633. // We use the fact that SkPath::transform path does subdivision based on
  634. // perspective. Otherwise, we apply the view matrix when copying to the
  635. // segment representation.
  636. const SkMatrix* viewMatrix = &args.fViewMatrix;
  637. // We avoid initializing the path unless we have to
  638. const SkPath* pathPtr = &args.fPath;
  639. SkTLazy<SkPath> tmpPath;
  640. if (viewMatrix->hasPerspective()) {
  641. SkPath* tmpPathPtr = tmpPath.init(*pathPtr);
  642. tmpPathPtr->setIsVolatile(true);
  643. tmpPathPtr->transform(*viewMatrix);
  644. viewMatrix = &SkMatrix::I();
  645. pathPtr = tmpPathPtr;
  646. }
  647. int vertexCount;
  648. int indexCount;
  649. enum {
  650. kPreallocSegmentCnt = 512 / sizeof(Segment),
  651. kPreallocDrawCnt = 4,
  652. };
  653. SkSTArray<kPreallocSegmentCnt, Segment, true> segments;
  654. SkPoint fanPt;
  655. if (!get_segments(*pathPtr, *viewMatrix, &segments, &fanPt, &vertexCount,
  656. &indexCount)) {
  657. continue;
  658. }
  659. sk_sp<const GrBuffer> vertexBuffer;
  660. int firstVertex;
  661. GrVertexWriter verts{target->makeVertexSpace(kVertexStride, vertexCount,
  662. &vertexBuffer, &firstVertex)};
  663. if (!verts.fPtr) {
  664. SkDebugf("Could not allocate vertices\n");
  665. return;
  666. }
  667. sk_sp<const GrBuffer> indexBuffer;
  668. int firstIndex;
  669. uint16_t *idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
  670. if (!idxs) {
  671. SkDebugf("Could not allocate indices\n");
  672. return;
  673. }
  674. SkSTArray<kPreallocDrawCnt, Draw, true> draws;
  675. GrVertexColor color(args.fColor, fWideColor);
  676. create_vertices(segments, fanPt, color, &draws, verts, idxs, kVertexStride);
  677. GrMesh* meshes = target->allocMeshes(draws.count());
  678. for (int j = 0; j < draws.count(); ++j) {
  679. const Draw& draw = draws[j];
  680. meshes[j].setPrimitiveType(GrPrimitiveType::kTriangles);
  681. meshes[j].setIndexed(indexBuffer, draw.fIndexCnt, firstIndex, 0,
  682. draw.fVertexCnt - 1, GrPrimitiveRestart::kNo);
  683. meshes[j].setVertexData(vertexBuffer, firstVertex);
  684. firstIndex += draw.fIndexCnt;
  685. firstVertex += draw.fVertexCnt;
  686. }
  687. target->recordDraw(quadProcessor, meshes, draws.count());
  688. }
  689. }
  690. void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
  691. fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
  692. }
  693. CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
  694. AAConvexPathOp* that = t->cast<AAConvexPathOp>();
  695. if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
  696. return CombineResult::kCannotCombine;
  697. }
  698. if (fHelper.usesLocalCoords() &&
  699. !fPaths[0].fViewMatrix.cheapEqualTo(that->fPaths[0].fViewMatrix)) {
  700. return CombineResult::kCannotCombine;
  701. }
  702. fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
  703. fWideColor |= that->fWideColor;
  704. return CombineResult::kMerged;
  705. }
  706. struct PathData {
  707. SkMatrix fViewMatrix;
  708. SkPath fPath;
  709. SkPMColor4f fColor;
  710. };
  711. Helper fHelper;
  712. SkSTArray<1, PathData, true> fPaths;
  713. bool fWideColor;
  714. typedef GrMeshDrawOp INHERITED;
  715. };
  716. } // anonymous namespace
  717. bool GrAAConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
  718. GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
  719. "GrAAConvexPathRenderer::onDrawPath");
  720. SkASSERT(args.fRenderTargetContext->numSamples() <= 1);
  721. SkASSERT(!args.fShape->isEmpty());
  722. SkPath path;
  723. args.fShape->asPath(&path);
  724. std::unique_ptr<GrDrawOp> op = AAConvexPathOp::Make(args.fContext, std::move(args.fPaint),
  725. *args.fViewMatrix,
  726. path, args.fUserStencilSettings);
  727. args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
  728. return true;
  729. }
  730. ///////////////////////////////////////////////////////////////////////////////////////////////////
  731. #if GR_TEST_UTILS
  732. GR_DRAW_OP_TEST_DEFINE(AAConvexPathOp) {
  733. SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
  734. SkPath path = GrTest::TestPathConvex(random);
  735. const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context);
  736. return AAConvexPathOp::Make(context, std::move(paint), viewMatrix, path, stencilSettings);
  737. }
  738. #endif