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