GrAALinearizingConvexPathRenderer.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392
  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 "include/core/SkString.h"
  8. #include "src/core/SkGeometry.h"
  9. #include "src/core/SkPathPriv.h"
  10. #include "src/core/SkTraceEvent.h"
  11. #include "src/gpu/GrAuditTrail.h"
  12. #include "src/gpu/GrCaps.h"
  13. #include "src/gpu/GrDefaultGeoProcFactory.h"
  14. #include "src/gpu/GrDrawOpTest.h"
  15. #include "src/gpu/GrGeometryProcessor.h"
  16. #include "src/gpu/GrOpFlushState.h"
  17. #include "src/gpu/GrProcessor.h"
  18. #include "src/gpu/GrRenderTargetContext.h"
  19. #include "src/gpu/GrStyle.h"
  20. #include "src/gpu/GrVertexWriter.h"
  21. #include "src/gpu/geometry/GrPathUtils.h"
  22. #include "src/gpu/geometry/GrShape.h"
  23. #include "src/gpu/glsl/GrGLSLGeometryProcessor.h"
  24. #include "src/gpu/ops/GrAAConvexTessellator.h"
  25. #include "src/gpu/ops/GrAALinearizingConvexPathRenderer.h"
  26. #include "src/gpu/ops/GrMeshDrawOp.h"
  27. #include "src/gpu/ops/GrSimpleMeshDrawOpHelper.h"
  28. static const int DEFAULT_BUFFER_SIZE = 100;
  29. // The thicker the stroke, the harder it is to produce high-quality results using tessellation. For
  30. // the time being, we simply drop back to software rendering above this stroke width.
  31. static const SkScalar kMaxStrokeWidth = 20.0;
  32. GrAALinearizingConvexPathRenderer::GrAALinearizingConvexPathRenderer() {
  33. }
  34. ///////////////////////////////////////////////////////////////////////////////
  35. GrPathRenderer::CanDrawPath
  36. GrAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
  37. if (GrAAType::kCoverage != args.fAAType) {
  38. return CanDrawPath::kNo;
  39. }
  40. if (!args.fShape->knownToBeConvex()) {
  41. return CanDrawPath::kNo;
  42. }
  43. if (args.fShape->style().pathEffect()) {
  44. return CanDrawPath::kNo;
  45. }
  46. if (args.fShape->inverseFilled()) {
  47. return CanDrawPath::kNo;
  48. }
  49. if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) {
  50. // Stroked zero length lines should draw, but this PR doesn't handle that case
  51. return CanDrawPath::kNo;
  52. }
  53. const SkStrokeRec& stroke = args.fShape->style().strokeRec();
  54. if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
  55. stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
  56. if (!args.fViewMatrix->isSimilarity()) {
  57. return CanDrawPath::kNo;
  58. }
  59. SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
  60. if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
  61. return CanDrawPath::kNo;
  62. }
  63. if (strokeWidth > kMaxStrokeWidth ||
  64. !args.fShape->knownToBeClosed() ||
  65. stroke.getJoin() == SkPaint::Join::kRound_Join) {
  66. return CanDrawPath::kNo;
  67. }
  68. return CanDrawPath::kYes;
  69. }
  70. if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
  71. return CanDrawPath::kNo;
  72. }
  73. return CanDrawPath::kYes;
  74. }
  75. // extract the result vertices and indices from the GrAAConvexTessellator
  76. static void extract_verts(const GrAAConvexTessellator& tess,
  77. void* vertData,
  78. const GrVertexColor& color,
  79. uint16_t firstIndex,
  80. uint16_t* idxs) {
  81. GrVertexWriter verts{vertData};
  82. for (int i = 0; i < tess.numPts(); ++i) {
  83. verts.write(tess.point(i), color, tess.coverage(i));
  84. }
  85. for (int i = 0; i < tess.numIndices(); ++i) {
  86. idxs[i] = tess.index(i) + firstIndex;
  87. }
  88. }
  89. static sk_sp<GrGeometryProcessor> create_lines_only_gp(const GrShaderCaps* shaderCaps,
  90. bool tweakAlphaForCoverage,
  91. const SkMatrix& viewMatrix,
  92. bool usesLocalCoords,
  93. bool wideColor) {
  94. using namespace GrDefaultGeoProcFactory;
  95. Coverage::Type coverageType =
  96. tweakAlphaForCoverage ? Coverage::kAttributeTweakAlpha_Type : Coverage::kAttribute_Type;
  97. LocalCoords::Type localCoordsType =
  98. usesLocalCoords ? LocalCoords::kUsePosition_Type : LocalCoords::kUnused_Type;
  99. Color::Type colorType =
  100. wideColor ? Color::kPremulWideColorAttribute_Type : Color::kPremulGrColorAttribute_Type;
  101. return MakeForDeviceSpace(shaderCaps, colorType, coverageType, localCoordsType, viewMatrix);
  102. }
  103. namespace {
  104. class AAFlatteningConvexPathOp final : public GrMeshDrawOp {
  105. private:
  106. using Helper = GrSimpleMeshDrawOpHelperWithStencil;
  107. public:
  108. DEFINE_OP_CLASS_ID
  109. static std::unique_ptr<GrDrawOp> Make(GrRecordingContext* context,
  110. GrPaint&& paint,
  111. const SkMatrix& viewMatrix,
  112. const SkPath& path,
  113. SkScalar strokeWidth,
  114. SkStrokeRec::Style style,
  115. SkPaint::Join join,
  116. SkScalar miterLimit,
  117. const GrUserStencilSettings* stencilSettings) {
  118. return Helper::FactoryHelper<AAFlatteningConvexPathOp>(context, std::move(paint),
  119. viewMatrix, path,
  120. strokeWidth, style, join, miterLimit,
  121. stencilSettings);
  122. }
  123. AAFlatteningConvexPathOp(const Helper::MakeArgs& helperArgs,
  124. const SkPMColor4f& color,
  125. const SkMatrix& viewMatrix,
  126. const SkPath& path,
  127. SkScalar strokeWidth,
  128. SkStrokeRec::Style style,
  129. SkPaint::Join join,
  130. SkScalar miterLimit,
  131. const GrUserStencilSettings* stencilSettings)
  132. : INHERITED(ClassID()), fHelper(helperArgs, GrAAType::kCoverage, stencilSettings) {
  133. fPaths.emplace_back(
  134. PathData{color, viewMatrix, path, strokeWidth, style, join, miterLimit});
  135. // compute bounds
  136. SkRect bounds = path.getBounds();
  137. SkScalar w = strokeWidth;
  138. if (w > 0) {
  139. w /= 2;
  140. // If the half stroke width is < 1 then we effectively fallback to bevel joins.
  141. if (SkPaint::kMiter_Join == join && w > 1.f) {
  142. w *= miterLimit;
  143. }
  144. bounds.outset(w, w);
  145. }
  146. this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kYes, IsZeroArea::kNo);
  147. }
  148. const char* name() const override { return "AAFlatteningConvexPathOp"; }
  149. void visitProxies(const VisitProxyFunc& func) const override {
  150. fHelper.visitProxies(func);
  151. }
  152. #ifdef SK_DEBUG
  153. SkString dumpInfo() const override {
  154. SkString string;
  155. for (const auto& path : fPaths) {
  156. string.appendf(
  157. "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, "
  158. "MiterLimit: %.2f\n",
  159. path.fColor.toBytes_RGBA(), path.fStrokeWidth, path.fStyle, path.fJoin,
  160. path.fMiterLimit);
  161. }
  162. string += fHelper.dumpInfo();
  163. string += INHERITED::dumpInfo();
  164. return string;
  165. }
  166. #endif
  167. FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
  168. GrProcessorSet::Analysis finalize(
  169. const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
  170. GrClampType clampType) override {
  171. return fHelper.finalizeProcessors(
  172. caps, clip, hasMixedSampledCoverage, clampType,
  173. GrProcessorAnalysisCoverage::kSingleChannel, &fPaths.back().fColor, &fWideColor);
  174. }
  175. private:
  176. void recordDraw(Target* target, sk_sp<const GrGeometryProcessor> gp, int vertexCount,
  177. size_t vertexStride, void* vertices, int indexCount, uint16_t* indices) const {
  178. if (vertexCount == 0 || indexCount == 0) {
  179. return;
  180. }
  181. sk_sp<const GrBuffer> vertexBuffer;
  182. int firstVertex;
  183. void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
  184. &firstVertex);
  185. if (!verts) {
  186. SkDebugf("Could not allocate vertices\n");
  187. return;
  188. }
  189. memcpy(verts, vertices, vertexCount * vertexStride);
  190. sk_sp<const GrBuffer> indexBuffer;
  191. int firstIndex;
  192. uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
  193. if (!idxs) {
  194. SkDebugf("Could not allocate indices\n");
  195. return;
  196. }
  197. memcpy(idxs, indices, indexCount * sizeof(uint16_t));
  198. GrMesh* mesh = target->allocMesh(GrPrimitiveType::kTriangles);
  199. mesh->setIndexed(std::move(indexBuffer), indexCount, firstIndex, 0, vertexCount - 1,
  200. GrPrimitiveRestart::kNo);
  201. mesh->setVertexData(std::move(vertexBuffer), firstVertex);
  202. target->recordDraw(std::move(gp), mesh);
  203. }
  204. void onPrepareDraws(Target* target) override {
  205. // Setup GrGeometryProcessor
  206. sk_sp<GrGeometryProcessor> gp(create_lines_only_gp(target->caps().shaderCaps(),
  207. fHelper.compatibleWithCoverageAsAlpha(),
  208. this->viewMatrix(),
  209. fHelper.usesLocalCoords(),
  210. fWideColor));
  211. if (!gp) {
  212. SkDebugf("Couldn't create a GrGeometryProcessor\n");
  213. return;
  214. }
  215. size_t vertexStride = gp->vertexStride();
  216. int instanceCount = fPaths.count();
  217. int64_t vertexCount = 0;
  218. int64_t indexCount = 0;
  219. int64_t maxVertices = DEFAULT_BUFFER_SIZE;
  220. int64_t maxIndices = DEFAULT_BUFFER_SIZE;
  221. uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
  222. uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
  223. for (int i = 0; i < instanceCount; i++) {
  224. const PathData& args = fPaths[i];
  225. GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth,
  226. args.fJoin, args.fMiterLimit);
  227. if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
  228. continue;
  229. }
  230. int currentVertices = tess.numPts();
  231. if (vertexCount + currentVertices > static_cast<int>(UINT16_MAX)) {
  232. // if we added the current instance, we would overflow the indices we can store in a
  233. // uint16_t. Draw what we've got so far and reset.
  234. this->recordDraw(
  235. target, gp, vertexCount, vertexStride, vertices, indexCount, indices);
  236. vertexCount = 0;
  237. indexCount = 0;
  238. }
  239. if (vertexCount + currentVertices > maxVertices) {
  240. maxVertices = SkTMax(vertexCount + currentVertices, maxVertices * 2);
  241. if (maxVertices * vertexStride > SK_MaxS32) {
  242. sk_free(vertices);
  243. sk_free(indices);
  244. return;
  245. }
  246. vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
  247. }
  248. int currentIndices = tess.numIndices();
  249. if (indexCount + currentIndices > maxIndices) {
  250. maxIndices = SkTMax(indexCount + currentIndices, maxIndices * 2);
  251. if (maxIndices * sizeof(uint16_t) > SK_MaxS32) {
  252. sk_free(vertices);
  253. sk_free(indices);
  254. return;
  255. }
  256. indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
  257. }
  258. extract_verts(tess, vertices + vertexStride * vertexCount,
  259. GrVertexColor(args.fColor, fWideColor), vertexCount,
  260. indices + indexCount);
  261. vertexCount += currentVertices;
  262. indexCount += currentIndices;
  263. }
  264. if (vertexCount <= SK_MaxS32 && indexCount <= SK_MaxS32) {
  265. this->recordDraw(target, std::move(gp), vertexCount, vertexStride, vertices, indexCount,
  266. indices);
  267. }
  268. sk_free(vertices);
  269. sk_free(indices);
  270. }
  271. void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
  272. fHelper.executeDrawsAndUploads(this, flushState, chainBounds);
  273. }
  274. CombineResult onCombineIfPossible(GrOp* t, const GrCaps& caps) override {
  275. AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
  276. if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
  277. return CombineResult::kCannotCombine;
  278. }
  279. fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
  280. fWideColor |= that->fWideColor;
  281. return CombineResult::kMerged;
  282. }
  283. const SkMatrix& viewMatrix() const { return fPaths[0].fViewMatrix; }
  284. struct PathData {
  285. SkPMColor4f fColor;
  286. SkMatrix fViewMatrix;
  287. SkPath fPath;
  288. SkScalar fStrokeWidth;
  289. SkStrokeRec::Style fStyle;
  290. SkPaint::Join fJoin;
  291. SkScalar fMiterLimit;
  292. };
  293. SkSTArray<1, PathData, true> fPaths;
  294. Helper fHelper;
  295. bool fWideColor;
  296. typedef GrMeshDrawOp INHERITED;
  297. };
  298. } // anonymous namespace
  299. bool GrAALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
  300. GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
  301. "GrAALinearizingConvexPathRenderer::onDrawPath");
  302. SkASSERT(args.fRenderTargetContext->numSamples() <= 1);
  303. SkASSERT(!args.fShape->isEmpty());
  304. SkASSERT(!args.fShape->style().pathEffect());
  305. SkPath path;
  306. args.fShape->asPath(&path);
  307. bool fill = args.fShape->style().isSimpleFill();
  308. const SkStrokeRec& stroke = args.fShape->style().strokeRec();
  309. SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
  310. SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
  311. SkScalar miterLimit = stroke.getMiter();
  312. std::unique_ptr<GrDrawOp> op = AAFlatteningConvexPathOp::Make(
  313. args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth,
  314. stroke.getStyle(), join, miterLimit, args.fUserStencilSettings);
  315. args.fRenderTargetContext->addDrawOp(*args.fClip, std::move(op));
  316. return true;
  317. }
  318. ///////////////////////////////////////////////////////////////////////////////////////////////////
  319. #if GR_TEST_UTILS
  320. GR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
  321. SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
  322. SkPath path = GrTest::TestPathConvex(random);
  323. SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style,
  324. SkStrokeRec::kStroke_Style,
  325. SkStrokeRec::kStrokeAndFill_Style };
  326. SkStrokeRec::Style style = styles[random->nextU() % 3];
  327. SkScalar strokeWidth = -1.f;
  328. SkPaint::Join join = SkPaint::kMiter_Join;
  329. SkScalar miterLimit = 0.5f;
  330. if (SkStrokeRec::kFill_Style != style) {
  331. strokeWidth = random->nextRangeF(1.0f, 10.0f);
  332. if (random->nextBool()) {
  333. join = SkPaint::kMiter_Join;
  334. } else {
  335. join = SkPaint::kBevel_Join;
  336. }
  337. miterLimit = random->nextRangeF(0.5f, 2.0f);
  338. }
  339. const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context);
  340. return AAFlatteningConvexPathOp::Make(context, std::move(paint), viewMatrix, path, strokeWidth,
  341. style, join, miterLimit, stencilSettings);
  342. }
  343. #endif