| /* | 
 |  * Copyright 2014 Google Inc. | 
 |  * | 
 |  * Use of this source code is governed by a BSD-style license that can be | 
 |  * found in the LICENSE file. | 
 |  */ | 
 |  | 
 | #include "bench/Benchmark.h" | 
 | #include "include/core/SkCanvas.h" | 
 | #include "include/core/SkPaint.h" | 
 | #include "include/effects/SkGradientShader.h" | 
 | #include "src/core/SkBlendModePriv.h" | 
 |  | 
 | #include <ctype.h> | 
 |  | 
 | /** This benchmark tests rendering rotated rectangles. It can optionally apply AA and/or change the | 
 |     paint color between each rect in different ways using the ColorType enum. The xfermode used can | 
 |     be specified as well. | 
 |   */ | 
 |  | 
 | enum ColorType { | 
 |     kConstantOpaque_ColorType, | 
 |     kConstantTransparent_ColorType, | 
 |     kChangingOpaque_ColorType, | 
 |     kChangingTransparent_ColorType, | 
 |     kAlternatingOpaqueAndTransparent_ColorType, | 
 |     kShaderOpaque_ColorType | 
 | }; | 
 |  | 
 | static inline SkColor start_color(ColorType ct) { | 
 |     switch (ct) { | 
 |         case kConstantOpaque_ColorType: | 
 |         case kChangingOpaque_ColorType: | 
 |         case kAlternatingOpaqueAndTransparent_ColorType: | 
 |             return 0xFFA07040; | 
 |         case kConstantTransparent_ColorType: | 
 |         case kChangingTransparent_ColorType: | 
 |             return 0x80A07040; | 
 |         case kShaderOpaque_ColorType: | 
 |             return SK_ColorWHITE; | 
 |     } | 
 |     SK_ABORT("Shouldn't reach here."); | 
 | } | 
 |  | 
 | static inline SkColor advance_color(SkColor old, ColorType ct, int step) { | 
 |     if (kAlternatingOpaqueAndTransparent_ColorType == ct) { | 
 |         ct = (step & 0x1) ? kChangingOpaque_ColorType : kChangingTransparent_ColorType ; | 
 |     } | 
 |     switch (ct) { | 
 |         case kConstantOpaque_ColorType: | 
 |         case kConstantTransparent_ColorType: | 
 |         case kShaderOpaque_ColorType: | 
 |             return old; | 
 |         case kChangingOpaque_ColorType: | 
 |             return 0xFF000000 | (old + 0x00010307); | 
 |         case kChangingTransparent_ColorType: | 
 |             return (0x00FFFFFF & (old + 0x00010307)) | 0x80000000; | 
 |         case kAlternatingOpaqueAndTransparent_ColorType: | 
 |             SK_ABORT("Can't get here"); | 
 |     } | 
 |     SK_ABORT("Shouldn't reach here."); | 
 | } | 
 |  | 
 | static SkString to_lower(const char* str) { | 
 |     SkString lower(str); | 
 |     for (size_t i = 0; i < lower.size(); i++) { | 
 |         lower[i] = tolower(lower[i]); | 
 |     } | 
 |     return lower; | 
 | } | 
 |  | 
 | class RotRectBench: public Benchmark { | 
 | public: | 
 |     RotRectBench(bool aa, ColorType ct, SkBlendMode mode, bool perspective = false) | 
 |         : fAA(aa) | 
 |         , fPerspective(perspective) | 
 |         , fColorType(ct) | 
 |         , fMode(mode) { | 
 |         this->makeName(); | 
 |     } | 
 |  | 
 | protected: | 
 |     const char* onGetName() override { return fName.c_str(); } | 
 |  | 
 |     void onDraw(int loops, SkCanvas* canvas) override { | 
 |         SkPaint paint; | 
 |         paint.setAntiAlias(fAA); | 
 |         paint.setBlendMode(fMode); | 
 |         SkColor color = start_color(fColorType); | 
 |  | 
 |         int w = this->getSize().x(); | 
 |         int h = this->getSize().y(); | 
 |  | 
 |         static const SkScalar kRectW = 25.1f; | 
 |         static const SkScalar kRectH = 25.9f; | 
 |  | 
 |         if (fColorType == kShaderOpaque_ColorType) { | 
 |             // The only requirement for the shader is that it requires local coordinates | 
 |             SkPoint pts[2] = { {0.0f, 0.0f}, {kRectW, kRectH} }; | 
 |             SkColor colors[] = { color, SK_ColorBLUE }; | 
 |             paint.setShader(SkGradientShader::MakeLinear(pts, colors, nullptr, 2, | 
 |                                                          SkTileMode::kClamp)); | 
 |         } | 
 |  | 
 |         SkMatrix rotate; | 
 |         // This value was chosen so that we frequently hit the axis-aligned case. | 
 |         rotate.setRotate(30.f, kRectW / 2, kRectH / 2); | 
 |         SkMatrix m = rotate; | 
 |  | 
 |         SkScalar tx = 0, ty = 0; | 
 |  | 
 |         if (fPerspective) { | 
 |             // Apply some fixed perspective to change how ops may draw the rects | 
 |             SkMatrix perspective; | 
 |             perspective.setIdentity(); | 
 |             perspective.setPerspX(1e-4f); | 
 |             perspective.setPerspY(1e-3f); | 
 |             perspective.setSkewX(0.1f); | 
 |             canvas->concat(perspective); | 
 |         } | 
 |  | 
 |         for (int i = 0; i < loops; ++i) { | 
 |             canvas->save(); | 
 |             canvas->translate(tx, ty); | 
 |             canvas->concat(m); | 
 |             paint.setColor(color); | 
 |             color = advance_color(color, fColorType, i); | 
 |  | 
 |             canvas->drawRect(SkRect::MakeWH(kRectW, kRectH), paint); | 
 |             canvas->restore(); | 
 |  | 
 |             tx += kRectW + 2; | 
 |             if (tx > w) { | 
 |                 tx = 0; | 
 |                 ty += kRectH + 2; | 
 |                 if (ty > h) { | 
 |                     ty = 0; | 
 |                 } | 
 |             } | 
 |  | 
 |             m.postConcat(rotate); | 
 |         } | 
 |     } | 
 |  | 
 | private: | 
 |     void makeName() { | 
 |         fName = "rotated_rects"; | 
 |         if (fAA) { | 
 |             fName.append("_aa"); | 
 |         } else { | 
 |             fName.append("_bw"); | 
 |         } | 
 |         if (fPerspective) { | 
 |             fName.append("_persp"); | 
 |         } | 
 |         switch (fColorType) { | 
 |             case kConstantOpaque_ColorType: | 
 |                 fName.append("_same_opaque"); | 
 |                 break; | 
 |             case kConstantTransparent_ColorType: | 
 |                 fName.append("_same_transparent"); | 
 |                 break; | 
 |             case kChangingOpaque_ColorType: | 
 |                 fName.append("_changing_opaque"); | 
 |                 break; | 
 |             case kChangingTransparent_ColorType: | 
 |                 fName.append("_changing_transparent"); | 
 |                 break; | 
 |             case kAlternatingOpaqueAndTransparent_ColorType: | 
 |                 fName.append("_alternating_transparent_and_opaque"); | 
 |                 break; | 
 |             case kShaderOpaque_ColorType: | 
 |                 fName.append("_shader_opaque"); | 
 |                 break; | 
 |         } | 
 |         fName.appendf("_%s", to_lower(SkBlendMode_Name(fMode)).c_str()); | 
 |     } | 
 |  | 
 |     bool        fAA; | 
 |     bool        fPerspective; | 
 |     ColorType   fColorType; | 
 |     SkBlendMode fMode; | 
 |     SkString    fName; | 
 |  | 
 |     typedef Benchmark INHERITED; | 
 | }; | 
 |  | 
 | #define DEF_FOR_COLOR_TYPES(aa, blend) \ | 
 |     DEF_BENCH(return new RotRectBench(aa,  kConstantOpaque_ColorType,                  blend);) \ | 
 |     DEF_BENCH(return new RotRectBench(aa,  kConstantTransparent_ColorType,             blend);) \ | 
 |     DEF_BENCH(return new RotRectBench(aa,  kChangingOpaque_ColorType,                  blend);) \ | 
 |     DEF_BENCH(return new RotRectBench(aa,  kChangingTransparent_ColorType,             blend);) \ | 
 |     DEF_BENCH(return new RotRectBench(aa,  kAlternatingOpaqueAndTransparent_ColorType, blend);) \ | 
 |     DEF_BENCH(return new RotRectBench(aa,  kShaderOpaque_ColorType,                    blend);) | 
 | #define DEF_FOR_AA_MODES(blend) \ | 
 |     DEF_FOR_COLOR_TYPES(true, blend) \ | 
 |     DEF_FOR_COLOR_TYPES(false, blend) | 
 |  | 
 | // Choose kSrcOver because it always allows coverage and alpha to be conflated. kSrc only allows | 
 | // conflation when opaque, and kDarken because it isn't possilbe with standard GL blending. | 
 | DEF_FOR_AA_MODES(SkBlendMode::kSrcOver) | 
 | DEF_FOR_AA_MODES(SkBlendMode::kSrc) | 
 | DEF_FOR_AA_MODES(SkBlendMode::kDarken) | 
 |  | 
 | // Only do a limited run of perspective tests | 
 | #define DEF_FOR_PERSP_MODES(aa) \ | 
 |     DEF_BENCH(return new RotRectBench(aa, kConstantOpaque_ColorType, SkBlendMode::kSrcOver, true);)\ | 
 |     DEF_BENCH(return new RotRectBench(aa, kShaderOpaque_ColorType, SkBlendMode::kSrcOver, true);) | 
 | DEF_FOR_PERSP_MODES(true) | 
 | DEF_FOR_PERSP_MODES(false) |