/*
 * 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
