/*
 * Copyright 2011 Google Inc.
 *
 * 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/SkCanvas.h"
#include "include/core/SkPaint.h"
#include "include/core/SkShader.h"
#include "include/core/SkString.h"
#include "include/core/SkVertices.h"
#include "src/base/SkRandom.h"
#include "tools/DecodeUtils.h"
#include "tools/Resources.h"

// Just want to trigger perspective handling, not dramatically change size
static void tiny_persp_effect(SkCanvas* canvas) {
    SkMatrix m;
    m.reset();
    m[7] = 0.000001f;
    canvas->concat(m);
}

enum VertFlags {
    kColors_VertFlag  = 1 << 0,
    kTexture_VertFlag = 1 << 1,
    kPersp_VertFlag   = 1 << 2,
    kBilerp_VertFlag  = 1 << 3,
};

class VertBench : public Benchmark {
    SkString fName;

    static constexpr int W = 64*2;
    static constexpr int H = 48*2;
    static constexpr int ROW = 20;
    static constexpr int COL = 20;
    static constexpr int PTS = (ROW + 1) * (COL + 1);
    static constexpr int IDX = ROW * COL * 6;

    sk_sp<SkShader> fShader;
    SkPoint fPts[PTS], fTex[PTS];
    SkColor fColors[PTS];
    uint16_t fIdx[IDX];
    unsigned fFlags;

    static void load_2_tris(uint16_t idx[], int x, int y, int rb) {
        int n = y * rb + x;
        idx[0] = n; idx[1] = n + 1; idx[2] = rb + n + 1;
        idx[3] = n; idx[4] = rb + n + 1; idx[5] = n + rb;
    }

    void onDelayedSetup() override {
        if (fFlags & kTexture_VertFlag) {
            auto img = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
            if (img) {
                SkFilterMode fm = (fFlags & kBilerp_VertFlag) ? SkFilterMode::kLinear
                                                              : SkFilterMode::kNearest;
                fShader = img->makeShader(SkSamplingOptions(fm));
            }
        }
    }

public:
    VertBench(unsigned flags) : fFlags(flags) {
        const SkScalar dx = SkIntToScalar(W) / COL;
        const SkScalar dy = SkIntToScalar(H) / COL;

        SkPoint* pts = fPts;
        uint16_t* idx = fIdx;

        SkScalar yy = 0;
        for (int y = 0; y <= ROW; y++) {
            SkScalar xx = 0;
            for (int x = 0; x <= COL; ++x) {
                pts->set(xx, yy);
                pts += 1;
                xx += dx;

                if (x < COL && y < ROW) {
                    load_2_tris(idx, x, y, COL + 1);
                    for (int i = 0; i < 6; i++) {
                        SkASSERT(idx[i] < PTS);
                    }
                    idx += 6;
                }
            }
            yy += dy;
        }
        SkASSERT(PTS == pts - fPts);
        SkASSERT(IDX == idx - fIdx);

        // We want to store texs in a separate array, so the blitters don't "cheat" and
        // skip the (normal) step of computing the new local-matrix. This is the common case
        // we think in the wild (where the texture coordinates are different from the positions.
        memcpy(fTex, fPts, sizeof(fPts));

        SkRandom rand;
        for (int i = 0; i < PTS; ++i) {
            fColors[i] = rand.nextU() | (0xFF << 24);
        }

        fName.set("verts");
        if (fFlags & kTexture_VertFlag) {
            fName.append("_textures");
        }
        if (fFlags & kColors_VertFlag) {
            fName.append("_colors");
        }
        if (fFlags & kPersp_VertFlag) {
            fName.append("_persp");
        }
        if (fFlags & kBilerp_VertFlag) {
            fName.append("_bilerp");
        }
    }

protected:
    const char* onGetName() override { return fName.c_str(); }
    void onDraw(int loops, SkCanvas* canvas) override {
        SkPaint paint;
        this->setupPaint(&paint);
        paint.setShader(fShader);

        if (fFlags & kPersp_VertFlag) {
            tiny_persp_effect(canvas);
        }

        const SkPoint* texs = (fFlags & kTexture_VertFlag) ? fTex    : nullptr;
        const SkColor* cols = (fFlags & kColors_VertFlag)  ? fColors : nullptr;
        auto verts = SkVertices::MakeCopy(SkVertices::kTriangles_VertexMode, PTS,
                                          fPts, texs, cols, IDX, fIdx);
        for (int i = 0; i < loops; i++) {
            canvas->drawVertices(verts, SkBlendMode::kModulate, paint);
        }
    }
private:
    using INHERITED = Benchmark;
};
DEF_BENCH(return new VertBench(kTexture_VertFlag | kPersp_VertFlag);)
DEF_BENCH(return new VertBench(kTexture_VertFlag | kPersp_VertFlag | kBilerp_VertFlag);)
DEF_BENCH(return new VertBench(kColors_VertFlag  | kPersp_VertFlag);)
DEF_BENCH(return new VertBench(kTexture_VertFlag);)
DEF_BENCH(return new VertBench(kTexture_VertFlag | kBilerp_VertFlag);)
DEF_BENCH(return new VertBench(kColors_VertFlag);)
DEF_BENCH(return new VertBench(kColors_VertFlag | kTexture_VertFlag);)
DEF_BENCH(return new VertBench(kColors_VertFlag | kTexture_VertFlag | kBilerp_VertFlag);)

/////////////////////////////////////////////////////////////////////////////////////////////////

#include "include/core/SkRSXform.h"
#include "src/base/SkRandom.h"
#include "tools/Resources.h"

enum AtlasFlags {
    kColors_Flag = 1 << 0,
    kRotate_Flag = 1 << 1,
    kPersp_Flag  = 1 << 2,
};

class AtlasBench : public Benchmark {
    unsigned fFlags;
    SkString fName;

    static constexpr int W = 640;
    static constexpr int H = 480;
    static constexpr int N = 10*1000;

    sk_sp<SkImage>  fAtlas;
    SkRSXform       fXforms[N];
    SkRect          fRects[N];
    SkColor         fColors[N];

public:
    AtlasBench(unsigned flags) : fFlags(flags) {
        fName.printf("drawAtlas");
        if (flags & kColors_Flag) {
            fName.append("_colors");
        }
        if (flags & kRotate_Flag) {
            fName.append("_rotated");
        }
        if (flags & kPersp_Flag) {
            fName.append("_persp");
        }
    }
    ~AtlasBench() override {}

protected:
    const char* onGetName() override { return fName.c_str(); }
    void onDelayedSetup() override {
        fAtlas = ToolUtils::GetResourceAsImage("images/mandrill_256.png");
        if (fAtlas) {
            fAtlas = fAtlas->makeRasterImage(nullptr);
        }

        const SkScalar imageW = fAtlas->width();
        const SkScalar imageH = fAtlas->height();
        SkScalar scos = 1;
        SkScalar ssin = 0;
        if (fFlags & kRotate_Flag) {
            scos = 0.866025403784439f;  // sqrt(3)/2
            ssin = 0.5f;
        }

        SkRandom rand;
        for (int i = 0; i < N; ++i) {
            fRects[i] = SkRect::MakeXYWH(rand.nextF() * (imageW - 8),
                                         rand.nextF() * (imageH - 8), 8, 8);
            fColors[i] = rand.nextU() | 0xFF000000;
            fXforms[i] = SkRSXform::Make(scos, ssin, rand.nextF() * W, rand.nextF() * H);
        }
    }
    void onDraw(int loops, SkCanvas* canvas) override {
        const SkRect* cullRect = nullptr;
        const SkPaint* paintPtr = nullptr;
        const SkColor* colors = nullptr;
        if (fFlags & kColors_Flag) {
            colors = fColors;
        }
        if (fFlags & kPersp_Flag) {
            tiny_persp_effect(canvas);
        }
        for (int i = 0; i < loops; i++) {
            canvas->drawAtlas(fAtlas.get(), fXforms, fRects,
                              {colors, colors ? N : 0}, SkBlendMode::kModulate,
                              SkSamplingOptions(), cullRect, paintPtr);
        }
    }
private:
    using INHERITED = Benchmark;
};
//DEF_BENCH(return new AtlasBench(0);)
//DEF_BENCH(return new AtlasBench(kColors_Flag);)
DEF_BENCH(return new AtlasBench(0);)
DEF_BENCH(return new AtlasBench(kRotate_Flag);)
DEF_BENCH(return new AtlasBench(kPersp_Flag);)
DEF_BENCH(return new AtlasBench(kColors_Flag);)
DEF_BENCH(return new AtlasBench(kColors_Flag | kRotate_Flag);)

