Home | History | Annotate | Download | only in bench
      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