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/AALinearizingConvexPathRenderer.h"
9cb93a386Sopenharmony_ci
10cb93a386Sopenharmony_ci#include "include/core/SkString.h"
11cb93a386Sopenharmony_ci#include "src/core/SkGeometry.h"
12cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
13cb93a386Sopenharmony_ci#include "src/core/SkTraceEvent.h"
14cb93a386Sopenharmony_ci#include "src/gpu/BufferWriter.h"
15cb93a386Sopenharmony_ci#include "src/gpu/GrAuditTrail.h"
16cb93a386Sopenharmony_ci#include "src/gpu/GrCaps.h"
17cb93a386Sopenharmony_ci#include "src/gpu/GrDefaultGeoProcFactory.h"
18cb93a386Sopenharmony_ci#include "src/gpu/GrDrawOpTest.h"
19cb93a386Sopenharmony_ci#include "src/gpu/GrGeometryProcessor.h"
20cb93a386Sopenharmony_ci#include "src/gpu/GrOpFlushState.h"
21cb93a386Sopenharmony_ci#include "src/gpu/GrProcessor.h"
22cb93a386Sopenharmony_ci#include "src/gpu/GrProgramInfo.h"
23cb93a386Sopenharmony_ci#include "src/gpu/GrStyle.h"
24cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrAAConvexTessellator.h"
25cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrPathUtils.h"
26cb93a386Sopenharmony_ci#include "src/gpu/geometry/GrStyledShape.h"
27cb93a386Sopenharmony_ci#include "src/gpu/ops/GrMeshDrawOp.h"
28cb93a386Sopenharmony_ci#include "src/gpu/ops/GrSimpleMeshDrawOpHelperWithStencil.h"
29cb93a386Sopenharmony_ci#include "src/gpu/v1/SurfaceDrawContext_v1.h"
30cb93a386Sopenharmony_ci
31cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////
32cb93a386Sopenharmony_cinamespace skgpu::v1 {
33cb93a386Sopenharmony_ci
34cb93a386Sopenharmony_cinamespace {
35cb93a386Sopenharmony_ci
36cb93a386Sopenharmony_cistatic const int DEFAULT_BUFFER_SIZE = 100;
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci// The thicker the stroke, the harder it is to produce high-quality results using tessellation. For
39cb93a386Sopenharmony_ci// the time being, we simply drop back to software rendering above this stroke width.
40cb93a386Sopenharmony_cistatic const SkScalar kMaxStrokeWidth = 20.0;
41cb93a386Sopenharmony_ci
42cb93a386Sopenharmony_ci// extract the result vertices and indices from the GrAAConvexTessellator
43cb93a386Sopenharmony_civoid extract_verts(const GrAAConvexTessellator& tess,
44cb93a386Sopenharmony_ci                   const SkMatrix* localCoordsMatrix,
45cb93a386Sopenharmony_ci                   void* vertData,
46cb93a386Sopenharmony_ci                   const GrVertexColor& color,
47cb93a386Sopenharmony_ci                   uint16_t firstIndex,
48cb93a386Sopenharmony_ci                   uint16_t* idxs) {
49cb93a386Sopenharmony_ci    VertexWriter verts{vertData};
50cb93a386Sopenharmony_ci    for (int i = 0; i < tess.numPts(); ++i) {
51cb93a386Sopenharmony_ci        SkPoint lc;
52cb93a386Sopenharmony_ci        if (localCoordsMatrix) {
53cb93a386Sopenharmony_ci            localCoordsMatrix->mapPoints(&lc, &tess.point(i), 1);
54cb93a386Sopenharmony_ci        }
55cb93a386Sopenharmony_ci        verts << tess.point(i) << color << VertexWriter::If(localCoordsMatrix, lc)
56cb93a386Sopenharmony_ci              << tess.coverage(i);
57cb93a386Sopenharmony_ci    }
58cb93a386Sopenharmony_ci
59cb93a386Sopenharmony_ci    for (int i = 0; i < tess.numIndices(); ++i) {
60cb93a386Sopenharmony_ci        idxs[i] = tess.index(i) + firstIndex;
61cb93a386Sopenharmony_ci    }
62cb93a386Sopenharmony_ci}
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ciGrGeometryProcessor* create_lines_only_gp(SkArenaAlloc* arena,
65cb93a386Sopenharmony_ci                                          bool tweakAlphaForCoverage,
66cb93a386Sopenharmony_ci                                          bool usesLocalCoords,
67cb93a386Sopenharmony_ci                                          bool wideColor) {
68cb93a386Sopenharmony_ci    using namespace GrDefaultGeoProcFactory;
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ci    Coverage::Type coverageType =
71cb93a386Sopenharmony_ci        tweakAlphaForCoverage ? Coverage::kAttributeTweakAlpha_Type : Coverage::kAttribute_Type;
72cb93a386Sopenharmony_ci    LocalCoords::Type localCoordsType =
73cb93a386Sopenharmony_ci            usesLocalCoords ? LocalCoords::kHasExplicit_Type : LocalCoords::kUnused_Type;
74cb93a386Sopenharmony_ci    Color::Type colorType =
75cb93a386Sopenharmony_ci        wideColor ? Color::kPremulWideColorAttribute_Type : Color::kPremulGrColorAttribute_Type;
76cb93a386Sopenharmony_ci
77cb93a386Sopenharmony_ci    return Make(arena, colorType, coverageType, localCoordsType, SkMatrix::I());
78cb93a386Sopenharmony_ci}
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ciclass AAFlatteningConvexPathOp final : public GrMeshDrawOp {
81cb93a386Sopenharmony_ciprivate:
82cb93a386Sopenharmony_ci    using Helper = GrSimpleMeshDrawOpHelperWithStencil;
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_cipublic:
85cb93a386Sopenharmony_ci    DEFINE_OP_CLASS_ID
86cb93a386Sopenharmony_ci
87cb93a386Sopenharmony_ci    static GrOp::Owner Make(GrRecordingContext* context,
88cb93a386Sopenharmony_ci                            GrPaint&& paint,
89cb93a386Sopenharmony_ci                            const SkMatrix& viewMatrix,
90cb93a386Sopenharmony_ci                            const SkPath& path,
91cb93a386Sopenharmony_ci                            SkScalar strokeWidth,
92cb93a386Sopenharmony_ci                            SkStrokeRec::Style style,
93cb93a386Sopenharmony_ci                            SkPaint::Join join,
94cb93a386Sopenharmony_ci                            SkScalar miterLimit,
95cb93a386Sopenharmony_ci                            const GrUserStencilSettings* stencilSettings) {
96cb93a386Sopenharmony_ci        return Helper::FactoryHelper<AAFlatteningConvexPathOp>(context, std::move(paint),
97cb93a386Sopenharmony_ci                                                               viewMatrix, path,
98cb93a386Sopenharmony_ci                                                               strokeWidth, style, join, miterLimit,
99cb93a386Sopenharmony_ci                                                               stencilSettings);
100cb93a386Sopenharmony_ci    }
101cb93a386Sopenharmony_ci
102cb93a386Sopenharmony_ci    AAFlatteningConvexPathOp(GrProcessorSet* processorSet,
103cb93a386Sopenharmony_ci                             const SkPMColor4f& color,
104cb93a386Sopenharmony_ci                             const SkMatrix& viewMatrix,
105cb93a386Sopenharmony_ci                             const SkPath& path,
106cb93a386Sopenharmony_ci                             SkScalar strokeWidth,
107cb93a386Sopenharmony_ci                             SkStrokeRec::Style style,
108cb93a386Sopenharmony_ci                             SkPaint::Join join,
109cb93a386Sopenharmony_ci                             SkScalar miterLimit,
110cb93a386Sopenharmony_ci                             const GrUserStencilSettings* stencilSettings)
111cb93a386Sopenharmony_ci            : INHERITED(ClassID()), fHelper(processorSet, GrAAType::kCoverage, stencilSettings) {
112cb93a386Sopenharmony_ci        fPaths.emplace_back(
113cb93a386Sopenharmony_ci                PathData{viewMatrix, path, color, strokeWidth, miterLimit, style, join});
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci        // compute bounds
116cb93a386Sopenharmony_ci        SkRect bounds = path.getBounds();
117cb93a386Sopenharmony_ci        SkScalar w = strokeWidth;
118cb93a386Sopenharmony_ci        if (w > 0) {
119cb93a386Sopenharmony_ci            w /= 2;
120cb93a386Sopenharmony_ci            SkScalar maxScale = viewMatrix.getMaxScale();
121cb93a386Sopenharmony_ci            // We should not have a perspective matrix, thus we should have a valid scale.
122cb93a386Sopenharmony_ci            SkASSERT(maxScale != -1);
123cb93a386Sopenharmony_ci            if (SkPaint::kMiter_Join == join && w * maxScale > 1.f) {
124cb93a386Sopenharmony_ci                w *= miterLimit;
125cb93a386Sopenharmony_ci            }
126cb93a386Sopenharmony_ci            bounds.outset(w, w);
127cb93a386Sopenharmony_ci        }
128cb93a386Sopenharmony_ci        this->setTransformedBounds(bounds, viewMatrix, HasAABloat::kYes, IsHairline::kNo);
129cb93a386Sopenharmony_ci    }
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci    const char* name() const override { return "AAFlatteningConvexPathOp"; }
132cb93a386Sopenharmony_ci
133cb93a386Sopenharmony_ci    void visitProxies(const GrVisitProxyFunc& func) const override {
134cb93a386Sopenharmony_ci        if (fProgramInfo) {
135cb93a386Sopenharmony_ci            fProgramInfo->visitFPProxies(func);
136cb93a386Sopenharmony_ci        } else {
137cb93a386Sopenharmony_ci            fHelper.visitProxies(func);
138cb93a386Sopenharmony_ci        }
139cb93a386Sopenharmony_ci    }
140cb93a386Sopenharmony_ci
141cb93a386Sopenharmony_ci    FixedFunctionFlags fixedFunctionFlags() const override { return fHelper.fixedFunctionFlags(); }
142cb93a386Sopenharmony_ci
143cb93a386Sopenharmony_ci    GrProcessorSet::Analysis finalize(const GrCaps& caps, const GrAppliedClip* clip,
144cb93a386Sopenharmony_ci                                      GrClampType clampType) override {
145cb93a386Sopenharmony_ci        return fHelper.finalizeProcessors(caps, clip, clampType,
146cb93a386Sopenharmony_ci                                          GrProcessorAnalysisCoverage::kSingleChannel,
147cb93a386Sopenharmony_ci                                          &fPaths.back().fColor, &fWideColor);
148cb93a386Sopenharmony_ci    }
149cb93a386Sopenharmony_ci
150cb93a386Sopenharmony_ciprivate:
151cb93a386Sopenharmony_ci    GrProgramInfo* programInfo() override { return fProgramInfo; }
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ci    void onCreateProgramInfo(const GrCaps* caps,
154cb93a386Sopenharmony_ci                             SkArenaAlloc* arena,
155cb93a386Sopenharmony_ci                             const GrSurfaceProxyView& writeView,
156cb93a386Sopenharmony_ci                             bool usesMSAASurface,
157cb93a386Sopenharmony_ci                             GrAppliedClip&& appliedClip,
158cb93a386Sopenharmony_ci                             const GrDstProxyView& dstProxyView,
159cb93a386Sopenharmony_ci                             GrXferBarrierFlags renderPassXferBarriers,
160cb93a386Sopenharmony_ci                             GrLoadOp colorLoadOp) override {
161cb93a386Sopenharmony_ci        GrGeometryProcessor* gp = create_lines_only_gp(arena,
162cb93a386Sopenharmony_ci                                                       fHelper.compatibleWithCoverageAsAlpha(),
163cb93a386Sopenharmony_ci                                                       fHelper.usesLocalCoords(),
164cb93a386Sopenharmony_ci                                                       fWideColor);
165cb93a386Sopenharmony_ci        if (!gp) {
166cb93a386Sopenharmony_ci            SkDebugf("Couldn't create a GrGeometryProcessor\n");
167cb93a386Sopenharmony_ci            return;
168cb93a386Sopenharmony_ci        }
169cb93a386Sopenharmony_ci
170cb93a386Sopenharmony_ci        fProgramInfo = fHelper.createProgramInfoWithStencil(caps, arena, writeView, usesMSAASurface,
171cb93a386Sopenharmony_ci                                                            std::move(appliedClip), dstProxyView,
172cb93a386Sopenharmony_ci                                                            gp, GrPrimitiveType::kTriangles,
173cb93a386Sopenharmony_ci                                                            renderPassXferBarriers, colorLoadOp);
174cb93a386Sopenharmony_ci    }
175cb93a386Sopenharmony_ci
176cb93a386Sopenharmony_ci    void recordDraw(GrMeshDrawTarget* target,
177cb93a386Sopenharmony_ci                    int vertexCount, size_t vertexStride, void* vertices,
178cb93a386Sopenharmony_ci                    int indexCount, uint16_t* indices) {
179cb93a386Sopenharmony_ci        if (vertexCount == 0 || indexCount == 0) {
180cb93a386Sopenharmony_ci            return;
181cb93a386Sopenharmony_ci        }
182cb93a386Sopenharmony_ci        sk_sp<const GrBuffer> vertexBuffer;
183cb93a386Sopenharmony_ci        int firstVertex;
184cb93a386Sopenharmony_ci        void* verts = target->makeVertexSpace(vertexStride, vertexCount, &vertexBuffer,
185cb93a386Sopenharmony_ci                                              &firstVertex);
186cb93a386Sopenharmony_ci        if (!verts) {
187cb93a386Sopenharmony_ci            SkDebugf("Could not allocate vertices\n");
188cb93a386Sopenharmony_ci            return;
189cb93a386Sopenharmony_ci        }
190cb93a386Sopenharmony_ci        memcpy(verts, vertices, vertexCount * vertexStride);
191cb93a386Sopenharmony_ci
192cb93a386Sopenharmony_ci        sk_sp<const GrBuffer> indexBuffer;
193cb93a386Sopenharmony_ci        int firstIndex;
194cb93a386Sopenharmony_ci        uint16_t* idxs = target->makeIndexSpace(indexCount, &indexBuffer, &firstIndex);
195cb93a386Sopenharmony_ci        if (!idxs) {
196cb93a386Sopenharmony_ci            SkDebugf("Could not allocate indices\n");
197cb93a386Sopenharmony_ci            return;
198cb93a386Sopenharmony_ci        }
199cb93a386Sopenharmony_ci        memcpy(idxs, indices, indexCount * sizeof(uint16_t));
200cb93a386Sopenharmony_ci        GrSimpleMesh* mesh = target->allocMesh();
201cb93a386Sopenharmony_ci        mesh->setIndexed(std::move(indexBuffer), indexCount, firstIndex, 0, vertexCount - 1,
202cb93a386Sopenharmony_ci                         GrPrimitiveRestart::kNo, std::move(vertexBuffer), firstVertex);
203cb93a386Sopenharmony_ci        fMeshes.push_back(mesh);
204cb93a386Sopenharmony_ci    }
205cb93a386Sopenharmony_ci
206cb93a386Sopenharmony_ci    void onPrepareDraws(GrMeshDrawTarget* target) override {
207cb93a386Sopenharmony_ci        if (!fProgramInfo) {
208cb93a386Sopenharmony_ci            this->createProgramInfo(target);
209cb93a386Sopenharmony_ci            if (!fProgramInfo) {
210cb93a386Sopenharmony_ci                return;
211cb93a386Sopenharmony_ci            }
212cb93a386Sopenharmony_ci        }
213cb93a386Sopenharmony_ci
214cb93a386Sopenharmony_ci        size_t vertexStride =  fProgramInfo->geomProc().vertexStride();
215cb93a386Sopenharmony_ci        int instanceCount = fPaths.count();
216cb93a386Sopenharmony_ci
217cb93a386Sopenharmony_ci        int64_t vertexCount = 0;
218cb93a386Sopenharmony_ci        int64_t indexCount = 0;
219cb93a386Sopenharmony_ci        int64_t maxVertices = DEFAULT_BUFFER_SIZE;
220cb93a386Sopenharmony_ci        int64_t maxIndices = DEFAULT_BUFFER_SIZE;
221cb93a386Sopenharmony_ci        uint8_t* vertices = (uint8_t*) sk_malloc_throw(maxVertices * vertexStride);
222cb93a386Sopenharmony_ci        uint16_t* indices = (uint16_t*) sk_malloc_throw(maxIndices * sizeof(uint16_t));
223cb93a386Sopenharmony_ci        for (int i = 0; i < instanceCount; i++) {
224cb93a386Sopenharmony_ci            const PathData& args = fPaths[i];
225cb93a386Sopenharmony_ci            GrAAConvexTessellator tess(args.fStyle, args.fStrokeWidth,
226cb93a386Sopenharmony_ci                                       args.fJoin, args.fMiterLimit);
227cb93a386Sopenharmony_ci
228cb93a386Sopenharmony_ci            if (!tess.tessellate(args.fViewMatrix, args.fPath)) {
229cb93a386Sopenharmony_ci                continue;
230cb93a386Sopenharmony_ci            }
231cb93a386Sopenharmony_ci
232cb93a386Sopenharmony_ci            int currentVertices = tess.numPts();
233cb93a386Sopenharmony_ci            if (vertexCount + currentVertices > static_cast<int>(UINT16_MAX)) {
234cb93a386Sopenharmony_ci                // if we added the current instance, we would overflow the indices we can store in a
235cb93a386Sopenharmony_ci                // uint16_t. Draw what we've got so far and reset.
236cb93a386Sopenharmony_ci                this->recordDraw(target, vertexCount, vertexStride, vertices, indexCount, indices);
237cb93a386Sopenharmony_ci                vertexCount = 0;
238cb93a386Sopenharmony_ci                indexCount = 0;
239cb93a386Sopenharmony_ci            }
240cb93a386Sopenharmony_ci            if (vertexCount + currentVertices > maxVertices) {
241cb93a386Sopenharmony_ci                maxVertices = std::max(vertexCount + currentVertices, maxVertices * 2);
242cb93a386Sopenharmony_ci                if (maxVertices * vertexStride > SK_MaxS32) {
243cb93a386Sopenharmony_ci                    sk_free(vertices);
244cb93a386Sopenharmony_ci                    sk_free(indices);
245cb93a386Sopenharmony_ci                    return;
246cb93a386Sopenharmony_ci                }
247cb93a386Sopenharmony_ci                vertices = (uint8_t*) sk_realloc_throw(vertices, maxVertices * vertexStride);
248cb93a386Sopenharmony_ci            }
249cb93a386Sopenharmony_ci            int currentIndices = tess.numIndices();
250cb93a386Sopenharmony_ci            if (indexCount + currentIndices > maxIndices) {
251cb93a386Sopenharmony_ci                maxIndices = std::max(indexCount + currentIndices, maxIndices * 2);
252cb93a386Sopenharmony_ci                if (maxIndices * sizeof(uint16_t) > SK_MaxS32) {
253cb93a386Sopenharmony_ci                    sk_free(vertices);
254cb93a386Sopenharmony_ci                    sk_free(indices);
255cb93a386Sopenharmony_ci                    return;
256cb93a386Sopenharmony_ci                }
257cb93a386Sopenharmony_ci                indices = (uint16_t*) sk_realloc_throw(indices, maxIndices * sizeof(uint16_t));
258cb93a386Sopenharmony_ci            }
259cb93a386Sopenharmony_ci
260cb93a386Sopenharmony_ci            const SkMatrix* localCoordsMatrix = nullptr;
261cb93a386Sopenharmony_ci            SkMatrix ivm;
262cb93a386Sopenharmony_ci            if (fHelper.usesLocalCoords()) {
263cb93a386Sopenharmony_ci                if (!args.fViewMatrix.invert(&ivm)) {
264cb93a386Sopenharmony_ci                    ivm = SkMatrix::I();
265cb93a386Sopenharmony_ci                }
266cb93a386Sopenharmony_ci                localCoordsMatrix = &ivm;
267cb93a386Sopenharmony_ci            }
268cb93a386Sopenharmony_ci
269cb93a386Sopenharmony_ci            extract_verts(tess, localCoordsMatrix, vertices + vertexStride * vertexCount,
270cb93a386Sopenharmony_ci                          GrVertexColor(args.fColor, fWideColor), vertexCount,
271cb93a386Sopenharmony_ci                          indices + indexCount);
272cb93a386Sopenharmony_ci            vertexCount += currentVertices;
273cb93a386Sopenharmony_ci            indexCount += currentIndices;
274cb93a386Sopenharmony_ci        }
275cb93a386Sopenharmony_ci        if (vertexCount <= SK_MaxS32 && indexCount <= SK_MaxS32) {
276cb93a386Sopenharmony_ci            this->recordDraw(target, vertexCount, vertexStride, vertices, indexCount, indices);
277cb93a386Sopenharmony_ci        }
278cb93a386Sopenharmony_ci        sk_free(vertices);
279cb93a386Sopenharmony_ci        sk_free(indices);
280cb93a386Sopenharmony_ci    }
281cb93a386Sopenharmony_ci
282cb93a386Sopenharmony_ci    void onExecute(GrOpFlushState* flushState, const SkRect& chainBounds) override {
283cb93a386Sopenharmony_ci        if (!fProgramInfo || fMeshes.isEmpty()) {
284cb93a386Sopenharmony_ci            return;
285cb93a386Sopenharmony_ci        }
286cb93a386Sopenharmony_ci
287cb93a386Sopenharmony_ci        flushState->bindPipelineAndScissorClip(*fProgramInfo, chainBounds);
288cb93a386Sopenharmony_ci        flushState->bindTextures(fProgramInfo->geomProc(), nullptr, fProgramInfo->pipeline());
289cb93a386Sopenharmony_ci        for (int i = 0; i < fMeshes.count(); ++i) {
290cb93a386Sopenharmony_ci            flushState->drawMesh(*fMeshes[i]);
291cb93a386Sopenharmony_ci        }
292cb93a386Sopenharmony_ci    }
293cb93a386Sopenharmony_ci
294cb93a386Sopenharmony_ci    CombineResult onCombineIfPossible(GrOp* t, SkArenaAlloc*, const GrCaps& caps) override {
295cb93a386Sopenharmony_ci        AAFlatteningConvexPathOp* that = t->cast<AAFlatteningConvexPathOp>();
296cb93a386Sopenharmony_ci        if (!fHelper.isCompatible(that->fHelper, caps, this->bounds(), that->bounds())) {
297cb93a386Sopenharmony_ci            return CombineResult::kCannotCombine;
298cb93a386Sopenharmony_ci        }
299cb93a386Sopenharmony_ci
300cb93a386Sopenharmony_ci        fPaths.push_back_n(that->fPaths.count(), that->fPaths.begin());
301cb93a386Sopenharmony_ci        fWideColor |= that->fWideColor;
302cb93a386Sopenharmony_ci        return CombineResult::kMerged;
303cb93a386Sopenharmony_ci    }
304cb93a386Sopenharmony_ci
305cb93a386Sopenharmony_ci#if GR_TEST_UTILS
306cb93a386Sopenharmony_ci    SkString onDumpInfo() const override {
307cb93a386Sopenharmony_ci        SkString string;
308cb93a386Sopenharmony_ci        for (const auto& path : fPaths) {
309cb93a386Sopenharmony_ci            string.appendf(
310cb93a386Sopenharmony_ci                    "Color: 0x%08x, StrokeWidth: %.2f, Style: %d, Join: %d, "
311cb93a386Sopenharmony_ci                    "MiterLimit: %.2f\n",
312cb93a386Sopenharmony_ci                    path.fColor.toBytes_RGBA(), path.fStrokeWidth, path.fStyle, path.fJoin,
313cb93a386Sopenharmony_ci                    path.fMiterLimit);
314cb93a386Sopenharmony_ci        }
315cb93a386Sopenharmony_ci        string += fHelper.dumpInfo();
316cb93a386Sopenharmony_ci        return string;
317cb93a386Sopenharmony_ci    }
318cb93a386Sopenharmony_ci#endif
319cb93a386Sopenharmony_ci
320cb93a386Sopenharmony_ci    struct PathData {
321cb93a386Sopenharmony_ci        SkMatrix fViewMatrix;
322cb93a386Sopenharmony_ci        SkPath fPath;
323cb93a386Sopenharmony_ci        SkPMColor4f fColor;
324cb93a386Sopenharmony_ci        SkScalar fStrokeWidth;
325cb93a386Sopenharmony_ci        SkScalar fMiterLimit;
326cb93a386Sopenharmony_ci        SkStrokeRec::Style fStyle;
327cb93a386Sopenharmony_ci        SkPaint::Join fJoin;
328cb93a386Sopenharmony_ci    };
329cb93a386Sopenharmony_ci
330cb93a386Sopenharmony_ci    SkSTArray<1, PathData, true> fPaths;
331cb93a386Sopenharmony_ci    Helper fHelper;
332cb93a386Sopenharmony_ci    bool fWideColor;
333cb93a386Sopenharmony_ci
334cb93a386Sopenharmony_ci    SkTDArray<GrSimpleMesh*> fMeshes;
335cb93a386Sopenharmony_ci    GrProgramInfo*           fProgramInfo = nullptr;
336cb93a386Sopenharmony_ci
337cb93a386Sopenharmony_ci    using INHERITED = GrMeshDrawOp;
338cb93a386Sopenharmony_ci};
339cb93a386Sopenharmony_ci
340cb93a386Sopenharmony_ci}  // anonymous namespace
341cb93a386Sopenharmony_ci
342cb93a386Sopenharmony_ci///////////////////////////////////////////////////////////////////////////////////////////////////
343cb93a386Sopenharmony_ci
344cb93a386Sopenharmony_ciPathRenderer::CanDrawPath
345cb93a386Sopenharmony_ciAALinearizingConvexPathRenderer::onCanDrawPath(const CanDrawPathArgs& args) const {
346cb93a386Sopenharmony_ci    if (GrAAType::kCoverage != args.fAAType) {
347cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
348cb93a386Sopenharmony_ci    }
349cb93a386Sopenharmony_ci    if (!args.fShape->knownToBeConvex()) {
350cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
351cb93a386Sopenharmony_ci    }
352cb93a386Sopenharmony_ci    if (args.fShape->style().pathEffect()) {
353cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
354cb93a386Sopenharmony_ci    }
355cb93a386Sopenharmony_ci    if (args.fShape->inverseFilled()) {
356cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
357cb93a386Sopenharmony_ci    }
358cb93a386Sopenharmony_ci    if (args.fShape->bounds().width() <= 0 && args.fShape->bounds().height() <= 0) {
359cb93a386Sopenharmony_ci        // Stroked zero length lines should draw, but this PR doesn't handle that case
360cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
361cb93a386Sopenharmony_ci    }
362cb93a386Sopenharmony_ci    const SkStrokeRec& stroke = args.fShape->style().strokeRec();
363cb93a386Sopenharmony_ci
364cb93a386Sopenharmony_ci    if (stroke.getStyle() == SkStrokeRec::kStroke_Style ||
365cb93a386Sopenharmony_ci        stroke.getStyle() == SkStrokeRec::kStrokeAndFill_Style) {
366cb93a386Sopenharmony_ci        if (!args.fViewMatrix->isSimilarity()) {
367cb93a386Sopenharmony_ci            return CanDrawPath::kNo;
368cb93a386Sopenharmony_ci        }
369cb93a386Sopenharmony_ci        SkScalar strokeWidth = args.fViewMatrix->getMaxScale() * stroke.getWidth();
370cb93a386Sopenharmony_ci        if (strokeWidth < 1.0f && stroke.getStyle() == SkStrokeRec::kStroke_Style) {
371cb93a386Sopenharmony_ci            return CanDrawPath::kNo;
372cb93a386Sopenharmony_ci        }
373cb93a386Sopenharmony_ci        if (strokeWidth > kMaxStrokeWidth ||
374cb93a386Sopenharmony_ci            !args.fShape->knownToBeClosed() ||
375cb93a386Sopenharmony_ci            stroke.getJoin() == SkPaint::Join::kRound_Join) {
376cb93a386Sopenharmony_ci            return CanDrawPath::kNo;
377cb93a386Sopenharmony_ci        }
378cb93a386Sopenharmony_ci        return CanDrawPath::kYes;
379cb93a386Sopenharmony_ci    }
380cb93a386Sopenharmony_ci    if (stroke.getStyle() != SkStrokeRec::kFill_Style) {
381cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
382cb93a386Sopenharmony_ci    }
383cb93a386Sopenharmony_ci    // This can almost handle perspective. It would need to use 3 component explicit local coords
384cb93a386Sopenharmony_ci    // when there are FPs that require them. This is difficult to test because AAConvexPathRenderer
385cb93a386Sopenharmony_ci    // takes almost all filled paths that could get here. So just avoid perspective fills.
386cb93a386Sopenharmony_ci    if (args.fViewMatrix->hasPerspective()) {
387cb93a386Sopenharmony_ci        return CanDrawPath::kNo;
388cb93a386Sopenharmony_ci    }
389cb93a386Sopenharmony_ci    return CanDrawPath::kYes;
390cb93a386Sopenharmony_ci}
391cb93a386Sopenharmony_ci
392cb93a386Sopenharmony_cibool AALinearizingConvexPathRenderer::onDrawPath(const DrawPathArgs& args) {
393cb93a386Sopenharmony_ci    GR_AUDIT_TRAIL_AUTO_FRAME(args.fContext->priv().auditTrail(),
394cb93a386Sopenharmony_ci                              "AALinearizingConvexPathRenderer::onDrawPath");
395cb93a386Sopenharmony_ci    SkASSERT(args.fSurfaceDrawContext->numSamples() <= 1);
396cb93a386Sopenharmony_ci    SkASSERT(!args.fShape->isEmpty());
397cb93a386Sopenharmony_ci    SkASSERT(!args.fShape->style().pathEffect());
398cb93a386Sopenharmony_ci
399cb93a386Sopenharmony_ci    SkPath path;
400cb93a386Sopenharmony_ci    args.fShape->asPath(&path);
401cb93a386Sopenharmony_ci    bool fill = args.fShape->style().isSimpleFill();
402cb93a386Sopenharmony_ci    const SkStrokeRec& stroke = args.fShape->style().strokeRec();
403cb93a386Sopenharmony_ci    SkScalar strokeWidth = fill ? -1.0f : stroke.getWidth();
404cb93a386Sopenharmony_ci    SkPaint::Join join = fill ? SkPaint::Join::kMiter_Join : stroke.getJoin();
405cb93a386Sopenharmony_ci    SkScalar miterLimit = stroke.getMiter();
406cb93a386Sopenharmony_ci
407cb93a386Sopenharmony_ci    GrOp::Owner op = AAFlatteningConvexPathOp::Make(
408cb93a386Sopenharmony_ci            args.fContext, std::move(args.fPaint), *args.fViewMatrix, path, strokeWidth,
409cb93a386Sopenharmony_ci            stroke.getStyle(), join, miterLimit, args.fUserStencilSettings);
410cb93a386Sopenharmony_ci    args.fSurfaceDrawContext->addDrawOp(args.fClip, std::move(op));
411cb93a386Sopenharmony_ci    return true;
412cb93a386Sopenharmony_ci}
413cb93a386Sopenharmony_ci
414cb93a386Sopenharmony_ci} // namespace skgpu::v1
415cb93a386Sopenharmony_ci
416cb93a386Sopenharmony_ci#if GR_TEST_UTILS
417cb93a386Sopenharmony_ci
418cb93a386Sopenharmony_ciGR_DRAW_OP_TEST_DEFINE(AAFlatteningConvexPathOp) {
419cb93a386Sopenharmony_ci    SkMatrix viewMatrix = GrTest::TestMatrixPreservesRightAngles(random);
420cb93a386Sopenharmony_ci    const SkPath& path = GrTest::TestPathConvex(random);
421cb93a386Sopenharmony_ci
422cb93a386Sopenharmony_ci    SkStrokeRec::Style styles[3] = { SkStrokeRec::kFill_Style,
423cb93a386Sopenharmony_ci                                     SkStrokeRec::kStroke_Style,
424cb93a386Sopenharmony_ci                                     SkStrokeRec::kStrokeAndFill_Style };
425cb93a386Sopenharmony_ci
426cb93a386Sopenharmony_ci    SkStrokeRec::Style style = styles[random->nextU() % 3];
427cb93a386Sopenharmony_ci
428cb93a386Sopenharmony_ci    SkScalar strokeWidth = -1.f;
429cb93a386Sopenharmony_ci    SkPaint::Join join = SkPaint::kMiter_Join;
430cb93a386Sopenharmony_ci    SkScalar miterLimit = 0.5f;
431cb93a386Sopenharmony_ci
432cb93a386Sopenharmony_ci    if (SkStrokeRec::kFill_Style != style) {
433cb93a386Sopenharmony_ci        strokeWidth = random->nextRangeF(1.0f, 10.0f);
434cb93a386Sopenharmony_ci        if (random->nextBool()) {
435cb93a386Sopenharmony_ci            join = SkPaint::kMiter_Join;
436cb93a386Sopenharmony_ci        } else {
437cb93a386Sopenharmony_ci            join = SkPaint::kBevel_Join;
438cb93a386Sopenharmony_ci        }
439cb93a386Sopenharmony_ci        miterLimit = random->nextRangeF(0.5f, 2.0f);
440cb93a386Sopenharmony_ci    }
441cb93a386Sopenharmony_ci    const GrUserStencilSettings* stencilSettings = GrGetRandomStencil(random, context);
442cb93a386Sopenharmony_ci    return skgpu::v1::AAFlatteningConvexPathOp::Make(context, std::move(paint), viewMatrix, path,
443cb93a386Sopenharmony_ci                                                     strokeWidth, style, join, miterLimit,
444cb93a386Sopenharmony_ci                                                     stencilSettings);
445cb93a386Sopenharmony_ci}
446cb93a386Sopenharmony_ci
447cb93a386Sopenharmony_ci#endif
448