1/*
2 * Copyright 2014 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include "Benchmark.h"
8#include "SkCanvas.h"
9#include "SkColorCubeFilter.h"
10#include "SkGradientShader.h"
11
12class ColorCubeBench : public Benchmark {
13    SkISize fSize;
14    int fCubeDimension;
15    SkData* fCubeData;
16    SkBitmap fBitmap;
17
18public:
19    ColorCubeBench()
20     : fCubeDimension(0)
21     , fCubeData(NULL) {
22        fSize = SkISize::Make(2880, 1800); // 2014 Macbook Pro resolution
23    }
24
25    ~ColorCubeBench() {
26        SkSafeUnref(fCubeData);
27    }
28
29protected:
30    const char* onGetName() override {
31        return "colorcube";
32    }
33
34    void onPreDraw() override {
35        if (!SkToBool(fCubeData)) {
36            this->makeCubeData();
37            this->make_bitmap();
38        }
39    }
40
41    void onDraw(const int loops, SkCanvas* canvas) override {
42        this->test(loops, canvas);
43    }
44
45    SkIPoint onGetSize() override {
46        return SkIPoint::Make(fSize.width(), fSize.height());
47    }
48
49private:
50    static SkShader* MakeLinear(const SkISize& size) {
51        const SkPoint pts[2] = {
52                { 0, 0 },
53                { SkIntToScalar(size.width()), SkIntToScalar(size.height()) }
54            };
55        static const SkColor colors[] = { SK_ColorYELLOW, SK_ColorBLUE };
56        return SkGradientShader::CreateLinear(
57            pts, colors, NULL, 2, SkShader::kRepeat_TileMode, 0, &SkMatrix::I());
58    }
59
60    void make_bitmap() {
61        fBitmap.allocN32Pixels(fSize.width(), fSize.height());
62        SkCanvas canvas(fBitmap);
63        canvas.clear(0x00000000);
64        SkPaint paint;
65        paint.setAntiAlias(true);
66        SkShader* shader = MakeLinear(fSize);
67        paint.setShader(shader);
68        SkRect r = { 0, 0, SkIntToScalar(fSize.width()), SkIntToScalar(fSize.height()) };
69        canvas.drawRect(r, paint);
70        shader->unref();
71    }
72
73    void makeCubeData() {
74        fCubeDimension = 32;
75        fCubeData = SkData::NewUninitialized(sizeof(SkColor) *
76            fCubeDimension * fCubeDimension * fCubeDimension);
77        SkColor* pixels = (SkColor*)(fCubeData->writable_data());
78        SkAutoMalloc lutMemory(fCubeDimension);
79        uint8_t* lut = (uint8_t*)lutMemory.get();
80        const int maxIndex = fCubeDimension - 1;
81        for (int i = 0; i < fCubeDimension; ++i) {
82            // Make an invert lut, but the content of
83            // the lut shouldn't affect performance.
84            lut[i] = ((maxIndex - i) * 255) / maxIndex;
85        }
86        for (int r = 0; r < fCubeDimension; ++r) {
87            for (int g = 0; g < fCubeDimension; ++g) {
88                for (int b = 0; b < fCubeDimension; ++b) {
89                    pixels[(fCubeDimension * ((fCubeDimension * b) + g)) + r] =
90                        SkColorSetARGB(0xFF, lut[r], lut[g], lut[b]);
91                }
92            }
93        }
94    }
95
96    void test(const int loops, SkCanvas* canvas) {
97        SkPaint paint;
98        for (int i = 0; i < loops; i++) {
99            SkAutoTUnref<SkColorFilter> colorCube(
100                SkColorCubeFilter::Create(fCubeData, fCubeDimension));
101            paint.setColorFilter(colorCube);
102            canvas->drawBitmap(fBitmap, 0, 0, &paint);
103        }
104    }
105
106    typedef Benchmark INHERITED;
107};
108
109///////////////////////////////////////////////////////////////////////////////
110
111DEF_BENCH( return new ColorCubeBench(); )
112