Home | History | Annotate | Download | only in bench
      1 /*
      2  * Copyright 2011 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 "SkBitmap.h"
     10 #include "SkCanvas.h"
     11 #include "SkColorPriv.h"
     12 #include "SkPaint.h"
     13 #include "SkRandom.h"
     14 #include "SkString.h"
     15 #include "sk_tool_utils.h"
     16 
     17 /*  Variants for bitmaps
     18 
     19     - src depth (32 w+w/o alpha), 565, 4444, index, a8
     20     - paint options: filtering, dither, alpha
     21     - matrix options: translate, scale, rotate, persp
     22     - tiling: none, repeat, mirror, clamp
     23 
     24  */
     25 
     26 class BitmapBench : public Benchmark {
     27     const SkColorType   fColorType;
     28     const SkAlphaType   fAlphaType;
     29     const bool          fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
     30     const bool          fIsVolatile;
     31     const bool          fDoScale;
     32 
     33     SkBitmap            fBitmap;
     34     SkPaint             fPaint;
     35     SkString            fName;
     36 
     37     enum { W = 128 };
     38     enum { H = 128 };
     39 public:
     40     BitmapBench(SkColorType ct, SkAlphaType at, bool forceUpdate, bool isVolatile, bool doScale)
     41         : fColorType(ct)
     42         , fAlphaType(at)
     43         , fForceUpdate(forceUpdate)
     44         , fIsVolatile(isVolatile)
     45         , fDoScale(doScale)
     46     {}
     47 
     48 protected:
     49     const char* onGetName() override {
     50         fName.set("bitmap");
     51         fName.appendf("_%s%s", sk_tool_utils::colortype_name(fColorType),
     52                       kOpaque_SkAlphaType == fAlphaType ? "" : "_A");
     53         if (fDoScale) {
     54             fName.append("_scale");
     55         }
     56         if (fForceUpdate) {
     57             fName.append("_update");
     58         }
     59         if (fIsVolatile) {
     60             fName.append("_volatile");
     61         }
     62 
     63         return fName.c_str();
     64     }
     65 
     66     void onDelayedSetup() override {
     67         SkBitmap bm;
     68 
     69         bm.allocPixels(SkImageInfo::Make(W, H, fColorType, fAlphaType));
     70         bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0);
     71 
     72         this->onDrawIntoBitmap(bm);
     73 
     74         fBitmap = bm;
     75         fBitmap.setIsVolatile(fIsVolatile);
     76     }
     77 
     78     void onDraw(int loops, SkCanvas* canvas) override {
     79         if (fDoScale) {
     80             canvas->scale(.99f, .99f);
     81         }
     82         SkIPoint dim = this->getSize();
     83         SkRandom rand;
     84 
     85         SkPaint paint(fPaint);
     86         this->setupPaint(&paint);
     87 
     88         const SkBitmap& bitmap = fBitmap;
     89         const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
     90         const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
     91 
     92         for (int i = 0; i < loops; i++) {
     93             SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
     94             SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
     95 
     96             if (fForceUpdate)
     97                 bitmap.notifyPixelsChanged();
     98 
     99             canvas->drawBitmap(bitmap, x, y, &paint);
    100         }
    101     }
    102 
    103      virtual void onDrawIntoBitmap(const SkBitmap& bm) {
    104         const int w = bm.width();
    105         const int h = bm.height();
    106 
    107         SkCanvas canvas(bm);
    108         SkPaint p;
    109         p.setAntiAlias(true);
    110         p.setColor(SK_ColorRED);
    111         canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
    112                           SkIntToScalar(SkMin32(w, h))*3/8, p);
    113 
    114         SkRect r;
    115         r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
    116         p.setStyle(SkPaint::kStroke_Style);
    117         p.setStrokeWidth(SkIntToScalar(4));
    118         p.setColor(SK_ColorBLUE);
    119         canvas.drawRect(r, p);
    120     }
    121 
    122 private:
    123     typedef Benchmark INHERITED;
    124 };
    125 
    126 /** Explicitly invoke some filter types to improve coverage of acceleration
    127     procs. */
    128 
    129 enum Flags {
    130     kScale_Flag             = 1 << 0,
    131     kRotate_Flag            = 1 << 1,
    132     kBilerp_Flag            = 1 << 2,
    133     kBicubic_Flag           = 1 << 3,
    134 };
    135 
    136 static bool isBilerp(uint32_t flags) {
    137     return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
    138 }
    139 
    140 static bool isBicubic(uint32_t flags) {
    141     return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
    142 }
    143 
    144 class FilterBitmapBench : public BitmapBench {
    145     uint32_t    fFlags;
    146     SkString    fFullName;
    147 public:
    148     FilterBitmapBench(SkColorType ct, SkAlphaType at,
    149                       bool forceUpdate, bool isVolitile, uint32_t flags)
    150         : INHERITED(ct, at, forceUpdate, isVolitile, false)
    151         , fFlags(flags) {
    152     }
    153 
    154 protected:
    155     const char* onGetName() override {
    156         fFullName.set(INHERITED::onGetName());
    157         if (fFlags & kScale_Flag) {
    158             fFullName.append("_scale");
    159         }
    160         if (fFlags & kRotate_Flag) {
    161             fFullName.append("_rotate");
    162         }
    163         if (isBilerp(fFlags)) {
    164             fFullName.append("_bilerp");
    165         } else if (isBicubic(fFlags)) {
    166             fFullName.append("_bicubic");
    167         }
    168 
    169         return fFullName.c_str();
    170     }
    171 
    172     void onDraw(int loops, SkCanvas* canvas) override {
    173         SkISize dim = canvas->getBaseLayerSize();
    174         if (fFlags & kScale_Flag) {
    175             const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
    176             const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
    177 
    178             canvas->translate(x, y);
    179             // just enough so we can't take the sprite case
    180             canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
    181             canvas->translate(-x, -y);
    182         }
    183         if (fFlags & kRotate_Flag) {
    184             const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
    185             const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
    186             canvas->rotate(SkIntToScalar(35), x, y);
    187         }
    188         INHERITED::onDraw(loops, canvas);
    189     }
    190 
    191     void setupPaint(SkPaint* paint) override {
    192         this->INHERITED::setupPaint(paint);
    193 
    194         int index = 0;
    195         if (fFlags & kBilerp_Flag) {
    196             index |= 1;
    197         }
    198         if (fFlags & kBicubic_Flag) {
    199             index |= 2;
    200         }
    201         static const SkFilterQuality gQualitys[] = {
    202             kNone_SkFilterQuality,
    203             kLow_SkFilterQuality,
    204             kMedium_SkFilterQuality,
    205             kHigh_SkFilterQuality
    206         };
    207         paint->setFilterQuality(gQualitys[index]);
    208 }
    209 
    210 private:
    211     typedef BitmapBench INHERITED;
    212 };
    213 
    214 /** Verify optimizations that test source alpha values. */
    215 
    216 class SourceAlphaBitmapBench : public BitmapBench {
    217 public:
    218     enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
    219                        kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
    220 private:
    221     SkString    fFullName;
    222     SourceAlpha fSourceAlpha;
    223 public:
    224     SourceAlphaBitmapBench(SourceAlpha alpha, SkColorType ct,
    225                 bool forceUpdate = false, bool bitmapVolatile = false)
    226         : INHERITED(ct, kPremul_SkAlphaType, forceUpdate, bitmapVolatile, false)
    227         , fSourceAlpha(alpha) {
    228     }
    229 
    230 protected:
    231     const char* onGetName() override {
    232         fFullName.set(INHERITED::onGetName());
    233 
    234         if (fSourceAlpha == kOpaque_SourceAlpha) {
    235                 fFullName.append("_source_opaque");
    236         } else if (fSourceAlpha == kTransparent_SourceAlpha) {
    237                 fFullName.append("_source_transparent");
    238         } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
    239                 fFullName.append("_source_stripes_two");
    240         } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
    241                 fFullName.append("_source_stripes_three");
    242         }
    243 
    244         return fFullName.c_str();
    245     }
    246 
    247     void onDrawIntoBitmap(const SkBitmap& bm) override {
    248         const int w = bm.width();
    249         const int h = bm.height();
    250 
    251         if (kOpaque_SourceAlpha == fSourceAlpha) {
    252             bm.eraseColor(SK_ColorBLACK);
    253         } else if (kTransparent_SourceAlpha == fSourceAlpha) {
    254             bm.eraseColor(0);
    255         } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
    256             bm.eraseColor(0);
    257 
    258             SkCanvas canvas(bm);
    259             SkPaint p;
    260             p.setAntiAlias(false);
    261             p.setStyle(SkPaint::kFill_Style);
    262             p.setColor(SK_ColorRED);
    263 
    264             // Draw red vertical stripes on transparent background
    265             SkRect r;
    266             for (int x = 0; x < w; x+=2)
    267             {
    268                 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
    269                 canvas.drawRect(r, p);
    270             }
    271 
    272         } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
    273             bm.eraseColor(0);
    274 
    275             SkCanvas canvas(bm);
    276             SkPaint p;
    277             p.setAntiAlias(false);
    278             p.setStyle(SkPaint::kFill_Style);
    279 
    280             // Draw vertical stripes on transparent background with a pattern
    281             // where the first pixel is fully transparent, the next is semi-transparent
    282             // and the third is fully opaque.
    283             SkRect r;
    284             for (int x = 0; x < w; x++)
    285             {
    286                 if (x % 3 == 0) {
    287                     continue; // Keep transparent
    288                 } else if (x % 3 == 1) {
    289                     p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
    290                 } else if (x % 3 == 2) {
    291                     p.setColor(SK_ColorRED); // Opaque
    292                 }
    293                 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
    294                 canvas.drawRect(r, p);
    295             }
    296         }
    297     }
    298 
    299 private:
    300     typedef BitmapBench INHERITED;
    301 };
    302 
    303 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, false); )
    304 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, false); )
    305 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, true); )
    306 DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType, false, false, false); )
    307 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, false); )
    308 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, false); )
    309 
    310 // scale filter -> S32_opaque_D32_filter_DX_{SSE2,SSSE3} and Fact9 is also for S32_D16_filter_DX_SSE2
    311 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
    312 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
    313 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kBilerp_Flag); )
    314 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kBilerp_Flag); )
    315 
    316 // The following two cases test the performance regression of b/70172912 .
    317 DEF_BENCH( return new FilterBitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
    318 DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType, false, false, true); )
    319 
    320 // scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
    321 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
    322 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
    323 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
    324 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
    325 
    326 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
    327 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag | kBicubic_Flag); )
    328 
    329 // source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
    330 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, kN32_SkColorType); )
    331 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, kN32_SkColorType); )
    332 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, kN32_SkColorType); )
    333 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, kN32_SkColorType); )
    334