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