|  | /* | 
|  | * 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 "Benchmark.h" | 
|  | #include "SkBlendModePriv.h" | 
|  | #include "SkCanvas.h" | 
|  | #include "SkPaint.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, | 
|  | }; | 
|  |  | 
|  | 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; | 
|  | } | 
|  | SkFAIL("Shouldn't reach here."); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | 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: | 
|  | return old; | 
|  | case kChangingOpaque_ColorType: | 
|  | return 0xFF000000 | (old + 0x00010307); | 
|  | case kChangingTransparent_ColorType: | 
|  | return (0x00FFFFFF & (old + 0x00010307)) | 0x80000000; | 
|  | case kAlternatingOpaqueAndTransparent_ColorType: | 
|  | SkFAIL("Can't get here"); | 
|  | } | 
|  | SkFAIL("Shouldn't reach here."); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | 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) | 
|  | : fAA(aa) | 
|  | , 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; | 
|  |  | 
|  | 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; | 
|  |  | 
|  | 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"); | 
|  | } | 
|  | 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; | 
|  | } | 
|  | fName.appendf("_%s", to_lower(SkBlendMode_Name(fMode)).c_str()); | 
|  | } | 
|  |  | 
|  | bool        fAA; | 
|  | ColorType   fColorType; | 
|  | SkBlendMode fMode; | 
|  | SkString    fName; | 
|  |  | 
|  | typedef Benchmark INHERITED; | 
|  | }; | 
|  |  | 
|  | // 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_BENCH(return new RotRectBench(true,  kConstantOpaque_ColorType,                  SkBlendMode::kSrcOver);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kConstantTransparent_ColorType,             SkBlendMode::kSrcOver);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kChangingOpaque_ColorType,                  SkBlendMode::kSrcOver);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kChangingTransparent_ColorType,             SkBlendMode::kSrcOver);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kSrcOver);) | 
|  |  | 
|  | DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType,                  SkBlendMode::kSrcOver);) | 
|  | DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType,             SkBlendMode::kSrcOver);) | 
|  | DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType,                  SkBlendMode::kSrcOver);) | 
|  | DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType,             SkBlendMode::kSrcOver);) | 
|  | DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kSrcOver);) | 
|  |  | 
|  | DEF_BENCH(return new RotRectBench(true,  kConstantOpaque_ColorType,                  SkBlendMode::kSrc);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kConstantTransparent_ColorType,             SkBlendMode::kSrc);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kChangingOpaque_ColorType,                  SkBlendMode::kSrc);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kChangingTransparent_ColorType,             SkBlendMode::kSrc);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kSrc);) | 
|  |  | 
|  | DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType,                  SkBlendMode::kSrc);) | 
|  | DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType,             SkBlendMode::kSrc);) | 
|  | DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType,                  SkBlendMode::kSrc);) | 
|  | DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType,             SkBlendMode::kSrc);) | 
|  | DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kSrc);) | 
|  |  | 
|  | DEF_BENCH(return new RotRectBench(true,  kConstantOpaque_ColorType,                  SkBlendMode::kDarken);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kConstantTransparent_ColorType,             SkBlendMode::kDarken);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kChangingOpaque_ColorType,                  SkBlendMode::kDarken);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kChangingTransparent_ColorType,             SkBlendMode::kDarken);) | 
|  | DEF_BENCH(return new RotRectBench(true,  kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kDarken);) | 
|  |  | 
|  | DEF_BENCH(return new RotRectBench(false, kConstantOpaque_ColorType,                  SkBlendMode::kDarken);) | 
|  | DEF_BENCH(return new RotRectBench(false, kConstantTransparent_ColorType,             SkBlendMode::kDarken);) | 
|  | DEF_BENCH(return new RotRectBench(false, kChangingOpaque_ColorType,                  SkBlendMode::kDarken);) | 
|  | DEF_BENCH(return new RotRectBench(false, kChangingTransparent_ColorType,             SkBlendMode::kDarken);) | 
|  | DEF_BENCH(return new RotRectBench(false, kAlternatingOpaqueAndTransparent_ColorType, SkBlendMode::kDarken);) |