1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2020 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 "bench/Benchmark.h"
9cb93a386Sopenharmony_ci#include "include/gpu/GrDirectContext.h"
10cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h"
11cb93a386Sopenharmony_ci#include "src/core/SkRectPriv.h"
12cb93a386Sopenharmony_ci#include "src/gpu/GrDirectContextPriv.h"
13cb93a386Sopenharmony_ci#include "src/gpu/mock/GrMockOpTarget.h"
14cb93a386Sopenharmony_ci#include "src/gpu/tessellate/AffineMatrix.h"
15cb93a386Sopenharmony_ci#include "src/gpu/tessellate/MiddleOutPolygonTriangulator.h"
16cb93a386Sopenharmony_ci#include "src/gpu/tessellate/PathCurveTessellator.h"
17cb93a386Sopenharmony_ci#include "src/gpu/tessellate/PathWedgeTessellator.h"
18cb93a386Sopenharmony_ci#include "src/gpu/tessellate/StrokeFixedCountTessellator.h"
19cb93a386Sopenharmony_ci#include "src/gpu/tessellate/StrokeHardwareTessellator.h"
20cb93a386Sopenharmony_ci#include "src/gpu/tessellate/WangsFormula.h"
21cb93a386Sopenharmony_ci#include "tools/ToolUtils.h"
22cb93a386Sopenharmony_ci#include <vector>
23cb93a386Sopenharmony_ci
24cb93a386Sopenharmony_cinamespace skgpu {
25cb93a386Sopenharmony_ci
26cb93a386Sopenharmony_ci// This is the number of cubics in desk_chalkboard.skp. (There are no quadratics in the chalkboard.)
27cb93a386Sopenharmony_ciconstexpr static int kNumCubicsInChalkboard = 47182;
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_cistatic sk_sp<GrDirectContext> make_mock_context() {
30cb93a386Sopenharmony_ci    GrMockOptions mockOptions;
31cb93a386Sopenharmony_ci    mockOptions.fDrawInstancedSupport = true;
32cb93a386Sopenharmony_ci    mockOptions.fMaxTessellationSegments = 64;
33cb93a386Sopenharmony_ci    mockOptions.fMapBufferFlags = GrCaps::kCanMap_MapFlag;
34cb93a386Sopenharmony_ci    mockOptions.fConfigOptions[(int)GrColorType::kAlpha_8].fRenderability =
35cb93a386Sopenharmony_ci            GrMockOptions::ConfigOptions::Renderability::kMSAA;
36cb93a386Sopenharmony_ci    mockOptions.fConfigOptions[(int)GrColorType::kAlpha_8].fTexturable = true;
37cb93a386Sopenharmony_ci    mockOptions.fIntegerSupport = true;
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_ci    GrContextOptions ctxOptions;
40cb93a386Sopenharmony_ci    ctxOptions.fGpuPathRenderers = GpuPathRenderers::kTessellation;
41cb93a386Sopenharmony_ci    ctxOptions.fEnableExperimentalHardwareTessellation = true;
42cb93a386Sopenharmony_ci
43cb93a386Sopenharmony_ci    return GrDirectContext::MakeMock(&mockOptions, ctxOptions);
44cb93a386Sopenharmony_ci}
45cb93a386Sopenharmony_ci
46cb93a386Sopenharmony_cistatic SkPath make_cubic_path(int maxPow2) {
47cb93a386Sopenharmony_ci    SkRandom rand;
48cb93a386Sopenharmony_ci    SkPath path;
49cb93a386Sopenharmony_ci    for (int i = 0; i < kNumCubicsInChalkboard/2; ++i) {
50cb93a386Sopenharmony_ci        float x = std::ldexp(rand.nextF(), (i % maxPow2)) / 1e3f;
51cb93a386Sopenharmony_ci        path.cubicTo(111.625f*x, 308.188f*x, 764.62f*x, -435.688f*x, 742.63f*x, 85.187f*x);
52cb93a386Sopenharmony_ci        path.cubicTo(764.62f*x, -435.688f*x, 111.625f*x, 308.188f*x, 0, 0);
53cb93a386Sopenharmony_ci    }
54cb93a386Sopenharmony_ci    return path;
55cb93a386Sopenharmony_ci}
56cb93a386Sopenharmony_ci
57cb93a386Sopenharmony_cistatic SkPath make_conic_path() {
58cb93a386Sopenharmony_ci    SkRandom rand;
59cb93a386Sopenharmony_ci    SkPath path;
60cb93a386Sopenharmony_ci    for (int i = 0; i < kNumCubicsInChalkboard / 40; ++i) {
61cb93a386Sopenharmony_ci        for (int j = -10; j <= 10; j++) {
62cb93a386Sopenharmony_ci            const float x = std::ldexp(rand.nextF(), (i % 18)) / 1e3f;
63cb93a386Sopenharmony_ci            const float w = std::ldexp(1 + rand.nextF(), j);
64cb93a386Sopenharmony_ci            path.conicTo(111.625f * x, 308.188f * x, 764.62f * x, -435.688f * x, w);
65cb93a386Sopenharmony_ci        }
66cb93a386Sopenharmony_ci    }
67cb93a386Sopenharmony_ci    return path;
68cb93a386Sopenharmony_ci}
69cb93a386Sopenharmony_ci
70cb93a386Sopenharmony_ciSK_MAYBE_UNUSED static SkPath make_quad_path(int maxPow2) {
71cb93a386Sopenharmony_ci    SkRandom rand;
72cb93a386Sopenharmony_ci    SkPath path;
73cb93a386Sopenharmony_ci    for (int i = 0; i < kNumCubicsInChalkboard; ++i) {
74cb93a386Sopenharmony_ci        float x = std::ldexp(rand.nextF(), (i % maxPow2)) / 1e3f;
75cb93a386Sopenharmony_ci        path.quadTo(111.625f * x, 308.188f * x, 764.62f * x, -435.688f * x);
76cb93a386Sopenharmony_ci    }
77cb93a386Sopenharmony_ci    return path;
78cb93a386Sopenharmony_ci}
79cb93a386Sopenharmony_ci
80cb93a386Sopenharmony_ciSK_MAYBE_UNUSED static SkPath make_line_path(int maxPow2) {
81cb93a386Sopenharmony_ci    SkRandom rand;
82cb93a386Sopenharmony_ci    SkPath path;
83cb93a386Sopenharmony_ci    for (int i = 0; i < kNumCubicsInChalkboard; ++i) {
84cb93a386Sopenharmony_ci        float x = std::ldexp(rand.nextF(), (i % maxPow2)) / 1e3f;
85cb93a386Sopenharmony_ci        path.lineTo(764.62f * x, -435.688f * x);
86cb93a386Sopenharmony_ci    }
87cb93a386Sopenharmony_ci    return path;
88cb93a386Sopenharmony_ci}
89cb93a386Sopenharmony_ci
90cb93a386Sopenharmony_ci// This serves as a base class for benchmarking individual methods on PathTessellateOp.
91cb93a386Sopenharmony_ciclass PathTessellateBenchmark : public Benchmark {
92cb93a386Sopenharmony_cipublic:
93cb93a386Sopenharmony_ci    PathTessellateBenchmark(const char* subName, const SkPath& p, const SkMatrix& m)
94cb93a386Sopenharmony_ci            : fPath(p), fMatrix(m) {
95cb93a386Sopenharmony_ci        fName.printf("tessellate_%s", subName);
96cb93a386Sopenharmony_ci    }
97cb93a386Sopenharmony_ci
98cb93a386Sopenharmony_ci    const char* onGetName() override { return fName.c_str(); }
99cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) final { return backend == kNonRendering_Backend; }
100cb93a386Sopenharmony_ci
101cb93a386Sopenharmony_ciprotected:
102cb93a386Sopenharmony_ci    void onDelayedSetup() override {
103cb93a386Sopenharmony_ci        fTarget = std::make_unique<GrMockOpTarget>(make_mock_context());
104cb93a386Sopenharmony_ci    }
105cb93a386Sopenharmony_ci
106cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) final {
107cb93a386Sopenharmony_ci        if (!fTarget->mockContext()) {
108cb93a386Sopenharmony_ci            SkDebugf("ERROR: could not create mock context.");
109cb93a386Sopenharmony_ci            return;
110cb93a386Sopenharmony_ci        }
111cb93a386Sopenharmony_ci        for (int i = 0; i < loops; ++i) {
112cb93a386Sopenharmony_ci            this->runBench();
113cb93a386Sopenharmony_ci            fTarget->resetAllocator();
114cb93a386Sopenharmony_ci        }
115cb93a386Sopenharmony_ci    }
116cb93a386Sopenharmony_ci
117cb93a386Sopenharmony_ci    virtual void runBench() = 0;
118cb93a386Sopenharmony_ci
119cb93a386Sopenharmony_ci    SkString fName;
120cb93a386Sopenharmony_ci    std::unique_ptr<GrMockOpTarget> fTarget;
121cb93a386Sopenharmony_ci    const SkPath fPath;
122cb93a386Sopenharmony_ci    const SkMatrix fMatrix;
123cb93a386Sopenharmony_ci};
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci#define DEF_PATH_TESS_BENCH(NAME, PATH, MATRIX) \
126cb93a386Sopenharmony_ci    class PathTessellateBenchmark_##NAME : public PathTessellateBenchmark { \
127cb93a386Sopenharmony_ci    public: \
128cb93a386Sopenharmony_ci        PathTessellateBenchmark_##NAME() : PathTessellateBenchmark(#NAME, (PATH), (MATRIX)) {} \
129cb93a386Sopenharmony_ci        void runBench() override; \
130cb93a386Sopenharmony_ci    }; \
131cb93a386Sopenharmony_ci    DEF_BENCH( return new PathTessellateBenchmark_##NAME(); ); \
132cb93a386Sopenharmony_ci    void PathTessellateBenchmark_##NAME::runBench()
133cb93a386Sopenharmony_ci
134cb93a386Sopenharmony_cistatic const SkMatrix gAlmostIdentity = SkMatrix::MakeAll(
135cb93a386Sopenharmony_ci        1.0001f, 0.0001f, 0.0001f,
136cb93a386Sopenharmony_ci        -.0001f, 0.9999f, -.0001f,
137cb93a386Sopenharmony_ci              0,       0,       1);
138cb93a386Sopenharmony_ci
139cb93a386Sopenharmony_ciDEF_PATH_TESS_BENCH(GrPathCurveTessellator, make_cubic_path(8), SkMatrix::I()) {
140cb93a386Sopenharmony_ci    SkArenaAlloc arena(1024);
141cb93a386Sopenharmony_ci    GrPipeline noVaryingsPipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver,
142cb93a386Sopenharmony_ci                                  GrSwizzle::RGBA());
143cb93a386Sopenharmony_ci    auto tess = PathCurveTessellator::Make(&arena,
144cb93a386Sopenharmony_ci                                           fTarget->caps().shaderCaps()->infinitySupport());
145cb93a386Sopenharmony_ci    tess->prepare(fTarget.get(),
146cb93a386Sopenharmony_ci                  1 << PathCurveTessellator::kMaxFixedResolveLevel,
147cb93a386Sopenharmony_ci                  fMatrix,
148cb93a386Sopenharmony_ci                  {gAlmostIdentity, fPath, SK_PMColor4fTRANSPARENT},
149cb93a386Sopenharmony_ci                  fPath.countVerbs(),
150cb93a386Sopenharmony_ci                  true);
151cb93a386Sopenharmony_ci}
152cb93a386Sopenharmony_ci
153cb93a386Sopenharmony_ciDEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(8), SkMatrix::I()) {
154cb93a386Sopenharmony_ci    SkArenaAlloc arena(1024);
155cb93a386Sopenharmony_ci    GrPipeline noVaryingsPipeline(GrScissorTest::kDisabled, SkBlendMode::kSrcOver,
156cb93a386Sopenharmony_ci                                  GrSwizzle::RGBA());
157cb93a386Sopenharmony_ci    auto tess = PathWedgeTessellator::Make(&arena,
158cb93a386Sopenharmony_ci                                           fTarget->caps().shaderCaps()->infinitySupport());
159cb93a386Sopenharmony_ci    tess->prepare(fTarget.get(),
160cb93a386Sopenharmony_ci                  1 << PathCurveTessellator::kMaxFixedResolveLevel,
161cb93a386Sopenharmony_ci                  fMatrix,
162cb93a386Sopenharmony_ci                  {gAlmostIdentity, fPath, SK_PMColor4fTRANSPARENT},
163cb93a386Sopenharmony_ci                  fPath.countVerbs(),
164cb93a386Sopenharmony_ci                  true);
165cb93a386Sopenharmony_ci}
166cb93a386Sopenharmony_ci
167cb93a386Sopenharmony_cistatic void benchmark_wangs_formula_cubic_log2(const SkMatrix& matrix, const SkPath& path) {
168cb93a386Sopenharmony_ci    int sum = 0;
169cb93a386Sopenharmony_ci    wangs_formula::VectorXform xform(matrix);
170cb93a386Sopenharmony_ci    for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
171cb93a386Sopenharmony_ci        if (verb == SkPathVerb::kCubic) {
172cb93a386Sopenharmony_ci            sum += wangs_formula::cubic_log2(4, pts, xform);
173cb93a386Sopenharmony_ci        }
174cb93a386Sopenharmony_ci    }
175cb93a386Sopenharmony_ci    // Don't let the compiler optimize away wangs_formula::cubic_log2.
176cb93a386Sopenharmony_ci    if (sum <= 0) {
177cb93a386Sopenharmony_ci        SK_ABORT("sum should be > 0.");
178cb93a386Sopenharmony_ci    }
179cb93a386Sopenharmony_ci}
180cb93a386Sopenharmony_ci
181cb93a386Sopenharmony_ciDEF_PATH_TESS_BENCH(wangs_formula_cubic_log2, make_cubic_path(18), SkMatrix::I()) {
182cb93a386Sopenharmony_ci    benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
183cb93a386Sopenharmony_ci}
184cb93a386Sopenharmony_ci
185cb93a386Sopenharmony_ciDEF_PATH_TESS_BENCH(wangs_formula_cubic_log2_scale, make_cubic_path(18),
186cb93a386Sopenharmony_ci                    SkMatrix::Scale(1.1f, 0.9f)) {
187cb93a386Sopenharmony_ci    benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
188cb93a386Sopenharmony_ci}
189cb93a386Sopenharmony_ci
190cb93a386Sopenharmony_ciDEF_PATH_TESS_BENCH(wangs_formula_cubic_log2_affine, make_cubic_path(18),
191cb93a386Sopenharmony_ci                    SkMatrix::MakeAll(.9f,0.9f,0,  1.1f,1.1f,0, 0,0,1)) {
192cb93a386Sopenharmony_ci    benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
193cb93a386Sopenharmony_ci}
194cb93a386Sopenharmony_ci
195cb93a386Sopenharmony_cistatic void benchmark_wangs_formula_conic(const SkMatrix& matrix, const SkPath& path) {
196cb93a386Sopenharmony_ci    int sum = 0;
197cb93a386Sopenharmony_ci    wangs_formula::VectorXform xform(matrix);
198cb93a386Sopenharmony_ci    for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
199cb93a386Sopenharmony_ci        if (verb == SkPathVerb::kConic) {
200cb93a386Sopenharmony_ci            sum += wangs_formula::conic(4, pts, *w, xform);
201cb93a386Sopenharmony_ci        }
202cb93a386Sopenharmony_ci    }
203cb93a386Sopenharmony_ci    // Don't let the compiler optimize away wangs_formula::conic.
204cb93a386Sopenharmony_ci    if (sum <= 0) {
205cb93a386Sopenharmony_ci        SK_ABORT("sum should be > 0.");
206cb93a386Sopenharmony_ci    }
207cb93a386Sopenharmony_ci}
208cb93a386Sopenharmony_ci
209cb93a386Sopenharmony_cistatic void benchmark_wangs_formula_conic_log2(const SkMatrix& matrix, const SkPath& path) {
210cb93a386Sopenharmony_ci    int sum = 0;
211cb93a386Sopenharmony_ci    wangs_formula::VectorXform xform(matrix);
212cb93a386Sopenharmony_ci    for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
213cb93a386Sopenharmony_ci        if (verb == SkPathVerb::kConic) {
214cb93a386Sopenharmony_ci            sum += wangs_formula::conic_log2(4, pts, *w, xform);
215cb93a386Sopenharmony_ci        }
216cb93a386Sopenharmony_ci    }
217cb93a386Sopenharmony_ci    // Don't let the compiler optimize away wangs_formula::conic.
218cb93a386Sopenharmony_ci    if (sum <= 0) {
219cb93a386Sopenharmony_ci        SK_ABORT("sum should be > 0.");
220cb93a386Sopenharmony_ci    }
221cb93a386Sopenharmony_ci}
222cb93a386Sopenharmony_ci
223cb93a386Sopenharmony_ciDEF_PATH_TESS_BENCH(wangs_formula_conic, make_conic_path(), SkMatrix::I()) {
224cb93a386Sopenharmony_ci    benchmark_wangs_formula_conic(fMatrix, fPath);
225cb93a386Sopenharmony_ci}
226cb93a386Sopenharmony_ci
227cb93a386Sopenharmony_ciDEF_PATH_TESS_BENCH(wangs_formula_conic_log2, make_conic_path(), SkMatrix::I()) {
228cb93a386Sopenharmony_ci    benchmark_wangs_formula_conic_log2(fMatrix, fPath);
229cb93a386Sopenharmony_ci}
230cb93a386Sopenharmony_ci
231cb93a386Sopenharmony_ciDEF_PATH_TESS_BENCH(middle_out_triangulation,
232cb93a386Sopenharmony_ci                    ToolUtils::make_star(SkRect::MakeWH(500, 500), kNumCubicsInChalkboard),
233cb93a386Sopenharmony_ci                    SkMatrix::I()) {
234cb93a386Sopenharmony_ci    sk_sp<const GrBuffer> buffer;
235cb93a386Sopenharmony_ci    int baseVertex;
236cb93a386Sopenharmony_ci    VertexWriter vertexWriter = static_cast<SkPoint*>(fTarget->makeVertexSpace(
237cb93a386Sopenharmony_ci            sizeof(SkPoint), kNumCubicsInChalkboard, &buffer, &baseVertex));
238cb93a386Sopenharmony_ci    AffineMatrix m(gAlmostIdentity);
239cb93a386Sopenharmony_ci    for (PathMiddleOutFanIter it(fPath); !it.done();) {
240cb93a386Sopenharmony_ci        for (auto [p0, p1, p2] : it.nextStack()) {
241cb93a386Sopenharmony_ci            vertexWriter << m.map2Points(p0, p1) << m.mapPoint(p2);
242cb93a386Sopenharmony_ci        }
243cb93a386Sopenharmony_ci    }
244cb93a386Sopenharmony_ci}
245cb93a386Sopenharmony_ci
246cb93a386Sopenharmony_ciusing PathStrokeList = StrokeTessellator::PathStrokeList;
247cb93a386Sopenharmony_ciusing MakeTessellatorFn = std::unique_ptr<StrokeTessellator>(*)(PatchAttribs);
248cb93a386Sopenharmony_ci
249cb93a386Sopenharmony_cistatic std::unique_ptr<StrokeTessellator> make_hw_tessellator(PatchAttribs attribs) {
250cb93a386Sopenharmony_ci    return std::make_unique<StrokeHardwareTessellator>(attribs);
251cb93a386Sopenharmony_ci}
252cb93a386Sopenharmony_ci
253cb93a386Sopenharmony_cistatic std::unique_ptr<StrokeTessellator> make_fixed_count_tessellator(PatchAttribs attribs) {
254cb93a386Sopenharmony_ci    return std::make_unique<StrokeFixedCountTessellator>(attribs);
255cb93a386Sopenharmony_ci}
256cb93a386Sopenharmony_ci
257cb93a386Sopenharmony_ciusing MakePathStrokesFn = std::vector<PathStrokeList>(*)();
258cb93a386Sopenharmony_ci
259cb93a386Sopenharmony_cistatic std::vector<PathStrokeList> make_simple_cubic_path() {
260cb93a386Sopenharmony_ci    auto path = SkPath().moveTo(0, 0);
261cb93a386Sopenharmony_ci    for (int i = 0; i < kNumCubicsInChalkboard/2; ++i) {
262cb93a386Sopenharmony_ci        path.cubicTo(100, 0, 50, 100, 100, 100);
263cb93a386Sopenharmony_ci        path.cubicTo(0, -100, 200, 100, 0, 0);
264cb93a386Sopenharmony_ci    }
265cb93a386Sopenharmony_ci    SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
266cb93a386Sopenharmony_ci    stroke.setStrokeStyle(8);
267cb93a386Sopenharmony_ci    stroke.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kMiter_Join, 4);
268cb93a386Sopenharmony_ci    return {{path, stroke, SK_PMColor4fWHITE}};
269cb93a386Sopenharmony_ci}
270cb93a386Sopenharmony_ci
271cb93a386Sopenharmony_ci// Generates a list of paths that resemble the MotionMark benchmark.
272cb93a386Sopenharmony_cistatic std::vector<PathStrokeList> make_motionmark_paths() {
273cb93a386Sopenharmony_ci    std::vector<PathStrokeList> pathStrokes;
274cb93a386Sopenharmony_ci    SkRandom rand;
275cb93a386Sopenharmony_ci    for (int i = 0; i < 8702; ++i) {
276cb93a386Sopenharmony_ci        // The number of paths with a given number of verbs in the MotionMark bench gets cut in half
277cb93a386Sopenharmony_ci        // every time the number of verbs increases by 1.
278cb93a386Sopenharmony_ci        int numVerbs = 28 - SkNextLog2(rand.nextRangeU(0, (1 << 27) - 1));
279cb93a386Sopenharmony_ci        SkPath path;
280cb93a386Sopenharmony_ci        for (int j = 0; j < numVerbs; ++j) {
281cb93a386Sopenharmony_ci            switch (rand.nextU() & 3) {
282cb93a386Sopenharmony_ci                case 0:
283cb93a386Sopenharmony_ci                case 1:
284cb93a386Sopenharmony_ci                    path.lineTo(rand.nextRangeF(0, 150), rand.nextRangeF(0, 150));
285cb93a386Sopenharmony_ci                    break;
286cb93a386Sopenharmony_ci                case 2:
287cb93a386Sopenharmony_ci                    if (rand.nextULessThan(10) == 0) {
288cb93a386Sopenharmony_ci                        // Cusp.
289cb93a386Sopenharmony_ci                        auto [x, y] = (path.isEmpty())
290cb93a386Sopenharmony_ci                                ? SkPoint{0,0}
291cb93a386Sopenharmony_ci                                : SkPathPriv::PointData(path)[path.countPoints() - 1];
292cb93a386Sopenharmony_ci                        path.quadTo(x + rand.nextRangeF(0, 150), y, x - rand.nextRangeF(0, 150), y);
293cb93a386Sopenharmony_ci                    } else {
294cb93a386Sopenharmony_ci                        path.quadTo(rand.nextRangeF(0, 150), rand.nextRangeF(0, 150),
295cb93a386Sopenharmony_ci                                    rand.nextRangeF(0, 150), rand.nextRangeF(0, 150));
296cb93a386Sopenharmony_ci                    }
297cb93a386Sopenharmony_ci                    break;
298cb93a386Sopenharmony_ci                case 3:
299cb93a386Sopenharmony_ci                    if (rand.nextULessThan(10) == 0) {
300cb93a386Sopenharmony_ci                        // Cusp.
301cb93a386Sopenharmony_ci                        float y = (path.isEmpty())
302cb93a386Sopenharmony_ci                                ? 0 : SkPathPriv::PointData(path)[path.countPoints() - 1].fY;
303cb93a386Sopenharmony_ci                        path.cubicTo(rand.nextRangeF(0, 150), y, rand.nextRangeF(0, 150), y,
304cb93a386Sopenharmony_ci                                     rand.nextRangeF(0, 150), y);
305cb93a386Sopenharmony_ci                    } else {
306cb93a386Sopenharmony_ci                        path.cubicTo(rand.nextRangeF(0, 150), rand.nextRangeF(0, 150),
307cb93a386Sopenharmony_ci                                     rand.nextRangeF(0, 150), rand.nextRangeF(0, 150),
308cb93a386Sopenharmony_ci                                     rand.nextRangeF(0, 150), rand.nextRangeF(0, 150));
309cb93a386Sopenharmony_ci                    }
310cb93a386Sopenharmony_ci                    break;
311cb93a386Sopenharmony_ci            }
312cb93a386Sopenharmony_ci        }
313cb93a386Sopenharmony_ci        SkStrokeRec stroke(SkStrokeRec::kFill_InitStyle);
314cb93a386Sopenharmony_ci        // The number of paths with a given stroke width in the MotionMark bench gets cut in half
315cb93a386Sopenharmony_ci        // every time the stroke width increases by 1.
316cb93a386Sopenharmony_ci        float strokeWidth = 21 - log2f(rand.nextRangeF(0, 1 << 20));
317cb93a386Sopenharmony_ci        stroke.setStrokeStyle(strokeWidth);
318cb93a386Sopenharmony_ci        stroke.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kBevel_Join, 0);
319cb93a386Sopenharmony_ci        pathStrokes.emplace_back(path, stroke, SK_PMColor4fWHITE);
320cb93a386Sopenharmony_ci    }
321cb93a386Sopenharmony_ci    return pathStrokes;
322cb93a386Sopenharmony_ci}
323cb93a386Sopenharmony_ci
324cb93a386Sopenharmony_ciclass TessPrepareBench : public Benchmark {
325cb93a386Sopenharmony_cipublic:
326cb93a386Sopenharmony_ci    TessPrepareBench(MakePathStrokesFn makePathStrokesFn, MakeTessellatorFn makeTessellatorFn,
327cb93a386Sopenharmony_ci                     PatchAttribs attribs, float matrixScale, const char* suffix)
328cb93a386Sopenharmony_ci            : fMakePathStrokesFn(makePathStrokesFn)
329cb93a386Sopenharmony_ci            , fMakeTessellatorFn(makeTessellatorFn)
330cb93a386Sopenharmony_ci            , fPatchAttribs(attribs)
331cb93a386Sopenharmony_ci            , fMatrixScale(matrixScale) {
332cb93a386Sopenharmony_ci        fName.printf("tessellate_%s", suffix);
333cb93a386Sopenharmony_ci    }
334cb93a386Sopenharmony_ci
335cb93a386Sopenharmony_ciprivate:
336cb93a386Sopenharmony_ci    const char* onGetName() override { return fName.c_str(); }
337cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) final { return backend == kNonRendering_Backend; }
338cb93a386Sopenharmony_ci
339cb93a386Sopenharmony_ci    void onDelayedSetup() override {
340cb93a386Sopenharmony_ci        fTarget = std::make_unique<GrMockOpTarget>(make_mock_context());
341cb93a386Sopenharmony_ci        if (!fTarget->mockContext()) {
342cb93a386Sopenharmony_ci            SkDebugf("ERROR: could not create mock context.");
343cb93a386Sopenharmony_ci            return;
344cb93a386Sopenharmony_ci        }
345cb93a386Sopenharmony_ci
346cb93a386Sopenharmony_ci        fPathStrokes = fMakePathStrokesFn();
347cb93a386Sopenharmony_ci        for (size_t i = 0; i < fPathStrokes.size(); ++i) {
348cb93a386Sopenharmony_ci            if (i + 1 < fPathStrokes.size()) {
349cb93a386Sopenharmony_ci                fPathStrokes[i].fNext = &fPathStrokes[i + 1];
350cb93a386Sopenharmony_ci            }
351cb93a386Sopenharmony_ci            fTotalVerbCount += fPathStrokes[i].fPath.countVerbs();
352cb93a386Sopenharmony_ci        }
353cb93a386Sopenharmony_ci
354cb93a386Sopenharmony_ci        fTessellator = fMakeTessellatorFn(fPatchAttribs);
355cb93a386Sopenharmony_ci    }
356cb93a386Sopenharmony_ci
357cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas*) final {
358cb93a386Sopenharmony_ci        for (int i = 0; i < loops; ++i) {
359cb93a386Sopenharmony_ci            fTessellator->prepare(fTarget.get(),
360cb93a386Sopenharmony_ci                                  SkMatrix::Scale(fMatrixScale, fMatrixScale),
361cb93a386Sopenharmony_ci                                  {fMatrixScale, fMatrixScale},
362cb93a386Sopenharmony_ci                                  fPathStrokes.data(),
363cb93a386Sopenharmony_ci                                  fTotalVerbCount);
364cb93a386Sopenharmony_ci            fTarget->resetAllocator();
365cb93a386Sopenharmony_ci        }
366cb93a386Sopenharmony_ci    }
367cb93a386Sopenharmony_ci
368cb93a386Sopenharmony_ci    SkString fName;
369cb93a386Sopenharmony_ci    MakePathStrokesFn fMakePathStrokesFn;
370cb93a386Sopenharmony_ci    MakeTessellatorFn fMakeTessellatorFn;
371cb93a386Sopenharmony_ci    const PatchAttribs fPatchAttribs;
372cb93a386Sopenharmony_ci    float fMatrixScale;
373cb93a386Sopenharmony_ci    std::unique_ptr<GrMockOpTarget> fTarget;
374cb93a386Sopenharmony_ci    std::vector<PathStrokeList> fPathStrokes;
375cb93a386Sopenharmony_ci    std::unique_ptr<StrokeTessellator> fTessellator;
376cb93a386Sopenharmony_ci    SkArenaAlloc fPersistentArena{1024};
377cb93a386Sopenharmony_ci    int fTotalVerbCount = 0;
378cb93a386Sopenharmony_ci};
379cb93a386Sopenharmony_ci
380cb93a386Sopenharmony_ciDEF_BENCH(return new TessPrepareBench(
381cb93a386Sopenharmony_ci        make_simple_cubic_path, make_hw_tessellator, PatchAttribs::kNone, 1,
382cb93a386Sopenharmony_ci        "GrStrokeHardwareTessellator");
383cb93a386Sopenharmony_ci)
384cb93a386Sopenharmony_ci
385cb93a386Sopenharmony_ciDEF_BENCH(return new TessPrepareBench(
386cb93a386Sopenharmony_ci        make_simple_cubic_path, make_hw_tessellator, PatchAttribs::kNone, 5,
387cb93a386Sopenharmony_ci        "GrStrokeHardwareTessellator_one_chop");
388cb93a386Sopenharmony_ci)
389cb93a386Sopenharmony_ci
390cb93a386Sopenharmony_ciDEF_BENCH(return new TessPrepareBench(
391cb93a386Sopenharmony_ci        make_motionmark_paths, make_hw_tessellator, PatchAttribs::kStrokeParams, 1,
392cb93a386Sopenharmony_ci        "GrStrokeHardwareTessellator_motionmark");
393cb93a386Sopenharmony_ci)
394cb93a386Sopenharmony_ci
395cb93a386Sopenharmony_ciDEF_BENCH(return new TessPrepareBench(
396cb93a386Sopenharmony_ci        make_simple_cubic_path, make_fixed_count_tessellator, PatchAttribs::kNone, 1,
397cb93a386Sopenharmony_ci        "GrStrokeFixedCountTessellator");
398cb93a386Sopenharmony_ci)
399cb93a386Sopenharmony_ci
400cb93a386Sopenharmony_ciDEF_BENCH(return new TessPrepareBench(
401cb93a386Sopenharmony_ci        make_simple_cubic_path, make_fixed_count_tessellator, PatchAttribs::kNone, 5,
402cb93a386Sopenharmony_ci        "GrStrokeFixedCountTessellator_one_chop");
403cb93a386Sopenharmony_ci)
404cb93a386Sopenharmony_ci
405cb93a386Sopenharmony_ciDEF_BENCH(return new TessPrepareBench(
406cb93a386Sopenharmony_ci        make_motionmark_paths, make_fixed_count_tessellator, PatchAttribs::kStrokeParams, 1,
407cb93a386Sopenharmony_ci        "GrStrokeFixedCountTessellator_motionmark");
408cb93a386Sopenharmony_ci)
409cb93a386Sopenharmony_ci
410cb93a386Sopenharmony_ci}  // namespace skgpu
411