blob: 993e45ebe5acd9d21bc7b00d69a36448b03577a2 [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"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050020#include "src/gpu/GrResourceCache.h"
21#include "src/gpu/GrResourceProvider.h"
Chris Daltoneb694b72020-03-16 09:25:50 -060022#include "src/gpu/GrSimpleMesh.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050023#include "src/gpu/GrStyle.h"
Brian Salomoneebe7352020-12-09 16:37:04 -050024#include "src/gpu/GrSurfaceDrawContext.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;
Chris Dalton86d4cfd2020-11-03 13:51:21 -070053 bool fIsLinear;
senorblanco84cd6212015-08-04 10:01:58 -070054 SkScalar fTolerance;
senorblanco84cd6212015-08-04 10:01:58 -070055};
56
Chris Dalton86d4cfd2020-11-03 13:51:21 -070057static sk_sp<SkData> create_data(int numVertices, bool isLinear, SkScalar tol) {
58 TessInfo info { numVertices, isLinear, tol };
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040059 return SkData::MakeWithCopy(&info, sizeof(info));
60}
61
Robert Phillips7ffdb692020-11-03 08:57:04 -050062bool cache_match(const SkData* data, SkScalar tol) {
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040063 SkASSERT(data);
64
65 const TessInfo* info = static_cast<const TessInfo*>(data->data());
Robert Phillips7ffdb692020-11-03 08:57:04 -050066
Chris Dalton86d4cfd2020-11-03 13:51:21 -070067 return info->fIsLinear || info->fTolerance < 3.0f * tol;
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040068}
69
Robert Phillipsf9a1b822020-11-02 11:40:00 -050070// Should 'challenger' replace 'incumbent' in the cache if there is a collision?
71bool is_newer_better(SkData* incumbent, SkData* challenger) {
72 const TessInfo* i = static_cast<const TessInfo*>(incumbent->data());
73 const TessInfo* c = static_cast<const TessInfo*>(challenger->data());
74
Chris Dalton86d4cfd2020-11-03 13:51:21 -070075 if (i->fIsLinear || i->fTolerance <= c->fTolerance) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -050076 return false; // prefer the incumbent
77 }
78
79 return true;
80}
81
ethannicholase9709e82016-01-07 13:34:16 -080082// When the SkPathRef genID changes, invalidate a corresponding GrResource described by key.
Brian Salomon99a813c2020-03-02 12:50:47 -050083class UniqueKeyInvalidator : public SkIDChangeListener {
ethannicholase9709e82016-01-07 13:34:16 -080084public:
Brian Salomon99a813c2020-03-02 12:50:47 -050085 UniqueKeyInvalidator(const GrUniqueKey& key, uint32_t contextUniqueID)
Robert Phillipsf9a1b822020-11-02 11:40:00 -050086 : fMsg(key, contextUniqueID, /* inThreadSafeCache */ true) {}
Brian Salomon238069b2018-07-11 15:58:57 -040087
ethannicholase9709e82016-01-07 13:34:16 -080088private:
89 GrUniqueKeyInvalidatedMessage fMsg;
90
Brian Salomon99a813c2020-03-02 12:50:47 -050091 void changed() override { SkMessageBus<GrUniqueKeyInvalidatedMessage>::Post(fMsg); }
ethannicholase9709e82016-01-07 13:34:16 -080092};
93
Chris Daltond081dce2020-01-23 12:09:04 -070094class StaticVertexAllocator : public GrEagerVertexAllocator {
senorblanco6599eff2016-03-10 08:38:45 -080095public:
Chris Daltond081dce2020-01-23 12:09:04 -070096 StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB)
Robert Phillips6ffcb232020-10-14 12:40:13 -040097 : fResourceProvider(resourceProvider)
Robert Phillipsf9a1b822020-11-02 11:40:00 -050098 , fCanMapVB(canMapVB) {
senorblanco6599eff2016-03-10 08:38:45 -080099 }
Robert Phillips6ffcb232020-10-14 12:40:13 -0400100
Chris Daltond081dce2020-01-23 12:09:04 -0700101#ifdef SK_DEBUG
102 ~StaticVertexAllocator() override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500103 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData);
Chris Daltond081dce2020-01-23 12:09:04 -0700104 }
105#endif
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500106
Chris Daltond081dce2020-01-23 12:09:04 -0700107 void* lock(size_t stride, int eagerCount) override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500108 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData);
109 SkASSERT(stride && eagerCount);
110
Chris Daltond081dce2020-01-23 12:09:04 -0700111 size_t size = eagerCount * stride;
Brian Salomonae64c192019-02-05 09:41:37 -0500112 fVertexBuffer = fResourceProvider->createBuffer(size, GrGpuBufferType::kVertex,
Brian Salomondbf70722019-02-07 11:31:24 -0500113 kStatic_GrAccessPattern);
John Stilesa008b0f2020-08-16 08:48:02 -0400114 if (!fVertexBuffer) {
senorblanco6599eff2016-03-10 08:38:45 -0800115 return nullptr;
116 }
117 if (fCanMapVB) {
senorblancof57372d2016-08-31 10:36:19 -0700118 fVertices = fVertexBuffer->map();
senorblanco6599eff2016-03-10 08:38:45 -0800119 } else {
Chris Daltond081dce2020-01-23 12:09:04 -0700120 fVertices = sk_malloc_throw(eagerCount * stride);
senorblanco6599eff2016-03-10 08:38:45 -0800121 }
Chris Daltond081dce2020-01-23 12:09:04 -0700122 fLockStride = stride;
senorblanco6599eff2016-03-10 08:38:45 -0800123 return fVertices;
124 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500125
senorblanco6599eff2016-03-10 08:38:45 -0800126 void unlock(int actualCount) override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500127 SkASSERT(fLockStride && fVertices && fVertexBuffer && !fVertexData);
128
senorblanco6599eff2016-03-10 08:38:45 -0800129 if (fCanMapVB) {
130 fVertexBuffer->unmap();
131 } else {
Chris Daltond081dce2020-01-23 12:09:04 -0700132 fVertexBuffer->updateData(fVertices, actualCount * fLockStride);
senorblancof57372d2016-08-31 10:36:19 -0700133 sk_free(fVertices);
senorblanco6599eff2016-03-10 08:38:45 -0800134 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500135
136 fVertexData = GrThreadSafeCache::MakeVertexData(std::move(fVertexBuffer),
137 actualCount, fLockStride);
138
senorblanco6599eff2016-03-10 08:38:45 -0800139 fVertices = nullptr;
Chris Daltond081dce2020-01-23 12:09:04 -0700140 fLockStride = 0;
senorblanco6599eff2016-03-10 08:38:45 -0800141 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500142
143 sk_sp<GrThreadSafeCache::VertexData> detachVertexData() {
144 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && fVertexData);
145
146 return std::move(fVertexData);
147 }
Brian Salomon12d22642019-01-29 14:38:50 -0500148
senorblanco6599eff2016-03-10 08:38:45 -0800149private:
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500150 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
Brian Salomondbf70722019-02-07 11:31:24 -0500151 sk_sp<GrGpuBuffer> fVertexBuffer;
senorblanco6599eff2016-03-10 08:38:45 -0800152 GrResourceProvider* fResourceProvider;
153 bool fCanMapVB;
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500154 void* fVertices = nullptr;
155 size_t fLockStride = 0;
156};
157
158class CpuVertexAllocator : public GrEagerVertexAllocator {
159public:
160 CpuVertexAllocator() = default;
161
162#ifdef SK_DEBUG
163 ~CpuVertexAllocator() override {
164 SkASSERT(!fLockStride && !fVertices && !fVertexData);
165 }
166#endif
167
168 void* lock(size_t stride, int eagerCount) override {
169 SkASSERT(!fLockStride && !fVertices && !fVertexData);
170 SkASSERT(stride && eagerCount);
171
172 fVertices = sk_malloc_throw(eagerCount * stride);
173 fLockStride = stride;
174
175 return fVertices;
176 }
177
178 void unlock(int actualCount) override {
179 SkASSERT(fLockStride && fVertices && !fVertexData);
180
181 fVertices = sk_realloc_throw(fVertices, actualCount * fLockStride);
182
183 fVertexData = GrThreadSafeCache::MakeVertexData(fVertices, actualCount, fLockStride);
184
185 fVertices = nullptr;
186 fLockStride = 0;
187 }
188
189 sk_sp<GrThreadSafeCache::VertexData> detachVertexData() {
190 SkASSERT(!fLockStride && !fVertices && fVertexData);
191
192 return std::move(fVertexData);
193 }
194
195private:
196 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
197
198 void* fVertices = nullptr;
Chris Daltond081dce2020-01-23 12:09:04 -0700199 size_t fLockStride = 0;
senorblanco6599eff2016-03-10 08:38:45 -0800200};
201
ethannicholase9709e82016-01-07 13:34:16 -0800202} // namespace
senorblancod6ed19c2015-02-26 06:58:17 -0800203
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400204
Chris Dalton17dc4182020-03-25 16:18:16 -0600205GrTriangulatingPathRenderer::GrTriangulatingPathRenderer()
Stephen White8a3c0592019-05-29 11:26:16 -0400206 : fMaxVerbCount(GR_AA_TESSELLATOR_MAX_VERB_COUNT) {
senorblancod6ed19c2015-02-26 06:58:17 -0800207}
208
Chris Dalton5ed44232017-09-07 13:22:46 -0600209GrPathRenderer::CanDrawPath
Chris Dalton17dc4182020-03-25 16:18:16 -0600210GrTriangulatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
Chris Daltone5ede4b2017-09-07 18:33:08 +0000211 // This path renderer can draw fill styles, and can do screenspace antialiasing via a
212 // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
213 // ones to simpler algorithms. We pass on paths that have styles, though they may come back
Chris Dalton09e56892019-03-13 00:22:01 -0600214 // around after applying the styling information to the geometry to create a filled path.
Chris Daltone5ede4b2017-09-07 18:33:08 +0000215 if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
Chris Dalton5ed44232017-09-07 13:22:46 -0600216 return CanDrawPath::kNo;
senorblancof57372d2016-08-31 10:36:19 -0700217 }
Chris Dalton6ce447a2019-06-23 18:07:38 -0600218 switch (args.fAAType) {
219 case GrAAType::kNone:
220 case GrAAType::kMSAA:
221 // Prefer MSAA, if any antialiasing. In the non-analytic-AA case, We skip paths that
222 // don't have a key since the real advantage of this path renderer comes from caching
223 // the tessellated geometry.
224 if (!args.fShape->hasUnstyledKey()) {
225 return CanDrawPath::kNo;
226 }
227 break;
228 case GrAAType::kCoverage:
229 // Use analytic AA if we don't have MSAA. In this case, we do not cache, so we accept
230 // paths without keys.
231 SkPath path;
232 args.fShape->asPath(&path);
233 if (path.countVerbs() > fMaxVerbCount) {
234 return CanDrawPath::kNo;
235 }
236 break;
senorblancof57372d2016-08-31 10:36:19 -0700237 }
Chris Dalton5ed44232017-09-07 13:22:46 -0600238 return CanDrawPath::kYes;
senorblancod6ed19c2015-02-26 06:58:17 -0800239}
240
Brian Salomon9530f7e2017-07-11 09:03:10 -0400241namespace {
242
Chris Dalton17dc4182020-03-25 16:18:16 -0600243class TriangulatingPathOp final : public GrMeshDrawOp {
Brian Salomon9530f7e2017-07-11 09:03:10 -0400244private:
245 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
246
senorblanco9ba39722015-03-05 07:13:42 -0800247public:
Brian Salomon25a88092016-12-01 09:36:50 -0500248 DEFINE_OP_CLASS_ID
senorblanco9ba39722015-03-05 07:13:42 -0800249
Herb Derbyc76d4092020-10-07 16:46:15 -0400250 static GrOp::Owner Make(GrRecordingContext* context,
251 GrPaint&& paint,
252 const GrStyledShape& shape,
253 const SkMatrix& viewMatrix,
254 SkIRect devClipBounds,
255 GrAAType aaType,
256 const GrUserStencilSettings* stencilSettings) {
Chris Dalton17dc4182020-03-25 16:18:16 -0600257 return Helper::FactoryHelper<TriangulatingPathOp>(context, std::move(paint), shape,
258 viewMatrix, devClipBounds, aaType,
259 stencilSettings);
senorblanco9ba39722015-03-05 07:13:42 -0800260 }
261
Chris Dalton17dc4182020-03-25 16:18:16 -0600262 const char* name() const override { return "TriangulatingPathOp"; }
senorblanco9ba39722015-03-05 07:13:42 -0800263
Chris Dalton1706cbf2019-05-21 19:35:29 -0600264 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillips740d34f2020-03-11 09:36:13 -0400265 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -0600266 fProgramInfo->visitFPProxies(func);
Robert Phillips740d34f2020-03-11 09:36:13 -0400267 } else {
268 fHelper.visitProxies(func);
269 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400270 }
271
Herb Derbyc76d4092020-10-07 16:46:15 -0400272 TriangulatingPathOp(GrProcessorSet* processorSet,
Chris Dalton17dc4182020-03-25 16:18:16 -0600273 const SkPMColor4f& color,
Michael Ludwig2686d692020-04-17 20:21:37 +0000274 const GrStyledShape& shape,
Chris Dalton17dc4182020-03-25 16:18:16 -0600275 const SkMatrix& viewMatrix,
276 const SkIRect& devClipBounds,
277 GrAAType aaType,
278 const GrUserStencilSettings* stencilSettings)
Brian Salomon9530f7e2017-07-11 09:03:10 -0400279 : INHERITED(ClassID())
Herb Derbyc76d4092020-10-07 16:46:15 -0400280 , fHelper(processorSet, aaType, stencilSettings)
Brian Salomon9530f7e2017-07-11 09:03:10 -0400281 , fColor(color)
282 , fShape(shape)
283 , fViewMatrix(viewMatrix)
284 , fDevClipBounds(devClipBounds)
285 , fAntiAlias(GrAAType::kCoverage == aaType) {
286 SkRect devBounds;
287 viewMatrix.mapRect(&devBounds, shape.bounds());
288 if (shape.inverseFilled()) {
289 // Because the clip bounds are used to add a contour for inverse fills, they must also
290 // include the path bounds.
291 devBounds.join(SkRect::Make(fDevClipBounds));
292 }
Michael Ludwigb6a38292020-12-18 09:01:03 -0500293 this->setBounds(devBounds, HasAABloat(fAntiAlias), IsHairline::kNo);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400294 }
295
296 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
297
Chris Dalton6ce447a2019-06-23 18:07:38 -0600298 GrProcessorSet::Analysis finalize(
299 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
300 GrClampType clampType) override {
Brian Salomon9530f7e2017-07-11 09:03:10 -0400301 GrProcessorAnalysisCoverage coverage = fAntiAlias
302 ? GrProcessorAnalysisCoverage::kSingleChannel
303 : GrProcessorAnalysisCoverage::kNone;
Brian Osman8fa7ab42019-03-18 10:22:42 -0400304 // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
305 return fHelper.finalizeProcessors(
Chris Dalton6ce447a2019-06-23 18:07:38 -0600306 caps, clip, hasMixedSampledCoverage, clampType, coverage, &fColor, nullptr);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400307 }
308
Brian Salomon92aee3d2016-12-21 09:20:25 -0500309private:
senorblancof57372d2016-08-31 10:36:19 -0700310 SkPath getPath() const {
311 SkASSERT(!fShape.style().applies());
bsalomonee432412016-06-27 07:18:18 -0700312 SkPath path;
313 fShape.asPath(&path);
senorblancof57372d2016-08-31 10:36:19 -0700314 return path;
315 }
316
Robert Phillips6ffcb232020-10-14 12:40:13 -0400317 static void CreateKey(GrUniqueKey* key,
318 const GrStyledShape& shape,
319 const SkIRect& devClipBounds) {
senorblanco84cd6212015-08-04 10:01:58 -0700320 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400321
322 bool inverseFill = shape.inverseFilled();
323
324 static constexpr int kClipBoundsCnt = sizeof(devClipBounds) / sizeof(uint32_t);
325 int shapeKeyDataCnt = shape.unstyledKeySize();
bsalomonee432412016-06-27 07:18:18 -0700326 SkASSERT(shapeKeyDataCnt >= 0);
Robert Phillips6ffcb232020-10-14 12:40:13 -0400327 GrUniqueKey::Builder builder(key, kDomain, shapeKeyDataCnt + kClipBoundsCnt, "Path");
328 shape.writeUnstyledKey(&builder[0]);
bsalomonee432412016-06-27 07:18:18 -0700329 // For inverse fills, the tessellation is dependent on clip bounds.
330 if (inverseFill) {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400331 memcpy(&builder[shapeKeyDataCnt], &devClipBounds, sizeof(devClipBounds));
bsalomonee432412016-06-27 07:18:18 -0700332 } else {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400333 memset(&builder[shapeKeyDataCnt], 0, sizeof(devClipBounds));
bsalomonee432412016-06-27 07:18:18 -0700334 }
Robert Phillips6ffcb232020-10-14 12:40:13 -0400335
bsalomonee432412016-06-27 07:18:18 -0700336 builder.finish();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400337 }
338
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400339 // Triangulate the provided 'shape' in the shape's coordinate space. 'tol' should already
340 // have been mapped back from device space.
341 static int Triangulate(GrEagerVertexAllocator* allocator,
342 const SkMatrix& viewMatrix,
343 const GrStyledShape& shape,
344 const SkIRect& devClipBounds,
345 SkScalar tol,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700346 bool* isLinear) {
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400347 SkRect clipBounds = SkRect::Make(devClipBounds);
348
349 SkMatrix vmi;
350 if (!viewMatrix.invert(&vmi)) {
351 return 0;
352 }
353 vmi.mapRect(&clipBounds);
354
355 SkASSERT(!shape.style().applies());
356 SkPath path;
357 shape.asPath(&path);
358
359 return GrTriangulator::PathToTriangles(path, tol, clipBounds, allocator,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700360 GrTriangulator::Mode::kNormal, isLinear);
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400361 }
362
Robert Phillips6ffcb232020-10-14 12:40:13 -0400363 void createNonAAMesh(Target* target) {
364 SkASSERT(!fAntiAlias);
365 GrResourceProvider* rp = target->resourceProvider();
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500366 auto threadSafeCache = target->threadSafeCache();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400367
368 GrUniqueKey key;
369 CreateKey(&key, fShape, fDevClipBounds);
370
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400371 SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance,
372 fViewMatrix, fShape.bounds());
373
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500374 if (!fVertexData) {
375 auto [cachedVerts, data] = threadSafeCache->findVertsWithData(key);
Robert Phillips7ffdb692020-11-03 08:57:04 -0500376 if (cachedVerts && cache_match(data.get(), tol)) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500377 fVertexData = std::move(cachedVerts);
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400378 }
senorblanco84cd6212015-08-04 10:01:58 -0700379 }
380
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500381 if (fVertexData) {
382 if (!fVertexData->gpuBuffer()) {
383 sk_sp<GrGpuBuffer> buffer = rp->createBuffer(fVertexData->size(),
384 GrGpuBufferType::kVertex,
385 kStatic_GrAccessPattern,
386 fVertexData->vertices());
387 if (!buffer) {
388 return;
389 }
390
391 // Since we have a direct context and a ref on 'fVertexData' we need not worry
392 // about any threading issues in this call.
393 fVertexData->setGpuBuffer(std::move(buffer));
394 }
395
396 fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices());
397 return;
398 }
399
senorblanco6599eff2016-03-10 08:38:45 -0800400 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
Chris Daltond081dce2020-01-23 12:09:04 -0700401 StaticVertexAllocator allocator(rp, canMapVB);
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400402
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700403 bool isLinear;
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400404 int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700405 &isLinear);
Chris Dalton8e2b6942020-04-22 15:55:00 -0600406 if (vertexCount == 0) {
senorblanco6599eff2016-03-10 08:38:45 -0800407 return;
408 }
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400409
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500410 fVertexData = allocator.detachVertexData();
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400411
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700412 key.setCustomData(create_data(vertexCount, isLinear, tol));
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400413
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500414 auto [tmpV, tmpD] = threadSafeCache->addVertsWithData(key, fVertexData, is_newer_better);
415 if (tmpV != fVertexData) {
416 SkASSERT(!tmpV->gpuBuffer());
417 // In this case, although the different triangulation found in the cache is better,
418 // we will continue on with the current triangulation since it is already on the gpu.
419 } else {
420 // This isn't perfect. The current triangulation is in the cache but it may have
421 // replaced a pre-existing one. A duplicated listener is unlikely and not that
422 // expensive so we just roll with it.
423 fShape.addGenIDChangeListener(
Brian Salomon99a813c2020-03-02 12:50:47 -0500424 sk_make_sp<UniqueKeyInvalidator>(key, target->contextUniqueID()));
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500425 }
Brian Salomon12d22642019-01-29 14:38:50 -0500426
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500427 fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices());
senorblanco6599eff2016-03-10 08:38:45 -0800428 }
429
Robert Phillips6ffcb232020-10-14 12:40:13 -0400430 void createAAMesh(Target* target) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500431 SkASSERT(!fVertexData);
senorblancof57372d2016-08-31 10:36:19 -0700432 SkASSERT(fAntiAlias);
Robert Phillips6ffcb232020-10-14 12:40:13 -0400433 SkPath path = this->getPath();
senorblancof57372d2016-08-31 10:36:19 -0700434 if (path.isEmpty()) {
435 return;
436 }
437 SkRect clipBounds = SkRect::Make(fDevClipBounds);
438 path.transform(fViewMatrix);
439 SkScalar tol = GrPathUtils::kDefaultTolerance;
Chris Daltond081dce2020-01-23 12:09:04 -0700440 sk_sp<const GrBuffer> vertexBuffer;
441 int firstVertex;
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700442 bool isLinear;
Chris Daltond081dce2020-01-23 12:09:04 -0700443 GrEagerDynamicVertexAllocator allocator(target, &vertexBuffer, &firstVertex);
Chris Dalton8e2b6942020-04-22 15:55:00 -0600444 int vertexCount = GrTriangulator::PathToTriangles(path, tol, clipBounds, &allocator,
445 GrTriangulator::Mode::kEdgeAntialias,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700446 &isLinear);
Chris Dalton8e2b6942020-04-22 15:55:00 -0600447 if (vertexCount == 0) {
senorblancof57372d2016-08-31 10:36:19 -0700448 return;
449 }
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400450 fMesh = CreateMesh(target, std::move(vertexBuffer), firstVertex, vertexCount);
senorblancof57372d2016-08-31 10:36:19 -0700451 }
452
Robert Phillips2669a7b2020-03-12 12:07:19 -0400453 GrProgramInfo* programInfo() override { return fProgramInfo; }
454
Robert Phillips4133dc42020-03-11 15:55:55 -0400455 void onCreateProgramInfo(const GrCaps* caps,
456 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500457 const GrSurfaceProxyView& writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400458 GrAppliedClip&& appliedClip,
Greg Danield358cbe2020-09-11 09:33:54 -0400459 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500460 GrXferBarrierFlags renderPassXferBarriers,
461 GrLoadOp colorLoadOp) override {
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500462 GrGeometryProcessor* gp;
joshualittdf0c5572015-08-03 11:35:28 -0700463 {
464 using namespace GrDefaultGeoProcFactory;
465
466 Color color(fColor);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400467 LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
Brian Salomon8c852be2017-01-04 10:44:42 -0500468 ? LocalCoords::kUsePosition_Type
469 : LocalCoords::kUnused_Type;
joshualittdf0c5572015-08-03 11:35:28 -0700470 Coverage::Type coverageType;
senorblancof57372d2016-08-31 10:36:19 -0700471 if (fAntiAlias) {
Brian Osman605c6d52019-03-15 12:10:35 -0400472 if (fHelper.compatibleWithCoverageAsAlpha()) {
Brian Osman80879d42019-01-07 16:15:27 -0500473 coverageType = Coverage::kAttributeTweakAlpha_Type;
senorblancof57372d2016-08-31 10:36:19 -0700474 } else {
475 coverageType = Coverage::kAttribute_Type;
476 }
Brian Salomon8c852be2017-01-04 10:44:42 -0500477 } else {
joshualittdf0c5572015-08-03 11:35:28 -0700478 coverageType = Coverage::kSolid_Type;
joshualittdf0c5572015-08-03 11:35:28 -0700479 }
senorblancof57372d2016-08-31 10:36:19 -0700480 if (fAntiAlias) {
Brian Osmanf0aee742020-03-12 09:28:44 -0400481 gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(arena, color, coverageType,
Brian Salomon8c852be2017-01-04 10:44:42 -0500482 localCoordsType, fViewMatrix);
senorblancof57372d2016-08-31 10:36:19 -0700483 } else {
Brian Osmanf0aee742020-03-12 09:28:44 -0400484 gp = GrDefaultGeoProcFactory::Make(arena, color, coverageType, localCoordsType,
Brian Salomon8c852be2017-01-04 10:44:42 -0500485 fViewMatrix);
senorblancof57372d2016-08-31 10:36:19 -0700486 }
joshualittdf0c5572015-08-03 11:35:28 -0700487 }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500488 if (!gp) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400489 return;
Stephen Whitecc700832017-02-15 11:45:16 -0500490 }
Robert Phillips740d34f2020-03-11 09:36:13 -0400491
Chris Daltondcc8c542020-01-28 17:55:56 -0700492#ifdef SK_DEBUG
Chris Dalton17dc4182020-03-25 16:18:16 -0600493 auto mode = (fAntiAlias) ? GrTriangulator::Mode::kEdgeAntialias
494 : GrTriangulator::Mode::kNormal;
495 SkASSERT(GrTriangulator::GetVertexStride(mode) == gp->vertexStride());
Chris Daltondcc8c542020-01-28 17:55:56 -0700496#endif
senorblanco84cd6212015-08-04 10:01:58 -0700497
Chris Dalton17dc4182020-03-25 16:18:16 -0600498 GrPrimitiveType primitiveType = TRIANGULATOR_WIREFRAME ? GrPrimitiveType::kLines
499 : GrPrimitiveType::kTriangles;
Robert Phillipse94cdd22019-11-04 14:15:58 -0500500
Brian Salomon8afde5f2020-04-01 16:22:00 -0400501 fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400502 std::move(appliedClip), dstProxyView,
Greg Danield358cbe2020-09-11 09:33:54 -0400503 gp, primitiveType,
Greg Daniel42dbca52020-11-20 10:22:43 -0500504 renderPassXferBarriers, colorLoadOp);
Robert Phillips740d34f2020-03-11 09:36:13 -0400505 }
506
Robert Phillips473a8482020-10-20 10:44:15 -0400507 void onPrePrepareDraws(GrRecordingContext* rContext,
Adlai Hollere2296f72020-11-19 13:41:26 -0500508 const GrSurfaceProxyView& writeView,
Robert Phillips473a8482020-10-20 10:44:15 -0400509 GrAppliedClip* clip,
510 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500511 GrXferBarrierFlags renderPassXferBarriers,
512 GrLoadOp colorLoadOp) override {
Robert Phillips473a8482020-10-20 10:44:15 -0400513 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
514
515 INHERITED::onPrePrepareDraws(rContext, writeView, clip, dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500516 renderPassXferBarriers, colorLoadOp);
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500517
518 if (fAntiAlias) {
519 // TODO: pull the triangulation work forward to the recording thread for the AA case
520 // too.
521 return;
522 }
523
524 auto threadSafeViewCache = rContext->priv().threadSafeCache();
525
526 GrUniqueKey key;
527 CreateKey(&key, fShape, fDevClipBounds);
528
529 SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance,
530 fViewMatrix, fShape.bounds());
531
532 auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key);
Robert Phillips7ffdb692020-11-03 08:57:04 -0500533 if (cachedVerts && cache_match(data.get(), tol)) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500534 fVertexData = std::move(cachedVerts);
535 return;
536 }
537
538 CpuVertexAllocator allocator;
539
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700540 bool isLinear;
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500541 int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700542 &isLinear);
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500543 if (vertexCount == 0) {
544 return;
545 }
546
547 fVertexData = allocator.detachVertexData();
548
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700549 key.setCustomData(create_data(vertexCount, isLinear, tol));
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500550
551 // If some other thread created and cached its own triangulation, the 'is_newer_better'
552 // predicate will replace the version in the cache if 'fVertexData' is a more accurate
553 // triangulation. This will leave some other recording threads using a poorer triangulation
554 // but will result in a version with greater applicability being in the cache.
555 auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData,
556 is_newer_better);
557 if (tmpV != fVertexData) {
558 // Someone beat us to creating the triangulation (and it is better than ours) so
559 // just go ahead and use it.
Robert Phillips7ffdb692020-11-03 08:57:04 -0500560 SkASSERT(cache_match(tmpD.get(), tol));
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500561 fVertexData = std::move(tmpV);
562 } else {
563 // This isn't perfect. The current triangulation is in the cache but it may have
564 // replaced a pre-existing one. A duplicated listener is unlikely and not that
565 // expensive so we just roll with it.
566 fShape.addGenIDChangeListener(
567 sk_make_sp<UniqueKeyInvalidator>(key, rContext->priv().contextID()));
568 }
Robert Phillips473a8482020-10-20 10:44:15 -0400569 }
570
Robert Phillips740d34f2020-03-11 09:36:13 -0400571 void onPrepareDraws(Target* target) override {
572 if (fAntiAlias) {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400573 this->createAAMesh(target);
Robert Phillips740d34f2020-03-11 09:36:13 -0400574 } else {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400575 this->createNonAAMesh(target);
Robert Phillips740d34f2020-03-11 09:36:13 -0400576 }
577 }
578
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400579 static GrSimpleMesh* CreateMesh(Target* target, sk_sp<const GrBuffer> vb,
580 int firstVertex, int count) {
581 auto mesh = target->allocMesh();
582 mesh->set(std::move(vb), count, firstVertex);
583 return mesh;
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700584 }
585
586 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillips740d34f2020-03-11 09:36:13 -0400587 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400588 this->createProgramInfo(flushState);
Robert Phillips740d34f2020-03-11 09:36:13 -0400589 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500590
Robert Phillips740d34f2020-03-11 09:36:13 -0400591 if (!fProgramInfo || !fMesh) {
592 return;
593 }
594
Chris Dalton765ed362020-03-16 17:34:44 -0600595 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
596 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
597 flushState->drawMesh(*fMesh);
senorblanco9ba39722015-03-05 07:13:42 -0800598 }
599
John Stilesaf366522020-08-13 09:57:34 -0400600#if GR_TEST_UTILS
601 SkString onDumpInfo() const override {
602 return SkStringPrintf("Color 0x%08x, aa: %d\n%s",
603 fColor.toBytes_RGBA(), fAntiAlias, fHelper.dumpInfo().c_str());
604 }
605#endif
606
Robert Phillips740d34f2020-03-11 09:36:13 -0400607 Helper fHelper;
608 SkPMColor4f fColor;
Michael Ludwig2686d692020-04-17 20:21:37 +0000609 GrStyledShape fShape;
Robert Phillips740d34f2020-03-11 09:36:13 -0400610 SkMatrix fViewMatrix;
611 SkIRect fDevClipBounds;
612 bool fAntiAlias;
613
Chris Daltoneb694b72020-03-16 09:25:50 -0600614 GrSimpleMesh* fMesh = nullptr;
Robert Phillips740d34f2020-03-11 09:36:13 -0400615 GrProgramInfo* fProgramInfo = nullptr;
reed1b55a962015-09-17 20:16:13 -0700616
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500617 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
618
John Stiles7571f9e2020-09-02 22:42:33 -0400619 using INHERITED = GrMeshDrawOp;
senorblanco9ba39722015-03-05 07:13:42 -0800620};
621
Brian Salomon9530f7e2017-07-11 09:03:10 -0400622} // anonymous namespace
623
Chris Dalton17dc4182020-03-25 16:18:16 -0600624bool GrTriangulatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400625 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
Chris Dalton17dc4182020-03-25 16:18:16 -0600626 "GrTriangulatingPathRenderer::onDrawPath");
Michael Ludwig7c12e282020-05-29 09:54:07 -0400627
Herb Derbyc76d4092020-10-07 16:46:15 -0400628 GrOp::Owner op = TriangulatingPathOp::Make(
Michael Ludwig7c12e282020-05-29 09:54:07 -0400629 args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix,
630 *args.fClipConservativeBounds, args.fAAType, args.fUserStencilSettings);
631 args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op));
senorblancod6ed19c2015-02-26 06:58:17 -0800632 return true;
633}
joshualitt2fbd4062015-05-07 13:06:41 -0700634
635///////////////////////////////////////////////////////////////////////////////////////////////////
636
Hal Canary6f6961e2017-01-31 13:50:44 -0500637#if GR_TEST_UTILS
joshualitt2fbd4062015-05-07 13:06:41 -0700638
Chris Dalton17dc4182020-03-25 16:18:16 -0600639GR_DRAW_OP_TEST_DEFINE(TriangulatingPathOp) {
joshualitt2fbd4062015-05-07 13:06:41 -0700640 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
John Stiles31954bf2020-08-07 17:35:54 -0400641 const SkPath& path = GrTest::TestPath(random);
bsalomond3030ac2016-09-01 07:20:29 -0700642 SkIRect devClipBounds = SkIRect::MakeLTRB(
senorblancof57372d2016-08-31 10:36:19 -0700643 random->nextU(), random->nextU(), random->nextU(), random->nextU());
bsalomond3030ac2016-09-01 07:20:29 -0700644 devClipBounds.sort();
Brian Salomon9530f7e2017-07-11 09:03:10 -0400645 static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kMSAA, GrAAType::kCoverage};
646 GrAAType aaType;
647 do {
648 aaType = kAATypes[random->nextULessThan(SK_ARRAY_COUNT(kAATypes))];
Chris Dalton6ce447a2019-06-23 18:07:38 -0600649 } while(GrAAType::kMSAA == aaType && numSamples <= 1);
bsalomon6663acf2016-05-10 09:14:17 -0700650 GrStyle style;
651 do {
652 GrTest::TestStyle(random, &style);
senorblancof57372d2016-08-31 10:36:19 -0700653 } while (!style.isSimpleFill());
Michael Ludwig2686d692020-04-17 20:21:37 +0000654 GrStyledShape shape(path, style);
Chris Dalton17dc4182020-03-25 16:18:16 -0600655 return TriangulatingPathOp::Make(context, std::move(paint), shape, viewMatrix, devClipBounds,
656 aaType, GrGetRandomStencil(random, context));
joshualitt2fbd4062015-05-07 13:06:41 -0700657}
658
659#endif