/*
 * Copyright 2014 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "Benchmark.h"
#include "SkCanvas.h"
#include "SkGradientShader.h"
#include "SkPaint.h"
#include "SkPath.h"
#include "SkString.h"

enum ColorPattern {
    kWhite_ColorPattern,
    kBlue_ColorPattern,
    kOpaqueBitmap_ColorPattern,
    kAlphaBitmap_ColorPattern,
};

static const struct ColorPatternData{
    SkColor         fColor;
    bool            fIsBitmap;
    const char*     fName;
} gColorPatterns[] = {
    // Keep this in same order as ColorPattern enum
    { SK_ColorWHITE, false,  "white"        }, // kWhite_ColorPattern
    { SK_ColorBLUE,  false,  "blue"         }, // kBlue_ColorPattern
    { SK_ColorWHITE, true,   "obaqueBitMap" }, // kOpaqueBitmap_ColorPattern
    { 0x10000000,    true,   "alphaBitmap"  }, // kAlphaBitmap_ColorPattern
};

enum DrawType {
    kRect_DrawType,
    kPath_DrawType,
};

static void makebm(SkBitmap* bm, int w, int h) {
    bm->allocN32Pixels(w, h);
    bm->eraseColor(SK_ColorTRANSPARENT);

    SkCanvas    canvas(*bm);
    SkScalar    s = SkIntToScalar(SkMin32(w, h));
    static const SkPoint     kPts0[] = { { 0, 0 }, { s, s } };
    static const SkPoint     kPts1[] = { { s/2, 0 }, { s/2, s } };
    static const SkScalar    kPos[] = { 0, SK_Scalar1/2, SK_Scalar1 };
    static const SkColor kColors0[] = {0x80F00080, 0xF0F08000, 0x800080F0 };
    static const SkColor kColors1[] = {0xF08000F0, 0x8080F000, 0xF000F080 };


    SkPaint     paint;

    paint.setShader(SkGradientShader::CreateLinear(kPts0, kColors0, kPos,
                    SK_ARRAY_COUNT(kColors0), SkShader::kClamp_TileMode))->unref();
    canvas.drawPaint(paint);
    paint.setShader(SkGradientShader::CreateLinear(kPts1, kColors1, kPos,
                    SK_ARRAY_COUNT(kColors1), SkShader::kClamp_TileMode))->unref();
    canvas.drawPaint(paint);
}

/**
 * This bench draws a grid of either rects or filled paths, with two alternating color patterns.
 * This color patterns are passed in as enums to the class. The options are:
 *   1) solid white color
 *   2) solid blue color
 *   3) opaque bitmap
 *   4) partial alpha bitmap
 * The same color pattern can be set for both arguments to create a uniform pattern on all draws.
 *
 * The bench is used to test a few things. First it can test any optimizations made for a specific
 * color pattern (for example drawing an opaque bitmap versus one with partial alpha). Also it can
 * be used to test the cost of program switching and/or batching when alternating between different
 * patterns when on the gpu.
 */
class AlternatingColorPatternBench : public Benchmark {
public:
    enum {
        NX = 5,
        NY = 5,
        NUM_DRAWS = NX * NY,
    };
    SkShader* fBmShader;

    SkPath  fPaths[NUM_DRAWS];
    SkRect  fRects[NUM_DRAWS];
    SkColor fColors[NUM_DRAWS];
    SkShader* fShaders[NUM_DRAWS];

    SkString        fName;
    ColorPatternData    fPattern1;
    ColorPatternData    fPattern2;
    DrawType fDrawType;
    SkBitmap fBmp;


    AlternatingColorPatternBench(ColorPattern pattern1, ColorPattern pattern2, DrawType drawType)
        : fBmShader(nullptr) {
        fPattern1 = gColorPatterns[pattern1];
        fPattern2 = gColorPatterns[pattern2];
        fName.printf("colorPattern_%s_%s_%s",
                     fPattern1.fName, fPattern2.fName,
                     kRect_DrawType == drawType ? "rect" : "path");
        fDrawType = drawType;
    }

    virtual ~AlternatingColorPatternBench() {
        SkSafeUnref(fBmShader);
    }

protected:
    const char* onGetName() override {
        return fName.c_str();
    }

    void onDelayedSetup() override {
        int w = 40;
        int h = 40;
        makebm(&fBmp, w, h);
        fBmShader = SkShader::CreateBitmapShader(fBmp,
                                                 SkShader::kRepeat_TileMode,
                                                 SkShader::kRepeat_TileMode);
        int offset = 2;
        int count = 0;
        for (int j = 0; j < NY; ++j) {
            for (int i = 0; i < NX; ++i) {
                int x = (w + offset) * i;
                int y = (h * offset) * j;
                if (kRect_DrawType == fDrawType) {
                    fRects[count].set(SkIntToScalar(x), SkIntToScalar(y),
                                      SkIntToScalar(x + w), SkIntToScalar(y + h));
                } else {
                    fPaths[count].moveTo(SkIntToScalar(x), SkIntToScalar(y));
                    fPaths[count].rLineTo(SkIntToScalar(w), 0);
                    fPaths[count].rLineTo(0, SkIntToScalar(h));
                    fPaths[count].rLineTo(SkIntToScalar(-w + 1), 0);
                }
                if (0 == count % 2) {
                    fColors[count]  = fPattern1.fColor;
                    fShaders[count] = fPattern1.fIsBitmap ? fBmShader : nullptr;
                } else {
                    fColors[count]  = fPattern2.fColor;
                    fShaders[count] = fPattern2.fIsBitmap ? fBmShader : nullptr;
                }
                ++count;
            }
        }
    }

    void onDraw(int loops, SkCanvas* canvas) override {
        SkPaint paint;
        paint.setAntiAlias(false);
        paint.setFilterQuality(kLow_SkFilterQuality);

        for (int i = 0; i < loops; ++i) {
            for (int j = 0; j < NUM_DRAWS; ++j) {
                paint.setColor(fColors[j]);
                paint.setShader(fShaders[j]);
                if (kRect_DrawType == fDrawType) {
                    canvas->drawRect(fRects[j], paint);
                } else {
                    canvas->drawPath(fPaths[j], paint);
                }
            }
        }
    }

private:
    typedef Benchmark INHERITED;
};

DEF_BENCH(return new AlternatingColorPatternBench(kWhite_ColorPattern,
                                                  kWhite_ColorPattern,
                                                  kPath_DrawType);)
DEF_BENCH(return new AlternatingColorPatternBench(kBlue_ColorPattern,
                                                  kBlue_ColorPattern,
                                                  kPath_DrawType);)
DEF_BENCH(return new AlternatingColorPatternBench(kWhite_ColorPattern,
                                                  kBlue_ColorPattern,
                                                  kPath_DrawType);)

DEF_BENCH(return new AlternatingColorPatternBench(kOpaqueBitmap_ColorPattern,
                                                  kOpaqueBitmap_ColorPattern,
                                                  kPath_DrawType);)
DEF_BENCH(return new AlternatingColorPatternBench(kAlphaBitmap_ColorPattern,
                                                  kAlphaBitmap_ColorPattern,
                                                  kPath_DrawType);)
DEF_BENCH(return new AlternatingColorPatternBench(kOpaqueBitmap_ColorPattern,
                                                  kAlphaBitmap_ColorPattern,
                                                  kPath_DrawType);)

DEF_BENCH(return new AlternatingColorPatternBench(kOpaqueBitmap_ColorPattern,
                                                  kOpaqueBitmap_ColorPattern,
                                                  kRect_DrawType);)
DEF_BENCH(return new AlternatingColorPatternBench(kAlphaBitmap_ColorPattern,
                                                  kAlphaBitmap_ColorPattern,
                                                  kRect_DrawType);)
DEF_BENCH(return new AlternatingColorPatternBench(kOpaqueBitmap_ColorPattern,
                                                  kAlphaBitmap_ColorPattern,
                                                  kRect_DrawType);)
