/*
 * 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 "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColorFilterImageFilter.h"
#include "SkColorMatrixFilter.h"
#include "SkGradientShader.h"
#include "SkImageFilter.h"
#include "SkTableColorFilter.h"

// Chains several matrix color filters image filter or several
// table filter image filters and draws a bitmap.
// This bench shows an improvement in performance and memory
// when collapsing matrices or tables is implemented since all
// the passes are collapsed in one.

class BaseImageFilterCollapseBench : public Benchmark {
public:
    BaseImageFilterCollapseBench(): fImageFilter(NULL) {}
    ~BaseImageFilterCollapseBench() {
        SkSafeUnref(fImageFilter);
    }

protected:
    void doPreDraw(SkColorFilter* colorFilters[], int nFilters) {
        // Create a chain of ImageFilters from colorFilters
        fImageFilter = NULL;
        for(int i = nFilters; i --> 0;) {
            SkAutoTUnref<SkImageFilter> filter(
                        SkColorFilterImageFilter::Create(colorFilters[i], fImageFilter, NULL, 0)
            );
            SkRefCnt_SafeAssign(fImageFilter, filter.get());
        }
    }

    void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
        makeBitmap();

        for(int i = 0; i < loops; i++) {
            SkPaint paint;
            paint.setImageFilter(fImageFilter);
            canvas->drawBitmap(fBitmap, 0, 0, &paint);
        }
    }

private:
    SkImageFilter* fImageFilter;
    SkBitmap fBitmap;

    void makeBitmap() {
        int W = 400;
        int H = 400;
        fBitmap.allocN32Pixels(W, H);
        fBitmap.eraseColor(SK_ColorTRANSPARENT);

        SkCanvas canvas(fBitmap);
        SkPaint paint;
        SkPoint pts[] = { {0, 0}, {SkIntToScalar(W), SkIntToScalar(H)} };
        SkColor colors[] = {
            SK_ColorBLACK, SK_ColorGREEN, SK_ColorCYAN,
            SK_ColorRED, 0, SK_ColorBLUE, SK_ColorWHITE
        };
        SkAutoTUnref<SkShader> shader(SkGradientShader::CreateLinear(
                    pts, colors, NULL, SK_ARRAY_COUNT(colors), SkShader::kClamp_TileMode
        ));
        paint.setShader(shader);
        canvas.drawPaint(paint);
    }
};

class TableCollapseBench: public BaseImageFilterCollapseBench {
public:
    virtual ~TableCollapseBench() {}

protected:
    virtual const char* onGetName() SK_OVERRIDE {
        return "image_filter_collapse_table";
    }

    virtual void onPreDraw() SK_OVERRIDE {
        for (int i = 0; i < 256; ++i) {
            int n = i >> 5;
            table1[i] = (n << 5) | (n << 2) | (n >> 1);

            table2[i] = i * i / 255;

            float fi = i / 255.0f;
            table3[i] = static_cast<uint8_t>(sqrtf(fi) * 255);
        }

        SkColorFilter* colorFilters[] = {
            SkTableColorFilter::Create(table1),
            SkTableColorFilter::Create(table2),
            SkTableColorFilter::Create(table3),
        };

        doPreDraw(colorFilters, SK_ARRAY_COUNT(colorFilters));

        for(unsigned i = 0; i < SK_ARRAY_COUNT(colorFilters); i++) {
            colorFilters[i]->unref();
        }
    }

private:
    uint8_t table1[256], table2[256], table3[256];
};

static SkColorFilter* make_brightness(float amount) {
    SkScalar amount255 = SkScalarMul(amount, SkIntToScalar(255));
    SkScalar matrix[20] = { 1, 0, 0, 0, amount255,
                            0, 1, 0, 0, amount255,
                            0, 0, 1, 0, amount255,
                            0, 0, 0, 1, 0 };
    return SkColorMatrixFilter::Create(matrix);
}

static SkColorFilter* make_grayscale() {
    SkScalar matrix[20];
    memset(matrix, 0, 20 * sizeof(SkScalar));
    matrix[0] = matrix[5] = matrix[10] = 0.2126f;
    matrix[1] = matrix[6] = matrix[11] = 0.7152f;
    matrix[2] = matrix[7] = matrix[12] = 0.0722f;
    matrix[18] = 1.0f;
    return SkColorMatrixFilter::Create(matrix);
}

class MatrixCollapseBench: public BaseImageFilterCollapseBench {
public:
    virtual ~MatrixCollapseBench() {}

protected:
    virtual const char* onGetName() SK_OVERRIDE {
        return "image_filter_collapse_matrix";
    }

    virtual void onPreDraw() SK_OVERRIDE {
        SkColorFilter* colorFilters[] = {
            make_brightness(0.1f),
            make_grayscale(),
            make_brightness(-0.1f),
        };

        doPreDraw(colorFilters, SK_ARRAY_COUNT(colorFilters));

        for(unsigned i = 0; i < SK_ARRAY_COUNT(colorFilters); i++) {
            colorFilters[i]->unref();
        }
    }
};

DEF_BENCH(return new TableCollapseBench;)
DEF_BENCH(return new MatrixCollapseBench;)
