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