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
8#include "Benchmark.h"
9#include "SkCanvas.h"
10#include "SkPaint.h"
11
12#include <ctype.h>
13
14/** This benchmark tests rendering rotated rectangles. It can optionally apply AA and/or change the
15    paint color between each rect in different ways using the ColorType enum. The xfermode used can
16    be specified as well.
17  */
18
19enum ColorType {
20    kConstantOpaque_ColorType,
21    kConstantTransparent_ColorType,
22    kChangingOpaque_ColorType,
23    kChangingTransparent_ColorType,
24    kAlternatingOpaqueAndTransparent_ColorType,
25};
26
27static inline SkColor start_color(ColorType ct) {
28    switch (ct) {
29        case kConstantOpaque_ColorType:
30        case kChangingOpaque_ColorType:
31        case kAlternatingOpaqueAndTransparent_ColorType:
32            return 0xFFA07040;
33        case kConstantTransparent_ColorType:
34        case kChangingTransparent_ColorType:
35            return 0x80A07040;
36    }
37    SkFAIL("Shouldn't reach here.");
38    return 0;
39}
40
41static inline SkColor advance_color(SkColor old, ColorType ct, int step) {
42    if (kAlternatingOpaqueAndTransparent_ColorType == ct) {
43        ct = (step & 0x1) ? kChangingOpaque_ColorType : kChangingTransparent_ColorType ;
44    }
45    switch (ct) {
46        case kConstantOpaque_ColorType:
47        case kConstantTransparent_ColorType:
48            return old;
49        case kChangingOpaque_ColorType:
50            return 0xFF000000 | (old + 0x00010307);
51        case kChangingTransparent_ColorType:
52            return (0x00FFFFFF & (old + 0x00010307)) | 0x80000000;
53        case kAlternatingOpaqueAndTransparent_ColorType:
54            SkFAIL("Can't get here");
55    }
56    SkFAIL("Shouldn't reach here.");
57    return 0;
58}
59
60static SkString to_lower(const char* str) {
61    SkString lower(str);
62    for (size_t i = 0; i < lower.size(); i++) {
63        lower[i] = tolower(lower[i]);
64    }
65    return lower;
66}
67
68class RotRectBench: public Benchmark {
69public:
70    RotRectBench(bool aa, ColorType ct, SkXfermode::Mode mode)
71        : fAA(aa)
72        , fColorType(ct)
73        , fMode(mode) {
74        this->makeName();
75    }
76
77protected:
78    virtual const char* onGetName() SK_OVERRIDE { return fName.c_str(); }
79
80    virtual void onDraw(const int loops, SkCanvas* canvas) SK_OVERRIDE {
81        SkPaint paint;
82        paint.setAntiAlias(fAA);
83        paint.setXfermodeMode(fMode);
84        SkColor color = start_color(fColorType);
85
86        int w = canvas->getBaseLayerSize().width();
87        int h = canvas->getBaseLayerSize().height();
88
89        static const SkScalar kRectW = 25.1f;
90        static const SkScalar kRectH = 25.9f;
91
92        SkMatrix rotate;
93        // This value was chosen so that we frequently hit the axis-aligned case.
94        rotate.setRotate(30.f, kRectW / 2, kRectH / 2);
95        SkMatrix m = rotate;
96
97        SkScalar tx = 0, ty = 0;
98
99        for (int i = 0; i < loops; ++i) {
100            canvas->save();
101            canvas->translate(tx, ty);
102            canvas->concat(m);
103            paint.setColor(color);
104            color = advance_color(color, fColorType, i);
105
106            canvas->drawRect(SkRect::MakeWH(kRectW, kRectH), paint);
107            canvas->restore();
108
109            tx += kRectW + 2;
110            if (tx > w) {
111                tx = 0;
112                ty += kRectH + 2;
113                if (ty > h) {
114                    ty = 0;
115                }
116            }
117
118            m.postConcat(rotate);
119        }
120    }
121
122private:
123    void makeName() {
124        fName = "rotated_rects";
125        if (fAA) {
126            fName.append("_aa");
127        } else {
128            fName.append("_bw");
129        }
130        switch (fColorType) {
131            case kConstantOpaque_ColorType:
132                fName.append("_same_opaque");
133                break;
134            case kConstantTransparent_ColorType:
135                fName.append("_same_transparent");
136                break;
137            case kChangingOpaque_ColorType:
138                fName.append("_changing_opaque");
139                break;
140            case kChangingTransparent_ColorType:
141                fName.append("_changing_transparent");
142                break;
143            case kAlternatingOpaqueAndTransparent_ColorType:
144                fName.append("_alternating_transparent_and_opaque");
145                break;
146        }
147        fName.appendf("_%s", to_lower(SkXfermode::ModeName(fMode)).c_str());
148    }
149
150    bool             fAA;
151    ColorType        fColorType;
152    SkXfermode::Mode fMode;
153    SkString         fName;
154
155    typedef Benchmark INHERITED;
156};
157
158// Choose kSrcOver because it always allows coverage and alpha to be conflated. kSrc only allows
159// conflation when opaque, and kDarken because it isn't possilbe with standard GL blending.
160DEF_BENCH(return new RotRectBench(true,  kConstantOpaque_ColorType,                  SkXfermode::kSrcOver_Mode);)
161DEF_BENCH(return new RotRectBench(true,  kConstantTransparent_ColorType,             SkXfermode::kSrcOver_Mode);)
162DEF_BENCH(return new RotRectBench(true,  kChangingOpaque_ColorType,                  SkXfermode::kSrcOver_Mode);)
163DEF_BENCH(return new RotRectBench(true,  kChangingTransparent_ColorType,             SkXfermode::kSrcOver_Mode);)
164DEF_BENCH(return new RotRectBench(true,  kAlternatingOpaqueAndTransparent_ColorType, SkXfermode::kSrcOver_Mode);)
165
166DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType,                  SkXfermode::kSrcOver_Mode);)
167DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType,             SkXfermode::kSrcOver_Mode);)
168DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType,                  SkXfermode::kSrcOver_Mode);)
169DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType,             SkXfermode::kSrcOver_Mode);)
170DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkXfermode::kSrcOver_Mode);)
171
172DEF_BENCH(return new RotRectBench(true,  kConstantOpaque_ColorType,                  SkXfermode::kSrc_Mode);)
173DEF_BENCH(return new RotRectBench(true,  kConstantTransparent_ColorType,             SkXfermode::kSrc_Mode);)
174DEF_BENCH(return new RotRectBench(true,  kChangingOpaque_ColorType,                  SkXfermode::kSrc_Mode);)
175DEF_BENCH(return new RotRectBench(true,  kChangingTransparent_ColorType,             SkXfermode::kSrc_Mode);)
176DEF_BENCH(return new RotRectBench(true,  kAlternatingOpaqueAndTransparent_ColorType, SkXfermode::kSrc_Mode);)
177
178DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType,                  SkXfermode::kSrc_Mode);)
179DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType,             SkXfermode::kSrc_Mode);)
180DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType,                  SkXfermode::kSrc_Mode);)
181DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType,             SkXfermode::kSrc_Mode);)
182DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkXfermode::kSrc_Mode);)
183
184DEF_BENCH(return new RotRectBench(true,  kConstantOpaque_ColorType,                  SkXfermode::kDarken_Mode);)
185DEF_BENCH(return new RotRectBench(true,  kConstantTransparent_ColorType,             SkXfermode::kDarken_Mode);)
186DEF_BENCH(return new RotRectBench(true,  kChangingOpaque_ColorType,                  SkXfermode::kDarken_Mode);)
187DEF_BENCH(return new RotRectBench(true,  kChangingTransparent_ColorType,             SkXfermode::kDarken_Mode);)
188DEF_BENCH(return new RotRectBench(true,  kAlternatingOpaqueAndTransparent_ColorType, SkXfermode::kDarken_Mode);)
189
190DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType,                  SkXfermode::kDarken_Mode);)
191DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType,             SkXfermode::kDarken_Mode);)
192DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType,                  SkXfermode::kDarken_Mode);)
193DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType,             SkXfermode::kDarken_Mode);)
194DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkXfermode::kDarken_Mode);)
195