blob: 82916fa0777ffbc1b400ae0041ef4bf251a218e4 [file] [log] [blame]
/*
* 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