blob: f3b9ef5367b4b5896015a970060d9cc951d96aec [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"
Chris Dalton47114db2021-01-06 00:35:20 -070012#include "src/gpu/GrAATriangulator.h"
Greg Danielf91aeb22019-06-18 09:58:02 -040013#include "src/gpu/GrAuditTrail.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050014#include "src/gpu/GrCaps.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050015#include "src/gpu/GrDefaultGeoProcFactory.h"
16#include "src/gpu/GrDrawOpTest.h"
Chris Daltond081dce2020-01-23 12:09:04 -070017#include "src/gpu/GrEagerVertexAllocator.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050018#include "src/gpu/GrOpFlushState.h"
Robert Phillips740d34f2020-03-11 09:36:13 -040019#include "src/gpu/GrProgramInfo.h"
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040020#include "src/gpu/GrRecordingContextPriv.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"
Brian Salomoneebe7352020-12-09 16:37:04 -050025#include "src/gpu/GrSurfaceDrawContext.h"
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040026#include "src/gpu/GrThreadSafeCache.h"
Chris Dalton17dc4182020-03-25 16:18:16 -060027#include "src/gpu/GrTriangulator.h"
Michael Ludwig663afe52019-06-03 16:46:19 -040028#include "src/gpu/geometry/GrPathUtils.h"
Michael Ludwig2686d692020-04-17 20:21:37 +000029#include "src/gpu/geometry/GrStyledShape.h"
Mike Kleinc0bd9f92019-04-23 12:05:21 -050030#include "src/gpu/ops/GrMeshDrawOp.h"
Robert Phillips55f681f2020-02-28 08:58:15 -050031#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
joshualitt74417822015-08-07 11:42:16 -070032
Chris Dalton17dc4182020-03-25 16:18:16 -060033#include <cstdio>
Brian Salomon71fe9452020-03-02 16:59:40 -050034
Stephen Whitea7701e02018-01-23 15:35:05 -050035#ifndef GR_AA_TESSELLATOR_MAX_VERB_COUNT
36#define GR_AA_TESSELLATOR_MAX_VERB_COUNT 10
37#endif
38
senorblancod6ed19c2015-02-26 06:58:17 -080039/*
Chris Dalton17dc4182020-03-25 16:18:16 -060040 * This path renderer linearizes and decomposes the path into triangles using GrTriangulator,
41 * uploads the triangles to a vertex buffer, and renders them with a single draw call. It can do
42 * screenspace antialiasing with a one-pixel coverage ramp.
senorblancod6ed19c2015-02-26 06:58:17 -080043 */
senorblancod6ed19c2015-02-26 06:58:17 -080044namespace {
45
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040046// The TessInfo struct contains ancillary data not specifically required for the triangle
47// data (which is stored in a GrThreadSafeCache::VertexData object).
48// The 'fNumVertices' field is a temporary exception. It is still needed to support the
49// AA triangulated path case - which doesn't use the GrThreadSafeCache nor the VertexData object).
50// When there is an associated VertexData, its numVertices should always match the TessInfo's
51// value.
senorblanco84cd6212015-08-04 10:01:58 -070052struct TessInfo {
Robert Phillips3ac83b2f2020-10-26 13:50:57 -040053 int fNumVertices;
Chris Dalton86d4cfd2020-11-03 13:51:21 -070054 bool fIsLinear;
senorblanco84cd6212015-08-04 10:01:58 -070055 SkScalar fTolerance;
senorblanco84cd6212015-08-04 10:01:58 -070056};
57
Chris Dalton86d4cfd2020-11-03 13:51:21 -070058static sk_sp<SkData> create_data(int numVertices, bool isLinear, SkScalar tol) {
59 TessInfo info { numVertices, isLinear, tol };
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040060 return SkData::MakeWithCopy(&info, sizeof(info));
61}
62
Robert Phillips7ffdb692020-11-03 08:57:04 -050063bool cache_match(const SkData* data, SkScalar tol) {
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040064 SkASSERT(data);
65
66 const TessInfo* info = static_cast<const TessInfo*>(data->data());
Robert Phillips7ffdb692020-11-03 08:57:04 -050067
Chris Dalton86d4cfd2020-11-03 13:51:21 -070068 return info->fIsLinear || info->fTolerance < 3.0f * tol;
Robert Phillips6cc9d8d2020-10-20 09:42:33 -040069}
70
Robert Phillipsf9a1b822020-11-02 11:40:00 -050071// Should 'challenger' replace 'incumbent' in the cache if there is a collision?
72bool is_newer_better(SkData* incumbent, SkData* challenger) {
73 const TessInfo* i = static_cast<const TessInfo*>(incumbent->data());
74 const TessInfo* c = static_cast<const TessInfo*>(challenger->data());
75
Chris Dalton86d4cfd2020-11-03 13:51:21 -070076 if (i->fIsLinear || i->fTolerance <= c->fTolerance) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -050077 return false; // prefer the incumbent
78 }
79
80 return true;
81}
82
ethannicholase9709e82016-01-07 13:34:16 -080083// When the SkPathRef genID changes, invalidate a corresponding GrResource described by key.
Brian Salomon99a813c2020-03-02 12:50:47 -050084class UniqueKeyInvalidator : public SkIDChangeListener {
ethannicholase9709e82016-01-07 13:34:16 -080085public:
Brian Salomon99a813c2020-03-02 12:50:47 -050086 UniqueKeyInvalidator(const GrUniqueKey& key, uint32_t contextUniqueID)
Robert Phillipsf9a1b822020-11-02 11:40:00 -050087 : fMsg(key, contextUniqueID, /* inThreadSafeCache */ true) {}
Brian Salomon238069b2018-07-11 15:58:57 -040088
ethannicholase9709e82016-01-07 13:34:16 -080089private:
90 GrUniqueKeyInvalidatedMessage fMsg;
91
Robert Phillipse7a959d2021-03-11 14:44:42 -050092 void changed() override { SkMessageBus<GrUniqueKeyInvalidatedMessage, uint32_t>::Post(fMsg); }
ethannicholase9709e82016-01-07 13:34:16 -080093};
94
Chris Daltond081dce2020-01-23 12:09:04 -070095class StaticVertexAllocator : public GrEagerVertexAllocator {
senorblanco6599eff2016-03-10 08:38:45 -080096public:
Chris Daltond081dce2020-01-23 12:09:04 -070097 StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB)
Robert Phillips6ffcb232020-10-14 12:40:13 -040098 : fResourceProvider(resourceProvider)
Robert Phillipsf9a1b822020-11-02 11:40:00 -050099 , fCanMapVB(canMapVB) {
senorblanco6599eff2016-03-10 08:38:45 -0800100 }
Robert Phillips6ffcb232020-10-14 12:40:13 -0400101
Chris Daltond081dce2020-01-23 12:09:04 -0700102#ifdef SK_DEBUG
103 ~StaticVertexAllocator() override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500104 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData);
Chris Daltond081dce2020-01-23 12:09:04 -0700105 }
106#endif
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500107
Chris Daltond081dce2020-01-23 12:09:04 -0700108 void* lock(size_t stride, int eagerCount) override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500109 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData);
110 SkASSERT(stride && eagerCount);
111
Chris Daltond081dce2020-01-23 12:09:04 -0700112 size_t size = eagerCount * stride;
Brian Salomonae64c192019-02-05 09:41:37 -0500113 fVertexBuffer = fResourceProvider->createBuffer(size, GrGpuBufferType::kVertex,
Brian Salomondbf70722019-02-07 11:31:24 -0500114 kStatic_GrAccessPattern);
John Stilesa008b0f2020-08-16 08:48:02 -0400115 if (!fVertexBuffer) {
senorblanco6599eff2016-03-10 08:38:45 -0800116 return nullptr;
117 }
118 if (fCanMapVB) {
senorblancof57372d2016-08-31 10:36:19 -0700119 fVertices = fVertexBuffer->map();
Greg Daniel5af72c12021-02-08 13:52:08 -0500120 }
121 if (!fVertices) {
Chris Daltond081dce2020-01-23 12:09:04 -0700122 fVertices = sk_malloc_throw(eagerCount * stride);
Greg Daniel5af72c12021-02-08 13:52:08 -0500123 fCanMapVB = false;
senorblanco6599eff2016-03-10 08:38:45 -0800124 }
Chris Daltond081dce2020-01-23 12:09:04 -0700125 fLockStride = stride;
senorblanco6599eff2016-03-10 08:38:45 -0800126 return fVertices;
127 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500128
senorblanco6599eff2016-03-10 08:38:45 -0800129 void unlock(int actualCount) override {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500130 SkASSERT(fLockStride && fVertices && fVertexBuffer && !fVertexData);
131
senorblanco6599eff2016-03-10 08:38:45 -0800132 if (fCanMapVB) {
133 fVertexBuffer->unmap();
134 } else {
Chris Daltond081dce2020-01-23 12:09:04 -0700135 fVertexBuffer->updateData(fVertices, actualCount * fLockStride);
senorblancof57372d2016-08-31 10:36:19 -0700136 sk_free(fVertices);
senorblanco6599eff2016-03-10 08:38:45 -0800137 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500138
139 fVertexData = GrThreadSafeCache::MakeVertexData(std::move(fVertexBuffer),
140 actualCount, fLockStride);
141
senorblanco6599eff2016-03-10 08:38:45 -0800142 fVertices = nullptr;
Chris Daltond081dce2020-01-23 12:09:04 -0700143 fLockStride = 0;
senorblanco6599eff2016-03-10 08:38:45 -0800144 }
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500145
146 sk_sp<GrThreadSafeCache::VertexData> detachVertexData() {
147 SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && fVertexData);
148
149 return std::move(fVertexData);
150 }
Brian Salomon12d22642019-01-29 14:38:50 -0500151
senorblanco6599eff2016-03-10 08:38:45 -0800152private:
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500153 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
Brian Salomondbf70722019-02-07 11:31:24 -0500154 sk_sp<GrGpuBuffer> fVertexBuffer;
senorblanco6599eff2016-03-10 08:38:45 -0800155 GrResourceProvider* fResourceProvider;
156 bool fCanMapVB;
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500157 void* fVertices = nullptr;
158 size_t fLockStride = 0;
159};
160
161class CpuVertexAllocator : public GrEagerVertexAllocator {
162public:
163 CpuVertexAllocator() = default;
164
165#ifdef SK_DEBUG
166 ~CpuVertexAllocator() override {
167 SkASSERT(!fLockStride && !fVertices && !fVertexData);
168 }
169#endif
170
171 void* lock(size_t stride, int eagerCount) override {
172 SkASSERT(!fLockStride && !fVertices && !fVertexData);
173 SkASSERT(stride && eagerCount);
174
175 fVertices = sk_malloc_throw(eagerCount * stride);
176 fLockStride = stride;
177
178 return fVertices;
179 }
180
181 void unlock(int actualCount) override {
182 SkASSERT(fLockStride && fVertices && !fVertexData);
183
184 fVertices = sk_realloc_throw(fVertices, actualCount * fLockStride);
185
186 fVertexData = GrThreadSafeCache::MakeVertexData(fVertices, actualCount, fLockStride);
187
188 fVertices = nullptr;
189 fLockStride = 0;
190 }
191
192 sk_sp<GrThreadSafeCache::VertexData> detachVertexData() {
193 SkASSERT(!fLockStride && !fVertices && fVertexData);
194
195 return std::move(fVertexData);
196 }
197
198private:
199 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
200
201 void* fVertices = nullptr;
Chris Daltond081dce2020-01-23 12:09:04 -0700202 size_t fLockStride = 0;
senorblanco6599eff2016-03-10 08:38:45 -0800203};
204
ethannicholase9709e82016-01-07 13:34:16 -0800205} // namespace
senorblancod6ed19c2015-02-26 06:58:17 -0800206
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400207
Chris Dalton17dc4182020-03-25 16:18:16 -0600208GrTriangulatingPathRenderer::GrTriangulatingPathRenderer()
Stephen White8a3c0592019-05-29 11:26:16 -0400209 : fMaxVerbCount(GR_AA_TESSELLATOR_MAX_VERB_COUNT) {
senorblancod6ed19c2015-02-26 06:58:17 -0800210}
211
Chris Dalton5ed44232017-09-07 13:22:46 -0600212GrPathRenderer::CanDrawPath
Chris Dalton17dc4182020-03-25 16:18:16 -0600213GrTriangulatingPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
Chris Daltone5ede4b2017-09-07 18:33:08 +0000214 // This path renderer can draw fill styles, and can do screenspace antialiasing via a
215 // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
216 // ones to simpler algorithms. We pass on paths that have styles, though they may come back
Chris Dalton09e56892019-03-13 00:22:01 -0600217 // around after applying the styling information to the geometry to create a filled path.
Chris Daltone5ede4b2017-09-07 18:33:08 +0000218 if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
Chris Dalton5ed44232017-09-07 13:22:46 -0600219 return CanDrawPath::kNo;
senorblancof57372d2016-08-31 10:36:19 -0700220 }
Chris Dalton6ce447a2019-06-23 18:07:38 -0600221 switch (args.fAAType) {
222 case GrAAType::kNone:
223 case GrAAType::kMSAA:
224 // Prefer MSAA, if any antialiasing. In the non-analytic-AA case, We skip paths that
225 // don't have a key since the real advantage of this path renderer comes from caching
226 // the tessellated geometry.
227 if (!args.fShape->hasUnstyledKey()) {
228 return CanDrawPath::kNo;
229 }
230 break;
231 case GrAAType::kCoverage:
232 // Use analytic AA if we don't have MSAA. In this case, we do not cache, so we accept
233 // paths without keys.
234 SkPath path;
235 args.fShape->asPath(&path);
236 if (path.countVerbs() > fMaxVerbCount) {
237 return CanDrawPath::kNo;
238 }
239 break;
senorblancof57372d2016-08-31 10:36:19 -0700240 }
Chris Dalton5ed44232017-09-07 13:22:46 -0600241 return CanDrawPath::kYes;
senorblancod6ed19c2015-02-26 06:58:17 -0800242}
243
Brian Salomon9530f7e2017-07-11 09:03:10 -0400244namespace {
245
Chris Dalton17dc4182020-03-25 16:18:16 -0600246class TriangulatingPathOp final : public GrMeshDrawOp {
Brian Salomon9530f7e2017-07-11 09:03:10 -0400247private:
248 using Helper = GrSimpleMeshDrawOpHelperWithStencil;
249
senorblanco9ba39722015-03-05 07:13:42 -0800250public:
Brian Salomon25a88092016-12-01 09:36:50 -0500251 DEFINE_OP_CLASS_ID
senorblanco9ba39722015-03-05 07:13:42 -0800252
Herb Derbyc76d4092020-10-07 16:46:15 -0400253 static GrOp::Owner Make(GrRecordingContext* context,
254 GrPaint&& paint,
255 const GrStyledShape& shape,
256 const SkMatrix& viewMatrix,
257 SkIRect devClipBounds,
258 GrAAType aaType,
259 const GrUserStencilSettings* stencilSettings) {
Chris Dalton17dc4182020-03-25 16:18:16 -0600260 return Helper::FactoryHelper<TriangulatingPathOp>(context, std::move(paint), shape,
261 viewMatrix, devClipBounds, aaType,
262 stencilSettings);
senorblanco9ba39722015-03-05 07:13:42 -0800263 }
264
Chris Dalton17dc4182020-03-25 16:18:16 -0600265 const char* name() const override { return "TriangulatingPathOp"; }
senorblanco9ba39722015-03-05 07:13:42 -0800266
Chris Dalton1706cbf2019-05-21 19:35:29 -0600267 void visitProxies(const VisitProxyFunc& func) const override {
Robert Phillips740d34f2020-03-11 09:36:13 -0400268 if (fProgramInfo) {
Chris Daltonbe457422020-03-16 18:05:03 -0600269 fProgramInfo->visitFPProxies(func);
Robert Phillips740d34f2020-03-11 09:36:13 -0400270 } else {
271 fHelper.visitProxies(func);
272 }
Robert Phillipsb493eeb2017-09-13 13:10:52 -0400273 }
274
Herb Derbyc76d4092020-10-07 16:46:15 -0400275 TriangulatingPathOp(GrProcessorSet* processorSet,
Chris Dalton17dc4182020-03-25 16:18:16 -0600276 const SkPMColor4f& color,
Michael Ludwig2686d692020-04-17 20:21:37 +0000277 const GrStyledShape& shape,
Chris Dalton17dc4182020-03-25 16:18:16 -0600278 const SkMatrix& viewMatrix,
279 const SkIRect& devClipBounds,
280 GrAAType aaType,
281 const GrUserStencilSettings* stencilSettings)
Brian Salomon9530f7e2017-07-11 09:03:10 -0400282 : INHERITED(ClassID())
Herb Derbyc76d4092020-10-07 16:46:15 -0400283 , fHelper(processorSet, aaType, stencilSettings)
Brian Salomon9530f7e2017-07-11 09:03:10 -0400284 , fColor(color)
285 , fShape(shape)
286 , fViewMatrix(viewMatrix)
287 , fDevClipBounds(devClipBounds)
288 , fAntiAlias(GrAAType::kCoverage == aaType) {
289 SkRect devBounds;
290 viewMatrix.mapRect(&devBounds, shape.bounds());
291 if (shape.inverseFilled()) {
292 // Because the clip bounds are used to add a contour for inverse fills, they must also
293 // include the path bounds.
294 devBounds.join(SkRect::Make(fDevClipBounds));
295 }
Michael Ludwigb6a38292020-12-18 09:01:03 -0500296 this->setBounds(devBounds, HasAABloat(fAntiAlias), IsHairline::kNo);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400297 }
298
299 FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
300
Chris Dalton6ce447a2019-06-23 18:07:38 -0600301 GrProcessorSet::Analysis finalize(
302 const GrCaps& caps, const GrAppliedClip* clip, bool hasMixedSampledCoverage,
303 GrClampType clampType) override {
Brian Salomon9530f7e2017-07-11 09:03:10 -0400304 GrProcessorAnalysisCoverage coverage = fAntiAlias
305 ? GrProcessorAnalysisCoverage::kSingleChannel
306 : GrProcessorAnalysisCoverage::kNone;
Brian Osman8fa7ab42019-03-18 10:22:42 -0400307 // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
308 return fHelper.finalizeProcessors(
Chris Dalton6ce447a2019-06-23 18:07:38 -0600309 caps, clip, hasMixedSampledCoverage, clampType, coverage, &fColor, nullptr);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400310 }
311
Brian Salomon92aee3d2016-12-21 09:20:25 -0500312private:
senorblancof57372d2016-08-31 10:36:19 -0700313 SkPath getPath() const {
314 SkASSERT(!fShape.style().applies());
bsalomonee432412016-06-27 07:18:18 -0700315 SkPath path;
316 fShape.asPath(&path);
senorblancof57372d2016-08-31 10:36:19 -0700317 return path;
318 }
319
Robert Phillips6ffcb232020-10-14 12:40:13 -0400320 static void CreateKey(GrUniqueKey* key,
321 const GrStyledShape& shape,
322 const SkIRect& devClipBounds) {
senorblanco84cd6212015-08-04 10:01:58 -0700323 static const GrUniqueKey::Domain kDomain = GrUniqueKey::GenerateDomain();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400324
325 bool inverseFill = shape.inverseFilled();
326
327 static constexpr int kClipBoundsCnt = sizeof(devClipBounds) / sizeof(uint32_t);
328 int shapeKeyDataCnt = shape.unstyledKeySize();
bsalomonee432412016-06-27 07:18:18 -0700329 SkASSERT(shapeKeyDataCnt >= 0);
Robert Phillips6ffcb232020-10-14 12:40:13 -0400330 GrUniqueKey::Builder builder(key, kDomain, shapeKeyDataCnt + kClipBoundsCnt, "Path");
331 shape.writeUnstyledKey(&builder[0]);
bsalomonee432412016-06-27 07:18:18 -0700332 // For inverse fills, the tessellation is dependent on clip bounds.
333 if (inverseFill) {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400334 memcpy(&builder[shapeKeyDataCnt], &devClipBounds, sizeof(devClipBounds));
bsalomonee432412016-06-27 07:18:18 -0700335 } else {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400336 memset(&builder[shapeKeyDataCnt], 0, sizeof(devClipBounds));
bsalomonee432412016-06-27 07:18:18 -0700337 }
Robert Phillips6ffcb232020-10-14 12:40:13 -0400338
bsalomonee432412016-06-27 07:18:18 -0700339 builder.finish();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400340 }
341
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400342 // Triangulate the provided 'shape' in the shape's coordinate space. 'tol' should already
343 // have been mapped back from device space.
344 static int Triangulate(GrEagerVertexAllocator* allocator,
345 const SkMatrix& viewMatrix,
346 const GrStyledShape& shape,
347 const SkIRect& devClipBounds,
348 SkScalar tol,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700349 bool* isLinear) {
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400350 SkRect clipBounds = SkRect::Make(devClipBounds);
351
352 SkMatrix vmi;
353 if (!viewMatrix.invert(&vmi)) {
354 return 0;
355 }
356 vmi.mapRect(&clipBounds);
357
358 SkASSERT(!shape.style().applies());
359 SkPath path;
360 shape.asPath(&path);
361
Chris Dalton854ee852021-01-05 15:12:59 -0700362 return GrTriangulator::PathToTriangles(path, tol, clipBounds, allocator, isLinear);
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400363 }
364
Robert Phillips6ffcb232020-10-14 12:40:13 -0400365 void createNonAAMesh(Target* target) {
366 SkASSERT(!fAntiAlias);
367 GrResourceProvider* rp = target->resourceProvider();
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500368 auto threadSafeCache = target->threadSafeCache();
Robert Phillips6ffcb232020-10-14 12:40:13 -0400369
370 GrUniqueKey key;
371 CreateKey(&key, fShape, fDevClipBounds);
372
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400373 SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance,
374 fViewMatrix, fShape.bounds());
375
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500376 if (!fVertexData) {
377 auto [cachedVerts, data] = threadSafeCache->findVertsWithData(key);
Robert Phillips7ffdb692020-11-03 08:57:04 -0500378 if (cachedVerts && cache_match(data.get(), tol)) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500379 fVertexData = std::move(cachedVerts);
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400380 }
senorblanco84cd6212015-08-04 10:01:58 -0700381 }
382
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500383 if (fVertexData) {
384 if (!fVertexData->gpuBuffer()) {
385 sk_sp<GrGpuBuffer> buffer = rp->createBuffer(fVertexData->size(),
386 GrGpuBufferType::kVertex,
387 kStatic_GrAccessPattern,
388 fVertexData->vertices());
389 if (!buffer) {
390 return;
391 }
392
393 // Since we have a direct context and a ref on 'fVertexData' we need not worry
394 // about any threading issues in this call.
395 fVertexData->setGpuBuffer(std::move(buffer));
396 }
397
398 fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices());
399 return;
400 }
401
senorblanco6599eff2016-03-10 08:38:45 -0800402 bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
Chris Daltond081dce2020-01-23 12:09:04 -0700403 StaticVertexAllocator allocator(rp, canMapVB);
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400404
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700405 bool isLinear;
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400406 int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700407 &isLinear);
Chris Dalton8e2b6942020-04-22 15:55:00 -0600408 if (vertexCount == 0) {
senorblanco6599eff2016-03-10 08:38:45 -0800409 return;
410 }
Robert Phillips9dfc6d82020-10-20 10:05:58 -0400411
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500412 fVertexData = allocator.detachVertexData();
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400413
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700414 key.setCustomData(create_data(vertexCount, isLinear, tol));
Robert Phillips6cc9d8d2020-10-20 09:42:33 -0400415
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500416 auto [tmpV, tmpD] = threadSafeCache->addVertsWithData(key, fVertexData, is_newer_better);
417 if (tmpV != fVertexData) {
418 SkASSERT(!tmpV->gpuBuffer());
419 // In this case, although the different triangulation found in the cache is better,
420 // we will continue on with the current triangulation since it is already on the gpu.
421 } else {
422 // This isn't perfect. The current triangulation is in the cache but it may have
423 // replaced a pre-existing one. A duplicated listener is unlikely and not that
424 // expensive so we just roll with it.
425 fShape.addGenIDChangeListener(
Brian Salomon99a813c2020-03-02 12:50:47 -0500426 sk_make_sp<UniqueKeyInvalidator>(key, target->contextUniqueID()));
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500427 }
Brian Salomon12d22642019-01-29 14:38:50 -0500428
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500429 fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices());
senorblanco6599eff2016-03-10 08:38:45 -0800430 }
431
Robert Phillips6ffcb232020-10-14 12:40:13 -0400432 void createAAMesh(Target* target) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500433 SkASSERT(!fVertexData);
senorblancof57372d2016-08-31 10:36:19 -0700434 SkASSERT(fAntiAlias);
Robert Phillips6ffcb232020-10-14 12:40:13 -0400435 SkPath path = this->getPath();
senorblancof57372d2016-08-31 10:36:19 -0700436 if (path.isEmpty()) {
437 return;
438 }
439 SkRect clipBounds = SkRect::Make(fDevClipBounds);
440 path.transform(fViewMatrix);
441 SkScalar tol = GrPathUtils::kDefaultTolerance;
Chris Daltond081dce2020-01-23 12:09:04 -0700442 sk_sp<const GrBuffer> vertexBuffer;
443 int firstVertex;
Chris Daltond081dce2020-01-23 12:09:04 -0700444 GrEagerDynamicVertexAllocator allocator(target, &vertexBuffer, &firstVertex);
Chris Daltond5384792021-01-20 15:43:24 -0700445 int vertexCount = GrAATriangulator::PathToAATriangles(path, tol, clipBounds, &allocator);
Chris Dalton8e2b6942020-04-22 15:55:00 -0600446 if (vertexCount == 0) {
senorblancof57372d2016-08-31 10:36:19 -0700447 return;
448 }
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400449 fMesh = CreateMesh(target, std::move(vertexBuffer), firstVertex, vertexCount);
senorblancof57372d2016-08-31 10:36:19 -0700450 }
451
Robert Phillips2669a7b2020-03-12 12:07:19 -0400452 GrProgramInfo* programInfo() override { return fProgramInfo; }
453
Robert Phillips4133dc42020-03-11 15:55:55 -0400454 void onCreateProgramInfo(const GrCaps* caps,
455 SkArenaAlloc* arena,
Adlai Hollere2296f72020-11-19 13:41:26 -0500456 const GrSurfaceProxyView& writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400457 GrAppliedClip&& appliedClip,
Greg Danield358cbe2020-09-11 09:33:54 -0400458 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500459 GrXferBarrierFlags renderPassXferBarriers,
460 GrLoadOp colorLoadOp) override {
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500461 GrGeometryProcessor* gp;
joshualittdf0c5572015-08-03 11:35:28 -0700462 {
463 using namespace GrDefaultGeoProcFactory;
464
465 Color color(fColor);
Brian Salomon9530f7e2017-07-11 09:03:10 -0400466 LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
Brian Salomon8c852be2017-01-04 10:44:42 -0500467 ? LocalCoords::kUsePosition_Type
468 : LocalCoords::kUnused_Type;
joshualittdf0c5572015-08-03 11:35:28 -0700469 Coverage::Type coverageType;
senorblancof57372d2016-08-31 10:36:19 -0700470 if (fAntiAlias) {
Brian Osman605c6d52019-03-15 12:10:35 -0400471 if (fHelper.compatibleWithCoverageAsAlpha()) {
Brian Osman80879d42019-01-07 16:15:27 -0500472 coverageType = Coverage::kAttributeTweakAlpha_Type;
senorblancof57372d2016-08-31 10:36:19 -0700473 } else {
474 coverageType = Coverage::kAttribute_Type;
475 }
Brian Salomon8c852be2017-01-04 10:44:42 -0500476 } else {
joshualittdf0c5572015-08-03 11:35:28 -0700477 coverageType = Coverage::kSolid_Type;
joshualittdf0c5572015-08-03 11:35:28 -0700478 }
senorblancof57372d2016-08-31 10:36:19 -0700479 if (fAntiAlias) {
Brian Osmanf0aee742020-03-12 09:28:44 -0400480 gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(arena, color, coverageType,
Brian Salomon8c852be2017-01-04 10:44:42 -0500481 localCoordsType, fViewMatrix);
senorblancof57372d2016-08-31 10:36:19 -0700482 } else {
Brian Osmanf0aee742020-03-12 09:28:44 -0400483 gp = GrDefaultGeoProcFactory::Make(arena, color, coverageType, localCoordsType,
Brian Salomon8c852be2017-01-04 10:44:42 -0500484 fViewMatrix);
senorblancof57372d2016-08-31 10:36:19 -0700485 }
joshualittdf0c5572015-08-03 11:35:28 -0700486 }
Robert Phillips7cd0bfe2019-11-20 16:08:10 -0500487 if (!gp) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400488 return;
Stephen Whitecc700832017-02-15 11:45:16 -0500489 }
Robert Phillips740d34f2020-03-11 09:36:13 -0400490
Chris Daltondcc8c542020-01-28 17:55:56 -0700491#ifdef SK_DEBUG
Chris Dalton854ee852021-01-05 15:12:59 -0700492 auto vertexStride = sizeof(SkPoint);
493 if (fAntiAlias) {
494 vertexStride += sizeof(float);
495 }
496 SkASSERT(vertexStride == gp->vertexStride());
Chris Daltondcc8c542020-01-28 17:55:56 -0700497#endif
senorblanco84cd6212015-08-04 10:01:58 -0700498
Chris Dalton17dc4182020-03-25 16:18:16 -0600499 GrPrimitiveType primitiveType = TRIANGULATOR_WIREFRAME ? GrPrimitiveType::kLines
500 : GrPrimitiveType::kTriangles;
Robert Phillipse94cdd22019-11-04 14:15:58 -0500501
Brian Salomon8afde5f2020-04-01 16:22:00 -0400502 fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView,
Robert Phillips4133dc42020-03-11 15:55:55 -0400503 std::move(appliedClip), dstProxyView,
Greg Danield358cbe2020-09-11 09:33:54 -0400504 gp, primitiveType,
Greg Daniel42dbca52020-11-20 10:22:43 -0500505 renderPassXferBarriers, colorLoadOp);
Robert Phillips740d34f2020-03-11 09:36:13 -0400506 }
507
Robert Phillips473a8482020-10-20 10:44:15 -0400508 void onPrePrepareDraws(GrRecordingContext* rContext,
Adlai Hollere2296f72020-11-19 13:41:26 -0500509 const GrSurfaceProxyView& writeView,
Robert Phillips473a8482020-10-20 10:44:15 -0400510 GrAppliedClip* clip,
511 const GrXferProcessor::DstProxyView& dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500512 GrXferBarrierFlags renderPassXferBarriers,
513 GrLoadOp colorLoadOp) override {
Robert Phillips473a8482020-10-20 10:44:15 -0400514 TRACE_EVENT0("skia.gpu", TRACE_FUNC);
515
516 INHERITED::onPrePrepareDraws(rContext, writeView, clip, dstProxyView,
Greg Daniel42dbca52020-11-20 10:22:43 -0500517 renderPassXferBarriers, colorLoadOp);
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500518
519 if (fAntiAlias) {
520 // TODO: pull the triangulation work forward to the recording thread for the AA case
521 // too.
522 return;
523 }
524
525 auto threadSafeViewCache = rContext->priv().threadSafeCache();
526
527 GrUniqueKey key;
528 CreateKey(&key, fShape, fDevClipBounds);
529
530 SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance,
531 fViewMatrix, fShape.bounds());
532
533 auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key);
Robert Phillips7ffdb692020-11-03 08:57:04 -0500534 if (cachedVerts && cache_match(data.get(), tol)) {
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500535 fVertexData = std::move(cachedVerts);
536 return;
537 }
538
539 CpuVertexAllocator allocator;
540
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700541 bool isLinear;
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500542 int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700543 &isLinear);
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500544 if (vertexCount == 0) {
545 return;
546 }
547
548 fVertexData = allocator.detachVertexData();
549
Chris Dalton86d4cfd2020-11-03 13:51:21 -0700550 key.setCustomData(create_data(vertexCount, isLinear, tol));
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500551
552 // If some other thread created and cached its own triangulation, the 'is_newer_better'
553 // predicate will replace the version in the cache if 'fVertexData' is a more accurate
554 // triangulation. This will leave some other recording threads using a poorer triangulation
555 // but will result in a version with greater applicability being in the cache.
556 auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData,
557 is_newer_better);
558 if (tmpV != fVertexData) {
559 // Someone beat us to creating the triangulation (and it is better than ours) so
560 // just go ahead and use it.
Robert Phillips7ffdb692020-11-03 08:57:04 -0500561 SkASSERT(cache_match(tmpD.get(), tol));
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500562 fVertexData = std::move(tmpV);
563 } else {
564 // This isn't perfect. The current triangulation is in the cache but it may have
565 // replaced a pre-existing one. A duplicated listener is unlikely and not that
566 // expensive so we just roll with it.
567 fShape.addGenIDChangeListener(
568 sk_make_sp<UniqueKeyInvalidator>(key, rContext->priv().contextID()));
569 }
Robert Phillips473a8482020-10-20 10:44:15 -0400570 }
571
Robert Phillips740d34f2020-03-11 09:36:13 -0400572 void onPrepareDraws(Target* target) override {
573 if (fAntiAlias) {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400574 this->createAAMesh(target);
Robert Phillips740d34f2020-03-11 09:36:13 -0400575 } else {
Robert Phillips6ffcb232020-10-14 12:40:13 -0400576 this->createNonAAMesh(target);
Robert Phillips740d34f2020-03-11 09:36:13 -0400577 }
578 }
579
Robert Phillips3ac83b2f2020-10-26 13:50:57 -0400580 static GrSimpleMesh* CreateMesh(Target* target, sk_sp<const GrBuffer> vb,
581 int firstVertex, int count) {
582 auto mesh = target->allocMesh();
583 mesh->set(std::move(vb), count, firstVertex);
584 return mesh;
Chris Dalton07cdcfc92019-02-26 11:13:22 -0700585 }
586
587 void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
Robert Phillips740d34f2020-03-11 09:36:13 -0400588 if (!fProgramInfo) {
Robert Phillips4133dc42020-03-11 15:55:55 -0400589 this->createProgramInfo(flushState);
Robert Phillips740d34f2020-03-11 09:36:13 -0400590 }
Robert Phillips3968fcb2019-12-05 16:40:31 -0500591
Robert Phillips740d34f2020-03-11 09:36:13 -0400592 if (!fProgramInfo || !fMesh) {
593 return;
594 }
595
Chris Dalton765ed362020-03-16 17:34:44 -0600596 flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
597 flushState->bindTextures(fProgramInfo->primProc(), nullptr, fProgramInfo->pipeline());
598 flushState->drawMesh(*fMesh);
senorblanco9ba39722015-03-05 07:13:42 -0800599 }
600
John Stilesaf366522020-08-13 09:57:34 -0400601#if GR_TEST_UTILS
602 SkString onDumpInfo() const override {
603 return SkStringPrintf("Color 0x%08x, aa: %d\n%s",
604 fColor.toBytes_RGBA(), fAntiAlias, fHelper.dumpInfo().c_str());
605 }
606#endif
607
Robert Phillips740d34f2020-03-11 09:36:13 -0400608 Helper fHelper;
609 SkPMColor4f fColor;
Michael Ludwig2686d692020-04-17 20:21:37 +0000610 GrStyledShape fShape;
Robert Phillips740d34f2020-03-11 09:36:13 -0400611 SkMatrix fViewMatrix;
612 SkIRect fDevClipBounds;
613 bool fAntiAlias;
614
Chris Daltoneb694b72020-03-16 09:25:50 -0600615 GrSimpleMesh* fMesh = nullptr;
Robert Phillips740d34f2020-03-11 09:36:13 -0400616 GrProgramInfo* fProgramInfo = nullptr;
reed1b55a962015-09-17 20:16:13 -0700617
Robert Phillipsf9a1b822020-11-02 11:40:00 -0500618 sk_sp<GrThreadSafeCache::VertexData> fVertexData;
619
John Stiles7571f9e2020-09-02 22:42:33 -0400620 using INHERITED = GrMeshDrawOp;
senorblanco9ba39722015-03-05 07:13:42 -0800621};
622
Brian Salomon9530f7e2017-07-11 09:03:10 -0400623} // anonymous namespace
624
Chris Dalton17dc4182020-03-25 16:18:16 -0600625bool GrTriangulatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
Brian Osman11052242016-10-27 14:47:55 -0400626 GR_AUDIT_TRAIL_AUTO_FRAME(args.fRenderTargetContext->auditTrail(),
Chris Dalton17dc4182020-03-25 16:18:16 -0600627 "GrTriangulatingPathRenderer::onDrawPath");
Michael Ludwig7c12e282020-05-29 09:54:07 -0400628
Herb Derbyc76d4092020-10-07 16:46:15 -0400629 GrOp::Owner op = TriangulatingPathOp::Make(
Michael Ludwig7c12e282020-05-29 09:54:07 -0400630 args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix,
631 *args.fClipConservativeBounds, args.fAAType, args.fUserStencilSettings);
632 args.fRenderTargetContext->addDrawOp(args.fClip, std::move(op));
senorblancod6ed19c2015-02-26 06:58:17 -0800633 return true;
634}
joshualitt2fbd4062015-05-07 13:06:41 -0700635
636///////////////////////////////////////////////////////////////////////////////////////////////////
637
Hal Canary6f6961e2017-01-31 13:50:44 -0500638#if GR_TEST_UTILS
joshualitt2fbd4062015-05-07 13:06:41 -0700639
Chris Dalton17dc4182020-03-25 16:18:16 -0600640GR_DRAW_OP_TEST_DEFINE(TriangulatingPathOp) {
joshualitt2fbd4062015-05-07 13:06:41 -0700641 SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
John Stiles31954bf2020-08-07 17:35:54 -0400642 const SkPath& path = GrTest::TestPath(random);
bsalomond3030ac2016-09-01 07:20:29 -0700643 SkIRect devClipBounds = SkIRect::MakeLTRB(
senorblancof57372d2016-08-31 10:36:19 -0700644 random->nextU(), random->nextU(), random->nextU(), random->nextU());
bsalomond3030ac2016-09-01 07:20:29 -0700645 devClipBounds.sort();
Brian Salomon9530f7e2017-07-11 09:03:10 -0400646 static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kMSAA, GrAAType::kCoverage};
647 GrAAType aaType;
648 do {
649 aaType = kAATypes[random->nextULessThan(SK_ARRAY_COUNT(kAATypes))];
Chris Dalton6ce447a2019-06-23 18:07:38 -0600650 } while(GrAAType::kMSAA == aaType && numSamples <= 1);
bsalomon6663acf2016-05-10 09:14:17 -0700651 GrStyle style;
652 do {
653 GrTest::TestStyle(random, &style);
senorblancof57372d2016-08-31 10:36:19 -0700654 } while (!style.isSimpleFill());
Michael Ludwig2686d692020-04-17 20:21:37 +0000655 GrStyledShape shape(path, style);
Chris Dalton17dc4182020-03-25 16:18:16 -0600656 return TriangulatingPathOp::Make(context, std::move(paint), shape, viewMatrix, devClipBounds,
657 aaType, GrGetRandomStencil(random, context));
joshualitt2fbd4062015-05-07 13:06:41 -0700658}
659
660#endif