xref: /aosp_15_r20/external/skia/bench/graphite/BoundsManagerBench.cpp (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
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