blob: 5cc7dd5c37cd261b5ef175ad87ca5b432aba87cb [file] [log] [blame]
Chris Dalton7f0b8972020-04-23 15:52:24 -06001/*
2 * Copyright 2020 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "bench/Benchmark.h"
Robert Phillipsf0288102020-07-06 13:45:34 -04009#include "include/gpu/GrDirectContext.h"
Chris Daltonf6bf5162020-05-13 19:18:46 -060010#include "src/core/SkPathPriv.h"
Adlai Hollera0693042020-10-14 11:23:11 -040011#include "src/gpu/GrDirectContextPriv.h"
Chris Dalton7f0b8972020-04-23 15:52:24 -060012#include "src/gpu/GrOpFlushState.h"
Chris Dalton90ad0fe2020-11-09 14:13:39 -070013#include "src/gpu/mock/GrMockOpTarget.h"
Chris Daltonb5391d92020-05-24 14:55:54 -060014#include "src/gpu/tessellate/GrMiddleOutPolygonTriangulator.h"
Chris Daltonebb37e72021-01-27 17:59:45 -070015#include "src/gpu/tessellate/GrPathTessellator.h"
Chris Dalton22241002021-02-04 09:47:40 -070016#include "src/gpu/tessellate/GrStrokeHardwareTessellator.h"
17#include "src/gpu/tessellate/GrStrokeIndirectTessellator.h"
Chris Daltonf6bf5162020-05-13 19:18:46 -060018#include "src/gpu/tessellate/GrWangsFormula.h"
Chris Daltonf5132a02020-04-27 23:40:03 -060019#include "tools/ToolUtils.h"
Chris Daltonc2a17462020-12-09 16:46:22 -070020#include <vector>
Chris Dalton7f0b8972020-04-23 15:52:24 -060021
22// This is the number of cubics in desk_chalkboard.skp. (There are no quadratics in the chalkboard.)
23constexpr static int kNumCubicsInChalkboard = 47182;
24
Chris Dalton90ad0fe2020-11-09 14:13:39 -070025static sk_sp<GrDirectContext> make_mock_context() {
26 GrMockOptions mockOptions;
27 mockOptions.fDrawInstancedSupport = true;
28 mockOptions.fMaxTessellationSegments = 64;
29 mockOptions.fMapBufferFlags = GrCaps::kCanMap_MapFlag;
30 mockOptions.fConfigOptions[(int)GrColorType::kAlpha_8].fRenderability =
31 GrMockOptions::ConfigOptions::Renderability::kMSAA;
32 mockOptions.fConfigOptions[(int)GrColorType::kAlpha_8].fTexturable = true;
33 mockOptions.fIntegerSupport = true;
34
35 GrContextOptions ctxOptions;
36 ctxOptions.fGpuPathRenderers = GpuPathRenderers::kTessellation;
Chris Dalton15f51842020-12-15 19:55:10 -070037 ctxOptions.fSuppressTessellationShaders = false;
Chris Dalton90ad0fe2020-11-09 14:13:39 -070038
39 return GrDirectContext::MakeMock(&mockOptions, ctxOptions);
40}
41
Chris Dalton7f0b8972020-04-23 15:52:24 -060042static SkPath make_cubic_path() {
43 SkRandom rand;
44 SkPath path;
45 for (int i = 0; i < kNumCubicsInChalkboard/2; ++i) {
Chris Dalton2f2d81c2020-05-13 17:57:37 -060046 float x = std::ldexp(rand.nextF(), (i % 18)) / 1e3f;
Chris Dalton7f0b8972020-04-23 15:52:24 -060047 path.cubicTo(111.625f*x, 308.188f*x, 764.62f*x, -435.688f*x, 742.63f*x, 85.187f*x);
48 path.cubicTo(764.62f*x, -435.688f*x, 111.625f*x, 308.188f*x, 0, 0);
49 }
50 return path;
51}
52
Tyler Denniston04f471a2021-02-04 13:07:03 -050053static SkPath make_conic_path() {
54 SkRandom rand;
55 SkPath path;
56 for (int i = 0; i < kNumCubicsInChalkboard / 40; ++i) {
57 for (int j = -10; j <= 10; j++) {
58 const float x = std::ldexp(rand.nextF(), (i % 18)) / 1e3f;
59 const float w = std::ldexp(1 + rand.nextF(), j);
60 path.conicTo(111.625f * x, 308.188f * x, 764.62f * x, -435.688f * x, w);
61 }
62 }
63 return path;
64}
65
Chris Dalton078f8752020-07-30 19:50:46 -060066// This serves as a base class for benchmarking individual methods on GrPathTessellateOp.
Chris Daltond7177432021-01-15 13:12:50 -070067class PathTessellateBenchmark : public Benchmark {
Chris Dalton7f0b8972020-04-23 15:52:24 -060068public:
Chris Daltond7177432021-01-15 13:12:50 -070069 PathTessellateBenchmark(const char* subName, const SkPath& p, const SkMatrix& m)
70 : fPath(p), fMatrix(m) {
Chris Dalton7f0b8972020-04-23 15:52:24 -060071 fName.printf("tessellate_%s", subName);
72 }
73
74 const char* onGetName() override { return fName.c_str(); }
75 bool isSuitableFor(Backend backend) final { return backend == kNonRendering_Backend; }
76
Chris Daltond7177432021-01-15 13:12:50 -070077protected:
Chris Dalton0e543092020-11-03 14:09:16 -070078 void onDelayedSetup() override {
Chris Dalton90ad0fe2020-11-09 14:13:39 -070079 fTarget = std::make_unique<GrMockOpTarget>(make_mock_context());
Chris Dalton0e543092020-11-03 14:09:16 -070080 }
81
Chris Dalton7f0b8972020-04-23 15:52:24 -060082 void onDraw(int loops, SkCanvas*) final {
Chris Dalton0e543092020-11-03 14:09:16 -070083 if (!fTarget->mockContext()) {
Chris Dalton1443c9d2020-05-27 09:43:34 -060084 SkDebugf("ERROR: could not create mock context.");
85 return;
86 }
Chris Dalton7f0b8972020-04-23 15:52:24 -060087 for (int i = 0; i < loops; ++i) {
Chris Daltond7177432021-01-15 13:12:50 -070088 this->runBench();
Chris Dalton0e543092020-11-03 14:09:16 -070089 fTarget->resetAllocator();
Chris Dalton7f0b8972020-04-23 15:52:24 -060090 }
91 }
92
Chris Daltond7177432021-01-15 13:12:50 -070093 virtual void runBench() = 0;
Chris Dalton7f0b8972020-04-23 15:52:24 -060094
Chris Dalton7f0b8972020-04-23 15:52:24 -060095 SkString fName;
Chris Daltond7177432021-01-15 13:12:50 -070096 std::unique_ptr<GrMockOpTarget> fTarget;
97 const SkPath fPath;
Chris Daltone1314a32021-01-29 13:22:33 -070098 const SkMatrix fMatrix;
Chris Dalton7f0b8972020-04-23 15:52:24 -060099};
100
Chris Daltond7177432021-01-15 13:12:50 -0700101#define DEF_PATH_TESS_BENCH(NAME, PATH, MATRIX) \
102 class PathTessellateBenchmark_##NAME : public PathTessellateBenchmark { \
Chris Daltonb5391d92020-05-24 14:55:54 -0600103 public: \
Chris Daltond7177432021-01-15 13:12:50 -0700104 PathTessellateBenchmark_##NAME() : PathTessellateBenchmark(#NAME, (PATH), (MATRIX)) {} \
105 void runBench() override; \
Chris Daltonb5391d92020-05-24 14:55:54 -0600106 }; \
Chris Daltond7177432021-01-15 13:12:50 -0700107 DEF_BENCH( return new PathTessellateBenchmark_##NAME(); ); \
108 void PathTessellateBenchmark_##NAME::runBench()
Chris Dalton7f0b8972020-04-23 15:52:24 -0600109
Chris Daltond7177432021-01-15 13:12:50 -0700110DEF_PATH_TESS_BENCH(GrPathIndirectTessellator, make_cubic_path(), SkMatrix::I()) {
111 GrPathIndirectTessellator tess(fMatrix, fPath, GrPathIndirectTessellator::DrawInnerFan::kNo);
Chris Daltonebb37e72021-01-27 17:59:45 -0700112 tess.prepare(fTarget.get(), fMatrix, fPath, nullptr);
Chris Daltonb5391d92020-05-24 14:55:54 -0600113}
Chris Dalton7f0b8972020-04-23 15:52:24 -0600114
Chris Daltond7177432021-01-15 13:12:50 -0700115DEF_PATH_TESS_BENCH(GrPathOuterCurveTessellator, make_cubic_path(), SkMatrix::I()) {
116 GrPathOuterCurveTessellator tess;
Chris Daltonebb37e72021-01-27 17:59:45 -0700117 tess.prepare(fTarget.get(), fMatrix, fPath, nullptr);
Chris Daltonb5391d92020-05-24 14:55:54 -0600118}
Chris Dalton7f0b8972020-04-23 15:52:24 -0600119
Chris Daltond7177432021-01-15 13:12:50 -0700120DEF_PATH_TESS_BENCH(GrPathWedgeTessellator, make_cubic_path(), SkMatrix::I()) {
121 GrPathWedgeTessellator tess;
Chris Daltonebb37e72021-01-27 17:59:45 -0700122 tess.prepare(fTarget.get(), fMatrix, fPath, nullptr);
Chris Daltonb5391d92020-05-24 14:55:54 -0600123}
Chris Daltonf6bf5162020-05-13 19:18:46 -0600124
Chris Daltonb5391d92020-05-24 14:55:54 -0600125static void benchmark_wangs_formula_cubic_log2(const SkMatrix& matrix, const SkPath& path) {
126 int sum = 0;
127 GrVectorXform xform(matrix);
128 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
129 if (verb == SkPathVerb::kCubic) {
130 sum += GrWangsFormula::cubic_log2(4, pts, xform);
Chris Daltonf6bf5162020-05-13 19:18:46 -0600131 }
132 }
Chris Daltonb5391d92020-05-24 14:55:54 -0600133 // Don't let the compiler optimize away GrWangsFormula::cubic_log2.
134 if (sum <= 0) {
135 SK_ABORT("sum should be > 0.");
136 }
137}
Chris Daltonf6bf5162020-05-13 19:18:46 -0600138
Chris Daltond7177432021-01-15 13:12:50 -0700139DEF_PATH_TESS_BENCH(wangs_formula_cubic_log2, make_cubic_path(), SkMatrix::I()) {
140 benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
Chris Daltonb5391d92020-05-24 14:55:54 -0600141}
142
Chris Daltond7177432021-01-15 13:12:50 -0700143DEF_PATH_TESS_BENCH(wangs_formula_cubic_log2_scale, make_cubic_path(),
144 SkMatrix::Scale(1.1f, 0.9f)) {
145 benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
Chris Daltonb5391d92020-05-24 14:55:54 -0600146}
147
Chris Daltone2067642020-09-23 11:07:20 -0600148DEF_PATH_TESS_BENCH(wangs_formula_cubic_log2_affine, make_cubic_path(),
Chris Daltond7177432021-01-15 13:12:50 -0700149 SkMatrix::MakeAll(.9f,0.9f,0, 1.1f,1.1f,0, 0,0,1)) {
150 benchmark_wangs_formula_cubic_log2(fMatrix, fPath);
Chris Daltonb5391d92020-05-24 14:55:54 -0600151}
152
Tyler Denniston04f471a2021-02-04 13:07:03 -0500153static void benchmark_wangs_formula_conic(const SkMatrix& matrix, const SkPath& path) {
154 // Conic version expects tolerance, not intolerance
155 constexpr float kTolerance = 4;
156 int sum = 0;
157 GrVectorXform xform(matrix);
158 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
159 if (verb == SkPathVerb::kConic) {
160 sum += GrWangsFormula::conic(kTolerance, pts, *w, xform);
161 }
162 }
163 // Don't let the compiler optimize away GrWangsFormula::conic.
164 if (sum <= 0) {
165 SK_ABORT("sum should be > 0.");
166 }
167}
168
169static void benchmark_wangs_formula_conic_log2(const SkMatrix& matrix, const SkPath& path) {
170 // Conic version expects tolerance, not intolerance
171 constexpr float kTolerance = 4;
172 int sum = 0;
173 GrVectorXform xform(matrix);
174 for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) {
175 if (verb == SkPathVerb::kConic) {
176 sum += GrWangsFormula::conic_log2(kTolerance, pts, *w, xform);
177 }
178 }
179 // Don't let the compiler optimize away GrWangsFormula::conic.
180 if (sum <= 0) {
181 SK_ABORT("sum should be > 0.");
182 }
183}
184
185DEF_PATH_TESS_BENCH(wangs_formula_conic, make_conic_path(), SkMatrix::I()) {
186 benchmark_wangs_formula_conic(fMatrix, fPath);
187}
188
189DEF_PATH_TESS_BENCH(wangs_formula_conic_log2, make_conic_path(), SkMatrix::I()) {
190 benchmark_wangs_formula_conic_log2(fMatrix, fPath);
191}
192
Chris Daltone2067642020-09-23 11:07:20 -0600193DEF_PATH_TESS_BENCH(middle_out_triangulation,
194 ToolUtils::make_star(SkRect::MakeWH(500, 500), kNumCubicsInChalkboard),
Chris Daltond7177432021-01-15 13:12:50 -0700195 SkMatrix::I()) {
Chris Daltonb5391d92020-05-24 14:55:54 -0600196 int baseVertex;
Chris Daltond7177432021-01-15 13:12:50 -0700197 auto vertexData = static_cast<SkPoint*>(fTarget->makeVertexSpace(
Chris Daltonb5391d92020-05-24 14:55:54 -0600198 sizeof(SkPoint), kNumCubicsInChalkboard, nullptr, &baseVertex));
Chris Daltond7177432021-01-15 13:12:50 -0700199 GrMiddleOutPolygonTriangulator::WritePathInnerFan(vertexData, 3, fPath);
Chris Daltonb5391d92020-05-24 14:55:54 -0600200}
Chris Daltone2067642020-09-23 11:07:20 -0600201
Chris Dalton22241002021-02-04 09:47:40 -0700202class GrStrokeHardwareTessellator::TestingOnly_Benchmark : public Benchmark {
Chris Dalton2882e702020-11-02 12:43:06 -0700203public:
Chris Dalton0e543092020-11-03 14:09:16 -0700204 TestingOnly_Benchmark(float matrixScale, const char* suffix) : fMatrixScale(matrixScale) {
Chris Dalton22241002021-02-04 09:47:40 -0700205 fName.printf("tessellate_GrStrokeHardwareTessellator_prepare%s", suffix);
Chris Dalton2882e702020-11-02 12:43:06 -0700206 }
207
208private:
209 const char* onGetName() override { return fName.c_str(); }
Chris Daltone2067642020-09-23 11:07:20 -0600210 bool isSuitableFor(Backend backend) final { return backend == kNonRendering_Backend; }
211
212 void onDelayedSetup() override {
Chris Dalton90ad0fe2020-11-09 14:13:39 -0700213 fTarget = std::make_unique<GrMockOpTarget>(make_mock_context());
Chris Daltone2067642020-09-23 11:07:20 -0600214 fPath.reset().moveTo(0, 0);
215 for (int i = 0; i < kNumCubicsInChalkboard/2; ++i) {
Chris Dalton2882e702020-11-02 12:43:06 -0700216 fPath.cubicTo(100, 0, 50, 100, 100, 100);
217 fPath.cubicTo(0, -100, 200, 100, 0, 0);
Chris Daltone2067642020-09-23 11:07:20 -0600218 }
219 fStrokeRec.setStrokeStyle(8);
220 fStrokeRec.setStrokeParams(SkPaint::kButt_Cap, SkPaint::kMiter_Join, 4);
221 }
222
223 void onDraw(int loops, SkCanvas*) final {
Chris Dalton0e543092020-11-03 14:09:16 -0700224 if (!fTarget->mockContext()) {
Chris Daltone2067642020-09-23 11:07:20 -0600225 SkDebugf("ERROR: could not create mock context.");
226 return;
227 }
228 for (int i = 0; i < loops; ++i) {
Chris Dalton22241002021-02-04 09:47:40 -0700229 SkMatrix matrix = SkMatrix::Scale(fMatrixScale, fMatrixScale);
230 GrStrokeHardwareTessellator tessellator(*fTarget->caps().shaderCaps(), matrix,
231 fStrokeRec);
232 tessellator.prepare(fTarget.get(), matrix, fPath, fStrokeRec, fPath.countVerbs());
Chris Daltone2067642020-09-23 11:07:20 -0600233 }
234 }
235
Chris Dalton2882e702020-11-02 12:43:06 -0700236 const float fMatrixScale;
237 SkString fName;
Chris Dalton90ad0fe2020-11-09 14:13:39 -0700238 std::unique_ptr<GrMockOpTarget> fTarget;
Chris Daltone2067642020-09-23 11:07:20 -0600239 SkPath fPath;
240 SkStrokeRec fStrokeRec = SkStrokeRec(SkStrokeRec::kFill_InitStyle);
Chris Daltone2067642020-09-23 11:07:20 -0600241};
242
Chris Dalton22241002021-02-04 09:47:40 -0700243DEF_BENCH( return new GrStrokeHardwareTessellator::TestingOnly_Benchmark(1, ""); )
244DEF_BENCH( return new GrStrokeHardwareTessellator::TestingOnly_Benchmark(5, "_one_chop"); )
Chris Daltonc2a17462020-12-09 16:46:22 -0700245
Chris Dalton22241002021-02-04 09:47:40 -0700246class GrStrokeIndirectTessellator::Benchmark : public ::Benchmark {
Chris Daltonad482802020-12-28 09:02:47 -0700247protected:
248 Benchmark(const char* nameSuffix, SkPaint::Join join) : fJoin(join) {
Chris Dalton22241002021-02-04 09:47:40 -0700249 fName.printf("tessellate_GrStrokeIndirectTessellator%s", nameSuffix);
Chris Daltonc2a17462020-12-09 16:46:22 -0700250 }
251
Chris Daltonad482802020-12-28 09:02:47 -0700252 const SkPaint::Join fJoin;
Chris Daltonc2a17462020-12-09 16:46:22 -0700253
Chris Daltonad482802020-12-28 09:02:47 -0700254private:
255 const char* onGetName() final { return fName.c_str(); }
256 bool isSuitableFor(Backend backend) final { return backend == kNonRendering_Backend; }
257 void onDelayedSetup() final {
Chris Daltonc2a17462020-12-09 16:46:22 -0700258 fTarget = std::make_unique<GrMockOpTarget>(make_mock_context());
Chris Daltonc2a17462020-12-09 16:46:22 -0700259 fStrokeRec.setStrokeStyle(8);
260 fStrokeRec.setStrokeParams(SkPaint::kButt_Cap, fJoin, 4);
Chris Daltonad482802020-12-28 09:02:47 -0700261 this->setupPaths(&fPaths);
Chris Daltonc2a17462020-12-09 16:46:22 -0700262 }
Chris Daltonc2a17462020-12-09 16:46:22 -0700263 void onDraw(int loops, SkCanvas*) final {
264 if (!fTarget->mockContext()) {
265 SkDebugf("ERROR: could not create mock context.");
266 return;
267 }
268 for (int i = 0; i < loops; ++i) {
Chris Daltonad482802020-12-28 09:02:47 -0700269 for (const SkPath& path : fPaths) {
Chris Dalton22241002021-02-04 09:47:40 -0700270 GrStrokeIndirectTessellator tessellator(SkMatrix::I(), path, fStrokeRec,
271 path.countVerbs(), fTarget->allocator());
272 tessellator.prepare(fTarget.get(), SkMatrix::I(), path, fStrokeRec,
273 path.countVerbs());
Chris Daltonad482802020-12-28 09:02:47 -0700274 }
275 fTarget->resetAllocator();
276 }
277 }
278 virtual void setupPaths(SkTArray<SkPath>*) = 0;
279
280 SkString fName;
281 std::unique_ptr<GrMockOpTarget> fTarget;
282 SkTArray<SkPath> fPaths;
283 SkStrokeRec fStrokeRec{SkStrokeRec::kHairline_InitStyle};
284};
285
Chris Dalton22241002021-02-04 09:47:40 -0700286class StrokeIndirectBenchmark : public GrStrokeIndirectTessellator::Benchmark {
Chris Daltonad482802020-12-28 09:02:47 -0700287public:
288 StrokeIndirectBenchmark(const char* nameSuffix, SkPaint::Join join, std::vector<SkPoint> pts)
289 : Benchmark(nameSuffix, join), fPts(std::move(pts)) {}
290
291private:
292 void setupPaths(SkTArray<SkPath>* paths) final {
293 SkPath& path = paths->push_back();
294 if (fJoin == SkPaint::kRound_Join) {
295 path.reset().moveTo(fPts.back());
296 for (size_t i = 0; i < kNumCubicsInChalkboard/fPts.size(); ++i) {
297 for (size_t j = 0; j < fPts.size(); ++j) {
298 path.lineTo(fPts[j]);
299 }
300 }
301 } else {
302 path.reset().moveTo(fPts[0]);
303 for (int i = 0; i < kNumCubicsInChalkboard/2; ++i) {
304 if (fPts.size() == 4) {
305 path.cubicTo(fPts[1], fPts[2], fPts[3]);
306 path.cubicTo(fPts[2], fPts[1], fPts[0]);
307 } else {
308 SkASSERT(fPts.size() == 3);
309 path.quadTo(fPts[1], fPts[2]);
310 path.quadTo(fPts[2], fPts[1]);
311 }
312 }
Chris Daltonc2a17462020-12-09 16:46:22 -0700313 }
314 }
315
Chris Daltonad482802020-12-28 09:02:47 -0700316 const std::vector<SkPoint> fPts;
Chris Daltonc2a17462020-12-09 16:46:22 -0700317};
318
Chris Daltonad482802020-12-28 09:02:47 -0700319DEF_BENCH( return new StrokeIndirectBenchmark(
Chris Daltonc2a17462020-12-09 16:46:22 -0700320 "_inflect1", SkPaint::kBevel_Join, {{0,0}, {100,0}, {0,100}, {100,100}}); )
321
Chris Daltonad482802020-12-28 09:02:47 -0700322DEF_BENCH( return new StrokeIndirectBenchmark(
Chris Daltonc2a17462020-12-09 16:46:22 -0700323 "_inflect2", SkPaint::kBevel_Join, {{37,162}, {412,160}, {249,65}, {112,360}}); )
324
Chris Daltonad482802020-12-28 09:02:47 -0700325DEF_BENCH( return new StrokeIndirectBenchmark(
Chris Daltonc2a17462020-12-09 16:46:22 -0700326 "_loop", SkPaint::kBevel_Join, {{0,0}, {100,0}, {0,100}, {0,0}}); )
327
Chris Daltonad482802020-12-28 09:02:47 -0700328DEF_BENCH( return new StrokeIndirectBenchmark(
Chris Daltonc2a17462020-12-09 16:46:22 -0700329 "_nochop", SkPaint::kBevel_Join, {{0,0}, {50,0}, {100,50}, {100,100}}); )
330
Chris Daltonad482802020-12-28 09:02:47 -0700331DEF_BENCH( return new StrokeIndirectBenchmark(
Chris Daltonc2a17462020-12-09 16:46:22 -0700332 "_quad", SkPaint::kBevel_Join, {{0,0}, {50,100}, {100,0}}); )
333
Chris Daltonad482802020-12-28 09:02:47 -0700334DEF_BENCH( return new StrokeIndirectBenchmark(
Chris Daltonc2a17462020-12-09 16:46:22 -0700335 "_roundjoin", SkPaint::kRound_Join, {{0,0}, {50,100}, {100,0}}); )
Chris Daltonad482802020-12-28 09:02:47 -0700336
Chris Dalton22241002021-02-04 09:47:40 -0700337class SingleVerbStrokeIndirectBenchmark : public GrStrokeIndirectTessellator::Benchmark {
Chris Daltonad482802020-12-28 09:02:47 -0700338public:
339 SingleVerbStrokeIndirectBenchmark(const char* nameSuffix, SkPathVerb verb)
340 : Benchmark(nameSuffix, SkPaint::kBevel_Join), fVerb(verb) {}
341
342private:
343 void setupPaths(SkTArray<SkPath>* paths) override {
344 SkRandom rand;
345 for (int i = 0; i < kNumCubicsInChalkboard; ++i) {
346 switch (fVerb) {
347 case SkPathVerb::kQuad:
348 paths->push_back().quadTo(rand.nextF(), rand.nextF(), rand.nextF(),
349 rand.nextF());
350 break;
351 case SkPathVerb::kCubic:
352 switch (i % 3) {
353 case 0:
354 paths->push_back().cubicTo(100, 0, 0, 100, 100, 100); // 1 inflection.
355 break;
356 case 1:
357 paths->push_back().cubicTo(100, 0, 0, 100, 0, 0); // loop.
358 break;
359 case 2:
360 paths->push_back().cubicTo(50, 0, 100, 50, 100, 100); // no chop.
361 break;
362 }
363 break;
364 default:
365 SkUNREACHABLE;
366 }
367 }
368 }
369
370 const SkPathVerb fVerb;
371};
372
373DEF_BENCH( return new SingleVerbStrokeIndirectBenchmark("_singlequads", SkPathVerb::kQuad); )
374DEF_BENCH( return new SingleVerbStrokeIndirectBenchmark("_singlecubics", SkPathVerb::kCubic); )