1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2018 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/core/SkPath.h"
10cb93a386Sopenharmony_ci#include "include/core/SkShader.h"
11cb93a386Sopenharmony_ci#include "include/core/SkString.h"
12cb93a386Sopenharmony_ci#include "include/pathops/SkPathOps.h"
13cb93a386Sopenharmony_ci#include "include/private/SkTArray.h"
14cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h"
15cb93a386Sopenharmony_ci
16cb93a386Sopenharmony_ciclass PathOpsBench : public Benchmark {
17cb93a386Sopenharmony_ci    SkString    fName;
18cb93a386Sopenharmony_ci    SkPath      fPath1, fPath2;
19cb93a386Sopenharmony_ci    SkPathOp    fOp;
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_cipublic:
22cb93a386Sopenharmony_ci    PathOpsBench(const char suffix[], SkPathOp op) : fOp(op) {
23cb93a386Sopenharmony_ci        fName.printf("pathops_%s", suffix);
24cb93a386Sopenharmony_ci
25cb93a386Sopenharmony_ci        fPath1.addOval({-10, -20, 10, 20});
26cb93a386Sopenharmony_ci        fPath2.addOval({-20, -10, 20, 10});
27cb93a386Sopenharmony_ci    }
28cb93a386Sopenharmony_ci
29cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
30cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
31cb93a386Sopenharmony_ci    }
32cb93a386Sopenharmony_ci
33cb93a386Sopenharmony_ciprotected:
34cb93a386Sopenharmony_ci    const char* onGetName() override {
35cb93a386Sopenharmony_ci        return fName.c_str();
36cb93a386Sopenharmony_ci    }
37cb93a386Sopenharmony_ci
38cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas* canvas) override {
39cb93a386Sopenharmony_ci        for (int i = 0; i < loops; i++) {
40cb93a386Sopenharmony_ci            for (int j = 0; j < 1000; ++j) {
41cb93a386Sopenharmony_ci                SkPath result;
42cb93a386Sopenharmony_ci                Op(fPath1, fPath2, fOp, &result);
43cb93a386Sopenharmony_ci            }
44cb93a386Sopenharmony_ci        }
45cb93a386Sopenharmony_ci    }
46cb93a386Sopenharmony_ci
47cb93a386Sopenharmony_ciprivate:
48cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
49cb93a386Sopenharmony_ci};
50cb93a386Sopenharmony_ci
51cb93a386Sopenharmony_ciclass PathOpsSimplifyBench : public Benchmark {
52cb93a386Sopenharmony_ci    SkString    fName;
53cb93a386Sopenharmony_ci    SkPath      fPath;
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_cipublic:
56cb93a386Sopenharmony_ci    PathOpsSimplifyBench(const char suffix[], const SkPath& path) : fPath(path) {
57cb93a386Sopenharmony_ci        fName.printf("pathops_simplify_%s", suffix);
58cb93a386Sopenharmony_ci    }
59cb93a386Sopenharmony_ci
60cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
61cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
62cb93a386Sopenharmony_ci    }
63cb93a386Sopenharmony_ci
64cb93a386Sopenharmony_ciprotected:
65cb93a386Sopenharmony_ci    const char* onGetName() override {
66cb93a386Sopenharmony_ci        return fName.c_str();
67cb93a386Sopenharmony_ci    }
68cb93a386Sopenharmony_ci
69cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas* canvas) override {
70cb93a386Sopenharmony_ci        for (int i = 0; i < loops; i++) {
71cb93a386Sopenharmony_ci            for (int j = 0; j < 100; ++j) {
72cb93a386Sopenharmony_ci                SkPath result;
73cb93a386Sopenharmony_ci                Simplify(fPath, &result);
74cb93a386Sopenharmony_ci            }
75cb93a386Sopenharmony_ci        }
76cb93a386Sopenharmony_ci    }
77cb93a386Sopenharmony_ci
78cb93a386Sopenharmony_ciprivate:
79cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
80cb93a386Sopenharmony_ci};
81cb93a386Sopenharmony_ciDEF_BENCH( return new PathOpsBench("sect", kIntersect_SkPathOp); )
82cb93a386Sopenharmony_ciDEF_BENCH( return new PathOpsBench("join", kUnion_SkPathOp); )
83cb93a386Sopenharmony_ci
84cb93a386Sopenharmony_cistatic SkPath makerects() {
85cb93a386Sopenharmony_ci    SkRandom rand;
86cb93a386Sopenharmony_ci    SkPath path;
87cb93a386Sopenharmony_ci    SkScalar scale = 100;
88cb93a386Sopenharmony_ci    for (int i = 0; i < 20; ++i) {
89cb93a386Sopenharmony_ci        SkScalar x = rand.nextUScalar1() * scale;
90cb93a386Sopenharmony_ci        SkScalar y = rand.nextUScalar1() * scale;
91cb93a386Sopenharmony_ci        path.addRect({x, y, x + scale, y + scale});
92cb93a386Sopenharmony_ci    }
93cb93a386Sopenharmony_ci    return path;
94cb93a386Sopenharmony_ci}
95cb93a386Sopenharmony_ciDEF_BENCH( return new PathOpsSimplifyBench("rects", makerects()); )
96cb93a386Sopenharmony_ci
97cb93a386Sopenharmony_ci#include "include/core/SkPathBuilder.h"
98cb93a386Sopenharmony_ci
99cb93a386Sopenharmony_citemplate <size_t N> struct ArrayPath {
100cb93a386Sopenharmony_ci    SkPoint fPts[N];
101cb93a386Sopenharmony_ci    uint8_t fVbs[N];
102cb93a386Sopenharmony_ci    int fPIndex = 0, fVIndex = 0;
103cb93a386Sopenharmony_ci
104cb93a386Sopenharmony_ci    void moveTo(float x, float y) {
105cb93a386Sopenharmony_ci        fVbs[fVIndex++] = (uint8_t)SkPathVerb::kMove;
106cb93a386Sopenharmony_ci        fPts[fPIndex++] = {x, y};
107cb93a386Sopenharmony_ci    }
108cb93a386Sopenharmony_ci    void lineTo(float x, float y) {
109cb93a386Sopenharmony_ci        fVbs[fVIndex++] = (uint8_t)SkPathVerb::kLine;
110cb93a386Sopenharmony_ci        fPts[fPIndex++] = {x, y};
111cb93a386Sopenharmony_ci    }
112cb93a386Sopenharmony_ci    void quadTo(float x, float y, float x1, float y1) {
113cb93a386Sopenharmony_ci        fVbs[fVIndex++] = (uint8_t)SkPathVerb::kQuad;
114cb93a386Sopenharmony_ci        fPts[fPIndex++] = {x, y};
115cb93a386Sopenharmony_ci        fPts[fPIndex++] = {x1, y1};
116cb93a386Sopenharmony_ci    }
117cb93a386Sopenharmony_ci    void cubicTo(float x, float y, float x1, float y1, float x2, float y2) {
118cb93a386Sopenharmony_ci        fVbs[fVIndex++] = (uint8_t)SkPathVerb::kCubic;
119cb93a386Sopenharmony_ci        fPts[fPIndex++] = {x, y};
120cb93a386Sopenharmony_ci        fPts[fPIndex++] = {x1, y1};
121cb93a386Sopenharmony_ci        fPts[fPIndex++] = {x2, y2};
122cb93a386Sopenharmony_ci    }
123cb93a386Sopenharmony_ci    void incReserve(int) {}
124cb93a386Sopenharmony_ci};
125cb93a386Sopenharmony_ci
126cb93a386Sopenharmony_citemplate <typename T> void run_builder(T& b, bool useReserve, int N) {
127cb93a386Sopenharmony_ci    if (useReserve) {
128cb93a386Sopenharmony_ci        b.incReserve(N * 12);
129cb93a386Sopenharmony_ci    }
130cb93a386Sopenharmony_ci
131cb93a386Sopenharmony_ci    float x = 0, y = 0;
132cb93a386Sopenharmony_ci    b.moveTo(x, y);
133cb93a386Sopenharmony_ci    for (int i = 1; i < N; ++i) {
134cb93a386Sopenharmony_ci        b.lineTo(x, y);
135cb93a386Sopenharmony_ci        b.quadTo(x, y, x, y);
136cb93a386Sopenharmony_ci        b.cubicTo(x, y, x, y, x, y);
137cb93a386Sopenharmony_ci    }
138cb93a386Sopenharmony_ci}
139cb93a386Sopenharmony_ci
140cb93a386Sopenharmony_cienum class MakeType {
141cb93a386Sopenharmony_ci    kPath,
142cb93a386Sopenharmony_ci    kSnapshot,
143cb93a386Sopenharmony_ci    kDetach,
144cb93a386Sopenharmony_ci    kArray,
145cb93a386Sopenharmony_ci};
146cb93a386Sopenharmony_ci
147cb93a386Sopenharmony_ciclass PathBuilderBench : public Benchmark {
148cb93a386Sopenharmony_ci    SkString    fName;
149cb93a386Sopenharmony_ci    MakeType    fMakeType;
150cb93a386Sopenharmony_ci    bool        fUseReserve;
151cb93a386Sopenharmony_ci
152cb93a386Sopenharmony_ci    enum { N = 100 };
153cb93a386Sopenharmony_ci    ArrayPath<N*12> fArrays;
154cb93a386Sopenharmony_ci
155cb93a386Sopenharmony_cipublic:
156cb93a386Sopenharmony_ci    PathBuilderBench(MakeType mt, bool reserve) : fMakeType(mt), fUseReserve(reserve) {
157cb93a386Sopenharmony_ci        const char* typenames[] = { "path", "snapshot", "detach", "arrays" };
158cb93a386Sopenharmony_ci
159cb93a386Sopenharmony_ci        fName.printf("makepath_%s_%s", typenames[(int)mt], reserve ? "reserve" : "noreserve");
160cb93a386Sopenharmony_ci    }
161cb93a386Sopenharmony_ci
162cb93a386Sopenharmony_ci    bool isSuitableFor(Backend backend) override {
163cb93a386Sopenharmony_ci        return backend == kNonRendering_Backend;
164cb93a386Sopenharmony_ci    }
165cb93a386Sopenharmony_ci
166cb93a386Sopenharmony_ciprotected:
167cb93a386Sopenharmony_ci    const char* onGetName() override {
168cb93a386Sopenharmony_ci        return fName.c_str();
169cb93a386Sopenharmony_ci    }
170cb93a386Sopenharmony_ci
171cb93a386Sopenharmony_ci    void onDelayedSetup() override {
172cb93a386Sopenharmony_ci        run_builder(fArrays, false, N);
173cb93a386Sopenharmony_ci    }
174cb93a386Sopenharmony_ci
175cb93a386Sopenharmony_ci    SkPath build() {
176cb93a386Sopenharmony_ci        switch (fMakeType) {
177cb93a386Sopenharmony_ci            case MakeType::kSnapshot:
178cb93a386Sopenharmony_ci            case MakeType::kDetach: {
179cb93a386Sopenharmony_ci                SkPathBuilder b;
180cb93a386Sopenharmony_ci                run_builder(b, fUseReserve, N);
181cb93a386Sopenharmony_ci                return MakeType::kSnapshot == fMakeType ? b.snapshot() : b.detach();
182cb93a386Sopenharmony_ci            }
183cb93a386Sopenharmony_ci            case MakeType::kPath: {
184cb93a386Sopenharmony_ci                SkPath p;
185cb93a386Sopenharmony_ci                run_builder(p, fUseReserve, N);
186cb93a386Sopenharmony_ci                return p;
187cb93a386Sopenharmony_ci            }
188cb93a386Sopenharmony_ci            case MakeType::kArray: {
189cb93a386Sopenharmony_ci            //    ArrayPath<N*12> arrays;
190cb93a386Sopenharmony_ci            //    run_builder(arrays, false, N);
191cb93a386Sopenharmony_ci                return SkPath::Make(fArrays.fPts, fArrays.fPIndex,
192cb93a386Sopenharmony_ci                                    fArrays.fVbs, fArrays.fVIndex,
193cb93a386Sopenharmony_ci                                    nullptr, 0, SkPathFillType::kWinding);
194cb93a386Sopenharmony_ci            }
195cb93a386Sopenharmony_ci        }
196cb93a386Sopenharmony_ci        return SkPath();
197cb93a386Sopenharmony_ci    }
198cb93a386Sopenharmony_ci
199cb93a386Sopenharmony_ci    void onDraw(int loops, SkCanvas* canvas) override {
200cb93a386Sopenharmony_ci        for (int i = 0; i < loops; i++) {
201cb93a386Sopenharmony_ci            for (int j = 0; j < 100; ++j) {
202cb93a386Sopenharmony_ci                SkPath result = this->build();
203cb93a386Sopenharmony_ci                // force bounds calc as part of the test
204cb93a386Sopenharmony_ci                if (!result.getBounds().isFinite()) {
205cb93a386Sopenharmony_ci                    SkDebugf("should never get here!\n");
206cb93a386Sopenharmony_ci                    return;
207cb93a386Sopenharmony_ci                }
208cb93a386Sopenharmony_ci            }
209cb93a386Sopenharmony_ci        }
210cb93a386Sopenharmony_ci    }
211cb93a386Sopenharmony_ci
212cb93a386Sopenharmony_ciprivate:
213cb93a386Sopenharmony_ci    using INHERITED = Benchmark;
214cb93a386Sopenharmony_ci};
215cb93a386Sopenharmony_ciDEF_BENCH( return new PathBuilderBench(MakeType::kPath, false); )
216cb93a386Sopenharmony_ciDEF_BENCH( return new PathBuilderBench(MakeType::kSnapshot, false); )
217cb93a386Sopenharmony_ciDEF_BENCH( return new PathBuilderBench(MakeType::kDetach, false); )
218cb93a386Sopenharmony_ciDEF_BENCH( return new PathBuilderBench(MakeType::kPath, true); )
219cb93a386Sopenharmony_ciDEF_BENCH( return new PathBuilderBench(MakeType::kSnapshot, true); )
220cb93a386Sopenharmony_ciDEF_BENCH( return new PathBuilderBench(MakeType::kDetach, true); )
221cb93a386Sopenharmony_ci
222cb93a386Sopenharmony_ciDEF_BENCH( return new PathBuilderBench(MakeType::kArray, true); )
223