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