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