1 /* 2 * Copyright 2022 Google LLC 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 #include "bench/Benchmark.h" 8 #include "include/core/SkPaint.h" 9 #include "include/core/SkPath.h" 10 #include "src/base/SkArenaAlloc.h" 11 #include "src/base/SkRandom.h" 12 #include "src/gpu/graphite/geom/BoundsManager.h" 13 #include "tools/ToolUtils.h" 14 #include "tools/flags/CommandLineFlags.h" 15 16 static DEFINE_string(boundsManagerFile, "", 17 "svg or skp for the BoundsManager bench to sniff paths from."); 18 19 #define PRINT_DRAWSET_COUNT 0 // set to 1 to display number of CompressedPaintersOrder groups 20 21 namespace skgpu::graphite { 22 23 class BoundsManagerBench : public Benchmark { 24 public: BoundsManagerBench(std::unique_ptr<BoundsManager> manager)25 BoundsManagerBench(std::unique_ptr<BoundsManager> manager) : fManager(std::move(manager)) {} 26 27 protected: 28 virtual void gatherRects(SkTArray<SkRect>* rects) = 0; 29 isSuitableFor(Backend backend)30 bool isSuitableFor(Backend backend) override { 31 return backend == kNonRendering_Backend; 32 } 33 onGetName()34 const char* onGetName() final { return fName.c_str(); } 35 onDelayedSetup()36 void onDelayedSetup() final { 37 SkTArray<SkRect> rects; 38 this->gatherRects(&rects); 39 40 fRectCount = rects.size(); 41 fRects = fAlignedAllocator.makeArray<Rect>(fRectCount); 42 for (int i = 0; i < fRectCount; ++i) { 43 fRects[i] = rects[i]; 44 } 45 } 46 onDraw(int loops,SkCanvas *)47 void onDraw(int loops, SkCanvas*) final { 48 for (int i = 0; i < loops; ++i) { 49 this->doBench(); 50 } 51 } 52 onPerCanvasPostDraw(SkCanvas *)53 void onPerCanvasPostDraw(SkCanvas*) override { 54 #if PRINT_DRAWSET_COUNT 55 SkDebugf("%s >> grouped %d draws into %d sets <<\n", 56 fName.c_str(), fRectCount, fMaxRead.bits()); 57 #endif 58 } 59 doBench()60 void doBench() { 61 CompressedPaintersOrder maxRead = CompressedPaintersOrder::First(); 62 for (int i = 0; i < fRectCount; ++i) { 63 const Rect& drawBounds = fRects[i]; 64 CompressedPaintersOrder order = fManager->getMostRecentDraw(drawBounds).next(); 65 fManager->recordDraw(drawBounds, order); 66 if (order > maxRead) { 67 maxRead = order; 68 } 69 } 70 71 fMaxRead = maxRead; 72 fManager->reset(); 73 } 74 75 std::unique_ptr<BoundsManager> fManager; 76 SkString fName; 77 SkArenaAlloc fAlignedAllocator{0}; 78 int fRectCount; 79 Rect* fRects; 80 81 CompressedPaintersOrder fMaxRead; 82 }; 83 84 class RandomBoundsManagerBench : public BoundsManagerBench { 85 public: RandomBoundsManagerBench(std::unique_ptr<BoundsManager> manager,const char * managerName,int numRandomRects)86 RandomBoundsManagerBench(std::unique_ptr<BoundsManager> manager, 87 const char* managerName, 88 int numRandomRects) 89 : BoundsManagerBench(std::move(manager)) 90 , fNumRandomRects(numRandomRects) { 91 fName.printf("BoundsManager_rand_%i_%s", numRandomRects, managerName); 92 } 93 94 private: gatherRects(SkTArray<SkRect> * rects)95 void gatherRects(SkTArray<SkRect>* rects) override { 96 SkRandom rand; 97 for (int i = 0; i < fNumRandomRects; ++i) { 98 rects->push_back(SkRect::MakeXYWH(rand.nextRangeF(0, 2000), 99 rand.nextRangeF(0, 2000), 100 rand.nextRangeF(0, 70), 101 rand.nextRangeF(0, 70))); 102 } 103 } 104 105 int fNumRandomRects; 106 }; 107 108 class FileBoundsManagerBench : public BoundsManagerBench { 109 public: FileBoundsManagerBench(std::unique_ptr<BoundsManager> manager,const char * managerName)110 FileBoundsManagerBench(std::unique_ptr<BoundsManager> manager, 111 const char* managerName) 112 : BoundsManagerBench(std::move(manager)) { 113 if (!FLAGS_boundsManagerFile.isEmpty()) { 114 const char* filename = strrchr(FLAGS_boundsManagerFile[0], '/'); 115 if (filename) { 116 ++filename; 117 } else { 118 filename = FLAGS_boundsManagerFile[0]; 119 } 120 fName.printf("BoundsManager_file_%s_%s", filename, managerName); 121 } 122 } 123 124 private: isSuitableFor(Backend backend)125 bool isSuitableFor(Backend backend) final { 126 if (FLAGS_boundsManagerFile.isEmpty()) { 127 return false; 128 } 129 return BoundsManagerBench::isSuitableFor(backend); 130 } 131 gatherRects(SkTArray<SkRect> * rects)132 void gatherRects(SkTArray<SkRect>* rects) override { 133 if (FLAGS_boundsManagerFile.isEmpty()) { 134 return; 135 } 136 SkRect fileBounds = SkRect::MakeEmpty(); 137 ToolUtils::sniff_paths(FLAGS_boundsManagerFile[0], [&](const SkMatrix& matrix, 138 const SkPath& path, 139 const SkPaint& paint) { 140 if (!paint.canComputeFastBounds() || path.isInverseFillType()) { 141 // These would pessimistically cover the entire canvas, but we don't have enough 142 // info in the benchmark to handle that, so just skip these draws. 143 return; 144 } 145 146 SkRect bounds = path.getBounds(); 147 SkRect drawBounds = matrix.mapRect(paint.computeFastBounds(bounds, &bounds)); 148 rects->push_back(drawBounds); 149 150 fileBounds.join(drawBounds); 151 }); 152 153 #if PRINT_DRAWSET_COUNT 154 SkDebugf("%s bounds are [%f %f %f %f]\n", 155 FLAGS_boundsManagerFile[0], 156 fileBounds.fLeft, fileBounds.fTop, fileBounds.fRight, fileBounds.fBottom); 157 #endif 158 } 159 160 }; 161 162 } // namespace skgpu::graphite 163 164 #define DEF_BOUNDS_MANAGER_BENCH_SET(manager, name) \ 165 DEF_BENCH( return new skgpu::graphite::RandomBoundsManagerBench(manager, name, 100); ) \ 166 DEF_BENCH( return new skgpu::graphite::RandomBoundsManagerBench(manager, name, 500); ) \ 167 DEF_BENCH( return new skgpu::graphite::RandomBoundsManagerBench(manager, name, 1000); ) \ 168 DEF_BENCH( return new skgpu::graphite::RandomBoundsManagerBench(manager, name, 10000); ) \ 169 DEF_BENCH( return new skgpu::graphite::FileBoundsManagerBench(manager, name); ) 170 171 172 DEF_BOUNDS_MANAGER_BENCH_SET(std::make_unique<skgpu::graphite::NaiveBoundsManager>(), "naive") 173 DEF_BOUNDS_MANAGER_BENCH_SET(std::make_unique<skgpu::graphite::BruteForceBoundsManager>(), "brute") 174 DEF_BOUNDS_MANAGER_BENCH_SET(skgpu::graphite::GridBoundsManager::Make({1800, 1800}, 128), "grid128") 175 DEF_BOUNDS_MANAGER_BENCH_SET(skgpu::graphite::GridBoundsManager::Make({1800, 1800}, 512), "grid512") 176 DEF_BOUNDS_MANAGER_BENCH_SET(std::make_unique<skgpu::graphite::HybridBoundsManager>(SkISize{1800, 1800}, 16, 64), "hybrid16x16n128") 177 DEF_BOUNDS_MANAGER_BENCH_SET(std::make_unique<skgpu::graphite::HybridBoundsManager>(SkISize{1800, 1800}, 16, 128), "hybrid16x16n256") 178 // Uncomment and adjust device size to match reported bounds from --boundsManagerFile 179 // DEF_BOUNDS_MANAGER_BENCH_SET(skgpu::graphite::GridBoundsManager::MakeRes({w, h}, 8), "gridRes8") 180 181 #undef DEF_BOUNDS_MANAGER_BENCH_SET 182