| /* |
| * 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/base/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.size(); |
| 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 |