1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2021 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#include "bench/Benchmark.h" 8cb93a386Sopenharmony_ci#include "experimental/graphite/src/geom/IntersectionTree.h" 9cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 10cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 11cb93a386Sopenharmony_ci#include "include/utils/SkRandom.h" 12cb93a386Sopenharmony_ci#include "src/core/SkMathPriv.h" 13cb93a386Sopenharmony_ci#include "tools/ToolUtils.h" 14cb93a386Sopenharmony_ci#include "tools/flags/CommandLineFlags.h" 15cb93a386Sopenharmony_ci 16cb93a386Sopenharmony_cistatic DEFINE_string(intersectionTreeFile, "", 17cb93a386Sopenharmony_ci "svg or skp for the IntersectionTree bench to sniff paths from."); 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_cinamespace skgpu { 20cb93a386Sopenharmony_ci 21cb93a386Sopenharmony_ciclass IntersectionTreeBench : public Benchmark { 22cb93a386Sopenharmony_ciprotected: 23cb93a386Sopenharmony_ci const char* onGetName() final { return fName.c_str(); } 24cb93a386Sopenharmony_ci 25cb93a386Sopenharmony_ci bool isSuitableFor(Backend backend) override { 26cb93a386Sopenharmony_ci return backend == kNonRendering_Backend; 27cb93a386Sopenharmony_ci } 28cb93a386Sopenharmony_ci 29cb93a386Sopenharmony_ci void onDelayedSetup() final { 30cb93a386Sopenharmony_ci SkTArray<SkRect> rects; 31cb93a386Sopenharmony_ci this->gatherRects(&rects); 32cb93a386Sopenharmony_ci fRectCount = rects.count(); 33cb93a386Sopenharmony_ci fRects = fAlignedAllocator.makeArray<Rect>(fRectCount); 34cb93a386Sopenharmony_ci for (int i = 0; i < fRectCount; ++i) { 35cb93a386Sopenharmony_ci fRects[i] = rects[i]; 36cb93a386Sopenharmony_ci } 37cb93a386Sopenharmony_ci fRectBufferA = fAlignedAllocator.makeArray<Rect>(fRectCount); 38cb93a386Sopenharmony_ci fRectBufferB = fAlignedAllocator.makeArray<Rect>(fRectCount); 39cb93a386Sopenharmony_ci } 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci virtual void gatherRects(SkTArray<SkRect>* rects) = 0; 42cb93a386Sopenharmony_ci 43cb93a386Sopenharmony_ci void onDraw(int loops, SkCanvas*) final { 44cb93a386Sopenharmony_ci for (int i = 0; i < loops; ++i) { 45cb93a386Sopenharmony_ci this->doBench(); 46cb93a386Sopenharmony_ci } 47cb93a386Sopenharmony_ci } 48cb93a386Sopenharmony_ci 49cb93a386Sopenharmony_ci void doBench() { 50cb93a386Sopenharmony_ci Rect* rects = fRects; 51cb93a386Sopenharmony_ci Rect* collided = fRectBufferA; 52cb93a386Sopenharmony_ci int rectCount = fRectCount; 53cb93a386Sopenharmony_ci fNumTrees = 0; 54cb93a386Sopenharmony_ci while (rectCount > 0) { 55cb93a386Sopenharmony_ci IntersectionTree intersectionTree; 56cb93a386Sopenharmony_ci int collidedCount = 0; 57cb93a386Sopenharmony_ci for (int i = 0; i < rectCount; ++i) { 58cb93a386Sopenharmony_ci if (!intersectionTree.add(rects[i])) { 59cb93a386Sopenharmony_ci collided[collidedCount++] = rects[i]; 60cb93a386Sopenharmony_ci } 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci std::swap(rects, collided); 63cb93a386Sopenharmony_ci if (collided == fRects) { 64cb93a386Sopenharmony_ci collided = fRectBufferB; 65cb93a386Sopenharmony_ci } 66cb93a386Sopenharmony_ci rectCount = collidedCount; 67cb93a386Sopenharmony_ci ++fNumTrees; 68cb93a386Sopenharmony_ci } 69cb93a386Sopenharmony_ci } 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci SkString fName; 72cb93a386Sopenharmony_ci SkArenaAlloc fAlignedAllocator{0}; 73cb93a386Sopenharmony_ci int fRectCount; 74cb93a386Sopenharmony_ci Rect* fRects; 75cb93a386Sopenharmony_ci Rect* fRectBufferA; 76cb93a386Sopenharmony_ci Rect* fRectBufferB; 77cb93a386Sopenharmony_ci int fNumTrees = 0; 78cb93a386Sopenharmony_ci}; 79cb93a386Sopenharmony_ci 80cb93a386Sopenharmony_ciclass RandomIntersectionBench : public IntersectionTreeBench { 81cb93a386Sopenharmony_cipublic: 82cb93a386Sopenharmony_ci RandomIntersectionBench(int numRandomRects) : fNumRandomRects(numRandomRects) { 83cb93a386Sopenharmony_ci fName.printf("IntersectionTree_%i", numRandomRects); 84cb93a386Sopenharmony_ci } 85cb93a386Sopenharmony_ci 86cb93a386Sopenharmony_ciprivate: 87cb93a386Sopenharmony_ci void gatherRects(SkTArray<SkRect>* rects) override { 88cb93a386Sopenharmony_ci SkRandom rand; 89cb93a386Sopenharmony_ci for (int i = 0; i < fNumRandomRects; ++i) { 90cb93a386Sopenharmony_ci rects->push_back(SkRect::MakeXYWH(rand.nextRangeF(0, 2000), 91cb93a386Sopenharmony_ci rand.nextRangeF(0, 2000), 92cb93a386Sopenharmony_ci rand.nextRangeF(0, 70), 93cb93a386Sopenharmony_ci rand.nextRangeF(0, 70))); 94cb93a386Sopenharmony_ci } 95cb93a386Sopenharmony_ci } 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_ci const int fNumRandomRects; 98cb93a386Sopenharmony_ci}; 99cb93a386Sopenharmony_ci 100cb93a386Sopenharmony_ciclass FileIntersectionBench : public IntersectionTreeBench { 101cb93a386Sopenharmony_cipublic: 102cb93a386Sopenharmony_ci FileIntersectionBench() { 103cb93a386Sopenharmony_ci if (FLAGS_intersectionTreeFile.isEmpty()) { 104cb93a386Sopenharmony_ci return; 105cb93a386Sopenharmony_ci } 106cb93a386Sopenharmony_ci const char* filename = strrchr(FLAGS_intersectionTreeFile[0], '/'); 107cb93a386Sopenharmony_ci if (filename) { 108cb93a386Sopenharmony_ci ++filename; 109cb93a386Sopenharmony_ci } else { 110cb93a386Sopenharmony_ci filename = FLAGS_intersectionTreeFile[0]; 111cb93a386Sopenharmony_ci } 112cb93a386Sopenharmony_ci fName.printf("IntersectionTree_file_%s", filename); 113cb93a386Sopenharmony_ci } 114cb93a386Sopenharmony_ci 115cb93a386Sopenharmony_ciprivate: 116cb93a386Sopenharmony_ci bool isSuitableFor(Backend backend) final { 117cb93a386Sopenharmony_ci if (FLAGS_intersectionTreeFile.isEmpty()) { 118cb93a386Sopenharmony_ci return false; 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci return IntersectionTreeBench::isSuitableFor(backend); 121cb93a386Sopenharmony_ci } 122cb93a386Sopenharmony_ci 123cb93a386Sopenharmony_ci void gatherRects(SkTArray<SkRect>* rects) override { 124cb93a386Sopenharmony_ci if (FLAGS_intersectionTreeFile.isEmpty()) { 125cb93a386Sopenharmony_ci return; 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci ToolUtils::sniff_paths(FLAGS_intersectionTreeFile[0], [&](const SkMatrix& matrix, 128cb93a386Sopenharmony_ci const SkPath& path, 129cb93a386Sopenharmony_ci const SkPaint& paint) { 130cb93a386Sopenharmony_ci if (paint.getStyle() == SkPaint::kStroke_Style) { 131cb93a386Sopenharmony_ci return; // Goes to stroker. 132cb93a386Sopenharmony_ci } 133cb93a386Sopenharmony_ci if (path.isConvex()) { 134cb93a386Sopenharmony_ci return; // Goes to convex renderer. 135cb93a386Sopenharmony_ci } 136cb93a386Sopenharmony_ci int numVerbs = path.countVerbs(); 137cb93a386Sopenharmony_ci SkRect drawBounds = matrix.mapRect(path.getBounds()); 138cb93a386Sopenharmony_ci float gpuFragmentWork = drawBounds.height() * drawBounds.width(); 139cb93a386Sopenharmony_ci float cpuTessellationWork = numVerbs * SkNextLog2(numVerbs); // N log N. 140cb93a386Sopenharmony_ci constexpr static float kCpuWeight = 512; 141cb93a386Sopenharmony_ci constexpr static float kMinNumPixelsToTriangulate = 256 * 256; 142cb93a386Sopenharmony_ci if (cpuTessellationWork * kCpuWeight + kMinNumPixelsToTriangulate < gpuFragmentWork) { 143cb93a386Sopenharmony_ci return; // Goes to inner triangulator. 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci rects->push_back(drawBounds); 146cb93a386Sopenharmony_ci }); 147cb93a386Sopenharmony_ci SkDebugf(">> Found %i stencil/cover paths in %s <<\n", 148cb93a386Sopenharmony_ci rects->count(), FLAGS_intersectionTreeFile[0]); 149cb93a386Sopenharmony_ci } 150cb93a386Sopenharmony_ci 151cb93a386Sopenharmony_ci void onPerCanvasPostDraw(SkCanvas*) override { 152cb93a386Sopenharmony_ci if (FLAGS_intersectionTreeFile.isEmpty()) { 153cb93a386Sopenharmony_ci return; 154cb93a386Sopenharmony_ci } 155cb93a386Sopenharmony_ci SkDebugf(">> Reordered %s into %i different stencil/cover draws <<\n", 156cb93a386Sopenharmony_ci FLAGS_intersectionTreeFile[0], fNumTrees); 157cb93a386Sopenharmony_ci } 158cb93a386Sopenharmony_ci}; 159cb93a386Sopenharmony_ci 160cb93a386Sopenharmony_ci} // namespace skgpu 161cb93a386Sopenharmony_ci 162cb93a386Sopenharmony_ciDEF_BENCH( return new skgpu::RandomIntersectionBench(100); ) 163cb93a386Sopenharmony_ciDEF_BENCH( return new skgpu::RandomIntersectionBench(500); ) 164cb93a386Sopenharmony_ciDEF_BENCH( return new skgpu::RandomIntersectionBench(1000); ) 165cb93a386Sopenharmony_ciDEF_BENCH( return new skgpu::RandomIntersectionBench(5000); ) 166cb93a386Sopenharmony_ciDEF_BENCH( return new skgpu::RandomIntersectionBench(10000); ) 167cb93a386Sopenharmony_ciDEF_BENCH( return new skgpu::FileIntersectionBench(); ) // Sniffs --intersectionTreeFile 168