| /* | 
 |  * Copyright 2022 Google LLC | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 | #include "bench/Benchmark.h" | 
 | #include "include/core/SkPaint.h" | 
 | #include "include/core/SkPath.h" | 
 | #include "include/utils/SkRandom.h" | 
 | #include "src/core/SkArenaAlloc.h" | 
 | #include "src/gpu/graphite/geom/BoundsManager.h" | 
 | #include "tools/ToolUtils.h" | 
 | #include "tools/flags/CommandLineFlags.h" | 
 |  | 
 | static DEFINE_string(boundsManagerFile, "", | 
 |                      "svg or skp for the BoundsManager bench to sniff paths from."); | 
 |  | 
 | #define PRINT_DRAWSET_COUNT 0 // set to 1 to display number of CompressedPaintersOrder groups | 
 |  | 
 | namespace skgpu::graphite { | 
 |  | 
 | class BoundsManagerBench : public Benchmark { | 
 | public: | 
 |     BoundsManagerBench(std::unique_ptr<BoundsManager> manager) : fManager(std::move(manager)) {} | 
 |  | 
 | protected: | 
 |     virtual void gatherRects(SkTArray<SkRect>* rects) = 0; | 
 |  | 
 |     bool isSuitableFor(Backend backend) override { | 
 |         return backend == kNonRendering_Backend; | 
 |     } | 
 |  | 
 |     const char* onGetName() final { return fName.c_str(); } | 
 |  | 
 |     void onDelayedSetup() final { | 
 |         SkTArray<SkRect> rects; | 
 |         this->gatherRects(&rects); | 
 |  | 
 |         fRectCount = rects.count(); | 
 |         fRects = fAlignedAllocator.makeArray<Rect>(fRectCount); | 
 |         for (int i = 0; i < fRectCount; ++i) { | 
 |             fRects[i] = rects[i]; | 
 |         } | 
 |     } | 
 |  | 
 |     void onDraw(int loops, SkCanvas*) final { | 
 |         for (int i = 0; i < loops; ++i) { | 
 |             this->doBench(); | 
 |         } | 
 |     } | 
 |  | 
 |     void onPerCanvasPostDraw(SkCanvas*) override { | 
 | #if PRINT_DRAWSET_COUNT | 
 |         SkDebugf("%s >> grouped %d draws into %d sets <<\n", | 
 |                  fName.c_str(), fRectCount, fMaxRead.bits()); | 
 | #endif | 
 |     } | 
 |  | 
 |     void doBench() { | 
 |         CompressedPaintersOrder maxRead = CompressedPaintersOrder::First(); | 
 |         for (int i = 0; i < fRectCount; ++i) { | 
 |             const Rect& drawBounds = fRects[i]; | 
 |             CompressedPaintersOrder order = fManager->getMostRecentDraw(drawBounds).next(); | 
 |             fManager->recordDraw(drawBounds, order); | 
 |             if (order > maxRead) { | 
 |                 maxRead = order; | 
 |             } | 
 |         } | 
 |  | 
 |         fMaxRead = maxRead; | 
 |         fManager->reset(); | 
 |     } | 
 |  | 
 |     std::unique_ptr<BoundsManager> fManager; | 
 |     SkString fName; | 
 |     SkArenaAlloc fAlignedAllocator{0}; | 
 |     int fRectCount; | 
 |     Rect* fRects; | 
 |  | 
 |     CompressedPaintersOrder fMaxRead; | 
 | }; | 
 |  | 
 | class RandomBoundsManagerBench : public BoundsManagerBench { | 
 | public: | 
 |     RandomBoundsManagerBench(std::unique_ptr<BoundsManager> manager, | 
 |                              const char* managerName, | 
 |                              int numRandomRects) | 
 |             : BoundsManagerBench(std::move(manager)) | 
 |             , fNumRandomRects(numRandomRects) { | 
 |         fName.printf("BoundsManager_rand_%i_%s", numRandomRects, managerName); | 
 |     } | 
 |  | 
 | private: | 
 |     void gatherRects(SkTArray<SkRect>* rects) override { | 
 |         SkRandom rand; | 
 |         for (int i = 0; i < fNumRandomRects; ++i) { | 
 |             rects->push_back(SkRect::MakeXYWH(rand.nextRangeF(0, 2000), | 
 |                                               rand.nextRangeF(0, 2000), | 
 |                                               rand.nextRangeF(0, 70), | 
 |                                               rand.nextRangeF(0, 70))); | 
 |         } | 
 |     } | 
 |  | 
 |     int fNumRandomRects; | 
 | }; | 
 |  | 
 | class FileBoundsManagerBench : public BoundsManagerBench { | 
 | public: | 
 |     FileBoundsManagerBench(std::unique_ptr<BoundsManager> manager, | 
 |                            const char* managerName) | 
 |             : BoundsManagerBench(std::move(manager)) { | 
 |         if (!FLAGS_boundsManagerFile.isEmpty()) { | 
 |             const char* filename = strrchr(FLAGS_boundsManagerFile[0], '/'); | 
 |             if (filename) { | 
 |                 ++filename; | 
 |             } else { | 
 |                 filename = FLAGS_boundsManagerFile[0]; | 
 |             } | 
 |             fName.printf("BoundsManager_file_%s_%s", filename, managerName); | 
 |         } | 
 |     } | 
 |  | 
 | private: | 
 |     bool isSuitableFor(Backend backend) final { | 
 |         if (FLAGS_boundsManagerFile.isEmpty()) { | 
 |             return false; | 
 |         } | 
 |         return BoundsManagerBench::isSuitableFor(backend); | 
 |     } | 
 |  | 
 |     void gatherRects(SkTArray<SkRect>* rects) override { | 
 |         if (FLAGS_boundsManagerFile.isEmpty()) { | 
 |             return; | 
 |         } | 
 |         SkRect fileBounds = SkRect::MakeEmpty(); | 
 |         ToolUtils::sniff_paths(FLAGS_boundsManagerFile[0], [&](const SkMatrix& matrix, | 
 |                                                                const SkPath& path, | 
 |                                                                const SkPaint& paint) { | 
 |             if (!paint.canComputeFastBounds() || path.isInverseFillType()) { | 
 |                 // These would pessimistically cover the entire canvas, but we don't have enough | 
 |                 // info in the benchmark to handle that, so just skip these draws. | 
 |                 return; | 
 |             } | 
 |  | 
 |             SkRect bounds = path.getBounds(); | 
 |             SkRect drawBounds = matrix.mapRect(paint.computeFastBounds(bounds, &bounds)); | 
 |             rects->push_back(drawBounds); | 
 |  | 
 |             fileBounds.join(drawBounds); | 
 |         }); | 
 |  | 
 | #if PRINT_DRAWSET_COUNT | 
 |         SkDebugf("%s bounds are [%f %f %f %f]\n", | 
 |             FLAGS_boundsManagerFile[0], | 
 |             fileBounds.fLeft, fileBounds.fTop, fileBounds.fRight, fileBounds.fBottom); | 
 | #endif | 
 |     } | 
 |  | 
 | }; | 
 |  | 
 | }  // namespace skgpu::graphite | 
 |  | 
 | #define DEF_BOUNDS_MANAGER_BENCH_SET(manager, name) \ | 
 |     DEF_BENCH( return new skgpu::graphite::RandomBoundsManagerBench(manager, name, 100); ) \ | 
 |     DEF_BENCH( return new skgpu::graphite::RandomBoundsManagerBench(manager, name, 500); ) \ | 
 |     DEF_BENCH( return new skgpu::graphite::RandomBoundsManagerBench(manager, name, 1000); ) \ | 
 |     DEF_BENCH( return new skgpu::graphite::RandomBoundsManagerBench(manager, name, 10000); ) \ | 
 |     DEF_BENCH( return new skgpu::graphite::FileBoundsManagerBench(manager, name); ) | 
 |  | 
 |  | 
 | DEF_BOUNDS_MANAGER_BENCH_SET(std::make_unique<skgpu::graphite::NaiveBoundsManager>(),      "naive") | 
 | DEF_BOUNDS_MANAGER_BENCH_SET(std::make_unique<skgpu::graphite::BruteForceBoundsManager>(), "brute") | 
 | DEF_BOUNDS_MANAGER_BENCH_SET(skgpu::graphite::GridBoundsManager::Make({1800, 1800}, 128), "grid128") | 
 | DEF_BOUNDS_MANAGER_BENCH_SET(skgpu::graphite::GridBoundsManager::Make({1800, 1800}, 512), "grid512") | 
 | DEF_BOUNDS_MANAGER_BENCH_SET(std::make_unique<skgpu::graphite::HybridBoundsManager>(SkISize{1800, 1800}, 16, 64), "hybrid16x16n128") | 
 | DEF_BOUNDS_MANAGER_BENCH_SET(std::make_unique<skgpu::graphite::HybridBoundsManager>(SkISize{1800, 1800}, 16, 128), "hybrid16x16n256") | 
 | // Uncomment and adjust device size to match reported bounds from --boundsManagerFile | 
 | // DEF_BOUNDS_MANAGER_BENCH_SET(skgpu::graphite::GridBoundsManager::MakeRes({w, h}, 8), "gridRes8") | 
 |  | 
 | #undef DEF_BOUNDS_MANAGER_BENCH_SET |