1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2011 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/DefaultPathRenderer.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkString.h"
11cb93a386Sopenharmony_ci#include "include/core/SkStrokeRec.h"
12cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h"
13cb93a386Sopenharmony_ci#include "src/core/SkMatrixPriv.h"
14cb93a386Sopenharmony_ci#include "src/core/SkTLazy.h"
15cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrClip.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrDefaultGeoProcFactory.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
22cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h"
23cb93a386Sopenharmony_ci#include "src/gpu/GrSimpleMesh.h"
24cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h"
25cb93a386Sopenharmony_ci#include "src/gpu/GrUtil.h"
26cb93a386Sopenharmony_ci#include "src/gpu/effects/GrDisableColorXP.h"
27cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h"
28cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h"
29cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h"
30cb93a386Sopenharmony_ci#include "src/gpu/ops/GrPathStencilSettings.h"
31cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
32cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h"
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_ci////////////////////////////////////////////////////////////////////////////////
35cb93a386Sopenharmony_ci// Helpers for drawPath
36cb93a386Sopenharmony_ci
37cb93a386Sopenharmony_cinamespace {
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci#define STENCIL_OFF     0   // Always disable stencil (even when needed)
40cb93a386Sopenharmony_ci
41cb93a386Sopenharmony_ciinline bool single_pass_shape(const GrStyledShape& shape) {
42cb93a386Sopenharmony_ci#if STENCIL_OFF
43cb93a386Sopenharmony_ci    return true;
44cb93a386Sopenharmony_ci#else
45cb93a386Sopenharmony_ci    // Inverse fill is always two pass.
46cb93a386Sopenharmony_ci    if (shape.inverseFilled()) {
47cb93a386Sopenharmony_ci        return false;
48cb93a386Sopenharmony_ci    }
49cb93a386Sopenharmony_ci    // This path renderer only accepts simple fill paths or stroke paths that are either hairline
50cb93a386Sopenharmony_ci    // or have a stroke width small enough to treat as hairline. Hairline paths are always single
51cb93a386Sopenharmony_ci    // pass. Filled paths are single pass if they're convex.
52cb93a386Sopenharmony_ci    if (shape.style().isSimpleFill()) {
53cb93a386Sopenharmony_ci        return shape.knownToBeConvex();
54cb93a386Sopenharmony_ci    }
55cb93a386Sopenharmony_ci    return true;
56cb93a386Sopenharmony_ci#endif
57cb93a386Sopenharmony_ci}
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ciclass PathGeoBuilder {
60cb93a386Sopenharmony_cipublic:
61cb93a386Sopenharmony_ci    PathGeoBuilder(GrPrimitiveType primitiveType,
62cb93a386Sopenharmony_ci                   GrMeshDrawTarget* target,
63cb93a386Sopenharmony_ci                   SkTDArray<GrSimpleMesh*>* meshes)
64cb93a386Sopenharmony_ci            : fPrimitiveType(primitiveType)
65cb93a386Sopenharmony_ci            , fTarget(target)
66cb93a386Sopenharmony_ci            , fVertexStride(sizeof(SkPoint))
67cb93a386Sopenharmony_ci            , fFirstIndex(0)
68cb93a386Sopenharmony_ci            , fIndicesInChunk(0)
69cb93a386Sopenharmony_ci            , fIndices(nullptr)
70cb93a386Sopenharmony_ci            , fMeshes(meshes) {
71cb93a386Sopenharmony_ci        this->allocNewBuffers();
72cb93a386Sopenharmony_ci    }
73cb93a386Sopenharmony_ci
74cb93a386Sopenharmony_ci    ~PathGeoBuilder() {
75cb93a386Sopenharmony_ci        this->createMeshAndPutBackReserve();
76cb93a386Sopenharmony_ci    }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ci    /**
79cb93a386Sopenharmony_ci     *  Path verbs
80cb93a386Sopenharmony_ci     */
81cb93a386Sopenharmony_ci    void moveTo(const SkPoint& p) {
82cb93a386Sopenharmony_ci        if (!this->ensureSpace(1)) {
83cb93a386Sopenharmony_ci            return;
84cb93a386Sopenharmony_ci        }
85cb93a386Sopenharmony_ci
86cb93a386Sopenharmony_ci        if (!this->isHairline()) {
87cb93a386Sopenharmony_ci            fSubpathIndexStart = this->currentIndex();
88cb93a386Sopenharmony_ci            fSubpathStartPoint = p;
89cb93a386Sopenharmony_ci        }
90cb93a386Sopenharmony_ci        *(fCurVert++) = p;
91cb93a386Sopenharmony_ci    }
92cb93a386Sopenharmony_ci
93cb93a386Sopenharmony_ci    void addLine(const SkPoint pts[]) {
94cb93a386Sopenharmony_ci        if (!this->ensureSpace(1, this->indexScale(), &pts[0])) {
95cb93a386Sopenharmony_ci            return;
96cb93a386Sopenharmony_ci        }
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci        if (this->isIndexed()) {
99cb93a386Sopenharmony_ci            uint16_t prevIdx = this->currentIndex() - 1;
100cb93a386Sopenharmony_ci            this->appendCountourEdgeIndices(prevIdx);
101cb93a386Sopenharmony_ci        }
102cb93a386Sopenharmony_ci        *(fCurVert++) = pts[1];
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci
105cb93a386Sopenharmony_ci    void addQuad(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
106cb93a386Sopenharmony_ci        if (!this->ensureSpace(GrPathUtils::kMaxPointsPerCurve,
107cb93a386Sopenharmony_ci                             GrPathUtils::kMaxPointsPerCurve * this->indexScale(),
108cb93a386Sopenharmony_ci                             &pts[0])) {
109cb93a386Sopenharmony_ci            return;
110cb93a386Sopenharmony_ci        }
111cb93a386Sopenharmony_ci
112cb93a386Sopenharmony_ci        // First pt of quad is the pt we ended on in previous step
113cb93a386Sopenharmony_ci        uint16_t firstQPtIdx = this->currentIndex() - 1;
114cb93a386Sopenharmony_ci        uint16_t numPts = (uint16_t)GrPathUtils::generateQuadraticPoints(
115cb93a386Sopenharmony_ci                pts[0], pts[1], pts[2], srcSpaceTolSqd, &fCurVert,
116cb93a386Sopenharmony_ci                GrPathUtils::quadraticPointCount(pts, srcSpaceTol));
117cb93a386Sopenharmony_ci        if (this->isIndexed()) {
118cb93a386Sopenharmony_ci            for (uint16_t i = 0; i < numPts; ++i) {
119cb93a386Sopenharmony_ci                this->appendCountourEdgeIndices(firstQPtIdx + i);
120cb93a386Sopenharmony_ci            }
121cb93a386Sopenharmony_ci        }
122cb93a386Sopenharmony_ci    }
123cb93a386Sopenharmony_ci
124cb93a386Sopenharmony_ci    void addConic(SkScalar weight, const SkPoint pts[], SkScalar srcSpaceTolSqd,
125cb93a386Sopenharmony_ci                  SkScalar srcSpaceTol) {
126cb93a386Sopenharmony_ci        SkAutoConicToQuads converter;
127cb93a386Sopenharmony_ci        const SkPoint* quadPts = converter.computeQuads(pts, weight, srcSpaceTol);
128cb93a386Sopenharmony_ci        for (int i = 0; i < converter.countQuads(); ++i) {
129cb93a386Sopenharmony_ci            this->addQuad(quadPts + i * 2, srcSpaceTolSqd, srcSpaceTol);
130cb93a386Sopenharmony_ci        }
131cb93a386Sopenharmony_ci    }
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci    void addCubic(const SkPoint pts[], SkScalar srcSpaceTolSqd, SkScalar srcSpaceTol) {
134cb93a386Sopenharmony_ci        if (!this->ensureSpace(GrPathUtils::kMaxPointsPerCurve,
135cb93a386Sopenharmony_ci                             GrPathUtils::kMaxPointsPerCurve * this->indexScale(),
136cb93a386Sopenharmony_ci                             &pts[0])) {
137cb93a386Sopenharmony_ci            return;
138cb93a386Sopenharmony_ci        }
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_ci        // First pt of cubic is the pt we ended on in previous step
141cb93a386Sopenharmony_ci        uint16_t firstCPtIdx = this->currentIndex() - 1;
142cb93a386Sopenharmony_ci        uint16_t numPts = (uint16_t) GrPathUtils::generateCubicPoints(
143cb93a386Sopenharmony_ci                pts[0], pts[1], pts[2], pts[3], srcSpaceTolSqd, &fCurVert,
144cb93a386Sopenharmony_ci                GrPathUtils::cubicPointCount(pts, srcSpaceTol));
145cb93a386Sopenharmony_ci        if (this->isIndexed()) {
146cb93a386Sopenharmony_ci            for (uint16_t i = 0; i < numPts; ++i) {
147cb93a386Sopenharmony_ci                this->appendCountourEdgeIndices(firstCPtIdx + i);
148cb93a386Sopenharmony_ci            }
149cb93a386Sopenharmony_ci        }
150cb93a386Sopenharmony_ci    }
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci    void addPath(const SkPath& path, SkScalar srcSpaceTol) {
153cb93a386Sopenharmony_ci        SkScalar srcSpaceTolSqd = srcSpaceTol * srcSpaceTol;
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_ci        SkPath::Iter iter(path, false);
156cb93a386Sopenharmony_ci        SkPoint pts[4];
157cb93a386Sopenharmony_ci
158cb93a386Sopenharmony_ci        bool done = false;
159cb93a386Sopenharmony_ci        while (!done) {
160cb93a386Sopenharmony_ci            SkPath::Verb verb = iter.next(pts);
161cb93a386Sopenharmony_ci            switch (verb) {
162cb93a386Sopenharmony_ci                case SkPath::kMove_Verb:
163cb93a386Sopenharmony_ci                    this->moveTo(pts[0]);
164cb93a386Sopenharmony_ci                    break;
165cb93a386Sopenharmony_ci                case SkPath::kLine_Verb:
166cb93a386Sopenharmony_ci                    this->addLine(pts);
167cb93a386Sopenharmony_ci                    break;
168cb93a386Sopenharmony_ci                case SkPath::kConic_Verb:
169cb93a386Sopenharmony_ci                    this->addConic(iter.conicWeight(), pts, srcSpaceTolSqd, srcSpaceTol);
170cb93a386Sopenharmony_ci                    break;
171cb93a386Sopenharmony_ci                case SkPath::kQuad_Verb:
172cb93a386Sopenharmony_ci                    this->addQuad(pts, srcSpaceTolSqd, srcSpaceTol);
173cb93a386Sopenharmony_ci                    break;
174cb93a386Sopenharmony_ci                case SkPath::kCubic_Verb:
175cb93a386Sopenharmony_ci                    this->addCubic(pts, srcSpaceTolSqd, srcSpaceTol);
176cb93a386Sopenharmony_ci                    break;
177cb93a386Sopenharmony_ci                case SkPath::kClose_Verb:
178cb93a386Sopenharmony_ci                    break;
179cb93a386Sopenharmony_ci                case SkPath::kDone_Verb:
180cb93a386Sopenharmony_ci                    done = true;
181cb93a386Sopenharmony_ci            }
182cb93a386Sopenharmony_ci        }
183cb93a386Sopenharmony_ci    }
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ci    static bool PathHasMultipleSubpaths(const SkPath& path) {
186cb93a386Sopenharmony_ci        bool first = true;
187cb93a386Sopenharmony_ci
188cb93a386Sopenharmony_ci        SkPath::Iter iter(path, false);
189cb93a386Sopenharmony_ci        SkPath::Verb verb;
190cb93a386Sopenharmony_ci
191cb93a386Sopenharmony_ci        SkPoint pts[4];
192cb93a386Sopenharmony_ci        while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
193cb93a386Sopenharmony_ci            if (SkPath::kMove_Verb == verb && !first) {
194cb93a386Sopenharmony_ci                return true;
195cb93a386Sopenharmony_ci            }
196cb93a386Sopenharmony_ci            first = false;
197cb93a386Sopenharmony_ci        }
198cb93a386Sopenharmony_ci        return false;
199cb93a386Sopenharmony_ci    }
200cb93a386Sopenharmony_ci
201cb93a386Sopenharmony_ciprivate:
202cb93a386Sopenharmony_ci    /**
203cb93a386Sopenharmony_ci     *  Derived properties
204cb93a386Sopenharmony_ci     *  TODO: Cache some of these for better performance, rather than re-computing?
205cb93a386Sopenharmony_ci     */
206cb93a386Sopenharmony_ci    bool isIndexed() const {
207cb93a386Sopenharmony_ci        return GrPrimitiveType::kLines == fPrimitiveType ||
208cb93a386Sopenharmony_ci               GrPrimitiveType::kTriangles == fPrimitiveType;
209cb93a386Sopenharmony_ci    }
210cb93a386Sopenharmony_ci    bool isHairline() const {
211cb93a386Sopenharmony_ci        return GrPrimitiveType::kLines == fPrimitiveType ||
212cb93a386Sopenharmony_ci               GrPrimitiveType::kLineStrip == fPrimitiveType;
213cb93a386Sopenharmony_ci    }
214cb93a386Sopenharmony_ci    int indexScale() const {
215cb93a386Sopenharmony_ci        switch (fPrimitiveType) {
216cb93a386Sopenharmony_ci            case GrPrimitiveType::kLines:
217cb93a386Sopenharmony_ci                return 2;
218cb93a386Sopenharmony_ci            case GrPrimitiveType::kTriangles:
219cb93a386Sopenharmony_ci                return 3;
220cb93a386Sopenharmony_ci            default:
221cb93a386Sopenharmony_ci                return 0;
222cb93a386Sopenharmony_ci        }
223cb93a386Sopenharmony_ci    }
224cb93a386Sopenharmony_ci
225cb93a386Sopenharmony_ci    uint16_t currentIndex() const { return fCurVert - fVertices; }
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ci    // Allocate vertex and (possibly) index buffers
228cb93a386Sopenharmony_ci    void allocNewBuffers() {
229cb93a386Sopenharmony_ci        SkASSERT(fValid);
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_ci        // Ensure that we always get enough verts for a worst-case quad/cubic, plus leftover points
232cb93a386Sopenharmony_ci        // from previous mesh piece (up to two verts to continue fanning). If we can't get that
233cb93a386Sopenharmony_ci        // many, ask for a much larger number. This needs to be fairly big to handle  quads/cubics,
234cb93a386Sopenharmony_ci        // which have a worst-case of 1k points.
235cb93a386Sopenharmony_ci        static const int kMinVerticesPerChunk = GrPathUtils::kMaxPointsPerCurve + 2;
236cb93a386Sopenharmony_ci        static const int kFallbackVerticesPerChunk = 16384;
237cb93a386Sopenharmony_ci
238cb93a386Sopenharmony_ci        fVertices = static_cast<SkPoint*>(fTarget->makeVertexSpaceAtLeast(fVertexStride,
239cb93a386Sopenharmony_ci                                                                          kMinVerticesPerChunk,
240cb93a386Sopenharmony_ci                                                                          kFallbackVerticesPerChunk,
241cb93a386Sopenharmony_ci                                                                          &fVertexBuffer,
242cb93a386Sopenharmony_ci                                                                          &fFirstVertex,
243cb93a386Sopenharmony_ci                                                                          &fVerticesInChunk));
244cb93a386Sopenharmony_ci        if (!fVertices) {
245cb93a386Sopenharmony_ci            SkDebugf("WARNING: Failed to allocate vertex buffer for DefaultPathRenderer.\n");
246cb93a386Sopenharmony_ci            fCurVert = nullptr;
247cb93a386Sopenharmony_ci            fCurIdx = fIndices = nullptr;
248cb93a386Sopenharmony_ci            fSubpathIndexStart = 0;
249cb93a386Sopenharmony_ci            fValid = false;
250cb93a386Sopenharmony_ci            return;
251cb93a386Sopenharmony_ci        }
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_ci        if (this->isIndexed()) {
254cb93a386Sopenharmony_ci            // Similar to above: Ensure we get enough indices for one worst-case quad/cubic.
255cb93a386Sopenharmony_ci            // No extra indices are needed for stitching, though. If we can't get that many, ask
256cb93a386Sopenharmony_ci            // for enough to match our large vertex request.
257cb93a386Sopenharmony_ci            const int kMinIndicesPerChunk = GrPathUtils::kMaxPointsPerCurve * this->indexScale();
258cb93a386Sopenharmony_ci            const int kFallbackIndicesPerChunk = kFallbackVerticesPerChunk * this->indexScale();
259cb93a386Sopenharmony_ci
260cb93a386Sopenharmony_ci            fIndices = fTarget->makeIndexSpaceAtLeast(kMinIndicesPerChunk, kFallbackIndicesPerChunk,
261cb93a386Sopenharmony_ci                                                      &fIndexBuffer, &fFirstIndex,
262cb93a386Sopenharmony_ci                                                      &fIndicesInChunk);
263cb93a386Sopenharmony_ci            if (!fIndices) {
264cb93a386Sopenharmony_ci                SkDebugf("WARNING: Failed to allocate index buffer for DefaultPathRenderer.\n");
265cb93a386Sopenharmony_ci                fVertices = nullptr;
266cb93a386Sopenharmony_ci                fValid = false;
267cb93a386Sopenharmony_ci            }
268cb93a386Sopenharmony_ci        }
269cb93a386Sopenharmony_ci
270cb93a386Sopenharmony_ci        fCurVert = fVertices;
271cb93a386Sopenharmony_ci        fCurIdx = fIndices;
272cb93a386Sopenharmony_ci        fSubpathIndexStart = 0;
273cb93a386Sopenharmony_ci    }
274cb93a386Sopenharmony_ci
275cb93a386Sopenharmony_ci    void appendCountourEdgeIndices(uint16_t edgeV0Idx) {
276cb93a386Sopenharmony_ci        SkASSERT(fCurIdx);
277cb93a386Sopenharmony_ci
278cb93a386Sopenharmony_ci        // When drawing lines we're appending line segments along the countour. When applying the
279cb93a386Sopenharmony_ci        // other fill rules we're drawing triangle fans around the start of the current (sub)path.
280cb93a386Sopenharmony_ci        if (!this->isHairline()) {
281cb93a386Sopenharmony_ci            *(fCurIdx++) = fSubpathIndexStart;
282cb93a386Sopenharmony_ci        }
283cb93a386Sopenharmony_ci        *(fCurIdx++) = edgeV0Idx;
284cb93a386Sopenharmony_ci        *(fCurIdx++) = edgeV0Idx + 1;
285cb93a386Sopenharmony_ci    }
286cb93a386Sopenharmony_ci
287cb93a386Sopenharmony_ci    // Emits a single draw with all accumulated vertex/index data
288cb93a386Sopenharmony_ci    void createMeshAndPutBackReserve() {
289cb93a386Sopenharmony_ci        if (!fValid) {
290cb93a386Sopenharmony_ci            return;
291cb93a386Sopenharmony_ci        }
292cb93a386Sopenharmony_ci
293cb93a386Sopenharmony_ci        int vertexCount = fCurVert - fVertices;
294cb93a386Sopenharmony_ci        int indexCount = fCurIdx - fIndices;
295cb93a386Sopenharmony_ci        SkASSERT(vertexCount <= fVerticesInChunk);
296cb93a386Sopenharmony_ci        SkASSERT(indexCount <= fIndicesInChunk);
297cb93a386Sopenharmony_ci
298cb93a386Sopenharmony_ci        GrSimpleMesh* mesh = nullptr;
299cb93a386Sopenharmony_ci        if (this->isIndexed() ? SkToBool(indexCount) : SkToBool(vertexCount)) {
300cb93a386Sopenharmony_ci            mesh = fTarget->allocMesh();
301cb93a386Sopenharmony_ci            if (!this->isIndexed()) {
302cb93a386Sopenharmony_ci                mesh->set(std::move(fVertexBuffer), vertexCount, fFirstVertex);
303cb93a386Sopenharmony_ci            } else {
304cb93a386Sopenharmony_ci                mesh->setIndexed(std::move(fIndexBuffer), indexCount, fFirstIndex, 0,
305cb93a386Sopenharmony_ci                                 vertexCount - 1, GrPrimitiveRestart::kNo, std::move(fVertexBuffer),
306cb93a386Sopenharmony_ci                                 fFirstVertex);
307cb93a386Sopenharmony_ci            }
308cb93a386Sopenharmony_ci        }
309cb93a386Sopenharmony_ci
310cb93a386Sopenharmony_ci        fTarget->putBackIndices((size_t)(fIndicesInChunk - indexCount));
311cb93a386Sopenharmony_ci        fTarget->putBackVertices((size_t)(fVerticesInChunk - vertexCount), fVertexStride);
312cb93a386Sopenharmony_ci
313cb93a386Sopenharmony_ci        if (mesh) {
314cb93a386Sopenharmony_ci            fMeshes->push_back(mesh);
315cb93a386Sopenharmony_ci        }
316cb93a386Sopenharmony_ci    }
317cb93a386Sopenharmony_ci
318cb93a386Sopenharmony_ci    bool ensureSpace(int vertsNeeded, int indicesNeeded = 0, const SkPoint* lastPoint = nullptr) {
319cb93a386Sopenharmony_ci        if (!fValid) {
320cb93a386Sopenharmony_ci            return false;
321cb93a386Sopenharmony_ci        }
322cb93a386Sopenharmony_ci
323cb93a386Sopenharmony_ci        if (fCurVert + vertsNeeded > fVertices + fVerticesInChunk ||
324cb93a386Sopenharmony_ci            fCurIdx + indicesNeeded > fIndices + fIndicesInChunk) {
325cb93a386Sopenharmony_ci            // We are about to run out of space (possibly)
326cb93a386Sopenharmony_ci
327cb93a386Sopenharmony_ci#ifdef SK_DEBUG
328cb93a386Sopenharmony_ci            // To maintain continuity, we need to remember one or two points from the current mesh.
329cb93a386Sopenharmony_ci            // Lines only need the last point, fills need the first point from the current contour.
330cb93a386Sopenharmony_ci            // We always grab both here, and append the ones we need at the end of this process.
331cb93a386Sopenharmony_ci            SkASSERT(fSubpathIndexStart < fVerticesInChunk);
332cb93a386Sopenharmony_ci            // This assert is reading from the gpu buffer fVertices and will be slow, but for debug
333cb93a386Sopenharmony_ci            // that is okay.
334cb93a386Sopenharmony_ci            if (!this->isHairline()) {
335cb93a386Sopenharmony_ci                SkASSERT(fSubpathStartPoint == fVertices[fSubpathIndexStart]);
336cb93a386Sopenharmony_ci            }
337cb93a386Sopenharmony_ci            if (lastPoint) {
338cb93a386Sopenharmony_ci                SkASSERT(*(fCurVert - 1) == *lastPoint);
339cb93a386Sopenharmony_ci            }
340cb93a386Sopenharmony_ci#endif
341cb93a386Sopenharmony_ci
342cb93a386Sopenharmony_ci            // Draw the mesh we've accumulated, and put back any unused space
343cb93a386Sopenharmony_ci            this->createMeshAndPutBackReserve();
344cb93a386Sopenharmony_ci
345cb93a386Sopenharmony_ci            // Get new buffers
346cb93a386Sopenharmony_ci            this->allocNewBuffers();
347cb93a386Sopenharmony_ci            if (!fValid) {
348cb93a386Sopenharmony_ci                return false;
349cb93a386Sopenharmony_ci            }
350cb93a386Sopenharmony_ci
351cb93a386Sopenharmony_ci            // On moves we don't need to copy over any points to the new buffer and we pass in a
352cb93a386Sopenharmony_ci            // null lastPoint.
353cb93a386Sopenharmony_ci            if (lastPoint) {
354cb93a386Sopenharmony_ci                // Append copies of the points we saved so the two meshes will weld properly
355cb93a386Sopenharmony_ci                if (!this->isHairline()) {
356cb93a386Sopenharmony_ci                    *(fCurVert++) = fSubpathStartPoint;
357cb93a386Sopenharmony_ci                }
358cb93a386Sopenharmony_ci                *(fCurVert++) = *lastPoint;
359cb93a386Sopenharmony_ci            }
360cb93a386Sopenharmony_ci        }
361cb93a386Sopenharmony_ci
362cb93a386Sopenharmony_ci        return true;
363cb93a386Sopenharmony_ci    }
364cb93a386Sopenharmony_ci
365cb93a386Sopenharmony_ci    GrPrimitiveType fPrimitiveType;
366cb93a386Sopenharmony_ci    GrMeshDrawTarget* fTarget;
367cb93a386Sopenharmony_ci    size_t fVertexStride;
368cb93a386Sopenharmony_ci
369cb93a386Sopenharmony_ci    sk_sp<const GrBuffer> fVertexBuffer;
370cb93a386Sopenharmony_ci    int fFirstVertex;
371cb93a386Sopenharmony_ci    int fVerticesInChunk;
372cb93a386Sopenharmony_ci    SkPoint* fVertices;
373cb93a386Sopenharmony_ci    SkPoint* fCurVert;
374cb93a386Sopenharmony_ci
375cb93a386Sopenharmony_ci    sk_sp<const GrBuffer> fIndexBuffer;
376cb93a386Sopenharmony_ci    int fFirstIndex;
377cb93a386Sopenharmony_ci    int fIndicesInChunk;
378cb93a386Sopenharmony_ci    uint16_t* fIndices;
379cb93a386Sopenharmony_ci    uint16_t* fCurIdx;
380cb93a386Sopenharmony_ci    uint16_t fSubpathIndexStart;
381cb93a386Sopenharmony_ci    SkPoint fSubpathStartPoint;
382cb93a386Sopenharmony_ci
383cb93a386Sopenharmony_ci    bool fValid = true;
384cb93a386Sopenharmony_ci    SkTDArray<GrSimpleMesh*>* fMeshes;
385cb93a386Sopenharmony_ci};
386cb93a386Sopenharmony_ci
387cb93a386Sopenharmony_ciclass DefaultPathOp final : public GrMeshDrawOp {
388cb93a386Sopenharmony_ciprivate:
389cb93a386Sopenharmony_ci    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
390cb93a386Sopenharmony_ci
391cb93a386Sopenharmony_cipublic:
392cb93a386Sopenharmony_ci    DEFINE_OP_CLASS_ID
393cb93a386Sopenharmony_ci
394cb93a386Sopenharmony_ci    static GrOp::Owner Make(GrRecordingContext* context,
395cb93a386Sopenharmony_ci                            GrPaint&& paint,
396cb93a386Sopenharmony_ci                            const SkPath& path,
397cb93a386Sopenharmony_ci                            SkScalar tolerance,
398cb93a386Sopenharmony_ci                            uint8_t coverage,
399cb93a386Sopenharmony_ci                            const SkMatrix& viewMatrix,
400cb93a386Sopenharmony_ci                            bool isHairline,
401cb93a386Sopenharmony_ci                            GrAAType aaType,
402cb93a386Sopenharmony_ci                            const SkRect& devBounds,
403cb93a386Sopenharmony_ci                            const GrUserStencilSettings* stencilSettings) {
404cb93a386Sopenharmony_ci        return Helper::FactoryHelper<DefaultPathOp>(context, std::move(paint), path, tolerance,
405cb93a386Sopenharmony_ci                                                    coverage, viewMatrix, isHairline, aaType,
406cb93a386Sopenharmony_ci                                                    devBounds, stencilSettings);
407cb93a386Sopenharmony_ci    }
408cb93a386Sopenharmony_ci
409cb93a386Sopenharmony_ci    const char* name() const override { return "DefaultPathOp"; }
410cb93a386Sopenharmony_ci
411cb93a386Sopenharmony_ci    void visitProxies(const GrVisitProxyFunc& func) const override {
412cb93a386Sopenharmony_ci        if (fProgramInfo) {
413cb93a386Sopenharmony_ci            fProgramInfo->visitFPProxies(func);
414cb93a386Sopenharmony_ci        } else {
415cb93a386Sopenharmony_ci            fHelper.visitProxies(func);
416cb93a386Sopenharmony_ci        }
417cb93a386Sopenharmony_ci    }
418cb93a386Sopenharmony_ci
419cb93a386Sopenharmony_ci    DefaultPathOp(GrProcessorSet* processorSet, const SkPMColor4f& color, const SkPath& path,
420cb93a386Sopenharmony_ci                  SkScalar tolerance, uint8_t coverage, const SkMatrix& viewMatrix, bool isHairline,
421cb93a386Sopenharmony_ci                  GrAAType aaType, const SkRect& devBounds,
422cb93a386Sopenharmony_ci                  const GrUserStencilSettings* stencilSettings)
423cb93a386Sopenharmony_ci            : INHERITED(ClassID())
424cb93a386Sopenharmony_ci            , fHelper(processorSet, aaType, stencilSettings)
425cb93a386Sopenharmony_ci            , fColor(color)
426cb93a386Sopenharmony_ci            , fCoverage(coverage)
427cb93a386Sopenharmony_ci            , fViewMatrix(viewMatrix)
428cb93a386Sopenharmony_ci            , fIsHairline(isHairline) {
429cb93a386Sopenharmony_ci        fPaths.emplace_back(PathData{path, tolerance});
430cb93a386Sopenharmony_ci
431cb93a386Sopenharmony_ci        HasAABloat aaBloat = (aaType == GrAAType::kNone) ? HasAABloat ::kNo : HasAABloat::kYes;
432cb93a386Sopenharmony_ci        this->setBounds(devBounds, aaBloat,
433cb93a386Sopenharmony_ci                        isHairline ? IsHairline::kYes : IsHairline::kNo);
434cb93a386Sopenharmony_ci    }
435cb93a386Sopenharmony_ci
436cb93a386Sopenharmony_ci    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
437cb93a386Sopenharmony_ci
438cb93a386Sopenharmony_ci    GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
439cb93a386Sopenharmony_ci                                      GrClampType clampType) override {
440cb93a386Sopenharmony_ci        GrProcessorAnalysisCoverage gpCoverage =
441cb93a386Sopenharmony_ci                this->coverage() == 0xFF ? GrProcessorAnalysisCoverage::kNone
442cb93a386Sopenharmony_ci                                         : GrProcessorAnalysisCoverage::kSingleChannel;
443cb93a386Sopenharmony_ci        // This Op uses uniform (not vertex) color, so doesn't need to track wide color.
444cb93a386Sopenharmony_ci        return fHelper.finalizeProcessors(caps, clip, clampType, gpCoverage, &fColor, nullptr);
445cb93a386Sopenharmony_ci    }
446cb93a386Sopenharmony_ci
447cb93a386Sopenharmony_ciprivate:
448cb93a386Sopenharmony_ci    GrPrimitiveType primType() const {
449cb93a386Sopenharmony_ci        if (this->isHairline()) {
450cb93a386Sopenharmony_ci            int instanceCount = fPaths.count();
451cb93a386Sopenharmony_ci
452cb93a386Sopenharmony_ci            // We avoid indices when we have a single hairline contour.
453cb93a386Sopenharmony_ci            bool isIndexed = instanceCount > 1 ||
454cb93a386Sopenharmony_ci                                PathGeoBuilder::PathHasMultipleSubpaths(fPaths[0].fPath);
455cb93a386Sopenharmony_ci
456cb93a386Sopenharmony_ci            return isIndexed ? GrPrimitiveType::kLines : GrPrimitiveType::kLineStrip;
457cb93a386Sopenharmony_ci        }
458cb93a386Sopenharmony_ci
459cb93a386Sopenharmony_ci        return GrPrimitiveType::kTriangles;
460cb93a386Sopenharmony_ci    }
461cb93a386Sopenharmony_ci
462cb93a386Sopenharmony_ci    GrProgramInfo* programInfo() override { return fProgramInfo; }
463cb93a386Sopenharmony_ci
464cb93a386Sopenharmony_ci    void onCreateProgramInfo(const GrCaps* caps,
465cb93a386Sopenharmony_ci                             SkArenaAlloc* arena,
466cb93a386Sopenharmony_ci                             const GrSurfaceProxyView& writeView,
467cb93a386Sopenharmony_ci                             bool usesMSAASurface,
468cb93a386Sopenharmony_ci                             GrAppliedClip&& appliedClip,
469cb93a386Sopenharmony_ci                             const GrDstProxyView& dstProxyView,
470cb93a386Sopenharmony_ci                             GrXferBarrierFlags renderPassXferBarriers,
471cb93a386Sopenharmony_ci                             GrLoadOp colorLoadOp) override {
472cb93a386Sopenharmony_ci        GrGeometryProcessor* gp;
473cb93a386Sopenharmony_ci        {
474cb93a386Sopenharmony_ci            using namespace GrDefaultGeoProcFactory;
475cb93a386Sopenharmony_ci            Color color(this->color());
476cb93a386Sopenharmony_ci            Coverage coverage(this->coverage());
477cb93a386Sopenharmony_ci            LocalCoords localCoords(fHelper.usesLocalCoords() ? LocalCoords::kUsePosition_Type
478cb93a386Sopenharmony_ci                                                              : LocalCoords::kUnused_Type);
479cb93a386Sopenharmony_ci            gp = GrDefaultGeoProcFactory::Make(arena,
480cb93a386Sopenharmony_ci                                               color,
481cb93a386Sopenharmony_ci                                               coverage,
482cb93a386Sopenharmony_ci                                               localCoords,
483cb93a386Sopenharmony_ci                                               this->viewMatrix());
484cb93a386Sopenharmony_ci        }
485cb93a386Sopenharmony_ci
486cb93a386Sopenharmony_ci        SkASSERT(gp->vertexStride() == sizeof(SkPoint));
487cb93a386Sopenharmony_ci
488cb93a386Sopenharmony_ci        fProgramInfo =  fHelper.createProgramInfoWithStencil(caps, arena, writeView,
489cb93a386Sopenharmony_ci                                                             usesMSAASurface,
490cb93a386Sopenharmony_ci                                                             std::move(appliedClip), dstProxyView,
491cb93a386Sopenharmony_ci                                                             gp, this->primType(),
492cb93a386Sopenharmony_ci                                                             renderPassXferBarriers, colorLoadOp);
493cb93a386Sopenharmony_ci
494cb93a386Sopenharmony_ci    }
495cb93a386Sopenharmony_ci
496cb93a386Sopenharmony_ci    void onPrepareDraws(GrMeshDrawTarget* target) override {
497cb93a386Sopenharmony_ci        PathGeoBuilder pathGeoBuilder(this->primType(), target, &fMeshes);
498cb93a386Sopenharmony_ci
499cb93a386Sopenharmony_ci        // fill buffers
500cb93a386Sopenharmony_ci        for (int i = 0; i < fPaths.count(); i++) {
501cb93a386Sopenharmony_ci            const PathData& args = fPaths[i];
502cb93a386Sopenharmony_ci            pathGeoBuilder.addPath(args.fPath, args.fTolerance);
503cb93a386Sopenharmony_ci        }
504cb93a386Sopenharmony_ci    }
505cb93a386Sopenharmony_ci
506cb93a386Sopenharmony_ci    void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
507cb93a386Sopenharmony_ci        if (!fProgramInfo) {
508cb93a386Sopenharmony_ci            this->createProgramInfo(flushState);
509cb93a386Sopenharmony_ci        }
510cb93a386Sopenharmony_ci
511cb93a386Sopenharmony_ci        if (!fProgramInfo || !fMeshes.count()) {
512cb93a386Sopenharmony_ci            return;
513cb93a386Sopenharmony_ci        }
514cb93a386Sopenharmony_ci
515cb93a386Sopenharmony_ci        flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
516cb93a386Sopenharmony_ci        flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
517cb93a386Sopenharmony_ci        for (int i = 0; i < fMeshes.count(); ++i) {
518cb93a386Sopenharmony_ci            flushState->drawMesh(*fMeshes[i]);
519cb93a386Sopenharmony_ci        }
520cb93a386Sopenharmony_ci    }
521cb93a386Sopenharmony_ci
522cb93a386Sopenharmony_ci    CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
523cb93a386Sopenharmony_ci        DefaultPathOp* that = t->cast<DefaultPathOp>();
524cb93a386Sopenharmony_ci        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
525cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
526cb93a386Sopenharmony_ci        }
527cb93a386Sopenharmony_ci
528cb93a386Sopenharmony_ci        if (this->color() != that->color()) {
529cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
530cb93a386Sopenharmony_ci        }
531cb93a386Sopenharmony_ci
532cb93a386Sopenharmony_ci        if (this->coverage() != that->coverage()) {
533cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
534cb93a386Sopenharmony_ci        }
535cb93a386Sopenharmony_ci
536cb93a386Sopenharmony_ci        if (!SkMatrixPriv::CheapEqual(this->viewMatrix(), that->viewMatrix())) {
537cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
538cb93a386Sopenharmony_ci        }
539cb93a386Sopenharmony_ci
540cb93a386Sopenharmony_ci        if (this->isHairline() != that->isHairline()) {
541cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
542cb93a386Sopenharmony_ci        }
543cb93a386Sopenharmony_ci
544cb93a386Sopenharmony_ci        fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
545cb93a386Sopenharmony_ci        return CombineResult::kMerged;
546cb93a386Sopenharmony_ci    }
547cb93a386Sopenharmony_ci
548cb93a386Sopenharmony_ci#if GR_TEST_UTILS
549cb93a386Sopenharmony_ci    SkString onDumpInfo() const override {
550cb93a386Sopenharmony_ci        SkString string = SkStringPrintf("Color: 0x%08x Count: %d\n",
551cb93a386Sopenharmony_ci                                         fColor.toBytes_RGBA(), fPaths.count());
552cb93a386Sopenharmony_ci        for (const auto& path : fPaths) {
553cb93a386Sopenharmony_ci            string.appendf("Tolerance: %.2f\n", path.fTolerance);
554cb93a386Sopenharmony_ci        }
555cb93a386Sopenharmony_ci        string += fHelper.dumpInfo();
556cb93a386Sopenharmony_ci        return string;
557cb93a386Sopenharmony_ci    }
558cb93a386Sopenharmony_ci#endif
559cb93a386Sopenharmony_ci
560cb93a386Sopenharmony_ci    const SkPMColor4f& color() const { return fColor; }
561cb93a386Sopenharmony_ci    uint8_t coverage() const { return fCoverage; }
562cb93a386Sopenharmony_ci    const SkMatrix& viewMatrix() const { return fViewMatrix; }
563cb93a386Sopenharmony_ci    bool isHairline() const { return fIsHairline; }
564cb93a386Sopenharmony_ci
565cb93a386Sopenharmony_ci    struct PathData {
566cb93a386Sopenharmony_ci        SkPath fPath;
567cb93a386Sopenharmony_ci        SkScalar fTolerance;
568cb93a386Sopenharmony_ci    };
569cb93a386Sopenharmony_ci
570cb93a386Sopenharmony_ci    SkSTArray<1, PathData, true> fPaths;
571cb93a386Sopenharmony_ci    Helper fHelper;
572cb93a386Sopenharmony_ci    SkPMColor4f fColor;
573cb93a386Sopenharmony_ci    uint8_t fCoverage;
574cb93a386Sopenharmony_ci    SkMatrix fViewMatrix;
575cb93a386Sopenharmony_ci    bool fIsHairline;
576cb93a386Sopenharmony_ci
577cb93a386Sopenharmony_ci    SkTDArray<GrSimpleMesh*> fMeshes;
578cb93a386Sopenharmony_ci    GrProgramInfo* fProgramInfo = nullptr;
579cb93a386Sopenharmony_ci
580cb93a386Sopenharmony_ci    using INHERITED = GrMeshDrawOp;
581cb93a386Sopenharmony_ci};
582cb93a386Sopenharmony_ci
583cb93a386Sopenharmony_ci}  // anonymous namespace
584cb93a386Sopenharmony_ci
585cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
586cb93a386Sopenharmony_ci
587cb93a386Sopenharmony_ci#if GR_TEST_UTILS
588cb93a386Sopenharmony_ci
589cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(DefaultPathOp) {
590cb93a386Sopenharmony_ci    SkMatrix viewMatrix = GrTest::TestMatrix(random);
591cb93a386Sopenharmony_ci
592cb93a386Sopenharmony_ci    // For now just hairlines because the other types of draws require two ops.
593cb93a386Sopenharmony_ci    // TODO we should figure out a way to combine the stencil and cover steps into one op.
594cb93a386Sopenharmony_ci    GrStyle style(SkStrokeRec::kHairline_InitStyle);
595cb93a386Sopenharmony_ci    const SkPath& path = GrTest::TestPath(random);
596cb93a386Sopenharmony_ci
597cb93a386Sopenharmony_ci    // Compute srcSpaceTol
598cb93a386Sopenharmony_ci    SkRect bounds = path.getBounds();
599cb93a386Sopenharmony_ci    SkScalar tol = GrPathUtils::kDefaultTolerance;
600cb93a386Sopenharmony_ci    SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, bounds);
601cb93a386Sopenharmony_ci
602cb93a386Sopenharmony_ci    viewMatrix.mapRect(&bounds);
603cb93a386Sopenharmony_ci    uint8_t coverage = GrTest::RandomCoverage(random);
604cb93a386Sopenharmony_ci    GrAAType aaType = GrAAType::kNone;
605cb93a386Sopenharmony_ci    if (numSamples > 1 && random->nextBool()) {
606cb93a386Sopenharmony_ci        aaType = GrAAType::kMSAA;
607cb93a386Sopenharmony_ci    }
608cb93a386Sopenharmony_ci    return DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, coverage, viewMatrix,
609cb93a386Sopenharmony_ci                               true, aaType, bounds, GrGetRandomStencil(random, context));
610cb93a386Sopenharmony_ci}
611cb93a386Sopenharmony_ci
612cb93a386Sopenharmony_ci#endif
613cb93a386Sopenharmony_ci
614cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
615cb93a386Sopenharmony_ci
616cb93a386Sopenharmony_cinamespace skgpu::v1 {
617cb93a386Sopenharmony_ci
618cb93a386Sopenharmony_cibool DefaultPathRenderer::internalDrawPath(skgpu::v1::SurfaceDrawContext* sdc,
619cb93a386Sopenharmony_ci                                           GrPaint&& paint,
620cb93a386Sopenharmony_ci                                           GrAAType aaType,
621cb93a386Sopenharmony_ci                                           const GrUserStencilSettings& userStencilSettings,
622cb93a386Sopenharmony_ci                                           const GrClip* clip,
623cb93a386Sopenharmony_ci                                           const SkMatrix& viewMatrix,
624cb93a386Sopenharmony_ci                                           const GrStyledShape& shape,
625cb93a386Sopenharmony_ci                                           bool stencilOnly) {
626cb93a386Sopenharmony_ci    auto context = sdc->recordingContext();
627cb93a386Sopenharmony_ci
628cb93a386Sopenharmony_ci    SkASSERT(GrAAType::kCoverage != aaType);
629cb93a386Sopenharmony_ci    SkPath path;
630cb93a386Sopenharmony_ci    shape.asPath(&path);
631cb93a386Sopenharmony_ci
632cb93a386Sopenharmony_ci    SkScalar hairlineCoverage;
633cb93a386Sopenharmony_ci    uint8_t newCoverage = 0xff;
634cb93a386Sopenharmony_ci    bool isHairline = false;
635cb93a386Sopenharmony_ci    if (GrIsStrokeHairlineOrEquivalent(shape.style(), viewMatrix, &hairlineCoverage)) {
636cb93a386Sopenharmony_ci        newCoverage = SkScalarRoundToInt(hairlineCoverage * 0xff);
637cb93a386Sopenharmony_ci        isHairline = true;
638cb93a386Sopenharmony_ci    } else {
639cb93a386Sopenharmony_ci        SkASSERT(shape.style().isSimpleFill());
640cb93a386Sopenharmony_ci    }
641cb93a386Sopenharmony_ci
642cb93a386Sopenharmony_ci    int                          passCount = 0;
643cb93a386Sopenharmony_ci    const GrUserStencilSettings* passes[2];
644cb93a386Sopenharmony_ci    bool                         reverse = false;
645cb93a386Sopenharmony_ci    bool                         lastPassIsBounds;
646cb93a386Sopenharmony_ci
647cb93a386Sopenharmony_ci    if (isHairline) {
648cb93a386Sopenharmony_ci        passCount = 1;
649cb93a386Sopenharmony_ci        if (stencilOnly) {
650cb93a386Sopenharmony_ci            passes[0] = &gDirectToStencil;
651cb93a386Sopenharmony_ci        } else {
652cb93a386Sopenharmony_ci            passes[0] = &userStencilSettings;
653cb93a386Sopenharmony_ci        }
654cb93a386Sopenharmony_ci        lastPassIsBounds = false;
655cb93a386Sopenharmony_ci    } else {
656cb93a386Sopenharmony_ci        if (single_pass_shape(shape)) {
657cb93a386Sopenharmony_ci            passCount = 1;
658cb93a386Sopenharmony_ci            if (stencilOnly) {
659cb93a386Sopenharmony_ci                passes[0] = &gDirectToStencil;
660cb93a386Sopenharmony_ci            } else {
661cb93a386Sopenharmony_ci                passes[0] = &userStencilSettings;
662cb93a386Sopenharmony_ci            }
663cb93a386Sopenharmony_ci            lastPassIsBounds = false;
664cb93a386Sopenharmony_ci        } else {
665cb93a386Sopenharmony_ci            switch (path.getFillType()) {
666cb93a386Sopenharmony_ci                case SkPathFillType::kInverseEvenOdd:
667cb93a386Sopenharmony_ci                    reverse = true;
668cb93a386Sopenharmony_ci                    [[fallthrough]];
669cb93a386Sopenharmony_ci                case SkPathFillType::kEvenOdd:
670cb93a386Sopenharmony_ci                    passes[0] = &gEOStencilPass;
671cb93a386Sopenharmony_ci                    if (stencilOnly) {
672cb93a386Sopenharmony_ci                        passCount = 1;
673cb93a386Sopenharmony_ci                        lastPassIsBounds = false;
674cb93a386Sopenharmony_ci                    } else {
675cb93a386Sopenharmony_ci                        passCount = 2;
676cb93a386Sopenharmony_ci                        lastPassIsBounds = true;
677cb93a386Sopenharmony_ci                        if (reverse) {
678cb93a386Sopenharmony_ci                            passes[1] = &gInvEOColorPass;
679cb93a386Sopenharmony_ci                        } else {
680cb93a386Sopenharmony_ci                            passes[1] = &gEOColorPass;
681cb93a386Sopenharmony_ci                        }
682cb93a386Sopenharmony_ci                    }
683cb93a386Sopenharmony_ci                    break;
684cb93a386Sopenharmony_ci
685cb93a386Sopenharmony_ci                case SkPathFillType::kInverseWinding:
686cb93a386Sopenharmony_ci                    reverse = true;
687cb93a386Sopenharmony_ci                    [[fallthrough]];
688cb93a386Sopenharmony_ci                case SkPathFillType::kWinding:
689cb93a386Sopenharmony_ci                    passes[0] = &gWindStencilPass;
690cb93a386Sopenharmony_ci                    passCount = 2;
691cb93a386Sopenharmony_ci                    if (stencilOnly) {
692cb93a386Sopenharmony_ci                        lastPassIsBounds = false;
693cb93a386Sopenharmony_ci                        --passCount;
694cb93a386Sopenharmony_ci                    } else {
695cb93a386Sopenharmony_ci                        lastPassIsBounds = true;
696cb93a386Sopenharmony_ci                        if (reverse) {
697cb93a386Sopenharmony_ci                            passes[passCount-1] = &gInvWindColorPass;
698cb93a386Sopenharmony_ci                        } else {
699cb93a386Sopenharmony_ci                            passes[passCount-1] = &gWindColorPass;
700cb93a386Sopenharmony_ci                        }
701cb93a386Sopenharmony_ci                    }
702cb93a386Sopenharmony_ci                    break;
703cb93a386Sopenharmony_ci                default:
704cb93a386Sopenharmony_ci                    SkDEBUGFAIL("Unknown path fFill!");
705cb93a386Sopenharmony_ci                    return false;
706cb93a386Sopenharmony_ci            }
707cb93a386Sopenharmony_ci        }
708cb93a386Sopenharmony_ci    }
709cb93a386Sopenharmony_ci
710cb93a386Sopenharmony_ci    SkScalar tol = GrPathUtils::kDefaultTolerance;
711cb93a386Sopenharmony_ci    SkScalar srcSpaceTol = GrPathUtils::scaleToleranceToSrc(tol, viewMatrix, path.getBounds());
712cb93a386Sopenharmony_ci
713cb93a386Sopenharmony_ci    SkRect devBounds;
714cb93a386Sopenharmony_ci    GetPathDevBounds(path, sdc->asRenderTargetProxy()->backingStoreDimensions(),
715cb93a386Sopenharmony_ci                     viewMatrix, &devBounds);
716cb93a386Sopenharmony_ci
717cb93a386Sopenharmony_ci    for (int p = 0; p < passCount; ++p) {
718cb93a386Sopenharmony_ci        if (lastPassIsBounds && (p == passCount-1)) {
719cb93a386Sopenharmony_ci            SkRect bounds;
720cb93a386Sopenharmony_ci            SkMatrix localMatrix = SkMatrix::I();
721cb93a386Sopenharmony_ci            if (reverse) {
722cb93a386Sopenharmony_ci                // draw over the dev bounds (which will be the whole dst surface for inv fill).
723cb93a386Sopenharmony_ci                bounds = devBounds;
724cb93a386Sopenharmony_ci                SkMatrix vmi;
725cb93a386Sopenharmony_ci                // mapRect through persp matrix may not be correct
726cb93a386Sopenharmony_ci                if (!viewMatrix.hasPerspective() && viewMatrix.invert(&vmi)) {
727cb93a386Sopenharmony_ci                    vmi.mapRect(&bounds);
728cb93a386Sopenharmony_ci                } else {
729cb93a386Sopenharmony_ci                    if (!viewMatrix.invert(&localMatrix)) {
730cb93a386Sopenharmony_ci                        return false;
731cb93a386Sopenharmony_ci                    }
732cb93a386Sopenharmony_ci                }
733cb93a386Sopenharmony_ci            } else {
734cb93a386Sopenharmony_ci                bounds = path.getBounds();
735cb93a386Sopenharmony_ci            }
736cb93a386Sopenharmony_ci            const SkMatrix& viewM = (reverse && viewMatrix.hasPerspective()) ? SkMatrix::I() :
737cb93a386Sopenharmony_ci                                                                               viewMatrix;
738cb93a386Sopenharmony_ci            // This is a non-coverage aa rect op since we assert aaType != kCoverage at the start
739cb93a386Sopenharmony_ci            assert_alive(paint);
740cb93a386Sopenharmony_ci            sdc->stencilRect(clip, passes[p], std::move(paint),
741cb93a386Sopenharmony_ci                             GrAA(aaType == GrAAType::kMSAA), viewM, bounds,
742cb93a386Sopenharmony_ci                             &localMatrix);
743cb93a386Sopenharmony_ci        } else {
744cb93a386Sopenharmony_ci            bool stencilPass = stencilOnly || passCount > 1;
745cb93a386Sopenharmony_ci            GrOp::Owner op;
746cb93a386Sopenharmony_ci            if (stencilPass) {
747cb93a386Sopenharmony_ci                GrPaint stencilPaint;
748cb93a386Sopenharmony_ci                stencilPaint.setXPFactory(GrDisableColorXPFactory::Get());
749cb93a386Sopenharmony_ci                op = DefaultPathOp::Make(context, std::move(stencilPaint), path, srcSpaceTol,
750cb93a386Sopenharmony_ci                                         newCoverage, viewMatrix, isHairline, aaType, devBounds,
751cb93a386Sopenharmony_ci                                         passes[p]);
752cb93a386Sopenharmony_ci            } else {
753cb93a386Sopenharmony_ci                assert_alive(paint);
754cb93a386Sopenharmony_ci                op = DefaultPathOp::Make(context, std::move(paint), path, srcSpaceTol, newCoverage,
755cb93a386Sopenharmony_ci                                         viewMatrix, isHairline, aaType, devBounds, passes[p]);
756cb93a386Sopenharmony_ci            }
757cb93a386Sopenharmony_ci            sdc->addDrawOp(clip, std::move(op));
758cb93a386Sopenharmony_ci        }
759cb93a386Sopenharmony_ci    }
760cb93a386Sopenharmony_ci    return true;
761cb93a386Sopenharmony_ci}
762cb93a386Sopenharmony_ci
763cb93a386Sopenharmony_ci
764cb93a386Sopenharmony_ciPathRenderer::StencilSupport
765cb93a386Sopenharmony_ciDefaultPathRenderer::onGetStencilSupport(const GrStyledShape& shape) const {
766cb93a386Sopenharmony_ci    if (single_pass_shape(shape)) {
767cb93a386Sopenharmony_ci        return kNoRestriction_StencilSupport;
768cb93a386Sopenharmony_ci    } else {
769cb93a386Sopenharmony_ci        return kStencilOnly_StencilSupport;
770cb93a386Sopenharmony_ci    }
771cb93a386Sopenharmony_ci}
772cb93a386Sopenharmony_ci
773cb93a386Sopenharmony_ciPathRenderer::CanDrawPath DefaultPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
774cb93a386Sopenharmony_ci    bool isHairline = GrIsStrokeHairlineOrEquivalent(
775cb93a386Sopenharmony_ci            args.fShape->style(), *args.fViewMatrix, nullptr);
776cb93a386Sopenharmony_ci    // If we aren't a single_pass_shape or hairline, we require stencil buffers.
777cb93a386Sopenharmony_ci    if (!(single_pass_shape(*args.fShape) || isHairline) &&
778cb93a386Sopenharmony_ci        !args.fProxy->canUseStencil(*args.fCaps)) {
779cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
780cb93a386Sopenharmony_ci    }
781cb93a386Sopenharmony_ci    // If antialiasing is required, we only support MSAA.
782cb93a386Sopenharmony_ci    if (GrAAType::kNone != args.fAAType && GrAAType::kMSAA != args.fAAType) {
783cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
784cb93a386Sopenharmony_ci    }
785cb93a386Sopenharmony_ci    // This can draw any path with any simple fill style.
786cb93a386Sopenharmony_ci    if (!args.fShape->style().isSimpleFill() && !isHairline) {
787cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
788cb93a386Sopenharmony_ci    }
789cb93a386Sopenharmony_ci    // This is the fallback renderer for when a path is too complicated for the others to draw.
790cb93a386Sopenharmony_ci    return CanDrawPath::kAsBackup;
791cb93a386Sopenharmony_ci}
792cb93a386Sopenharmony_ci
793cb93a386Sopenharmony_cibool DefaultPathRenderer::onDrawPath(const DrawPathArgs& args) {
794cb93a386Sopenharmony_ci    GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
795cb93a386Sopenharmony_ci                              "DefaultPathRenderer::onDrawPath");
796cb93a386Sopenharmony_ci    GrAAType aaType = (GrAAType::kNone != args.fAAType) ? GrAAType::kMSAA : GrAAType::kNone;
797cb93a386Sopenharmony_ci
798cb93a386Sopenharmony_ci    return this->internalDrawPath(
799cb93a386Sopenharmony_ci            args.fSurfaceDrawContext, std::move(args.fPaint), aaType, *args.fUserStencilSettings,
800cb93a386Sopenharmony_ci            args.fClip, *args.fViewMatrix, *args.fShape, false);
801cb93a386Sopenharmony_ci}
802cb93a386Sopenharmony_ci
803cb93a386Sopenharmony_civoid DefaultPathRenderer::onStencilPath(const StencilPathArgs& args) {
804cb93a386Sopenharmony_ci    GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
805cb93a386Sopenharmony_ci                              "DefaultPathRenderer::onStencilPath");
806cb93a386Sopenharmony_ci    SkASSERT(!args.fShape->inverseFilled());
807cb93a386Sopenharmony_ci
808cb93a386Sopenharmony_ci    GrPaint paint;
809cb93a386Sopenharmony_ci    paint.setXPFactory(GrDisableColorXPFactory::Get());
810cb93a386Sopenharmony_ci
811cb93a386Sopenharmony_ci    auto aaType = (GrAA::kYes == args.fDoStencilMSAA) ? GrAAType::kMSAA : GrAAType::kNone;
812cb93a386Sopenharmony_ci
813cb93a386Sopenharmony_ci    this->internalDrawPath(
814cb93a386Sopenharmony_ci            args.fSurfaceDrawContext, std::move(paint), aaType, GrUserStencilSettings::kUnused,
815cb93a386Sopenharmony_ci            args.fClip, *args.fViewMatrix, *args.fShape, true);
816cb93a386Sopenharmony_ci}
817cb93a386Sopenharmony_ci
818cb93a386Sopenharmony_ci} // namespace skgpu::v1
819