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 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 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 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: 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: 85 const char* onGetName() override { return fName.c_str(); } 86 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: 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