xref: /aosp_15_r20/external/skia/src/gpu/ganesh/ops/TriangulatingPathRenderer.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2015 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/TriangulatingPathRenderer.h"
8*c8dee2aaSAndroid Build Coastguard Worker 
9*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkData.h"
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkMatrix.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRect.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkRefCnt.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkString.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkSurfaceProps.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "include/gpu/ganesh/GrRecordingContext.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkColorData.h"
21*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/SkIDChangeListener.h"
22*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkMalloc.h"
23*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/gpu/ganesh/GrTypesPriv.h"
24*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkMessageBus.h"
25*c8dee2aaSAndroid Build Coastguard Worker #include "src/core/SkTraceEvent.h"
26*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ResourceKey.h"
27*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAppliedClip.h"
28*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrAuditTrail.h"
29*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrBuffer.h"
30*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrCaps.h"
31*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDefaultGeoProcFactory.h"
32*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrDrawOpTest.h"
33*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrEagerVertexAllocator.h"
34*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGeometryProcessor.h"
35*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrGpuBuffer.h"
36*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrMeshDrawTarget.h"
37*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrOpFlushState.h"
38*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrPaint.h"
39*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorAnalysis.h"
40*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProcessorSet.h"
41*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrProgramInfo.h"
42*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrRecordingContextPriv.h"
43*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrResourceProvider.h"
44*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrSimpleMesh.h"
45*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrStyle.h"
46*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrThreadSafeCache.h"
47*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/SurfaceDrawContext.h"
48*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrAATriangulator.h"
49*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrPathUtils.h"
50*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrStyledShape.h"
51*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/geometry/GrTriangulator.h"
52*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrMeshDrawOp.h"
53*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrOp.h"
54*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
55*c8dee2aaSAndroid Build Coastguard Worker 
56*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
57*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkRandom.h"
58*c8dee2aaSAndroid Build Coastguard Worker #include "src/gpu/ganesh/GrTestUtils.h"
59*c8dee2aaSAndroid Build Coastguard Worker #endif
60*c8dee2aaSAndroid Build Coastguard Worker 
61*c8dee2aaSAndroid Build Coastguard Worker #include <array>
62*c8dee2aaSAndroid Build Coastguard Worker #include <cstdint>
63*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
64*c8dee2aaSAndroid Build Coastguard Worker #include <utility>
65*c8dee2aaSAndroid Build Coastguard Worker 
66*c8dee2aaSAndroid Build Coastguard Worker class GrDstProxyView;
67*c8dee2aaSAndroid Build Coastguard Worker class GrSurfaceProxyView;
68*c8dee2aaSAndroid Build Coastguard Worker class SkArenaAlloc;
69*c8dee2aaSAndroid Build Coastguard Worker enum class GrXferBarrierFlags;
70*c8dee2aaSAndroid Build Coastguard Worker struct GrUserStencilSettings;
71*c8dee2aaSAndroid Build Coastguard Worker 
72*c8dee2aaSAndroid Build Coastguard Worker #if !defined(SK_ENABLE_OPTIMIZE_SIZE)
73*c8dee2aaSAndroid Build Coastguard Worker 
74*c8dee2aaSAndroid Build Coastguard Worker #ifndef GR_AA_TESSELLATOR_MAX_VERB_COUNT
75*c8dee2aaSAndroid Build Coastguard Worker #define GR_AA_TESSELLATOR_MAX_VERB_COUNT 10
76*c8dee2aaSAndroid Build Coastguard Worker #endif
77*c8dee2aaSAndroid Build Coastguard Worker 
78*c8dee2aaSAndroid Build Coastguard Worker /*
79*c8dee2aaSAndroid Build Coastguard Worker  * This path renderer linearizes and decomposes the path into triangles using GrTriangulator,
80*c8dee2aaSAndroid Build Coastguard Worker  * uploads the triangles to a vertex buffer, and renders them with a single draw call. It can do
81*c8dee2aaSAndroid Build Coastguard Worker  * screenspace antialiasing with a one-pixel coverage ramp.
82*c8dee2aaSAndroid Build Coastguard Worker  */
83*c8dee2aaSAndroid Build Coastguard Worker namespace {
84*c8dee2aaSAndroid Build Coastguard Worker 
85*c8dee2aaSAndroid Build Coastguard Worker // The TessInfo struct contains ancillary data not specifically required for the triangle
86*c8dee2aaSAndroid Build Coastguard Worker // data (which is stored in a GrThreadSafeCache::VertexData object).
87*c8dee2aaSAndroid Build Coastguard Worker // The 'fNumVertices' field is a temporary exception. It is still needed to support the
88*c8dee2aaSAndroid Build Coastguard Worker // AA triangulated path case - which doesn't use the GrThreadSafeCache nor the VertexData object).
89*c8dee2aaSAndroid Build Coastguard Worker // When there is an associated VertexData, its numVertices should always match the TessInfo's
90*c8dee2aaSAndroid Build Coastguard Worker // value.
91*c8dee2aaSAndroid Build Coastguard Worker struct TessInfo {
92*c8dee2aaSAndroid Build Coastguard Worker     int       fNumVertices;
93*c8dee2aaSAndroid Build Coastguard Worker     bool      fIsLinear;
94*c8dee2aaSAndroid Build Coastguard Worker     SkScalar  fTolerance;
95*c8dee2aaSAndroid Build Coastguard Worker };
96*c8dee2aaSAndroid Build Coastguard Worker 
create_data(int numVertices,bool isLinear,SkScalar tol)97*c8dee2aaSAndroid Build Coastguard Worker static sk_sp<SkData> create_data(int numVertices, bool isLinear, SkScalar tol) {
98*c8dee2aaSAndroid Build Coastguard Worker     TessInfo info { numVertices, isLinear, tol };
99*c8dee2aaSAndroid Build Coastguard Worker     return SkData::MakeWithCopy(&info, sizeof(info));
100*c8dee2aaSAndroid Build Coastguard Worker }
101*c8dee2aaSAndroid Build Coastguard Worker 
cache_match(const SkData * data,SkScalar tol)102*c8dee2aaSAndroid Build Coastguard Worker bool cache_match(const SkData* data, SkScalar tol) {
103*c8dee2aaSAndroid Build Coastguard Worker     SkASSERT(data);
104*c8dee2aaSAndroid Build Coastguard Worker 
105*c8dee2aaSAndroid Build Coastguard Worker     const TessInfo* info = static_cast<const TessInfo*>(data->data());
106*c8dee2aaSAndroid Build Coastguard Worker 
107*c8dee2aaSAndroid Build Coastguard Worker     return info->fIsLinear || info->fTolerance < 3.0f * tol;
108*c8dee2aaSAndroid Build Coastguard Worker }
109*c8dee2aaSAndroid Build Coastguard Worker 
110*c8dee2aaSAndroid Build Coastguard Worker // Should 'challenger' replace 'incumbent' in the cache if there is a collision?
is_newer_better(SkData * incumbent,SkData * challenger)111*c8dee2aaSAndroid Build Coastguard Worker bool is_newer_better(SkData* incumbent, SkData* challenger) {
112*c8dee2aaSAndroid Build Coastguard Worker     const TessInfo* i = static_cast<const TessInfo*>(incumbent->data());
113*c8dee2aaSAndroid Build Coastguard Worker     const TessInfo* c = static_cast<const TessInfo*>(challenger->data());
114*c8dee2aaSAndroid Build Coastguard Worker 
115*c8dee2aaSAndroid Build Coastguard Worker     if (i->fIsLinear || i->fTolerance <= c->fTolerance) {
116*c8dee2aaSAndroid Build Coastguard Worker         return false;  // prefer the incumbent
117*c8dee2aaSAndroid Build Coastguard Worker     }
118*c8dee2aaSAndroid Build Coastguard Worker 
119*c8dee2aaSAndroid Build Coastguard Worker     return true;
120*c8dee2aaSAndroid Build Coastguard Worker }
121*c8dee2aaSAndroid Build Coastguard Worker 
122*c8dee2aaSAndroid Build Coastguard Worker // When the SkPathRef genID changes, invalidate a corresponding GrResource described by key.
123*c8dee2aaSAndroid Build Coastguard Worker class UniqueKeyInvalidator : public SkIDChangeListener {
124*c8dee2aaSAndroid Build Coastguard Worker public:
UniqueKeyInvalidator(const skgpu::UniqueKey & key,uint32_t contextUniqueID)125*c8dee2aaSAndroid Build Coastguard Worker     UniqueKeyInvalidator(const skgpu::UniqueKey& key, uint32_t contextUniqueID)
126*c8dee2aaSAndroid Build Coastguard Worker             : fMsg(key, contextUniqueID, /* inThreadSafeCache */ true) {}
127*c8dee2aaSAndroid Build Coastguard Worker 
128*c8dee2aaSAndroid Build Coastguard Worker private:
129*c8dee2aaSAndroid Build Coastguard Worker     skgpu::UniqueKeyInvalidatedMessage fMsg;
130*c8dee2aaSAndroid Build Coastguard Worker 
changed()131*c8dee2aaSAndroid Build Coastguard Worker     void changed() override {
132*c8dee2aaSAndroid Build Coastguard Worker         SkMessageBus<skgpu::UniqueKeyInvalidatedMessage, uint32_t>::Post(fMsg);
133*c8dee2aaSAndroid Build Coastguard Worker     }
134*c8dee2aaSAndroid Build Coastguard Worker };
135*c8dee2aaSAndroid Build Coastguard Worker 
136*c8dee2aaSAndroid Build Coastguard Worker class StaticVertexAllocator : public GrEagerVertexAllocator {
137*c8dee2aaSAndroid Build Coastguard Worker public:
StaticVertexAllocator(GrResourceProvider * resourceProvider,bool canMapVB)138*c8dee2aaSAndroid Build Coastguard Worker     StaticVertexAllocator(GrResourceProvider* resourceProvider, bool canMapVB)
139*c8dee2aaSAndroid Build Coastguard Worker             : fResourceProvider(resourceProvider)
140*c8dee2aaSAndroid Build Coastguard Worker             , fCanMapVB(canMapVB) {
141*c8dee2aaSAndroid Build Coastguard Worker     }
142*c8dee2aaSAndroid Build Coastguard Worker 
143*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
~StaticVertexAllocator()144*c8dee2aaSAndroid Build Coastguard Worker     ~StaticVertexAllocator() override {
145*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData);
146*c8dee2aaSAndroid Build Coastguard Worker     }
147*c8dee2aaSAndroid Build Coastguard Worker #endif
148*c8dee2aaSAndroid Build Coastguard Worker 
lock(size_t stride,int eagerCount)149*c8dee2aaSAndroid Build Coastguard Worker     void* lock(size_t stride, int eagerCount) override {
150*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && !fVertexData);
151*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(stride && eagerCount);
152*c8dee2aaSAndroid Build Coastguard Worker 
153*c8dee2aaSAndroid Build Coastguard Worker         size_t size = eagerCount * stride;
154*c8dee2aaSAndroid Build Coastguard Worker         fVertexBuffer = fResourceProvider->createBuffer(size,
155*c8dee2aaSAndroid Build Coastguard Worker                                                         GrGpuBufferType::kVertex,
156*c8dee2aaSAndroid Build Coastguard Worker                                                         kStatic_GrAccessPattern,
157*c8dee2aaSAndroid Build Coastguard Worker                                                         GrResourceProvider::ZeroInit::kNo);
158*c8dee2aaSAndroid Build Coastguard Worker         if (!fVertexBuffer) {
159*c8dee2aaSAndroid Build Coastguard Worker             return nullptr;
160*c8dee2aaSAndroid Build Coastguard Worker         }
161*c8dee2aaSAndroid Build Coastguard Worker         if (fCanMapVB) {
162*c8dee2aaSAndroid Build Coastguard Worker             fVertices = fVertexBuffer->map();
163*c8dee2aaSAndroid Build Coastguard Worker         }
164*c8dee2aaSAndroid Build Coastguard Worker         if (!fVertices) {
165*c8dee2aaSAndroid Build Coastguard Worker             fVertices = sk_malloc_throw(eagerCount * stride);
166*c8dee2aaSAndroid Build Coastguard Worker             fCanMapVB = false;
167*c8dee2aaSAndroid Build Coastguard Worker         }
168*c8dee2aaSAndroid Build Coastguard Worker         fLockStride = stride;
169*c8dee2aaSAndroid Build Coastguard Worker         return fVertices;
170*c8dee2aaSAndroid Build Coastguard Worker     }
171*c8dee2aaSAndroid Build Coastguard Worker 
unlock(int actualCount)172*c8dee2aaSAndroid Build Coastguard Worker     void unlock(int actualCount) override {
173*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fLockStride && fVertices && fVertexBuffer && !fVertexData);
174*c8dee2aaSAndroid Build Coastguard Worker 
175*c8dee2aaSAndroid Build Coastguard Worker         if (fCanMapVB) {
176*c8dee2aaSAndroid Build Coastguard Worker             fVertexBuffer->unmap();
177*c8dee2aaSAndroid Build Coastguard Worker         } else {
178*c8dee2aaSAndroid Build Coastguard Worker             fVertexBuffer->updateData(fVertices,
179*c8dee2aaSAndroid Build Coastguard Worker                                       /*offset=*/0,
180*c8dee2aaSAndroid Build Coastguard Worker                                       /*size=*/actualCount*fLockStride,
181*c8dee2aaSAndroid Build Coastguard Worker                                       /*preserve=*/false);
182*c8dee2aaSAndroid Build Coastguard Worker             sk_free(fVertices);
183*c8dee2aaSAndroid Build Coastguard Worker         }
184*c8dee2aaSAndroid Build Coastguard Worker 
185*c8dee2aaSAndroid Build Coastguard Worker         fVertexData = GrThreadSafeCache::MakeVertexData(std::move(fVertexBuffer),
186*c8dee2aaSAndroid Build Coastguard Worker                                                         actualCount, fLockStride);
187*c8dee2aaSAndroid Build Coastguard Worker 
188*c8dee2aaSAndroid Build Coastguard Worker         fVertices = nullptr;
189*c8dee2aaSAndroid Build Coastguard Worker         fLockStride = 0;
190*c8dee2aaSAndroid Build Coastguard Worker     }
191*c8dee2aaSAndroid Build Coastguard Worker 
detachVertexData()192*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrThreadSafeCache::VertexData> detachVertexData() {
193*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fLockStride && !fVertices && !fVertexBuffer && fVertexData);
194*c8dee2aaSAndroid Build Coastguard Worker 
195*c8dee2aaSAndroid Build Coastguard Worker         return std::move(fVertexData);
196*c8dee2aaSAndroid Build Coastguard Worker     }
197*c8dee2aaSAndroid Build Coastguard Worker 
198*c8dee2aaSAndroid Build Coastguard Worker private:
199*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrThreadSafeCache::VertexData> fVertexData;
200*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrGpuBuffer> fVertexBuffer;
201*c8dee2aaSAndroid Build Coastguard Worker     GrResourceProvider* fResourceProvider;
202*c8dee2aaSAndroid Build Coastguard Worker     bool fCanMapVB;
203*c8dee2aaSAndroid Build Coastguard Worker     void* fVertices = nullptr;
204*c8dee2aaSAndroid Build Coastguard Worker     size_t fLockStride = 0;
205*c8dee2aaSAndroid Build Coastguard Worker };
206*c8dee2aaSAndroid Build Coastguard Worker 
207*c8dee2aaSAndroid Build Coastguard Worker class TriangulatingPathOp final : public GrMeshDrawOp {
208*c8dee2aaSAndroid Build Coastguard Worker private:
209*c8dee2aaSAndroid Build Coastguard Worker     using Helper = GrSimpleMeshDrawOpHelperWithStencil;
210*c8dee2aaSAndroid Build Coastguard Worker 
211*c8dee2aaSAndroid Build Coastguard Worker public:
212*c8dee2aaSAndroid Build Coastguard Worker     DEFINE_OP_CLASS_ID
213*c8dee2aaSAndroid Build Coastguard Worker 
Make(GrRecordingContext * context,GrPaint && paint,const GrStyledShape & shape,const SkMatrix & viewMatrix,SkIRect devClipBounds,GrAAType aaType,const GrUserStencilSettings * stencilSettings)214*c8dee2aaSAndroid Build Coastguard Worker     static GrOp::Owner Make(GrRecordingContext* context,
215*c8dee2aaSAndroid Build Coastguard Worker                             GrPaint&& paint,
216*c8dee2aaSAndroid Build Coastguard Worker                             const GrStyledShape& shape,
217*c8dee2aaSAndroid Build Coastguard Worker                             const SkMatrix& viewMatrix,
218*c8dee2aaSAndroid Build Coastguard Worker                             SkIRect devClipBounds,
219*c8dee2aaSAndroid Build Coastguard Worker                             GrAAType aaType,
220*c8dee2aaSAndroid Build Coastguard Worker                             const GrUserStencilSettings* stencilSettings) {
221*c8dee2aaSAndroid Build Coastguard Worker         return Helper::FactoryHelper<TriangulatingPathOp>(context, std::move(paint), shape,
222*c8dee2aaSAndroid Build Coastguard Worker                                                           viewMatrix, devClipBounds, aaType,
223*c8dee2aaSAndroid Build Coastguard Worker                                                           stencilSettings);
224*c8dee2aaSAndroid Build Coastguard Worker     }
225*c8dee2aaSAndroid Build Coastguard Worker 
name() const226*c8dee2aaSAndroid Build Coastguard Worker     const char* name() const override { return "TriangulatingPathOp"; }
227*c8dee2aaSAndroid Build Coastguard Worker 
visitProxies(const GrVisitProxyFunc & func) const228*c8dee2aaSAndroid Build Coastguard Worker     void visitProxies(const GrVisitProxyFunc& func) const override {
229*c8dee2aaSAndroid Build Coastguard Worker         if (fProgramInfo) {
230*c8dee2aaSAndroid Build Coastguard Worker             fProgramInfo->visitFPProxies(func);
231*c8dee2aaSAndroid Build Coastguard Worker         } else {
232*c8dee2aaSAndroid Build Coastguard Worker             fHelper.visitProxies(func);
233*c8dee2aaSAndroid Build Coastguard Worker         }
234*c8dee2aaSAndroid Build Coastguard Worker     }
235*c8dee2aaSAndroid Build Coastguard Worker 
TriangulatingPathOp(GrProcessorSet * processorSet,const SkPMColor4f & color,const GrStyledShape & shape,const SkMatrix & viewMatrix,const SkIRect & devClipBounds,GrAAType aaType,const GrUserStencilSettings * stencilSettings)236*c8dee2aaSAndroid Build Coastguard Worker     TriangulatingPathOp(GrProcessorSet* processorSet,
237*c8dee2aaSAndroid Build Coastguard Worker                         const SkPMColor4f& color,
238*c8dee2aaSAndroid Build Coastguard Worker                         const GrStyledShape& shape,
239*c8dee2aaSAndroid Build Coastguard Worker                         const SkMatrix& viewMatrix,
240*c8dee2aaSAndroid Build Coastguard Worker                         const SkIRect& devClipBounds,
241*c8dee2aaSAndroid Build Coastguard Worker                         GrAAType aaType,
242*c8dee2aaSAndroid Build Coastguard Worker                         const GrUserStencilSettings* stencilSettings)
243*c8dee2aaSAndroid Build Coastguard Worker             : INHERITED(ClassID())
244*c8dee2aaSAndroid Build Coastguard Worker             , fHelper(processorSet, aaType, stencilSettings)
245*c8dee2aaSAndroid Build Coastguard Worker             , fColor(color)
246*c8dee2aaSAndroid Build Coastguard Worker             , fShape(shape)
247*c8dee2aaSAndroid Build Coastguard Worker             , fViewMatrix(viewMatrix)
248*c8dee2aaSAndroid Build Coastguard Worker             , fDevClipBounds(devClipBounds)
249*c8dee2aaSAndroid Build Coastguard Worker             , fAntiAlias(GrAAType::kCoverage == aaType) {
250*c8dee2aaSAndroid Build Coastguard Worker         SkRect devBounds;
251*c8dee2aaSAndroid Build Coastguard Worker         viewMatrix.mapRect(&devBounds, shape.bounds());
252*c8dee2aaSAndroid Build Coastguard Worker         if (shape.inverseFilled()) {
253*c8dee2aaSAndroid Build Coastguard Worker             // Because the clip bounds are used to add a contour for inverse fills, they must also
254*c8dee2aaSAndroid Build Coastguard Worker             // include the path bounds.
255*c8dee2aaSAndroid Build Coastguard Worker             devBounds.join(SkRect::Make(fDevClipBounds));
256*c8dee2aaSAndroid Build Coastguard Worker         }
257*c8dee2aaSAndroid Build Coastguard Worker         this->setBounds(devBounds, HasAABloat(fAntiAlias), IsHairline::kNo);
258*c8dee2aaSAndroid Build Coastguard Worker     }
259*c8dee2aaSAndroid Build Coastguard Worker 
fixedFunctionFlags() const260*c8dee2aaSAndroid Build Coastguard Worker     FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
261*c8dee2aaSAndroid Build Coastguard Worker 
finalize(const GrCaps & caps,const GrAppliedClip * clip,GrClampType clampType)262*c8dee2aaSAndroid Build Coastguard Worker     GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
263*c8dee2aaSAndroid Build Coastguard Worker                                       GrClampType clampType) override {
264*c8dee2aaSAndroid Build Coastguard Worker         GrProcessorAnalysisCoverage coverage = fAntiAlias
265*c8dee2aaSAndroid Build Coastguard Worker                                                        ? GrProcessorAnalysisCoverage::kSingleChannel
266*c8dee2aaSAndroid Build Coastguard Worker                                                        : GrProcessorAnalysisCoverage::kNone;
267*c8dee2aaSAndroid Build Coastguard Worker         // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
268*c8dee2aaSAndroid Build Coastguard Worker         return fHelper.finalizeProcessors(caps, clip, clampType, coverage, &fColor, nullptr);
269*c8dee2aaSAndroid Build Coastguard Worker     }
270*c8dee2aaSAndroid Build Coastguard Worker 
271*c8dee2aaSAndroid Build Coastguard Worker private:
getPath() const272*c8dee2aaSAndroid Build Coastguard Worker     SkPath getPath() const {
273*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fShape.style().applies());
274*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
275*c8dee2aaSAndroid Build Coastguard Worker         fShape.asPath(&path);
276*c8dee2aaSAndroid Build Coastguard Worker         return path;
277*c8dee2aaSAndroid Build Coastguard Worker     }
278*c8dee2aaSAndroid Build Coastguard Worker 
CreateKey(skgpu::UniqueKey * key,const GrStyledShape & shape,const SkIRect & devClipBounds)279*c8dee2aaSAndroid Build Coastguard Worker     static void CreateKey(skgpu::UniqueKey* key,
280*c8dee2aaSAndroid Build Coastguard Worker                           const GrStyledShape& shape,
281*c8dee2aaSAndroid Build Coastguard Worker                           const SkIRect& devClipBounds) {
282*c8dee2aaSAndroid Build Coastguard Worker         static const skgpu::UniqueKey::Domain kDomain = skgpu::UniqueKey::GenerateDomain();
283*c8dee2aaSAndroid Build Coastguard Worker 
284*c8dee2aaSAndroid Build Coastguard Worker         bool inverseFill = shape.inverseFilled();
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker         static constexpr int kClipBoundsCnt = sizeof(devClipBounds) / sizeof(uint32_t);
287*c8dee2aaSAndroid Build Coastguard Worker         int shapeKeyDataCnt = shape.unstyledKeySize();
288*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(shapeKeyDataCnt >= 0);
289*c8dee2aaSAndroid Build Coastguard Worker         skgpu::UniqueKey::Builder builder(key, kDomain, shapeKeyDataCnt + kClipBoundsCnt, "Path");
290*c8dee2aaSAndroid Build Coastguard Worker         shape.writeUnstyledKey(&builder[0]);
291*c8dee2aaSAndroid Build Coastguard Worker         // For inverse fills, the tessellation is dependent on clip bounds.
292*c8dee2aaSAndroid Build Coastguard Worker         if (inverseFill) {
293*c8dee2aaSAndroid Build Coastguard Worker             memcpy(&builder[shapeKeyDataCnt], &devClipBounds, sizeof(devClipBounds));
294*c8dee2aaSAndroid Build Coastguard Worker         } else {
295*c8dee2aaSAndroid Build Coastguard Worker             memset(&builder[shapeKeyDataCnt], 0, sizeof(devClipBounds));
296*c8dee2aaSAndroid Build Coastguard Worker         }
297*c8dee2aaSAndroid Build Coastguard Worker 
298*c8dee2aaSAndroid Build Coastguard Worker         builder.finish();
299*c8dee2aaSAndroid Build Coastguard Worker     }
300*c8dee2aaSAndroid Build Coastguard Worker 
301*c8dee2aaSAndroid Build Coastguard Worker     // Triangulate the provided 'shape' in the shape's coordinate space. 'tol' should already
302*c8dee2aaSAndroid Build Coastguard Worker     // have been mapped back from device space.
Triangulate(GrEagerVertexAllocator * allocator,const SkMatrix & viewMatrix,const GrStyledShape & shape,const SkIRect & devClipBounds,SkScalar tol,bool * isLinear)303*c8dee2aaSAndroid Build Coastguard Worker     static int Triangulate(GrEagerVertexAllocator* allocator,
304*c8dee2aaSAndroid Build Coastguard Worker                            const SkMatrix& viewMatrix,
305*c8dee2aaSAndroid Build Coastguard Worker                            const GrStyledShape& shape,
306*c8dee2aaSAndroid Build Coastguard Worker                            const SkIRect& devClipBounds,
307*c8dee2aaSAndroid Build Coastguard Worker                            SkScalar tol,
308*c8dee2aaSAndroid Build Coastguard Worker                            bool* isLinear) {
309*c8dee2aaSAndroid Build Coastguard Worker         SkRect clipBounds = SkRect::Make(devClipBounds);
310*c8dee2aaSAndroid Build Coastguard Worker 
311*c8dee2aaSAndroid Build Coastguard Worker         SkMatrix vmi;
312*c8dee2aaSAndroid Build Coastguard Worker         if (!viewMatrix.invert(&vmi)) {
313*c8dee2aaSAndroid Build Coastguard Worker             return 0;
314*c8dee2aaSAndroid Build Coastguard Worker         }
315*c8dee2aaSAndroid Build Coastguard Worker         vmi.mapRect(&clipBounds);
316*c8dee2aaSAndroid Build Coastguard Worker 
317*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!shape.style().applies());
318*c8dee2aaSAndroid Build Coastguard Worker         SkPath path;
319*c8dee2aaSAndroid Build Coastguard Worker         shape.asPath(&path);
320*c8dee2aaSAndroid Build Coastguard Worker 
321*c8dee2aaSAndroid Build Coastguard Worker         return GrTriangulator::PathToTriangles(path, tol, clipBounds, allocator, isLinear);
322*c8dee2aaSAndroid Build Coastguard Worker     }
323*c8dee2aaSAndroid Build Coastguard Worker 
createNonAAMesh(GrMeshDrawTarget * target)324*c8dee2aaSAndroid Build Coastguard Worker     void createNonAAMesh(GrMeshDrawTarget* target) {
325*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fAntiAlias);
326*c8dee2aaSAndroid Build Coastguard Worker         GrResourceProvider* rp = target->resourceProvider();
327*c8dee2aaSAndroid Build Coastguard Worker         auto threadSafeCache = target->threadSafeCache();
328*c8dee2aaSAndroid Build Coastguard Worker 
329*c8dee2aaSAndroid Build Coastguard Worker         skgpu::UniqueKey key;
330*c8dee2aaSAndroid Build Coastguard Worker         CreateKey(&key, fShape, fDevClipBounds);
331*c8dee2aaSAndroid Build Coastguard Worker 
332*c8dee2aaSAndroid Build Coastguard Worker         SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance,
333*c8dee2aaSAndroid Build Coastguard Worker                                                         fViewMatrix, fShape.bounds());
334*c8dee2aaSAndroid Build Coastguard Worker 
335*c8dee2aaSAndroid Build Coastguard Worker         if (!fVertexData) {
336*c8dee2aaSAndroid Build Coastguard Worker             auto [cachedVerts, data] = threadSafeCache->findVertsWithData(key);
337*c8dee2aaSAndroid Build Coastguard Worker             if (cachedVerts && cache_match(data.get(), tol)) {
338*c8dee2aaSAndroid Build Coastguard Worker                 fVertexData = std::move(cachedVerts);
339*c8dee2aaSAndroid Build Coastguard Worker             }
340*c8dee2aaSAndroid Build Coastguard Worker         }
341*c8dee2aaSAndroid Build Coastguard Worker 
342*c8dee2aaSAndroid Build Coastguard Worker         if (fVertexData) {
343*c8dee2aaSAndroid Build Coastguard Worker             if (!fVertexData->gpuBuffer()) {
344*c8dee2aaSAndroid Build Coastguard Worker                 sk_sp<GrGpuBuffer> buffer = rp->createBuffer(fVertexData->vertices(),
345*c8dee2aaSAndroid Build Coastguard Worker                                                              fVertexData->size(),
346*c8dee2aaSAndroid Build Coastguard Worker                                                              GrGpuBufferType::kVertex,
347*c8dee2aaSAndroid Build Coastguard Worker                                                              kStatic_GrAccessPattern);
348*c8dee2aaSAndroid Build Coastguard Worker                 if (!buffer) {
349*c8dee2aaSAndroid Build Coastguard Worker                     return;
350*c8dee2aaSAndroid Build Coastguard Worker                 }
351*c8dee2aaSAndroid Build Coastguard Worker 
352*c8dee2aaSAndroid Build Coastguard Worker                 // Since we have a direct context and a ref on 'fVertexData' we need not worry
353*c8dee2aaSAndroid Build Coastguard Worker                 // about any threading issues in this call.
354*c8dee2aaSAndroid Build Coastguard Worker                 fVertexData->setGpuBuffer(std::move(buffer));
355*c8dee2aaSAndroid Build Coastguard Worker             }
356*c8dee2aaSAndroid Build Coastguard Worker 
357*c8dee2aaSAndroid Build Coastguard Worker             fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices());
358*c8dee2aaSAndroid Build Coastguard Worker             return;
359*c8dee2aaSAndroid Build Coastguard Worker         }
360*c8dee2aaSAndroid Build Coastguard Worker 
361*c8dee2aaSAndroid Build Coastguard Worker         bool canMapVB = GrCaps::kNone_MapFlags != target->caps().mapBufferFlags();
362*c8dee2aaSAndroid Build Coastguard Worker         StaticVertexAllocator allocator(rp, canMapVB);
363*c8dee2aaSAndroid Build Coastguard Worker 
364*c8dee2aaSAndroid Build Coastguard Worker         bool isLinear;
365*c8dee2aaSAndroid Build Coastguard Worker         int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
366*c8dee2aaSAndroid Build Coastguard Worker                                       &isLinear);
367*c8dee2aaSAndroid Build Coastguard Worker         if (vertexCount == 0) {
368*c8dee2aaSAndroid Build Coastguard Worker             return;
369*c8dee2aaSAndroid Build Coastguard Worker         }
370*c8dee2aaSAndroid Build Coastguard Worker 
371*c8dee2aaSAndroid Build Coastguard Worker         fVertexData = allocator.detachVertexData();
372*c8dee2aaSAndroid Build Coastguard Worker 
373*c8dee2aaSAndroid Build Coastguard Worker         key.setCustomData(create_data(vertexCount, isLinear, tol));
374*c8dee2aaSAndroid Build Coastguard Worker 
375*c8dee2aaSAndroid Build Coastguard Worker         auto [tmpV, tmpD] = threadSafeCache->addVertsWithData(key, fVertexData, is_newer_better);
376*c8dee2aaSAndroid Build Coastguard Worker         if (tmpV != fVertexData) {
377*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(!tmpV->gpuBuffer());
378*c8dee2aaSAndroid Build Coastguard Worker             // In this case, although the different triangulation found in the cache is better,
379*c8dee2aaSAndroid Build Coastguard Worker             // we will continue on with the current triangulation since it is already on the gpu.
380*c8dee2aaSAndroid Build Coastguard Worker         } else {
381*c8dee2aaSAndroid Build Coastguard Worker             // This isn't perfect. The current triangulation is in the cache but it may have
382*c8dee2aaSAndroid Build Coastguard Worker             // replaced a pre-existing one. A duplicated listener is unlikely and not that
383*c8dee2aaSAndroid Build Coastguard Worker             // expensive so we just roll with it.
384*c8dee2aaSAndroid Build Coastguard Worker             fShape.addGenIDChangeListener(
385*c8dee2aaSAndroid Build Coastguard Worker                 sk_make_sp<UniqueKeyInvalidator>(key, target->contextUniqueID()));
386*c8dee2aaSAndroid Build Coastguard Worker         }
387*c8dee2aaSAndroid Build Coastguard Worker 
388*c8dee2aaSAndroid Build Coastguard Worker         fMesh = CreateMesh(target, fVertexData->refGpuBuffer(), 0, fVertexData->numVertices());
389*c8dee2aaSAndroid Build Coastguard Worker     }
390*c8dee2aaSAndroid Build Coastguard Worker 
createAAMesh(GrMeshDrawTarget * target)391*c8dee2aaSAndroid Build Coastguard Worker     void createAAMesh(GrMeshDrawTarget* target) {
392*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(!fVertexData);
393*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fAntiAlias);
394*c8dee2aaSAndroid Build Coastguard Worker         SkPath path = this->getPath();
395*c8dee2aaSAndroid Build Coastguard Worker         if (path.isEmpty()) {
396*c8dee2aaSAndroid Build Coastguard Worker             return;
397*c8dee2aaSAndroid Build Coastguard Worker         }
398*c8dee2aaSAndroid Build Coastguard Worker         SkRect clipBounds = SkRect::Make(fDevClipBounds);
399*c8dee2aaSAndroid Build Coastguard Worker         path.transform(fViewMatrix);
400*c8dee2aaSAndroid Build Coastguard Worker         SkScalar tol = GrPathUtils::kDefaultTolerance;
401*c8dee2aaSAndroid Build Coastguard Worker         sk_sp<const GrBuffer> vertexBuffer;
402*c8dee2aaSAndroid Build Coastguard Worker         int firstVertex;
403*c8dee2aaSAndroid Build Coastguard Worker         GrEagerDynamicVertexAllocator allocator(target, &vertexBuffer, &firstVertex);
404*c8dee2aaSAndroid Build Coastguard Worker         int vertexCount = GrAATriangulator::PathToAATriangles(path, tol, clipBounds, &allocator);
405*c8dee2aaSAndroid Build Coastguard Worker         if (vertexCount == 0) {
406*c8dee2aaSAndroid Build Coastguard Worker             return;
407*c8dee2aaSAndroid Build Coastguard Worker         }
408*c8dee2aaSAndroid Build Coastguard Worker         fMesh = CreateMesh(target, std::move(vertexBuffer), firstVertex, vertexCount);
409*c8dee2aaSAndroid Build Coastguard Worker     }
410*c8dee2aaSAndroid Build Coastguard Worker 
programInfo()411*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* programInfo() override { return fProgramInfo; }
412*c8dee2aaSAndroid Build Coastguard Worker 
onCreateProgramInfo(const GrCaps * caps,SkArenaAlloc * arena,const GrSurfaceProxyView & writeView,bool usesMSAASurface,GrAppliedClip && appliedClip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)413*c8dee2aaSAndroid Build Coastguard Worker     void onCreateProgramInfo(const GrCaps* caps,
414*c8dee2aaSAndroid Build Coastguard Worker                              SkArenaAlloc* arena,
415*c8dee2aaSAndroid Build Coastguard Worker                              const GrSurfaceProxyView& writeView,
416*c8dee2aaSAndroid Build Coastguard Worker                              bool usesMSAASurface,
417*c8dee2aaSAndroid Build Coastguard Worker                              GrAppliedClip&& appliedClip,
418*c8dee2aaSAndroid Build Coastguard Worker                              const GrDstProxyView& dstProxyView,
419*c8dee2aaSAndroid Build Coastguard Worker                              GrXferBarrierFlags renderPassXferBarriers,
420*c8dee2aaSAndroid Build Coastguard Worker                              GrLoadOp colorLoadOp) override {
421*c8dee2aaSAndroid Build Coastguard Worker         GrGeometryProcessor* gp;
422*c8dee2aaSAndroid Build Coastguard Worker         {
423*c8dee2aaSAndroid Build Coastguard Worker             using namespace GrDefaultGeoProcFactory;
424*c8dee2aaSAndroid Build Coastguard Worker 
425*c8dee2aaSAndroid Build Coastguard Worker             Color color(fColor);
426*c8dee2aaSAndroid Build Coastguard Worker             LocalCoords::Type localCoordsType = fHelper.usesLocalCoords()
427*c8dee2aaSAndroid Build Coastguard Worker                                                         ? LocalCoords::kUsePosition_Type
428*c8dee2aaSAndroid Build Coastguard Worker                                                         : LocalCoords::kUnused_Type;
429*c8dee2aaSAndroid Build Coastguard Worker             Coverage::Type coverageType;
430*c8dee2aaSAndroid Build Coastguard Worker             if (fAntiAlias) {
431*c8dee2aaSAndroid Build Coastguard Worker                 if (fHelper.compatibleWithCoverageAsAlpha()) {
432*c8dee2aaSAndroid Build Coastguard Worker                     coverageType = Coverage::kAttributeTweakAlpha_Type;
433*c8dee2aaSAndroid Build Coastguard Worker                 } else {
434*c8dee2aaSAndroid Build Coastguard Worker                     coverageType = Coverage::kAttribute_Type;
435*c8dee2aaSAndroid Build Coastguard Worker                 }
436*c8dee2aaSAndroid Build Coastguard Worker             } else {
437*c8dee2aaSAndroid Build Coastguard Worker                 coverageType = Coverage::kSolid_Type;
438*c8dee2aaSAndroid Build Coastguard Worker             }
439*c8dee2aaSAndroid Build Coastguard Worker             if (fAntiAlias) {
440*c8dee2aaSAndroid Build Coastguard Worker                 gp = GrDefaultGeoProcFactory::MakeForDeviceSpace(arena, color, coverageType,
441*c8dee2aaSAndroid Build Coastguard Worker                                                                  localCoordsType, fViewMatrix);
442*c8dee2aaSAndroid Build Coastguard Worker             } else {
443*c8dee2aaSAndroid Build Coastguard Worker                 gp = GrDefaultGeoProcFactory::Make(arena, color, coverageType, localCoordsType,
444*c8dee2aaSAndroid Build Coastguard Worker                                                    fViewMatrix);
445*c8dee2aaSAndroid Build Coastguard Worker             }
446*c8dee2aaSAndroid Build Coastguard Worker         }
447*c8dee2aaSAndroid Build Coastguard Worker         if (!gp) {
448*c8dee2aaSAndroid Build Coastguard Worker             return;
449*c8dee2aaSAndroid Build Coastguard Worker         }
450*c8dee2aaSAndroid Build Coastguard Worker 
451*c8dee2aaSAndroid Build Coastguard Worker #ifdef SK_DEBUG
452*c8dee2aaSAndroid Build Coastguard Worker         auto vertexStride = sizeof(SkPoint);
453*c8dee2aaSAndroid Build Coastguard Worker         if (fAntiAlias) {
454*c8dee2aaSAndroid Build Coastguard Worker             vertexStride += sizeof(float);
455*c8dee2aaSAndroid Build Coastguard Worker         }
456*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(vertexStride == gp->vertexStride());
457*c8dee2aaSAndroid Build Coastguard Worker #endif
458*c8dee2aaSAndroid Build Coastguard Worker 
459*c8dee2aaSAndroid Build Coastguard Worker         GrPrimitiveType primitiveType = TRIANGULATOR_WIREFRAME ? GrPrimitiveType::kLines
460*c8dee2aaSAndroid Build Coastguard Worker                                                                : GrPrimitiveType::kTriangles;
461*c8dee2aaSAndroid Build Coastguard Worker 
462*c8dee2aaSAndroid Build Coastguard Worker         fProgramInfo =  fHelper.createProgramInfoWithStencil(caps, arena, writeView,
463*c8dee2aaSAndroid Build Coastguard Worker                                                              usesMSAASurface,
464*c8dee2aaSAndroid Build Coastguard Worker                                                              std::move(appliedClip), dstProxyView,
465*c8dee2aaSAndroid Build Coastguard Worker                                                              gp, primitiveType,
466*c8dee2aaSAndroid Build Coastguard Worker                                                              renderPassXferBarriers, colorLoadOp);
467*c8dee2aaSAndroid Build Coastguard Worker     }
468*c8dee2aaSAndroid Build Coastguard Worker 
onPrePrepareDraws(GrRecordingContext * rContext,const GrSurfaceProxyView & writeView,GrAppliedClip * clip,const GrDstProxyView & dstProxyView,GrXferBarrierFlags renderPassXferBarriers,GrLoadOp colorLoadOp)469*c8dee2aaSAndroid Build Coastguard Worker     void onPrePrepareDraws(GrRecordingContext* rContext,
470*c8dee2aaSAndroid Build Coastguard Worker                            const GrSurfaceProxyView& writeView,
471*c8dee2aaSAndroid Build Coastguard Worker                            GrAppliedClip* clip,
472*c8dee2aaSAndroid Build Coastguard Worker                            const GrDstProxyView& dstProxyView,
473*c8dee2aaSAndroid Build Coastguard Worker                            GrXferBarrierFlags renderPassXferBarriers,
474*c8dee2aaSAndroid Build Coastguard Worker                            GrLoadOp colorLoadOp) override {
475*c8dee2aaSAndroid Build Coastguard Worker         TRACE_EVENT0("skia.gpu", TRACE_FUNC);
476*c8dee2aaSAndroid Build Coastguard Worker 
477*c8dee2aaSAndroid Build Coastguard Worker         INHERITED::onPrePrepareDraws(rContext, writeView, clip, dstProxyView,
478*c8dee2aaSAndroid Build Coastguard Worker                                      renderPassXferBarriers, colorLoadOp);
479*c8dee2aaSAndroid Build Coastguard Worker 
480*c8dee2aaSAndroid Build Coastguard Worker         if (fAntiAlias) {
481*c8dee2aaSAndroid Build Coastguard Worker             // TODO: pull the triangulation work forward to the recording thread for the AA case
482*c8dee2aaSAndroid Build Coastguard Worker             // too.
483*c8dee2aaSAndroid Build Coastguard Worker             return;
484*c8dee2aaSAndroid Build Coastguard Worker         }
485*c8dee2aaSAndroid Build Coastguard Worker 
486*c8dee2aaSAndroid Build Coastguard Worker         auto threadSafeViewCache = rContext->priv().threadSafeCache();
487*c8dee2aaSAndroid Build Coastguard Worker 
488*c8dee2aaSAndroid Build Coastguard Worker         skgpu::UniqueKey key;
489*c8dee2aaSAndroid Build Coastguard Worker         CreateKey(&key, fShape, fDevClipBounds);
490*c8dee2aaSAndroid Build Coastguard Worker 
491*c8dee2aaSAndroid Build Coastguard Worker         SkScalar tol = GrPathUtils::scaleToleranceToSrc(GrPathUtils::kDefaultTolerance,
492*c8dee2aaSAndroid Build Coastguard Worker                                                         fViewMatrix, fShape.bounds());
493*c8dee2aaSAndroid Build Coastguard Worker 
494*c8dee2aaSAndroid Build Coastguard Worker         auto [cachedVerts, data] = threadSafeViewCache->findVertsWithData(key);
495*c8dee2aaSAndroid Build Coastguard Worker         if (cachedVerts && cache_match(data.get(), tol)) {
496*c8dee2aaSAndroid Build Coastguard Worker             fVertexData = std::move(cachedVerts);
497*c8dee2aaSAndroid Build Coastguard Worker             return;
498*c8dee2aaSAndroid Build Coastguard Worker         }
499*c8dee2aaSAndroid Build Coastguard Worker 
500*c8dee2aaSAndroid Build Coastguard Worker         GrCpuVertexAllocator allocator;
501*c8dee2aaSAndroid Build Coastguard Worker 
502*c8dee2aaSAndroid Build Coastguard Worker         bool isLinear;
503*c8dee2aaSAndroid Build Coastguard Worker         int vertexCount = Triangulate(&allocator, fViewMatrix, fShape, fDevClipBounds, tol,
504*c8dee2aaSAndroid Build Coastguard Worker                                       &isLinear);
505*c8dee2aaSAndroid Build Coastguard Worker         if (vertexCount == 0) {
506*c8dee2aaSAndroid Build Coastguard Worker             return;
507*c8dee2aaSAndroid Build Coastguard Worker         }
508*c8dee2aaSAndroid Build Coastguard Worker 
509*c8dee2aaSAndroid Build Coastguard Worker         fVertexData = allocator.detachVertexData();
510*c8dee2aaSAndroid Build Coastguard Worker 
511*c8dee2aaSAndroid Build Coastguard Worker         key.setCustomData(create_data(vertexCount, isLinear, tol));
512*c8dee2aaSAndroid Build Coastguard Worker 
513*c8dee2aaSAndroid Build Coastguard Worker         // If some other thread created and cached its own triangulation, the 'is_newer_better'
514*c8dee2aaSAndroid Build Coastguard Worker         // predicate will replace the version in the cache if 'fVertexData' is a more accurate
515*c8dee2aaSAndroid Build Coastguard Worker         // triangulation. This will leave some other recording threads using a poorer triangulation
516*c8dee2aaSAndroid Build Coastguard Worker         // but will result in a version with greater applicability being in the cache.
517*c8dee2aaSAndroid Build Coastguard Worker         auto [tmpV, tmpD] = threadSafeViewCache->addVertsWithData(key, fVertexData,
518*c8dee2aaSAndroid Build Coastguard Worker                                                                   is_newer_better);
519*c8dee2aaSAndroid Build Coastguard Worker         if (tmpV != fVertexData) {
520*c8dee2aaSAndroid Build Coastguard Worker             // Someone beat us to creating the triangulation (and it is better than ours) so
521*c8dee2aaSAndroid Build Coastguard Worker             // just go ahead and use it.
522*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(cache_match(tmpD.get(), tol));
523*c8dee2aaSAndroid Build Coastguard Worker             fVertexData = std::move(tmpV);
524*c8dee2aaSAndroid Build Coastguard Worker         } else {
525*c8dee2aaSAndroid Build Coastguard Worker             // This isn't perfect. The current triangulation is in the cache but it may have
526*c8dee2aaSAndroid Build Coastguard Worker             // replaced a pre-existing one. A duplicated listener is unlikely and not that
527*c8dee2aaSAndroid Build Coastguard Worker             // expensive so we just roll with it.
528*c8dee2aaSAndroid Build Coastguard Worker             fShape.addGenIDChangeListener(
529*c8dee2aaSAndroid Build Coastguard Worker                     sk_make_sp<UniqueKeyInvalidator>(key, rContext->priv().contextID()));
530*c8dee2aaSAndroid Build Coastguard Worker         }
531*c8dee2aaSAndroid Build Coastguard Worker     }
532*c8dee2aaSAndroid Build Coastguard Worker 
onPrepareDraws(GrMeshDrawTarget * target)533*c8dee2aaSAndroid Build Coastguard Worker     void onPrepareDraws(GrMeshDrawTarget* target) override {
534*c8dee2aaSAndroid Build Coastguard Worker         if (fAntiAlias) {
535*c8dee2aaSAndroid Build Coastguard Worker             this->createAAMesh(target);
536*c8dee2aaSAndroid Build Coastguard Worker         } else {
537*c8dee2aaSAndroid Build Coastguard Worker             this->createNonAAMesh(target);
538*c8dee2aaSAndroid Build Coastguard Worker         }
539*c8dee2aaSAndroid Build Coastguard Worker     }
540*c8dee2aaSAndroid Build Coastguard Worker 
CreateMesh(GrMeshDrawTarget * target,sk_sp<const GrBuffer> vb,int firstVertex,int count)541*c8dee2aaSAndroid Build Coastguard Worker     static GrSimpleMesh* CreateMesh(GrMeshDrawTarget* target,
542*c8dee2aaSAndroid Build Coastguard Worker                                     sk_sp<const GrBuffer> vb,
543*c8dee2aaSAndroid Build Coastguard Worker                                     int firstVertex,
544*c8dee2aaSAndroid Build Coastguard Worker                                     int count) {
545*c8dee2aaSAndroid Build Coastguard Worker         auto mesh = target->allocMesh();
546*c8dee2aaSAndroid Build Coastguard Worker         mesh->set(std::move(vb), count, firstVertex);
547*c8dee2aaSAndroid Build Coastguard Worker         return mesh;
548*c8dee2aaSAndroid Build Coastguard Worker     }
549*c8dee2aaSAndroid Build Coastguard Worker 
onExecute(GrOpFlushState * flushState,const SkRect & chainBounds)550*c8dee2aaSAndroid Build Coastguard Worker     void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
551*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo) {
552*c8dee2aaSAndroid Build Coastguard Worker             this->createProgramInfo(flushState);
553*c8dee2aaSAndroid Build Coastguard Worker         }
554*c8dee2aaSAndroid Build Coastguard Worker 
555*c8dee2aaSAndroid Build Coastguard Worker         if (!fProgramInfo || !fMesh) {
556*c8dee2aaSAndroid Build Coastguard Worker             return;
557*c8dee2aaSAndroid Build Coastguard Worker         }
558*c8dee2aaSAndroid Build Coastguard Worker 
559*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
560*c8dee2aaSAndroid Build Coastguard Worker         flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
561*c8dee2aaSAndroid Build Coastguard Worker         flushState->drawMesh(*fMesh);
562*c8dee2aaSAndroid Build Coastguard Worker     }
563*c8dee2aaSAndroid Build Coastguard Worker 
564*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
onDumpInfo() const565*c8dee2aaSAndroid Build Coastguard Worker     SkString onDumpInfo() const override {
566*c8dee2aaSAndroid Build Coastguard Worker         return SkStringPrintf("Color 0x%08x, aa: %d\n%s",
567*c8dee2aaSAndroid Build Coastguard Worker                               fColor.toBytes_RGBA(), fAntiAlias, fHelper.dumpInfo().c_str());
568*c8dee2aaSAndroid Build Coastguard Worker     }
569*c8dee2aaSAndroid Build Coastguard Worker #endif
570*c8dee2aaSAndroid Build Coastguard Worker 
571*c8dee2aaSAndroid Build Coastguard Worker     Helper         fHelper;
572*c8dee2aaSAndroid Build Coastguard Worker     SkPMColor4f    fColor;
573*c8dee2aaSAndroid Build Coastguard Worker     GrStyledShape  fShape;
574*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix       fViewMatrix;
575*c8dee2aaSAndroid Build Coastguard Worker     SkIRect        fDevClipBounds;
576*c8dee2aaSAndroid Build Coastguard Worker     bool           fAntiAlias;
577*c8dee2aaSAndroid Build Coastguard Worker 
578*c8dee2aaSAndroid Build Coastguard Worker     GrSimpleMesh*  fMesh = nullptr;
579*c8dee2aaSAndroid Build Coastguard Worker     GrProgramInfo* fProgramInfo = nullptr;
580*c8dee2aaSAndroid Build Coastguard Worker 
581*c8dee2aaSAndroid Build Coastguard Worker     sk_sp<GrThreadSafeCache::VertexData> fVertexData;
582*c8dee2aaSAndroid Build Coastguard Worker 
583*c8dee2aaSAndroid Build Coastguard Worker     using INHERITED = GrMeshDrawOp;
584*c8dee2aaSAndroid Build Coastguard Worker };
585*c8dee2aaSAndroid Build Coastguard Worker 
586*c8dee2aaSAndroid Build Coastguard Worker }  // anonymous namespace
587*c8dee2aaSAndroid Build Coastguard Worker 
588*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
589*c8dee2aaSAndroid Build Coastguard Worker 
590*c8dee2aaSAndroid Build Coastguard Worker #if defined(GPU_TEST_UTILS)
591*c8dee2aaSAndroid Build Coastguard Worker 
GR_DRAW_OP_TEST_DEFINE(TriangulatingPathOp)592*c8dee2aaSAndroid Build Coastguard Worker GR_DRAW_OP_TEST_DEFINE(TriangulatingPathOp) {
593*c8dee2aaSAndroid Build Coastguard Worker     SkMatrix viewMatrix = GrTest::TestMatrixInvertible(random);
594*c8dee2aaSAndroid Build Coastguard Worker     const SkPath& path = GrTest::TestPath(random);
595*c8dee2aaSAndroid Build Coastguard Worker     SkIRect devClipBounds = SkIRect::MakeLTRB(
596*c8dee2aaSAndroid Build Coastguard Worker         random->nextU(), random->nextU(), random->nextU(), random->nextU());
597*c8dee2aaSAndroid Build Coastguard Worker     devClipBounds.sort();
598*c8dee2aaSAndroid Build Coastguard Worker     static constexpr GrAAType kAATypes[] = {GrAAType::kNone, GrAAType::kMSAA, GrAAType::kCoverage};
599*c8dee2aaSAndroid Build Coastguard Worker     GrAAType aaType;
600*c8dee2aaSAndroid Build Coastguard Worker     do {
601*c8dee2aaSAndroid Build Coastguard Worker         aaType = kAATypes[random->nextULessThan(std::size(kAATypes))];
602*c8dee2aaSAndroid Build Coastguard Worker     } while(GrAAType::kMSAA == aaType && numSamples <= 1);
603*c8dee2aaSAndroid Build Coastguard Worker     GrStyle style;
604*c8dee2aaSAndroid Build Coastguard Worker     do {
605*c8dee2aaSAndroid Build Coastguard Worker         GrTest::TestStyle(random, &style);
606*c8dee2aaSAndroid Build Coastguard Worker     } while (!style.isSimpleFill());
607*c8dee2aaSAndroid Build Coastguard Worker     GrStyledShape shape(path, style);
608*c8dee2aaSAndroid Build Coastguard Worker     return TriangulatingPathOp::Make(context, std::move(paint), shape, viewMatrix, devClipBounds,
609*c8dee2aaSAndroid Build Coastguard Worker                                      aaType, GrGetRandomStencil(random, context));
610*c8dee2aaSAndroid Build Coastguard Worker }
611*c8dee2aaSAndroid Build Coastguard Worker 
612*c8dee2aaSAndroid Build Coastguard Worker #endif
613*c8dee2aaSAndroid Build Coastguard Worker 
614*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////////////////////////
615*c8dee2aaSAndroid Build Coastguard Worker 
616*c8dee2aaSAndroid Build Coastguard Worker namespace skgpu::ganesh {
617*c8dee2aaSAndroid Build Coastguard Worker 
TriangulatingPathRenderer()618*c8dee2aaSAndroid Build Coastguard Worker TriangulatingPathRenderer::TriangulatingPathRenderer()
619*c8dee2aaSAndroid Build Coastguard Worker     : fMaxVerbCount(GR_AA_TESSELLATOR_MAX_VERB_COUNT) {
620*c8dee2aaSAndroid Build Coastguard Worker }
621*c8dee2aaSAndroid Build Coastguard Worker 
onCanDrawPath(const CanDrawPathArgs & args) const622*c8dee2aaSAndroid Build Coastguard Worker PathRenderer::CanDrawPath TriangulatingPathRenderer::onCanDrawPath(
623*c8dee2aaSAndroid Build Coastguard Worker         const CanDrawPathArgs& args) const {
624*c8dee2aaSAndroid Build Coastguard Worker 
625*c8dee2aaSAndroid Build Coastguard Worker     // Don't use this path renderer with dynamic MSAA. DMSAA tries to not rely on caching.
626*c8dee2aaSAndroid Build Coastguard Worker     if (args.fSurfaceProps->flags() & SkSurfaceProps::kDynamicMSAA_Flag) {
627*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
628*c8dee2aaSAndroid Build Coastguard Worker     }
629*c8dee2aaSAndroid Build Coastguard Worker     // This path renderer can draw fill styles, and can do screenspace antialiasing via a
630*c8dee2aaSAndroid Build Coastguard Worker     // one-pixel coverage ramp. It can do convex and concave paths, but we'll leave the convex
631*c8dee2aaSAndroid Build Coastguard Worker     // ones to simpler algorithms. We pass on paths that have styles, though they may come back
632*c8dee2aaSAndroid Build Coastguard Worker     // around after applying the styling information to the geometry to create a filled path.
633*c8dee2aaSAndroid Build Coastguard Worker     if (!args.fShape->style().isSimpleFill() || args.fShape->knownToBeConvex()) {
634*c8dee2aaSAndroid Build Coastguard Worker         return CanDrawPath::kNo;
635*c8dee2aaSAndroid Build Coastguard Worker     }
636*c8dee2aaSAndroid Build Coastguard Worker     switch (args.fAAType) {
637*c8dee2aaSAndroid Build Coastguard Worker         case GrAAType::kNone:
638*c8dee2aaSAndroid Build Coastguard Worker         case GrAAType::kMSAA:
639*c8dee2aaSAndroid Build Coastguard Worker             // Prefer MSAA, if any antialiasing. In the non-analytic-AA case, We skip paths that
640*c8dee2aaSAndroid Build Coastguard Worker             // don't have a key since the real advantage of this path renderer comes from caching
641*c8dee2aaSAndroid Build Coastguard Worker             // the tessellated geometry.
642*c8dee2aaSAndroid Build Coastguard Worker             if (!args.fShape->hasUnstyledKey()) {
643*c8dee2aaSAndroid Build Coastguard Worker                 return CanDrawPath::kNo;
644*c8dee2aaSAndroid Build Coastguard Worker             }
645*c8dee2aaSAndroid Build Coastguard Worker             break;
646*c8dee2aaSAndroid Build Coastguard Worker         case GrAAType::kCoverage:
647*c8dee2aaSAndroid Build Coastguard Worker             // Use analytic AA if we don't have MSAA. In this case, we do not cache, so we accept
648*c8dee2aaSAndroid Build Coastguard Worker             // paths without keys.
649*c8dee2aaSAndroid Build Coastguard Worker             SkPath path;
650*c8dee2aaSAndroid Build Coastguard Worker             args.fShape->asPath(&path);
651*c8dee2aaSAndroid Build Coastguard Worker             if (path.countVerbs() > fMaxVerbCount) {
652*c8dee2aaSAndroid Build Coastguard Worker                 return CanDrawPath::kNo;
653*c8dee2aaSAndroid Build Coastguard Worker             }
654*c8dee2aaSAndroid Build Coastguard Worker             break;
655*c8dee2aaSAndroid Build Coastguard Worker     }
656*c8dee2aaSAndroid Build Coastguard Worker     return CanDrawPath::kYes;
657*c8dee2aaSAndroid Build Coastguard Worker }
658*c8dee2aaSAndroid Build Coastguard Worker 
onDrawPath(const DrawPathArgs & args)659*c8dee2aaSAndroid Build Coastguard Worker bool TriangulatingPathRenderer::onDrawPath(const DrawPathArgs& args) {
660*c8dee2aaSAndroid Build Coastguard Worker     GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
661*c8dee2aaSAndroid Build Coastguard Worker                               "GrTriangulatingPathRenderer::onDrawPath");
662*c8dee2aaSAndroid Build Coastguard Worker 
663*c8dee2aaSAndroid Build Coastguard Worker     GrOp::Owner op = TriangulatingPathOp::Make(
664*c8dee2aaSAndroid Build Coastguard Worker             args.fContext, std::move(args.fPaint), *args.fShape, *args.fViewMatrix,
665*c8dee2aaSAndroid Build Coastguard Worker             *args.fClipConservativeBounds, args.fAAType, args.fUserStencilSettings);
666*c8dee2aaSAndroid Build Coastguard Worker     args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
667*c8dee2aaSAndroid Build Coastguard Worker     return true;
668*c8dee2aaSAndroid Build Coastguard Worker }
669*c8dee2aaSAndroid Build Coastguard Worker 
670*c8dee2aaSAndroid Build Coastguard Worker }  // namespace skgpu::ganesh
671*c8dee2aaSAndroid Build Coastguard Worker 
672*c8dee2aaSAndroid Build Coastguard Worker #endif // SK_ENABLE_OPTIMIZE_SIZE
673