GrDefaultPathRenderer.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713
  1. /*
  2. * Copyright 2011 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 "src/gpu/ops/GrDefaultPathRenderer.h"
  8. #include "include/core/SkString.h"
  9. #include "include/core/SkStrokeRec.h"
  10. #include "src/core/SkGeometry.h"
  11. #include "src/core/SkTLazy.h"
  12. #include "src/core/SkTraceEvent.h"
  13. #include "src/gpu/GrAuditTrail.h"
  14. #include "src/gpu/GrCaps.h"
  15. #include "src/gpu/GrDefaultGeoProcFactory.h"
  16. #include "src/gpu/GrDrawOpTest.h"
  17. #include "src/gpu/GrFixedClip.h"
  18. #include "src/gpu/GrMesh.h"
  19. #include "src/gpu/GrOpFlushState.h"
  20. #include "src/gpu/GrRenderTargetContextPriv.h"
  21. #include "src/gpu/GrStyle.h"
  22. #include "src/gpu/GrSurfaceContextPriv.h"
  23. #include "src/gpu/geometry/GrPathUtils.h"
  24. #include "src/gpu/geometry/GrShape.h"
  25. #include "src/gpu/ops/GrMeshDrawOp.h"
  26. #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
  27. GrDefaultPathRenderer::GrDefaultPathRenderer() {
  28. }
  29. ////////////////////////////////////////////////////////////////////////////////
  30. // Helpers for drawPath
  31. #define STENCIL_OFF 0 // Always disable stencil (even when needed)
  32. static inline bool single_pass_shape(const GrShape& shape) {
  33. #if STENCIL_OFF
  34. return true;
  35. #else
  36. // Inverse fill is always two pass.
  37. if (shape.inverseFilled()) {
  38. return false;
  39. }
  40. // This path renderer only accepts simple fill paths or stroke paths that are either hairline
  41. // or have a stroke width small enough to treat as hairline. Hairline paths are always single
  42. // pass. Filled paths are single pass if they're convex.
  43. if (shape.style().isSimpleFill()) {
  44. return shape.knownToBeConvex();
  45. }
  46. return true;
  47. #endif
  48. }
  49. GrPathRenderer::StencilSupport
  50. GrDefaultPathRenderer::onGetStencilSupport(const GrShape& shape) const {
  51. if (single_pass_shape(shape)) {
  52. return GrPathRenderer::kNoRestriction_StencilSupport;
  53. } else {
  54. return GrPathRenderer::kStencilOnly_StencilSupport;
  55. }
  56. }
  57. namespace {
  58. class PathGeoBuilder {
  59. public:
  60. PathGeoBuilder(GrPrimitiveType primitiveType, GrMeshDrawOp::Target* target,
  61. sk_sp<const GrGeometryProcessor> geometryProcessor)
  62. : fPrimitiveType(primitiveType)
  63. , fTarget(target)
  64. , fVertexStride(sizeof(SkPoint))
  65. , fGeometryProcessor(std::move(geometryProcessor))
  66. , fFirstIndex(0)
  67. , fIndicesInChunk(0)
  68. , fIndices(nullptr) {
  69. this->allocNewBuffers();
  70. }
  71. ~PathGeoBuilder() {
  72. this->emitMeshAndPutBackReserve();
  73. }
  74. /**
  75. * Path verbs
  76. */
  77. void moveTo(const SkPoint& p) {
  78. needSpace(1);
  79. fSubpathIndexStart = this->currentIndex();
  80. *(fCurVert++) = p;
  81. }
  82. void addLine(const SkPoint& p) {
  83. needSpace(1, this->indexScale());
  84. if (this->isIndexed()) {
  85. uint16_t prevIdx = this->currentIndex() - 1;
  86. appendCountourEdgeIndices(prevIdx);
  87. }
  88. *(fCurVert++) = p;
  89. }
  90. void addQuad(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
  91. this->needSpace(GrPathUtils::kMaxPointsPerCurve,
  92. GrPathUtils::kMaxPointsPerCurve * this->indexScale());
  93. // First pt of quad is the pt we ended on in previous step
  94. uint16_t firstQPtIdx = this->currentIndex() - 1;
  95. uint16_t numPts = (uint16_t)GrPathUtils::generateQuadraticPoints(
  96. pts[0], pts[1], pts[2], srcSpaceTolSqd, &fCurVert,
  97. GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
  98. if (this->isIndexed()) {
  99. for (uint16_t i = 0; i < numPts; ++i) {
  100. appendCountourEdgeIndices(firstQPtIdx + i);
  101. }
  102. }
  103. }
  104. void addConic(SkScalar weight, const SkPoint pts[], SkScalar srcSpaceTolSqd,
  105. SkScalar srcSpaceTol) {
  106. SkAutoConicToQuads converter;
  107. const SkPoint* quadPts = converter.computeQuads(pts, weight, srcSpaceTol);
  108. for (int i = 0; i < converter.countQuads(); ++i) {
  109. this->addQuad(quadPts + i * 2, srcSpaceTolSqd, srcSpaceTol);
  110. }
  111. }
  112. void addCubic(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
  113. this->needSpace(GrPathUtils::kMaxPointsPerCurve,
  114. GrPathUtils::kMaxPointsPerCurve * this->indexScale());
  115. // First pt of cubic is the pt we ended on in previous step
  116. uint16_t firstCPtIdx = this->currentIndex() - 1;
  117. uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
  118. pts[0], pts[1], pts[2], pts[3], srcSpaceTolSqd, &fCurVert,
  119. GrPathUtils::cubicPointCount(pts, srcSpaceTol));
  120. if (this->isIndexed()) {
  121. for (uint16_t i = 0; i < numPts; ++i) {
  122. appendCountourEdgeIndices(firstCPtIdx + i);
  123. }
  124. }
  125. }
  126. void addPath(const SkPath& path, SkScalar srcSpaceTol) {
  127. SkScalar srcSpaceTolSqd = srcSpaceTol * srcSpaceTol;
  128. SkPath::Iter iter(path, false);
  129. SkPoint pts[4];
  130. bool done = false;
  131. while (!done) {
  132. SkPath::Verb verb = iter.next(pts, false);
  133. switch (verb) {
  134. case SkPath::kMove_Verb:
  135. this->moveTo(pts[0]);
  136. break;
  137. case SkPath::kLine_Verb:
  138. this->addLine(pts[1]);
  139. break;
  140. case SkPath::kConic_Verb:
  141. this->addConic(iter.conicWeight(), pts, srcSpaceTolSqd, srcSpaceTol);
  142. break;
  143. case SkPath::kQuad_Verb:
  144. this->addQuad(pts, srcSpaceTolSqd, srcSpaceTol);
  145. break;
  146. case SkPath::kCubic_Verb:
  147. this->addCubic(pts, srcSpaceTolSqd, srcSpaceTol);
  148. break;
  149. case SkPath::kClose_Verb:
  150. break;
  151. case SkPath::kDone_Verb:
  152. done = true;
  153. }
  154. }
  155. }
  156. static bool PathHasMultipleSubpaths(const SkPath& path) {
  157. bool first = true;
  158. SkPath::Iter iter(path, false);
  159. SkPath::Verb verb;
  160. SkPoint pts[4];
  161. while ((verb = iter.next(pts, false)) != SkPath::kDone_Verb) {
  162. if (SkPath::kMove_Verb == verb && !first) {
  163. return true;
  164. }
  165. first = false;
  166. }
  167. return false;
  168. }
  169. private:
  170. /**
  171. * Derived properties
  172. * TODO: Cache some of these for better performance, rather than re-computing?
  173. */
  174. bool isIndexed() const {
  175. return GrPrimitiveType::kLines == fPrimitiveType ||
  176. GrPrimitiveType::kTriangles == fPrimitiveType;
  177. }
  178. bool isHairline() const {
  179. return GrPrimitiveType::kLines == fPrimitiveType ||
  180. GrPrimitiveType::kLineStrip == fPrimitiveType;
  181. }
  182. int indexScale() const {
  183. switch (fPrimitiveType) {
  184. case GrPrimitiveType::kLines:
  185. return 2;
  186. case GrPrimitiveType::kTriangles:
  187. return 3;
  188. default:
  189. return 0;
  190. }
  191. }
  192. uint16_t currentIndex() const { return fCurVert - fVertices; }
  193. // Allocate vertex and (possibly) index buffers
  194. void allocNewBuffers() {
  195. // Ensure that we always get enough verts for a worst-case quad/cubic, plus leftover points
  196. // from previous mesh piece (up to two verts to continue fanning). If we can't get that
  197. // many, ask for a much larger number. This needs to be fairly big to handle quads/cubics,
  198. // which have a worst-case of 1k points.
  199. static const int kMinVerticesPerChunk = GrPathUtils::kMaxPointsPerCurve + 2;
  200. static const int kFallbackVerticesPerChunk = 16384;
  201. fVertices = static_cast<SkPoint*>(fTarget->makeVertexSpaceAtLeast(fVertexStride,
  202. kMinVerticesPerChunk,
  203. kFallbackVerticesPerChunk,
  204. &fVertexBuffer,
  205. &fFirstVertex,
  206. &fVerticesInChunk));
  207. if (this->isIndexed()) {
  208. // Similar to above: Ensure we get enough indices for one worst-case quad/cubic.
  209. // No extra indices are needed for stitching, though. If we can't get that many, ask
  210. // for enough to match our large vertex request.
  211. const int kMinIndicesPerChunk = GrPathUtils::kMaxPointsPerCurve * this->indexScale();
  212. const int kFallbackIndicesPerChunk = kFallbackVerticesPerChunk * this->indexScale();
  213. fIndices = fTarget->makeIndexSpaceAtLeast(kMinIndicesPerChunk, kFallbackIndicesPerChunk,
  214. &fIndexBuffer, &fFirstIndex,
  215. &fIndicesInChunk);
  216. }
  217. fCurVert = fVertices;
  218. fCurIdx = fIndices;
  219. fSubpathIndexStart = 0;
  220. }
  221. void appendCountourEdgeIndices(uint16_t edgeV0Idx) {
  222. // When drawing lines we're appending line segments along the countour. When applying the
  223. // other fill rules we're drawing triangle fans around the start of the current (sub)path.
  224. if (!this->isHairline()) {
  225. *(fCurIdx++) = fSubpathIndexStart;
  226. }
  227. *(fCurIdx++) = edgeV0Idx;
  228. *(fCurIdx++) = edgeV0Idx + 1;
  229. }
  230. // Emits a single draw with all accumulated vertex/index data
  231. void emitMeshAndPutBackReserve() {
  232. int vertexCount = fCurVert - fVertices;
  233. int indexCount = fCurIdx - fIndices;
  234. SkASSERT(vertexCount <= fVerticesInChunk);
  235. SkASSERT(indexCount <= fIndicesInChunk);
  236. if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) {
  237. GrMesh* mesh = fTarget->allocMesh(fPrimitiveType);
  238. if (!this->isIndexed()) {
  239. mesh->setNonIndexedNonInstanced(vertexCount);
  240. } else {
  241. mesh->setIndexed(std::move(fIndexBuffer), indexCount, fFirstIndex, 0,
  242. vertexCount - 1, GrPrimitiveRestart::kNo);
  243. }
  244. mesh->setVertexData(std::move(fVertexBuffer), fFirstVertex);
  245. fTarget->recordDraw(fGeometryProcessor, mesh);
  246. }
  247. fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount));
  248. fTarget->putBackVertices((size_t)(fVerticesInChunk - vertexCount), fVertexStride);
  249. }
  250. void needSpace(int vertsNeeded, int indicesNeeded = 0) {
  251. if (fCurVert + vertsNeeded > fVertices + fVerticesInChunk ||
  252. fCurIdx + indicesNeeded > fIndices + fIndicesInChunk) {
  253. // We are about to run out of space (possibly)
  254. // To maintain continuity, we need to remember one or two points from the current mesh.
  255. // Lines only need the last point, fills need the first point from the current contour.
  256. // We always grab both here, and append the ones we need at the end of this process.
  257. SkPoint lastPt = *(fCurVert - 1);
  258. SkASSERT(fSubpathIndexStart < fVerticesInChunk);
  259. SkPoint subpathStartPt = fVertices[fSubpathIndexStart];
  260. // Draw the mesh we've accumulated, and put back any unused space
  261. this->emitMeshAndPutBackReserve();
  262. // Get new buffers
  263. this->allocNewBuffers();
  264. // Append copies of the points we saved so the two meshes will weld properly
  265. if (!this->isHairline()) {
  266. *(fCurVert++) = subpathStartPt;
  267. }
  268. *(fCurVert++) = lastPt;
  269. }
  270. }
  271. GrPrimitiveType fPrimitiveType;
  272. GrMeshDrawOp::Target* fTarget;
  273. size_t fVertexStride;
  274. sk_sp<const GrGeometryProcessor> fGeometryProcessor;
  275. sk_sp<const GrBuffer> fVertexBuffer;
  276. int fFirstVertex;
  277. int fVerticesInChunk;
  278. SkPoint* fVertices;
  279. SkPoint* fCurVert;
  280. sk_sp<const GrBuffer> fIndexBuffer;
  281. int fFirstIndex;
  282. int fIndicesInChunk;
  283. uint16_t* fIndices;
  284. uint16_t* fCurIdx;
  285. uint16_t fSubpathIndexStart;
  286. };
  287. class DefaultPathOp final : public GrMeshDrawOp {
  288. private:
  289. using Helper = GrSimpleMeshDrawOpHelperWithStencil;
  290. public:
  291. DEFINE_OP_CLASS_ID
  292. static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
  293. GrPaint&& paint,
  294. const SkPath& path,
  295. SkScalar tolerance,
  296. uint8_t coverage,
  297. const SkMatrix& viewMatrix,
  298. bool isHairline,
  299. GrAAType aaType,
  300. const SkRect& devBounds,
  301. const GrUserStencilSettings* stencilSettings) {
  302. return Helper::FactoryHelper<DefaultPathOp>(context, std::move(paint), path, tolerance,
  303. coverage, viewMatrix, isHairline, aaType,
  304. devBounds, stencilSettings);
  305. }
  306. const char* name() const override { return "DefaultPathOp"; }
  307. void visitProxies(const VisitProxyFunc& func) const override {
  308. fHelper.visitProxies(func);
  309. }
  310. #ifdef SK_DEBUG
  311. SkString dumpInfo() const override {
  312. SkString string;
  313. string.appendf("Color: 0x%08x Count: %d\n", fColor.toBytes_RGBA(), fPaths.count());
  314. for (const auto& path : fPaths) {
  315. string.appendf("Tolerance: %.2f\n", path.fTolerance);
  316. }
  317. string += fHelper.dumpInfo();
  318. string += INHERITED::dumpInfo();
  319. return string;
  320. }
  321. #endif
  322. DefaultPathOp(const Helper::MakeArgs& helperArgs, const SkPMColor4f& color, const SkPath& path,
  323. SkScalar tolerance, uint8_t coverage, const SkMatrix& viewMatrix, bool isHairline,
  324. GrAAType aaType, const SkRect& devBounds,
  325. const GrUserStencilSettings* stencilSettings)
  326. : INHERITED(ClassID())
  327. , fHelper(helperArgs, aaType, stencilSettings)
  328. , fColor(color)
  329. , fCoverage(coverage)
  330. , fViewMatrix(viewMatrix)
  331. , fIsHairline(isHairline) {
  332. fPaths.emplace_back(PathData{path, tolerance});
  333. this->setBounds(devBounds, HasAABloat::kNo,
  334. isHairline ? IsZeroArea::kYes : IsZeroArea::kNo);
  335. }
  336. FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
  337. GrProcessorSet::Analysis finalize(
  338. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  339. GrClampType clampType) override {
  340. GrProcessorAnalysisCoverage gpCoverage =
  341. this->coverage() == 0xFF ? GrProcessorAnalysisCoverage::kNone
  342. : GrProcessorAnalysisCoverage::kSingleChannel;
  343. // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
  344. return fHelper.finalizeProcessors(
  345. caps, clip, hasMixedSampledCoverage, clampType, gpCoverage, &fColor, nullptr);
  346. }
  347. private:
  348. void onPrepareDraws(Target* target) override {
  349. sk_sp<GrGeometryProcessor> gp;
  350. {
  351. using namespace GrDefaultGeoProcFactory;
  352. Color color(this->color());
  353. Coverage coverage(this->coverage());
  354. LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
  355. : LocalCoords::kUnused_Type);
  356. gp = GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(),
  357. color,
  358. coverage,
  359. localCoords,
  360. this->viewMatrix());
  361. }
  362. SkASSERT(gp->vertexStride() == sizeof(SkPoint));
  363. int instanceCount = fPaths.count();
  364. // We avoid indices when we have a single hairline contour.
  365. bool isIndexed = !this->isHairline() || instanceCount > 1 ||
  366. PathGeoBuilder::PathHasMultipleSubpaths(fPaths[0].fPath);
  367. // determine primitiveType
  368. GrPrimitiveType primitiveType;
  369. if (this->isHairline()) {
  370. primitiveType = isIndexed ? GrPrimitiveType::kLines : GrPrimitiveType::kLineStrip;
  371. } else {
  372. primitiveType = GrPrimitiveType::kTriangles;
  373. }
  374. PathGeoBuilder pathGeoBuilder(primitiveType, target, std::move(gp));
  375. // fill buffers
  376. for (int i = 0; i < instanceCount; i++) {
  377. const PathData& args = fPaths[i];
  378. pathGeoBuilder.addPath(args.fPath, args.fTolerance);
  379. }
  380. }
  381. void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
  382. fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
  383. }
  384. CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
  385. DefaultPathOp* that = t->cast<DefaultPathOp>();
  386. if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
  387. return CombineResult::kCannotCombine;
  388. }
  389. if (this->color() != that->color()) {
  390. return CombineResult::kCannotCombine;
  391. }
  392. if (this->coverage() != that->coverage()) {
  393. return CombineResult::kCannotCombine;
  394. }
  395. if (!this->viewMatrix().cheapEqualTo(that->viewMatrix())) {
  396. return CombineResult::kCannotCombine;
  397. }
  398. if (this->isHairline() != that->isHairline()) {
  399. return CombineResult::kCannotCombine;
  400. }
  401. fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
  402. return CombineResult::kMerged;
  403. }
  404. const SkPMColor4f& color() const { return fColor; }
  405. uint8_t coverage() const { return fCoverage; }
  406. const SkMatrix& viewMatrix() const { return fViewMatrix; }
  407. bool isHairline() const { return fIsHairline; }
  408. struct PathData {
  409. SkPath fPath;
  410. SkScalar fTolerance;
  411. };
  412. SkSTArray<1, PathData, true> fPaths;
  413. Helper fHelper;
  414. SkPMColor4f fColor;
  415. uint8_t fCoverage;
  416. SkMatrix fViewMatrix;
  417. bool fIsHairline;
  418. typedef GrMeshDrawOp INHERITED;
  419. };
  420. } // anonymous namespace
  421. bool GrDefaultPathRenderer::internalDrawPath(GrRenderTargetContext* renderTargetContext,
  422. GrPaint&& paint,
  423. GrAAType aaType,
  424. const GrUserStencilSettings& userStencilSettings,
  425. const GrClip& clip,
  426. const SkMatrix& viewMatrix,
  427. const GrShape& shape,
  428. bool stencilOnly) {
  429. auto context = renderTargetContext->surfPriv().getContext();
  430. SkASSERT(GrAAType::kCoverage != aaType);
  431. SkPath path;
  432. shape.asPath(&path);
  433. SkScalar hairlineCoverage;
  434. uint8_t newCoverage = 0xff;
  435. bool isHairline = false;
  436. if (IsStrokeHairlineOrEquivalent(shape.style(), viewMatrix, &hairlineCoverage)) {
  437. newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
  438. isHairline = true;
  439. } else {
  440. SkASSERT(shape.style().isSimpleFill());
  441. }
  442. int passCount = 0;
  443. const GrUserStencilSettings* passes[2];
  444. bool reverse = false;
  445. bool lastPassIsBounds;
  446. if (isHairline) {
  447. passCount = 1;
  448. if (stencilOnly) {
  449. passes[0] = &gDirectToStencil;
  450. } else {
  451. passes[0] = &userStencilSettings;
  452. }
  453. lastPassIsBounds = false;
  454. } else {
  455. if (single_pass_shape(shape)) {
  456. passCount = 1;
  457. if (stencilOnly) {
  458. passes[0] = &gDirectToStencil;
  459. } else {
  460. passes[0] = &userStencilSettings;
  461. }
  462. lastPassIsBounds = false;
  463. } else {
  464. switch (path.getFillType()) {
  465. case SkPath::kInverseEvenOdd_FillType:
  466. reverse = true;
  467. // fallthrough
  468. case SkPath::kEvenOdd_FillType:
  469. passes[0] = &gEOStencilPass;
  470. if (stencilOnly) {
  471. passCount = 1;
  472. lastPassIsBounds = false;
  473. } else {
  474. passCount = 2;
  475. lastPassIsBounds = true;
  476. if (reverse) {
  477. passes[1] = &gInvEOColorPass;
  478. } else {
  479. passes[1] = &gEOColorPass;
  480. }
  481. }
  482. break;
  483. case SkPath::kInverseWinding_FillType:
  484. reverse = true;
  485. // fallthrough
  486. case SkPath::kWinding_FillType:
  487. passes[0] = &gWindStencilPass;
  488. passCount = 2;
  489. if (stencilOnly) {
  490. lastPassIsBounds = false;
  491. --passCount;
  492. } else {
  493. lastPassIsBounds = true;
  494. if (reverse) {
  495. passes[passCount-1] = &gInvWindColorPass;
  496. } else {
  497. passes[passCount-1] = &gWindColorPass;
  498. }
  499. }
  500. break;
  501. default:
  502. SkDEBUGFAIL("Unknown path fFill!");
  503. return false;
  504. }
  505. }
  506. }
  507. SkScalar tol = GrPathUtils::kDefaultTolerance;
  508. SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
  509. SkRect devBounds;
  510. GetPathDevBounds(path,
  511. renderTargetContext->asRenderTargetProxy()->worstCaseWidth(),
  512. renderTargetContext->asRenderTargetProxy()->worstCaseHeight(),
  513. viewMatrix, &devBounds);
  514. for (int p = 0; p < passCount; ++p) {
  515. if (lastPassIsBounds && (p == passCount-1)) {
  516. SkRect bounds;
  517. SkMatrix localMatrix = SkMatrix::I();
  518. if (reverse) {
  519. // draw over the dev bounds (which will be the whole dst surface for inv fill).
  520. bounds = devBounds;
  521. SkMatrix vmi;
  522. // mapRect through persp matrix may not be correct
  523. if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
  524. vmi.mapRect(&bounds);
  525. } else {
  526. if (!viewMatrix.invert(&localMatrix)) {
  527. return false;
  528. }
  529. }
  530. } else {
  531. bounds = path.getBounds();
  532. }
  533. const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
  534. viewMatrix;
  535. // This is a non-coverage aa rect op since we assert aaType != kCoverage at the start
  536. assert_alive(paint);
  537. renderTargetContext->priv().stencilRect(clip, passes[p], std::move(paint),
  538. GrAA(aaType == GrAAType::kMSAA), viewM, bounds, &localMatrix);
  539. } else {
  540. bool stencilPass = stencilOnly || passCount > 1;
  541. std::unique_ptr<GrDrawOp> op;
  542. if (stencilPass) {
  543. GrPaint stencilPaint;
  544. stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
  545. op = DefaultPathOp::Make(context, std::move(stencilPaint), path, srcSpaceTol,
  546. newCoverage, viewMatrix, isHairline, aaType, devBounds,
  547. passes[p]);
  548. } else {
  549. assert_alive(paint);
  550. op = DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, newCoverage,
  551. viewMatrix, isHairline, aaType, devBounds, passes[p]);
  552. }
  553. renderTargetContext->addDrawOp(clip, std::move(op));
  554. }
  555. }
  556. return true;
  557. }
  558. GrPathRenderer::CanDrawPath
  559. GrDefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
  560. bool isHairline = IsStrokeHairlineOrEquivalent(
  561. args.fShape->style(), *args.fViewMatrix, nullptr);
  562. // If we aren't a single_pass_shape or hairline, we require stencil buffers.
  563. if (!(single_pass_shape(*args.fShape) || isHairline) &&
  564. (args.fCaps->avoidStencilBuffers() || args.fTargetIsWrappedVkSecondaryCB)) {
  565. return CanDrawPath::kNo;
  566. }
  567. // If antialiasing is required, we only support MSAA.
  568. if (GrAAType::kNone != args.fAAType && GrAAType::kMSAA != args.fAAType) {
  569. return CanDrawPath::kNo;
  570. }
  571. // This can draw any path with any simple fill style.
  572. if (!args.fShape->style().isSimpleFill() && !isHairline) {
  573. return CanDrawPath::kNo;
  574. }
  575. // This is the fallback renderer for when a path is too complicated for the others to draw.
  576. return CanDrawPath::kAsBackup;
  577. }
  578. bool GrDefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
  579. GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
  580. "GrDefaultPathRenderer::onDrawPath");
  581. GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone;
  582. return this->internalDrawPath(
  583. args.fRenderTargetContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings,
  584. *args.fClip, *args.fViewMatrix, *args.fShape, false);
  585. }
  586. void GrDefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
  587. GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
  588. "GrDefaultPathRenderer::onStencilPath");
  589. SkASSERT(!args.fShape->inverseFilled());
  590. GrPaint paint;
  591. paint.setXPFactory(GrDisableColorXPFactory::Get());
  592. auto aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
  593. this->internalDrawPath(
  594. args.fRenderTargetContext, std::move(paint), aaType, GrUserStencilSettings::kUnused,
  595. *args.fClip, *args.fViewMatrix, *args.fShape, true);
  596. }
  597. ///////////////////////////////////////////////////////////////////////////////////////////////////
  598. #if GR_TEST_UTILS
  599. GR_DRAW_OP_TEST_DEFINE(DefaultPathOp) {
  600. SkMatrix viewMatrix = GrTest::TestMatrix(random);
  601. // For now just hairlines because the other types of draws require two ops.
  602. // TODO we should figure out a way to combine the stencil and cover steps into one op.
  603. GrStyle style(SkStrokeRec::kHairline_InitStyle);
  604. SkPath path = GrTest::TestPath(random);
  605. // Compute srcSpaceTol
  606. SkRect bounds = path.getBounds();
  607. SkScalar tol = GrPathUtils::kDefaultTolerance;
  608. SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
  609. viewMatrix.mapRect(&bounds);
  610. uint8_t coverage = GrRandomCoverage(random);
  611. GrAAType aaType = GrAAType::kNone;
  612. if (numSamples > 1 && random->nextBool()) {
  613. aaType = GrAAType::kMSAA;
  614. }
  615. return DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, coverage, viewMatrix,
  616. true, aaType, bounds, GrGetRandomStencil(random, context));
  617. }
  618. #endif