blob: c598461b96802cf30bb82a5f1af760f065921e00 [file] [log] [blame]
senorblancod6ed19c2015-02-26 06:58:17 -08001/*
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
Chris Dalton17dc4182020-03-25 16:18:16 -06008#include "src/gpu/ops/GrTriangulatingPathRenderer.h"
Brian Salomon71fe9452020-03-02 16:59:40 -05009
10#include "include/private/SkIDChangeListener.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050011#include "src/core/SkGeometry.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040012#include "src/gpu/GrAuditTrail.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050013#include "src/gpu/GrCaps.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/gpu/GrDefaultGeoProcFactory.h"
15#include "src/gpu/GrDrawOpTest.h"
Chris Daltond081dce2020-01-23 12:09:04 -070016#include "src/gpu/GrEagerVertexAllocator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050017#include "src/gpu/GrOpFlushState.h"
Robert Phillips740d34f2020-03-11 09:36:13 -040018#include "src/gpu/GrProgramInfo.h"
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040019#include "src/gpu/GrRecordingContextPriv.h"
Michael Ludwig7c12e282020-05-29 09:54:07 -040020#include "src/gpu/GrRenderTargetContext.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050021#include "src/gpu/GrResourceCache.h"
22#include "src/gpu/GrResourceProvider.h"
Chris Daltoneb694b72020-03-16 09:25:50 -060023#include "src/gpu/GrSimpleMesh.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050024#include "src/gpu/GrStyle.h"
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040025#include "src/gpu/GrThreadSafeCache.h"
Chris Dalton17dc4182020-03-25 16:18:16 -060026#include "src/gpu/GrTriangulator.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040027#include "src/gpu/geometry/GrPathUtils.h"
Michael Ludwig2686d692020-04-17 20:21:37 +000028#include "src/gpu/geometry/GrStyledShape.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050029#include "src/gpu/ops/GrMeshDrawOp.h"
Robert Phillips55f681f2020-02-28 08:58:15 -050030#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
joshualitt74417822015-08-07 11:42:16 -070031
Chris Dalton17dc4182020-03-25 16:18:16 -060032#include <cstdio>
Brian Salomon71fe9452020-03-02 16:59:40 -050033
Stephen Whitea7701e02018-01-23 15:35:05 -050034#ifndef GR_AA_TESSELLATOR_MAX_VERB_COUNT
35#define GR_AA_TESSELLATOR_MAX_VERB_COUNT 10
36#endif
37
senorblancod6ed19c2015-02-26 06:58:17 -080038/*
Chris Dalton17dc4182020-03-25 16:18:16 -060039 * This path renderer linearizes and decomposes the path into triangles using GrTriangulator,
40 * uploads the triangles to a vertex buffer, and renders them with a single draw call. It can do
41 * screenspace antialiasing with a one-pixel coverage ramp.
senorblancod6ed19c2015-02-26 06:58:17 -080042 */
senorblancod6ed19c2015-02-26 06:58:17 -080043namespace {
44
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040045// The TessInfo struct contains ancillary data not specifically required for the triangle
46// data (which is stored in a GrThreadSafeCache::VertexData object).
47// The 'fNumVertices' field is a temporary exception. It is still needed to support the
48// AA triangulated path case - which doesn't use the GrThreadSafeCache nor the VertexData object).
49// When there is an associated VertexData, its numVertices should always match the TessInfo's
50// value.
senorblanco84cd6212015-08-04 10:01:58 -070051struct TessInfo {
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040052 int fNumVertices;
53 int fNumCountedCurves;
senorblanco84cd6212015-08-04 10:01:58 -070054 SkScalar fTolerance;
senorblanco84cd6212015-08-04 10:01:58 -070055};
56
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040057static sk_sp<SkData> create_data(int numVertices, int numCountedCurves, SkScalar tol) {
58 TessInfo info { numVertices, numCountedCurves, tol };
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040059 return SkData::MakeWithCopy(&info, sizeof(info));
60}
61
Robert Phillipsf9a1b822020-11-02 11:40:00 -050062// TODO: remove 'actualNumVertices' and 'actualNumCountedCurves' in a follow up CL
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040063bool cache_match(const SkData* data, SkScalar tol,
64 int* actualNumVertices, int* actualNumCountedCurves) {
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040065 SkASSERT(data);
66
67 const TessInfo* info = static_cast<const TessInfo*>(data->data());
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040068 if (info->fNumCountedCurves == 0 || info->fTolerance < 3.0f * tol) {
69 if (actualNumVertices) {
70 *actualNumVertices = info->fNumVertices;
71 }
72 if (actualNumCountedCurves) {
73 *actualNumCountedCurves = info->fNumCountedCurves;
74 }
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040075 return true;
76 }
77 return false;
78}
79
Robert Phillipsf9a1b822020-11-02 11:40:00 -050080// Should 'challenger' replace 'incumbent' in the cache if there is a collision?
81bool is_newer_better(SkData* incumbent, SkData* challenger) {
82 const TessInfo* i = static_cast<const TessInfo*>(incumbent->data());
83 const TessInfo* c = static_cast<const TessInfo*>(challenger->data());
84
85 if (i->fNumCountedCurves == 0 || i->fTolerance <= c->fTolerance) {
86 return false; // prefer the incumbent
87 }
88
89 return true;
90}
91
ethannicholase9709e82016-01-07 13:34:16 -080092// When the SkPathRef genID changes, invalidate a corresponding GrResource described by key.
Brian Salomon99a813c2020-03-02 12:50:47 -050093class UniqueKeyInvalidator : public SkIDChangeListener {
ethannicholase9709e82016-01-07 13:34:16 -080094public:
Brian Salomon99a813c2020-03-02 12:50:47 -050095 UniqueKeyInvalidator(const GrUniqueKey& key, uint32_t contextUniqueID)
Robert Phillipsf9a1b822020-11-02 11:40:00 -050096 : fMsg(key, contextUniqueID, /* inThreadSafeCache */ true) {}
Brian Salomon238069b2018-07-11 15:58:57 -040097
ethannicholase9709e82016-01-07 13:34:16 -080098private:
99 GrUniqueKeyInvalidatedMessage fMsg;
100
Brian Salomon99a813c2020-03-02 12:50:47 -0500101 void changed() override { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
ethannicholase9709e82016-01-07 13:34:16 -0800102};
103
Chris Daltond081dce2020-01-23 12:09:04 -0700104class StaticVertexAllocator : public GrEagerVertexAllocator {
senorblanco6599eff2016-03-10 08:38:45 -0800105public:
Chris Daltond081dce2020-01-23 12:09:04 -0700106 StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB)
Robert Phillips6ffcb232020-10-14 12:40:13 -0400107 : fResourceProvider(resourceProvider)
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500108 , fCanMapVB(canMapVB) {
senorblanco6599eff2016-03-10 08:38:45 -0800109 }
Robert Phillips6ffcb232020-10-14 12:40:13 -0400110
Chris Daltond081dce2020-01-23 12:09:04 -0700111#ifdef SK_DEBUG
112 ~StaticVertexAllocator() override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500113 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData);
Chris Daltond081dce2020-01-23 12:09:04 -0700114 }
115#endif
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500116
Chris Daltond081dce2020-01-23 12:09:04 -0700117 void* lock(size_t stride, int eagerCount) override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500118 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData);
119 SkASSERT(stride && eagerCount);
120
Chris Daltond081dce2020-01-23 12:09:04 -0700121 size_t size = eagerCount * stride;
Brian Salomonae64c192019-02-05 09:41:37 -0500122 fVertexBuffer = fResourceProvider->createBuffer(size, GrGpuBufferType::kVertex,
Brian Salomondbf70722019-02-07 11:31:24 -0500123 kStatic_GrAccessPattern);
John Stilesa008b0f2020-08-16 08:48:02 -0400124 if (!fVertexBuffer) {
senorblanco6599eff2016-03-10 08:38:45 -0800125 return nullptr;
126 }
127 if (fCanMapVB) {
senorblancof57372d2016-08-31 10:36:19 -0700128 fVertices = fVertexBuffer->map();
senorblanco6599eff2016-03-10 08:38:45 -0800129 } else {
Chris Daltond081dce2020-01-23 12:09:04 -0700130 fVertices = sk_malloc_throw(eagerCount * stride);
senorblanco6599eff2016-03-10 08:38:45 -0800131 }
Chris Daltond081dce2020-01-23 12:09:04 -0700132 fLockStride = stride;
senorblanco6599eff2016-03-10 08:38:45 -0800133 return fVertices;
134 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500135
senorblanco6599eff2016-03-10 08:38:45 -0800136 void unlock(int actualCount) override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500137 SkASSERT(fLockStride && fVertices && fVertexBuffer && !fVertexData);
138
senorblanco6599eff2016-03-10 08:38:45 -0800139 if (fCanMapVB) {
140 fVertexBuffer->unmap();
141 } else {
Chris Daltond081dce2020-01-23 12:09:04 -0700142 fVertexBuffer->updateData(fVertices, actualCount * fLockStride);
senorblancof57372d2016-08-31 10:36:19 -0700143 sk_free(fVertices);
senorblanco6599eff2016-03-10 08:38:45 -0800144 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500145
146 fVertexData = GrThreadSafeCache::MakeVertexData(std::move(fVertexBuffer),
147 actualCount, fLockStride);
148
senorblanco6599eff2016-03-10 08:38:45 -0800149 fVertices = nullptr;
Chris Daltond081dce2020-01-23 12:09:04 -0700150 fLockStride = 0;
senorblanco6599eff2016-03-10 08:38:45 -0800151 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500152
153 sk_sp<GrThreadSafeCache::VertexData> detachVertexData() {
154 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && fVertexData);
155
156 return std::move(fVertexData);
157 }
Brian Salomon12d22642019-01-29 14:38:50 -0500158
senorblanco6599eff2016-03-10 08:38:45 -0800159private:
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500160 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
Brian Salomondbf70722019-02-07 11:31:24 -0500161 sk_sp<GrGpuBuffer> fVertexBuffer;
senorblanco6599eff2016-03-10 08:38:45 -0800162 GrResourceProvider* fResourceProvider;
163 bool fCanMapVB;
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500164 void* fVertices = nullptr;
165 size_t fLockStride = 0;
166};
167
168class CpuVertexAllocator : public GrEagerVertexAllocator {
169public:
170 CpuVertexAllocator() = default;
171
172#ifdef SK_DEBUG
173 ~CpuVertexAllocator() override {
174 SkASSERT(!fLockStride && !fVertices && !fVertexData);
175 }
176#endif
177
178 void* lock(size_t stride, int eagerCount) override {
179 SkASSERT(!fLockStride && !fVertices && !fVertexData);
180 SkASSERT(stride && eagerCount);
181
182 fVertices = sk_malloc_throw(eagerCount * stride);
183 fLockStride = stride;
184
185 return fVertices;
186 }
187
188 void unlock(int actualCount) override {
189 SkASSERT(fLockStride && fVertices && !fVertexData);
190
191 fVertices = sk_realloc_throw(fVertices, actualCount * fLockStride);
192
193 fVertexData = GrThreadSafeCache::MakeVertexData(fVertices, actualCount, fLockStride);
194
195 fVertices = nullptr;
196 fLockStride = 0;
197 }
198
199 sk_sp<GrThreadSafeCache::VertexData> detachVertexData() {
200 SkASSERT(!fLockStride && !fVertices && fVertexData);
201
202 return std::move(fVertexData);
203 }
204
205private:
206 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
207
208 void* fVertices = nullptr;
Chris Daltond081dce2020-01-23 12:09:04 -0700209 size_t fLockStride = 0;
senorblanco6599eff2016-03-10 08:38:45 -0800210};
211
ethannicholase9709e82016-01-07 13:34:16 -0800212} // namespace
senorblancod6ed19c2015-02-26 06:58:17 -0800213
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400214
Chris Dalton17dc4182020-03-25 16:18:16 -0600215GrTriangulatingPathRenderer::GrTriangulatingPathRenderer()
Stephen White8a3c0592019-05-29 11:26:16 -0400216 : fMaxVerbCount(GR_AA_TESSELLATOR_MAX_VERB_COUNT) {
senorblancod6ed19c2015-02-26 06:58:17 -0800217}
218
Chris Dalton5ed44232017-09-07 13:22:46 -0600219GrPathRenderer::CanDrawPath
Chris Dalton17dc4182020-03-25 16:18:16 -0600220GrTriangulatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
Chris Daltone5ede4b2017-09-07 18:33:08 +0000221 // This path renderer can draw fill styles, and can do screenspace antialiasing via a
222 // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
223 // ones to simpler algorithms. We pass on paths that have styles, though they may come back
Chris Dalton09e56892019-03-13 00:22:01 -0600224 // around after applying the styling information to the geometry to create a filled path.
Chris Daltone5ede4b2017-09-07 18:33:08 +0000225 if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
Chris Dalton5ed44232017-09-07 13:22:46 -0600226 return CanDrawPath::kNo;
senorblancof57372d2016-08-31 10:36:19 -0700227 }
Chris Dalton6ce447a2019-06-23 18:07:38 -0600228 switch (args.fAAType) {
229 case GrAAType::kNone:
230 case GrAAType::kMSAA:
231 // Prefer MSAA, if any antialiasing. In the non-analytic-AA case, We skip paths that
232 // don't have a key since the real advantage of this path renderer comes from caching
233 // the tessellated geometry.
234 if (!args.fShape->hasUnstyledKey()) {
235 return CanDrawPath::kNo;
236 }
237 break;
238 case GrAAType::kCoverage:
239 // Use analytic AA if we don't have MSAA. In this case, we do not cache, so we accept
240 // paths without keys.
241 SkPath path;
242 args.fShape->asPath(&path);
243 if (path.countVerbs() > fMaxVerbCount) {
244 return CanDrawPath::kNo;
245 }
246 break;
senorblancof57372d2016-08-31 10:36:19 -0700247 }
Chris Dalton5ed44232017-09-07 13:22:46 -0600248 return CanDrawPath::kYes;
senorblancod6ed19c2015-02-26 06:58:17 -0800249}
250
Brian Salomon9530f7e2017-07-11 09:03:10 -0400251namespace {
252
Chris Dalton17dc4182020-03-25 16:18:16 -0600253class TriangulatingPathOp final : public GrMeshDrawOp {
Brian Salomon9530f7e2017-07-11 09:03:10 -0400254private:
255 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
256
senorblanco9ba39722015-03-05 07:13:42 -0800257public:
Brian Salomon25a88092016-12-01 09:36:50 -0500258 DEFINE_OP_CLASS_ID
senorblanco9ba39722015-03-05 07:13:42 -0800259
Herb Derbyc76d4092020-10-07 16:46:15 -0400260 static GrOp::Owner Make(GrRecordingContext* context,
261 GrPaint&& paint,
262 const GrStyledShape& shape,
263 const SkMatrix& viewMatrix,
264 SkIRect devClipBounds,
265 GrAAType aaType,
266 const GrUserStencilSettings* stencilSettings) {
Chris Dalton17dc4182020-03-25 16:18:16 -0600267 return Helper::FactoryHelper<TriangulatingPathOp>(context, std::move(paint), shape,
268 viewMatrix, devClipBounds, aaType,
269 stencilSettings);
senorblanco9ba39722015-03-05 07:13:42 -0800270 }
271
Chris Dalton17dc4182020-03-25 16:18:16 -0600272 const char* name() const override { return "TriangulatingPathOp"; }
senorblanco9ba39722015-03-05 07:13:42 -0800273
Chris Dalton1706cbf2019-05-21 19:35:29 -0600274 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillips740d34f2020-03-11 09:36:13 -0400275 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -0600276 fProgramInfo->visitFPProxies(func);
Robert Phillips740d34f2020-03-11 09:36:13 -0400277 } else {
278 fHelper.visitProxies(func);
279 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400280 }
281
Herb Derbyc76d4092020-10-07 16:46:15 -0400282 TriangulatingPathOp(GrProcessorSet* processorSet,
Chris Dalton17dc4182020-03-25 16:18:16 -0600283 const SkPMColor4f& color,
Michael Ludwig2686d692020-04-17 20:21:37 +0000284 const GrStyledShape& shape,
Chris Dalton17dc4182020-03-25 16:18:16 -0600285 const SkMatrix& viewMatrix,
286 const SkIRect& devClipBounds,
287 GrAAType aaType,
288 const GrUserStencilSettings* stencilSettings)
Brian Salomon9530f7e2017-07-11 09:03:10 -0400289 : INHERITED(ClassID())
Herb Derbyc76d4092020-10-07 16:46:15 -0400290 , fHelper(processorSet, aaType, stencilSettings)
Brian Salomon9530f7e2017-07-11 09:03:10 -0400291 , fColor(color)
292 , fShape(shape)
293 , fViewMatrix(viewMatrix)
294 , fDevClipBounds(devClipBounds)
295 , fAntiAlias(GrAAType::kCoverage == aaType) {
296 SkRect devBounds;
297 viewMatrix.mapRect(&devBounds, shape.bounds());
298 if (shape.inverseFilled()) {
299 // Because the clip bounds are used to add a contour for inverse fills, they must also
300 // include the path bounds.
301 devBounds.join(SkRect::Make(fDevClipBounds));
302 }
Greg Daniel5faf4742019-10-01 15:14:44 -0400303 this->setBounds(devBounds, HasAABloat::kNo, IsHairline::kNo);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400304 }
305
306 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
307
Chris Dalton6ce447a2019-06-23 18:07:38 -0600308 GrProcessorSet::Analysis finalize(
309 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
310 GrClampType clampType) override {
Brian Salomon9530f7e2017-07-11 09:03:10 -0400311 GrProcessorAnalysisCoverage coverage = fAntiAlias
312 ? GrProcessorAnalysisCoverage::kSingleChannel
313 : GrProcessorAnalysisCoverage::kNone;
Brian Osman8fa7ab42019-03-18 10:22:42 -0400314 // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
315 return fHelper.finalizeProcessors(
Chris Dalton6ce447a2019-06-23 18:07:38 -0600316 caps, clip, hasMixedSampledCoverage, clampType, coverage, &fColor, nullptr);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400317 }
318
Brian Salomon92aee3d2016-12-21 09:20:25 -0500319private:
senorblancof57372d2016-08-31 10:36:19 -0700320 SkPath getPath() const {
321 SkASSERT(!fShape.style().applies());
bsalomonee432412016-06-27 07:18:18 -0700322 SkPath path;
323 fShape.asPath(&path);
senorblancof57372d2016-08-31 10:36:19 -0700324 return path;
325 }
326
Robert Phillips6ffcb232020-10-14 12:40:13 -0400327 static void CreateKey(GrUniqueKey* key,
328 const GrStyledShape& shape,
329 const SkIRect& devClipBounds) {
senorblanco84cd6212015-08-04 10:01:58 -0700330 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400331
332 bool inverseFill = shape.inverseFilled();
333
334 static constexpr int kClipBoundsCnt = sizeof(devClipBounds) / sizeof(uint32_t);
335 int shapeKeyDataCnt = shape.unstyledKeySize();
bsalomonee432412016-06-27 07:18:18 -0700336 SkASSERT(shapeKeyDataCnt >= 0);
Robert Phillips6ffcb232020-10-14 12:40:13 -0400337 GrUniqueKey::Builder builder(key, kDomain, shapeKeyDataCnt + kClipBoundsCnt, "Path");
338 shape.writeUnstyledKey(&builder[0]);
bsalomonee432412016-06-27 07:18:18 -0700339 // For inverse fills, the tessellation is dependent on clip bounds.
340 if (inverseFill) {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400341 memcpy(&builder[shapeKeyDataCnt], &devClipBounds, sizeof(devClipBounds));
bsalomonee432412016-06-27 07:18:18 -0700342 } else {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400343 memset(&builder[shapeKeyDataCnt], 0, sizeof(devClipBounds));
bsalomonee432412016-06-27 07:18:18 -0700344 }
Robert Phillips6ffcb232020-10-14 12:40:13 -0400345
bsalomonee432412016-06-27 07:18:18 -0700346 builder.finish();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400347 }
348
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400349 // Triangulate the provided 'shape' in the shape's coordinate space. 'tol' should already
350 // have been mapped back from device space.
351 static int Triangulate(GrEagerVertexAllocator* allocator,
352 const SkMatrix& viewMatrix,
353 const GrStyledShape& shape,
354 const SkIRect& devClipBounds,
355 SkScalar tol,
356 int* numCountedCurves) {
357 SkRect clipBounds = SkRect::Make(devClipBounds);
358
359 SkMatrix vmi;
360 if (!viewMatrix.invert(&vmi)) {
361 return 0;
362 }
363 vmi.mapRect(&clipBounds);
364
365 SkASSERT(!shape.style().applies());
366 SkPath path;
367 shape.asPath(&path);
368
369 return GrTriangulator::PathToTriangles(path, tol, clipBounds, allocator,
370 GrTriangulator::Mode::kNormal, numCountedCurves);
371 }
372
Robert Phillips6ffcb232020-10-14 12:40:13 -0400373 void createNonAAMesh(Target* target) {
374 SkASSERT(!fAntiAlias);
375 GrResourceProvider* rp = target->resourceProvider();
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500376 auto threadSafeCache = target->threadSafeCache();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400377
378 GrUniqueKey key;
379 CreateKey(&key, fShape, fDevClipBounds);
380
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400381 SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance,
382 fViewMatrix, fShape.bounds());
383
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500384 if (!fVertexData) {
385 auto [cachedVerts, data] = threadSafeCache->findVertsWithData(key);
386 if (cachedVerts && cache_match(data.get(), tol, nullptr, nullptr)) {
387 fVertexData = std::move(cachedVerts);
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400388 }
senorblanco84cd6212015-08-04 10:01:58 -0700389 }
390
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500391 if (fVertexData) {
392 if (!fVertexData->gpuBuffer()) {
393 sk_sp<GrGpuBuffer> buffer = rp->createBuffer(fVertexData->size(),
394 GrGpuBufferType::kVertex,
395 kStatic_GrAccessPattern,
396 fVertexData->vertices());
397 if (!buffer) {
398 return;
399 }
400
401 // Since we have a direct context and a ref on 'fVertexData' we need not worry
402 // about any threading issues in this call.
403 fVertexData->setGpuBuffer(std::move(buffer));
404 }
405
406 fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices());
407 return;
408 }
409
senorblanco6599eff2016-03-10 08:38:45 -0800410 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
Chris Daltond081dce2020-01-23 12:09:04 -0700411 StaticVertexAllocator allocator(rp, canMapVB);
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400412
413 int numCountedCurves;
414 int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
415 &numCountedCurves);
Chris Dalton8e2b6942020-04-22 15:55:00 -0600416 if (vertexCount == 0) {
senorblanco6599eff2016-03-10 08:38:45 -0800417 return;
418 }
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400419
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500420 fVertexData = allocator.detachVertexData();
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400421
422 key.setCustomData(create_data(vertexCount, numCountedCurves, tol));
423
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500424 auto [tmpV, tmpD] = threadSafeCache->addVertsWithData(key, fVertexData, is_newer_better);
425 if (tmpV != fVertexData) {
426 SkASSERT(!tmpV->gpuBuffer());
427 // In this case, although the different triangulation found in the cache is better,
428 // we will continue on with the current triangulation since it is already on the gpu.
429 } else {
430 // This isn't perfect. The current triangulation is in the cache but it may have
431 // replaced a pre-existing one. A duplicated listener is unlikely and not that
432 // expensive so we just roll with it.
433 fShape.addGenIDChangeListener(
Brian Salomon99a813c2020-03-02 12:50:47 -0500434 sk_make_sp<UniqueKeyInvalidator>(key, target->contextUniqueID()));
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500435 }
Brian Salomon12d22642019-01-29 14:38:50 -0500436
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500437 fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices());
senorblanco6599eff2016-03-10 08:38:45 -0800438 }
439
Robert Phillips6ffcb232020-10-14 12:40:13 -0400440 void createAAMesh(Target* target) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500441 SkASSERT(!fVertexData);
senorblancof57372d2016-08-31 10:36:19 -0700442 SkASSERT(fAntiAlias);
Robert Phillips6ffcb232020-10-14 12:40:13 -0400443 SkPath path = this->getPath();
senorblancof57372d2016-08-31 10:36:19 -0700444 if (path.isEmpty()) {
445 return;
446 }
447 SkRect clipBounds = SkRect::Make(fDevClipBounds);
448 path.transform(fViewMatrix);
449 SkScalar tol = GrPathUtils::kDefaultTolerance;
Chris Daltond081dce2020-01-23 12:09:04 -0700450 sk_sp<const GrBuffer> vertexBuffer;
451 int firstVertex;
Chris Dalton8e2b6942020-04-22 15:55:00 -0600452 int numCountedCurves;
Chris Daltond081dce2020-01-23 12:09:04 -0700453 GrEagerDynamicVertexAllocator allocator(target, &vertexBuffer, &firstVertex);
Chris Dalton8e2b6942020-04-22 15:55:00 -0600454 int vertexCount = GrTriangulator::PathToTriangles(path, tol, clipBounds, &allocator,
455 GrTriangulator::Mode::kEdgeAntialias,
456 &numCountedCurves);
457 if (vertexCount == 0) {
senorblancof57372d2016-08-31 10:36:19 -0700458 return;
459 }
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400460 fMesh = CreateMesh(target, std::move(vertexBuffer), firstVertex, vertexCount);
senorblancof57372d2016-08-31 10:36:19 -0700461 }
462
Robert Phillips2669a7b2020-03-12 12:07:19 -0400463 GrProgramInfo* programInfo() override { return fProgramInfo; }
464
Robert Phillips4133dc42020-03-11 15:55:55 -0400465 void onCreateProgramInfo(const GrCaps* caps,
466 SkArenaAlloc* arena,
Brian Salomon8afde5f2020-04-01 16:22:00 -0400467 const GrSurfaceProxyView* writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400468 GrAppliedClip&& appliedClip,
Greg Danield358cbe2020-09-11 09:33:54 -0400469 const GrXferProcessor::DstProxyView& dstProxyView,
470 GrXferBarrierFlags renderPassXferBarriers) override {
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500471 GrGeometryProcessor* gp;
joshualittdf0c5572015-08-03 11:35:28 -0700472 {
473 using namespace GrDefaultGeoProcFactory;
474
475 Color color(fColor);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400476 LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
Brian Salomon8c852be2017-01-04 10:44:42 -0500477 ? LocalCoords::kUsePosition_Type
478 : LocalCoords::kUnused_Type;
joshualittdf0c5572015-08-03 11:35:28 -0700479 Coverage::Type coverageType;
senorblancof57372d2016-08-31 10:36:19 -0700480 if (fAntiAlias) {
Brian Osman605c6d52019-03-15 12:10:35 -0400481 if (fHelper.compatibleWithCoverageAsAlpha()) {
Brian Osman80879d42019-01-07 16:15:27 -0500482 coverageType = Coverage::kAttributeTweakAlpha_Type;
senorblancof57372d2016-08-31 10:36:19 -0700483 } else {
484 coverageType = Coverage::kAttribute_Type;
485 }
Brian Salomon8c852be2017-01-04 10:44:42 -0500486 } else {
joshualittdf0c5572015-08-03 11:35:28 -0700487 coverageType = Coverage::kSolid_Type;
joshualittdf0c5572015-08-03 11:35:28 -0700488 }
senorblancof57372d2016-08-31 10:36:19 -0700489 if (fAntiAlias) {
Brian Osmanf0aee742020-03-12 09:28:44 -0400490 gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(arena, color, coverageType,
Brian Salomon8c852be2017-01-04 10:44:42 -0500491 localCoordsType, fViewMatrix);
senorblancof57372d2016-08-31 10:36:19 -0700492 } else {
Brian Osmanf0aee742020-03-12 09:28:44 -0400493 gp = GrDefaultGeoProcFactory::Make(arena, color, coverageType, localCoordsType,
Brian Salomon8c852be2017-01-04 10:44:42 -0500494 fViewMatrix);
senorblancof57372d2016-08-31 10:36:19 -0700495 }
joshualittdf0c5572015-08-03 11:35:28 -0700496 }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500497 if (!gp) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400498 return;
Stephen Whitecc700832017-02-15 11:45:16 -0500499 }
Robert Phillips740d34f2020-03-11 09:36:13 -0400500
Chris Daltondcc8c542020-01-28 17:55:56 -0700501#ifdef SK_DEBUG
Chris Dalton17dc4182020-03-25 16:18:16 -0600502 auto mode = (fAntiAlias) ? GrTriangulator::Mode::kEdgeAntialias
503 : GrTriangulator::Mode::kNormal;
504 SkASSERT(GrTriangulator::GetVertexStride(mode) == gp->vertexStride());
Chris Daltondcc8c542020-01-28 17:55:56 -0700505#endif
senorblanco84cd6212015-08-04 10:01:58 -0700506
Chris Dalton17dc4182020-03-25 16:18:16 -0600507 GrPrimitiveType primitiveType = TRIANGULATOR_WIREFRAME ? GrPrimitiveType::kLines
508 : GrPrimitiveType::kTriangles;
Robert Phillipse94cdd22019-11-04 14:15:58 -0500509
Brian Salomon8afde5f2020-04-01 16:22:00 -0400510 fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400511 std::move(appliedClip), dstProxyView,
Greg Danield358cbe2020-09-11 09:33:54 -0400512 gp, primitiveType,
513 renderPassXferBarriers);
Robert Phillips740d34f2020-03-11 09:36:13 -0400514 }
515
Robert Phillips473a8482020-10-20 10:44:15 -0400516 void onPrePrepareDraws(GrRecordingContext* rContext,
517 const GrSurfaceProxyView* writeView,
518 GrAppliedClip* clip,
519 const GrXferProcessor::DstProxyView& dstProxyView,
520 GrXferBarrierFlags renderPassXferBarriers) override {
521 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
522
523 INHERITED::onPrePrepareDraws(rContext, writeView, clip, dstProxyView,
524 renderPassXferBarriers);
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500525
526 if (fAntiAlias) {
527 // TODO: pull the triangulation work forward to the recording thread for the AA case
528 // too.
529 return;
530 }
531
532 auto threadSafeViewCache = rContext->priv().threadSafeCache();
533
534 GrUniqueKey key;
535 CreateKey(&key, fShape, fDevClipBounds);
536
537 SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance,
538 fViewMatrix, fShape.bounds());
539
540 auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key);
541 if (cachedVerts && cache_match(data.get(), tol, nullptr, nullptr)) {
542 fVertexData = std::move(cachedVerts);
543 return;
544 }
545
546 CpuVertexAllocator allocator;
547
548 int numCountedCurves;
549 int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
550 &numCountedCurves);
551 if (vertexCount == 0) {
552 return;
553 }
554
555 fVertexData = allocator.detachVertexData();
556
557 key.setCustomData(create_data(vertexCount, numCountedCurves, tol));
558
559 // If some other thread created and cached its own triangulation, the 'is_newer_better'
560 // predicate will replace the version in the cache if 'fVertexData' is a more accurate
561 // triangulation. This will leave some other recording threads using a poorer triangulation
562 // but will result in a version with greater applicability being in the cache.
563 auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData,
564 is_newer_better);
565 if (tmpV != fVertexData) {
566 // Someone beat us to creating the triangulation (and it is better than ours) so
567 // just go ahead and use it.
568 SkASSERT(cache_match(tmpD.get(), tol, nullptr, nullptr));
569 fVertexData = std::move(tmpV);
570 } else {
571 // This isn't perfect. The current triangulation is in the cache but it may have
572 // replaced a pre-existing one. A duplicated listener is unlikely and not that
573 // expensive so we just roll with it.
574 fShape.addGenIDChangeListener(
575 sk_make_sp<UniqueKeyInvalidator>(key, rContext->priv().contextID()));
576 }
Robert Phillips473a8482020-10-20 10:44:15 -0400577 }
578
Robert Phillips740d34f2020-03-11 09:36:13 -0400579 void onPrepareDraws(Target* target) override {
580 if (fAntiAlias) {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400581 this->createAAMesh(target);
Robert Phillips740d34f2020-03-11 09:36:13 -0400582 } else {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400583 this->createNonAAMesh(target);
Robert Phillips740d34f2020-03-11 09:36:13 -0400584 }
585 }
586
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400587 static GrSimpleMesh* CreateMesh(Target* target, sk_sp<const GrBuffer> vb,
588 int firstVertex, int count) {
589 auto mesh = target->allocMesh();
590 mesh->set(std::move(vb), count, firstVertex);
591 return mesh;
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700592 }
593
594 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillips740d34f2020-03-11 09:36:13 -0400595 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400596 this->createProgramInfo(flushState);
Robert Phillips740d34f2020-03-11 09:36:13 -0400597 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500598
Robert Phillips740d34f2020-03-11 09:36:13 -0400599 if (!fProgramInfo || !fMesh) {
600 return;
601 }
602
Chris Dalton765ed362020-03-16 17:34:44 -0600603 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
604 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
605 flushState->drawMesh(*fMesh);
senorblanco9ba39722015-03-05 07:13:42 -0800606 }
607
John Stilesaf366522020-08-13 09:57:34 -0400608#if GR_TEST_UTILS
609 SkString onDumpInfo() const override {
610 return SkStringPrintf("Color 0x%08x, aa: %d\n%s",
611 fColor.toBytes_RGBA(), fAntiAlias, fHelper.dumpInfo().c_str());
612 }
613#endif
614
Robert Phillips740d34f2020-03-11 09:36:13 -0400615 Helper fHelper;
616 SkPMColor4f fColor;
Michael Ludwig2686d692020-04-17 20:21:37 +0000617 GrStyledShape fShape;
Robert Phillips740d34f2020-03-11 09:36:13 -0400618 SkMatrix fViewMatrix;
619 SkIRect fDevClipBounds;
620 bool fAntiAlias;
621
Chris Daltoneb694b72020-03-16 09:25:50 -0600622 GrSimpleMesh* fMesh = nullptr;
Robert Phillips740d34f2020-03-11 09:36:13 -0400623 GrProgramInfo* fProgramInfo = nullptr;
reed1b55a962015-09-17 20:16:13 -0700624
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500625 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
626
John Stiles7571f9e2020-09-02 22:42:33 -0400627 using INHERITED = GrMeshDrawOp;
senorblanco9ba39722015-03-05 07:13:42 -0800628};
629
Brian Salomon9530f7e2017-07-11 09:03:10 -0400630} // anonymous namespace
631
Chris Dalton17dc4182020-03-25 16:18:16 -0600632bool GrTriangulatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400633 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
Chris Dalton17dc4182020-03-25 16:18:16 -0600634 "GrTriangulatingPathRenderer::onDrawPath");
Michael Ludwig7c12e282020-05-29 09:54:07 -0400635
Herb Derbyc76d4092020-10-07 16:46:15 -0400636 GrOp::Owner op = TriangulatingPathOp::Make(
Michael Ludwig7c12e282020-05-29 09:54:07 -0400637 args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix,
638 *args.fClipConservativeBounds, args.fAAType, args.fUserStencilSettings);
639 args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op));
senorblancod6ed19c2015-02-26 06:58:17 -0800640 return true;
641}
joshualitt2fbd4062015-05-07 13:06:41 -0700642
643///////////////////////////////////////////////////////////////////////////////////////////////////
644
Hal Canary6f6961e2017-01-31 13:50:44 -0500645#if GR_TEST_UTILS
joshualitt2fbd4062015-05-07 13:06:41 -0700646
Chris Dalton17dc4182020-03-25 16:18:16 -0600647GR_DRAW_OP_TEST_DEFINE(TriangulatingPathOp) {
joshualitt2fbd4062015-05-07 13:06:41 -0700648 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
John Stiles31954bf2020-08-07 17:35:54 -0400649 const SkPath& path = GrTest::TestPath(random);
bsalomond3030ac2016-09-01 07:20:29 -0700650 SkIRect devClipBounds = SkIRect::MakeLTRB(
senorblancof57372d2016-08-31 10:36:19 -0700651 random->nextU(), random->nextU(), random->nextU(), random->nextU());
bsalomond3030ac2016-09-01 07:20:29 -0700652 devClipBounds.sort();
Brian Salomon9530f7e2017-07-11 09:03:10 -0400653 static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kMSAA, GrAAType::kCoverage};
654 GrAAType aaType;
655 do {
656 aaType = kAATypes[random->nextULessThan(SK_ARRAY_COUNT(kAATypes))];
Chris Dalton6ce447a2019-06-23 18:07:38 -0600657 } while(GrAAType::kMSAA == aaType && numSamples <= 1);
bsalomon6663acf2016-05-10 09:14:17 -0700658 GrStyle style;
659 do {
660 GrTest::TestStyle(random, &style);
senorblancof57372d2016-08-31 10:36:19 -0700661 } while (!style.isSimpleFill());
Michael Ludwig2686d692020-04-17 20:21:37 +0000662 GrStyledShape shape(path, style);
Chris Dalton17dc4182020-03-25 16:18:16 -0600663 return TriangulatingPathOp::Make(context, std::move(paint), shape, viewMatrix, devClipBounds,
664 aaType, GrGetRandomStencil(random, context));
joshualitt2fbd4062015-05-07 13:06:41 -0700665}
666
667#endif