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