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