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