| /* |
| * 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 "SkGradientShader.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, |
| 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."); |
| 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: |
| 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."); |
| 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, 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, |
| SkShader::kClamp_TileMode)); |
| } |
| |
| 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) |