GrTessellatingPathRenderer.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*
  2. * Copyright 2015 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/GrTessellatingPathRenderer.h"
  8. #include <stdio.h>
  9. #include "src/core/SkGeometry.h"
  10. #include "src/gpu/GrAuditTrail.h"
  11. #include "src/gpu/GrCaps.h"
  12. #include "src/gpu/GrClip.h"
  13. #include "src/gpu/GrDefaultGeoProcFactory.h"
  14. #include "src/gpu/GrDrawOpTest.h"
  15. #include "src/gpu/GrMesh.h"
  16. #include "src/gpu/GrOpFlushState.h"
  17. #include "src/gpu/GrResourceCache.h"
  18. #include "src/gpu/GrResourceProvider.h"
  19. #include "src/gpu/GrStyle.h"
  20. #include "src/gpu/GrTessellator.h"
  21. #include "src/gpu/geometry/GrPathUtils.h"
  22. #include "src/gpu/geometry/GrShape.h"
  23. #include "src/gpu/ops/GrMeshDrawOp.h"
  24. #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
  25. #ifndef GR_AA_TESSELLATOR_MAX_VERB_COUNT
  26. #define GR_AA_TESSELLATOR_MAX_VERB_COUNT 10
  27. #endif
  28. /*
  29. * This path renderer tessellates the path into triangles using GrTessellator, uploads the
  30. * triangles to a vertex buffer, and renders them with a single draw call. It can do screenspace
  31. * antialiasing with a one-pixel coverage ramp.
  32. */
  33. namespace {
  34. struct TessInfo {
  35. SkScalar fTolerance;
  36. int fCount;
  37. };
  38. // When the SkPathRef genID changes, invalidate a corresponding GrResource described by key.
  39. class PathInvalidator : public SkPathRef::GenIDChangeListener {
  40. public:
  41. PathInvalidator(const GrUniqueKey& key, uint32_t contextUniqueID)
  42. : fMsg(key, contextUniqueID) {}
  43. private:
  44. GrUniqueKeyInvalidatedMessage fMsg;
  45. void onChange() override {
  46. SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg);
  47. }
  48. };
  49. bool cache_match(GrGpuBuffer* vertexBuffer, SkScalar tol, int* actualCount) {
  50. if (!vertexBuffer) {
  51. return false;
  52. }
  53. const SkData* data = vertexBuffer->getUniqueKey().getCustomData();
  54. SkASSERT(data);
  55. const TessInfo* info = static_cast<const TessInfo*>(data->data());
  56. if (info->fTolerance == 0 || info->fTolerance < 3.0f * tol) {
  57. *actualCount = info->fCount;
  58. return true;
  59. }
  60. return false;
  61. }
  62. class StaticVertexAllocator : public GrTessellator::VertexAllocator {
  63. public:
  64. StaticVertexAllocator(size_t stride, GrResourceProvider* resourceProvider, bool canMapVB)
  65. : VertexAllocator(stride)
  66. , fResourceProvider(resourceProvider)
  67. , fCanMapVB(canMapVB)
  68. , fVertices(nullptr) {
  69. }
  70. void* lock(int vertexCount) override {
  71. size_t size = vertexCount * stride();
  72. fVertexBuffer = fResourceProvider->createBuffer(size, GrGpuBufferType::kVertex,
  73. kStatic_GrAccessPattern);
  74. if (!fVertexBuffer.get()) {
  75. return nullptr;
  76. }
  77. if (fCanMapVB) {
  78. fVertices = fVertexBuffer->map();
  79. } else {
  80. fVertices = sk_malloc_throw(vertexCount * stride());
  81. }
  82. return fVertices;
  83. }
  84. void unlock(int actualCount) override {
  85. if (fCanMapVB) {
  86. fVertexBuffer->unmap();
  87. } else {
  88. fVertexBuffer->updateData(fVertices, actualCount * stride());
  89. sk_free(fVertices);
  90. }
  91. fVertices = nullptr;
  92. }
  93. sk_sp<GrGpuBuffer> detachVertexBuffer() { return std::move(fVertexBuffer); }
  94. private:
  95. sk_sp<GrGpuBuffer> fVertexBuffer;
  96. GrResourceProvider* fResourceProvider;
  97. bool fCanMapVB;
  98. void* fVertices;
  99. };
  100. class DynamicVertexAllocator : public GrTessellator::VertexAllocator {
  101. public:
  102. DynamicVertexAllocator(size_t stride, GrMeshDrawOp::Target* target)
  103. : VertexAllocator(stride)
  104. , fTarget(target)
  105. , fVertexBuffer(nullptr)
  106. , fVertices(nullptr) {}
  107. void* lock(int vertexCount) override {
  108. fVertexCount = vertexCount;
  109. fVertices = fTarget->makeVertexSpace(stride(), vertexCount, &fVertexBuffer, &fFirstVertex);
  110. return fVertices;
  111. }
  112. void unlock(int actualCount) override {
  113. fTarget->putBackVertices(fVertexCount - actualCount, stride());
  114. fVertices = nullptr;
  115. }
  116. sk_sp<const GrBuffer> detachVertexBuffer() const { return std::move(fVertexBuffer); }
  117. int firstVertex() const { return fFirstVertex; }
  118. private:
  119. GrMeshDrawOp::Target* fTarget;
  120. sk_sp<const GrBuffer> fVertexBuffer;
  121. int fVertexCount;
  122. int fFirstVertex;
  123. void* fVertices;
  124. };
  125. } // namespace
  126. GrTessellatingPathRenderer::GrTessellatingPathRenderer()
  127. : fMaxVerbCount(GR_AA_TESSELLATOR_MAX_VERB_COUNT) {
  128. }
  129. GrPathRenderer::CanDrawPath
  130. GrTessellatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
  131. // This path renderer can draw fill styles, and can do screenspace antialiasing via a
  132. // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
  133. // ones to simpler algorithms. We pass on paths that have styles, though they may come back
  134. // around after applying the styling information to the geometry to create a filled path.
  135. if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
  136. return CanDrawPath::kNo;
  137. }
  138. switch (args.fAAType) {
  139. case GrAAType::kNone:
  140. case GrAAType::kMSAA:
  141. // Prefer MSAA, if any antialiasing. In the non-analytic-AA case, We skip paths that
  142. // don't have a key since the real advantage of this path renderer comes from caching
  143. // the tessellated geometry.
  144. if (!args.fShape->hasUnstyledKey()) {
  145. return CanDrawPath::kNo;
  146. }
  147. break;
  148. case GrAAType::kCoverage:
  149. // Use analytic AA if we don't have MSAA. In this case, we do not cache, so we accept
  150. // paths without keys.
  151. SkPath path;
  152. args.fShape->asPath(&path);
  153. if (path.countVerbs() > fMaxVerbCount) {
  154. return CanDrawPath::kNo;
  155. }
  156. break;
  157. }
  158. return CanDrawPath::kYes;
  159. }
  160. namespace {
  161. class TessellatingPathOp final : public GrMeshDrawOp {
  162. private:
  163. using Helper = GrSimpleMeshDrawOpHelperWithStencil;
  164. public:
  165. DEFINE_OP_CLASS_ID
  166. static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
  167. GrPaint&& paint,
  168. const GrShape& shape,
  169. const SkMatrix& viewMatrix,
  170. SkIRect devClipBounds,
  171. GrAAType aaType,
  172. const GrUserStencilSettings* stencilSettings) {
  173. return Helper::FactoryHelper<TessellatingPathOp>(context, std::move(paint), shape,
  174. viewMatrix, devClipBounds,
  175. aaType, stencilSettings);
  176. }
  177. const char* name() const override { return "TessellatingPathOp"; }
  178. void visitProxies(const VisitProxyFunc& func) const override {
  179. fHelper.visitProxies(func);
  180. }
  181. #ifdef SK_DEBUG
  182. SkString dumpInfo() const override {
  183. SkString string;
  184. string.appendf("Color 0x%08x, aa: %d\n", fColor.toBytes_RGBA(), fAntiAlias);
  185. string += fHelper.dumpInfo();
  186. string += INHERITED::dumpInfo();
  187. return string;
  188. }
  189. #endif
  190. TessellatingPathOp(Helper::MakeArgs helperArgs,
  191. const SkPMColor4f& color,
  192. const GrShape& shape,
  193. const SkMatrix& viewMatrix,
  194. const SkIRect& devClipBounds,
  195. GrAAType aaType,
  196. const GrUserStencilSettings* stencilSettings)
  197. : INHERITED(ClassID())
  198. , fHelper(helperArgs, aaType, stencilSettings)
  199. , fColor(color)
  200. , fShape(shape)
  201. , fViewMatrix(viewMatrix)
  202. , fDevClipBounds(devClipBounds)
  203. , fAntiAlias(GrAAType::kCoverage == aaType) {
  204. SkRect devBounds;
  205. viewMatrix.mapRect(&devBounds, shape.bounds());
  206. if (shape.inverseFilled()) {
  207. // Because the clip bounds are used to add a contour for inverse fills, they must also
  208. // include the path bounds.
  209. devBounds.join(SkRect::Make(fDevClipBounds));
  210. }
  211. this->setBounds(devBounds, HasAABloat::kNo, IsZeroArea::kNo);
  212. }
  213. FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
  214. GrProcessorSet::Analysis finalize(
  215. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  216. GrClampType clampType) override {
  217. GrProcessorAnalysisCoverage coverage = fAntiAlias
  218. ? GrProcessorAnalysisCoverage::kSingleChannel
  219. : GrProcessorAnalysisCoverage::kNone;
  220. // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
  221. return fHelper.finalizeProcessors(
  222. caps, clip, hasMixedSampledCoverage, clampType, coverage, &fColor, nullptr);
  223. }
  224. private:
  225. SkPath getPath() const {
  226. SkASSERT(!fShape.style().applies());
  227. SkPath path;
  228. fShape.asPath(&path);
  229. return path;
  230. }
  231. void draw(Target* target, sk_sp<const GrGeometryProcessor> gp, size_t vertexStride) {
  232. SkASSERT(!fAntiAlias);
  233. GrResourceProvider* rp = target->resourceProvider();
  234. bool inverseFill = fShape.inverseFilled();
  235. // construct a cache key from the path's genID and the view matrix
  236. static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
  237. GrUniqueKey key;
  238. static constexpr int kClipBoundsCnt = sizeof(fDevClipBounds) / sizeof(uint32_t);
  239. int shapeKeyDataCnt = fShape.unstyledKeySize();
  240. SkASSERT(shapeKeyDataCnt >= 0);
  241. GrUniqueKey::Builder builder(&key, kDomain, shapeKeyDataCnt + kClipBoundsCnt, "Path");
  242. fShape.writeUnstyledKey(&builder[0]);
  243. // For inverse fills, the tessellation is dependent on clip bounds.
  244. if (inverseFill) {
  245. memcpy(&builder[shapeKeyDataCnt], &fDevClipBounds, sizeof(fDevClipBounds));
  246. } else {
  247. memset(&builder[shapeKeyDataCnt], 0, sizeof(fDevClipBounds));
  248. }
  249. builder.finish();
  250. sk_sp<GrGpuBuffer> cachedVertexBuffer(rp->findByUniqueKey<GrGpuBuffer>(key));
  251. int actualCount;
  252. SkScalar tol = GrPathUtils::kDefaultTolerance;
  253. tol = GrPathUtils::scaleToleranceToSrc(tol, fViewMatrix, fShape.bounds());
  254. if (cache_match(cachedVertexBuffer.get(), tol, &actualCount)) {
  255. this->drawVertices(target, std::move(gp), std::move(cachedVertexBuffer), 0,
  256. actualCount);
  257. return;
  258. }
  259. SkRect clipBounds = SkRect::Make(fDevClipBounds);
  260. SkMatrix vmi;
  261. if (!fViewMatrix.invert(&vmi)) {
  262. return;
  263. }
  264. vmi.mapRect(&clipBounds);
  265. bool isLinear;
  266. bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
  267. StaticVertexAllocator allocator(vertexStride, rp, canMapVB);
  268. int count = GrTessellator::PathToTriangles(getPath(), tol, clipBounds, &allocator, false,
  269. &isLinear);
  270. if (count == 0) {
  271. return;
  272. }
  273. sk_sp<GrGpuBuffer> vb = allocator.detachVertexBuffer();
  274. TessInfo info;
  275. info.fTolerance = isLinear ? 0 : tol;
  276. info.fCount = count;
  277. fShape.addGenIDChangeListener(sk_make_sp<PathInvalidator>(key, target->contextUniqueID()));
  278. key.setCustomData(SkData::MakeWithCopy(&info, sizeof(info)));
  279. rp->assignUniqueKeyToResource(key, vb.get());
  280. this->drawVertices(target, std::move(gp), std::move(vb), 0, count);
  281. }
  282. void drawAA(Target* target, sk_sp<const GrGeometryProcessor> gp, size_t vertexStride) {
  283. SkASSERT(fAntiAlias);
  284. SkPath path = getPath();
  285. if (path.isEmpty()) {
  286. return;
  287. }
  288. SkRect clipBounds = SkRect::Make(fDevClipBounds);
  289. path.transform(fViewMatrix);
  290. SkScalar tol = GrPathUtils::kDefaultTolerance;
  291. bool isLinear;
  292. DynamicVertexAllocator allocator(vertexStride, target);
  293. int count = GrTessellator::PathToTriangles(path, tol, clipBounds, &allocator, true,
  294. &isLinear);
  295. if (count == 0) {
  296. return;
  297. }
  298. this->drawVertices(target, std::move(gp), allocator.detachVertexBuffer(),
  299. allocator.firstVertex(), count);
  300. }
  301. void onPrepareDraws(Target* target) override {
  302. sk_sp<GrGeometryProcessor> gp;
  303. {
  304. using namespace GrDefaultGeoProcFactory;
  305. Color color(fColor);
  306. LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
  307. ? LocalCoords::kUsePosition_Type
  308. : LocalCoords::kUnused_Type;
  309. Coverage::Type coverageType;
  310. if (fAntiAlias) {
  311. if (fHelper.compatibleWithCoverageAsAlpha()) {
  312. coverageType = Coverage::kAttributeTweakAlpha_Type;
  313. } else {
  314. coverageType = Coverage::kAttribute_Type;
  315. }
  316. } else {
  317. coverageType = Coverage::kSolid_Type;
  318. }
  319. if (fAntiAlias) {
  320. gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(target->caps().shaderCaps(),
  321. color, coverageType,
  322. localCoordsType, fViewMatrix);
  323. } else {
  324. gp = GrDefaultGeoProcFactory::Make(target->caps().shaderCaps(),
  325. color, coverageType, localCoordsType,
  326. fViewMatrix);
  327. }
  328. }
  329. if (!gp.get()) {
  330. return;
  331. }
  332. size_t vertexStride = gp->vertexStride();
  333. if (fAntiAlias) {
  334. this->drawAA(target, std::move(gp), vertexStride);
  335. } else {
  336. this->draw(target, std::move(gp), vertexStride);
  337. }
  338. }
  339. void drawVertices(Target* target, sk_sp<const GrGeometryProcessor> gp, sk_sp<const GrBuffer> vb,
  340. int firstVertex, int count) {
  341. GrMesh* mesh = target->allocMesh(TESSELLATOR_WIREFRAME ? GrPrimitiveType::kLines
  342. : GrPrimitiveType::kTriangles);
  343. mesh->setNonIndexedNonInstanced(count);
  344. mesh->setVertexData(std::move(vb), firstVertex);
  345. target->recordDraw(std::move(gp), mesh);
  346. }
  347. void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
  348. fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
  349. }
  350. Helper fHelper;
  351. SkPMColor4f fColor;
  352. GrShape fShape;
  353. SkMatrix fViewMatrix;
  354. SkIRect fDevClipBounds;
  355. bool fAntiAlias;
  356. typedef GrMeshDrawOp INHERITED;
  357. };
  358. } // anonymous namespace
  359. bool GrTessellatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
  360. GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
  361. "GrTessellatingPathRenderer::onDrawPath");
  362. SkIRect clipBoundsI;
  363. args.fClip->getConservativeBounds(args.fRenderTargetContext->width(),
  364. args.fRenderTargetContext->height(),
  365. &clipBoundsI);
  366. std::unique_ptr<GrDrawOp> op = TessellatingPathOp::Make(
  367. args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix, clipBoundsI,
  368. args.fAAType, args.fUserStencilSettings);
  369. args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
  370. return true;
  371. }
  372. ///////////////////////////////////////////////////////////////////////////////////////////////////
  373. #if GR_TEST_UTILS
  374. GR_DRAW_OP_TEST_DEFINE(TesselatingPathOp) {
  375. SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
  376. SkPath path = GrTest::TestPath(random);
  377. SkIRect devClipBounds = SkIRect::MakeLTRB(
  378. random->nextU(), random->nextU(), random->nextU(), random->nextU());
  379. devClipBounds.sort();
  380. static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kMSAA, GrAAType::kCoverage};
  381. GrAAType aaType;
  382. do {
  383. aaType = kAATypes[random->nextULessThan(SK_ARRAY_COUNT(kAATypes))];
  384. } while(GrAAType::kMSAA == aaType && numSamples <= 1);
  385. GrStyle style;
  386. do {
  387. GrTest::TestStyle(random, &style);
  388. } while (!style.isSimpleFill());
  389. GrShape shape(path, style);
  390. return TessellatingPathOp::Make(context, std::move(paint), shape, viewMatrix, devClipBounds,
  391. aaType, GrGetRandomStencil(random, context));
  392. }
  393. #endif