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