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, aType);
     48     dst->allocPixels(SkImageInfo::Make(src.width(), src.height(), kIndex_8_SkColorType, aType),
     49                      NULL, 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 
     79     SkBitmap            fBitmap;
     80     SkPaint             fPaint;
     81     SkString            fName;
     82 
     83     enum { W = 128 };
     84     enum { H = 128 };
     85 public:
     86     BitmapBench(SkColorType ct, SkAlphaType at, bool forceUpdate = false, bool isVolatile = false)
     87         : fColorType(ct)
     88         , fAlphaType(at)
     89         , fForceUpdate(forceUpdate)
     90         , fIsVolatile(isVolatile)
     91     {}
     92 
     93 protected:
     94     virtual const char* onGetName() {
     95         fName.set("bitmap");
     96         fName.appendf("_%s%s", sk_tool_utils::colortype_name(fColorType),
     97                       kOpaque_SkAlphaType == fAlphaType ? "" : "_A");
     98         if (fForceUpdate)
     99             fName.append("_update");
    100         if (fIsVolatile)
    101             fName.append("_volatile");
    102 
    103         return fName.c_str();
    104     }
    105 
    106     virtual void onPreDraw() {
    107         SkBitmap bm;
    108 
    109         if (kIndex_8_SkColorType == fColorType) {
    110             bm.setInfo(SkImageInfo::MakeN32(W, H, fAlphaType));
    111         } else {
    112             bm.setInfo(SkImageInfo::Make(W, H, fColorType, fAlphaType));
    113         }
    114 
    115         bm.allocPixels();
    116         bm.eraseColor(kOpaque_SkAlphaType == fAlphaType ? SK_ColorBLACK : 0);
    117 
    118         onDrawIntoBitmap(bm);
    119 
    120         if (kIndex_8_SkColorType == fColorType) {
    121             convertToIndex666(bm, &fBitmap, fAlphaType);
    122         } else {
    123             fBitmap = bm;
    124         }
    125 
    126         fBitmap.setIsVolatile(fIsVolatile);
    127     }
    128 
    129     virtual void onDraw(const int loops, SkCanvas* canvas) {
    130         SkIPoint dim = this->getSize();
    131         SkRandom rand;
    132 
    133         SkPaint paint(fPaint);
    134         this->setupPaint(&paint);
    135 
    136         const SkBitmap& bitmap = fBitmap;
    137         const SkScalar x0 = SkIntToScalar(-bitmap.width() / 2);
    138         const SkScalar y0 = SkIntToScalar(-bitmap.height() / 2);
    139 
    140         for (int i = 0; i < loops; i++) {
    141             SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
    142             SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
    143 
    144             if (fForceUpdate)
    145                 bitmap.notifyPixelsChanged();
    146 
    147             canvas->drawBitmap(bitmap, x, y, &paint);
    148         }
    149     }
    150 
    151     virtual void onDrawIntoBitmap(const SkBitmap& bm) {
    152         const int w = bm.width();
    153         const int h = bm.height();
    154 
    155         SkCanvas canvas(bm);
    156         SkPaint p;
    157         p.setAntiAlias(true);
    158         p.setColor(SK_ColorRED);
    159         canvas.drawCircle(SkIntToScalar(w)/2, SkIntToScalar(h)/2,
    160                           SkIntToScalar(SkMin32(w, h))*3/8, p);
    161 
    162         SkRect r;
    163         r.set(0, 0, SkIntToScalar(w), SkIntToScalar(h));
    164         p.setStyle(SkPaint::kStroke_Style);
    165         p.setStrokeWidth(SkIntToScalar(4));
    166         p.setColor(SK_ColorBLUE);
    167         canvas.drawRect(r, p);
    168     }
    169 
    170 private:
    171     typedef Benchmark INHERITED;
    172 };
    173 
    174 /** Explicitly invoke some filter types to improve coverage of acceleration
    175     procs. */
    176 
    177 enum Flags {
    178     kScale_Flag             = 1 << 0,
    179     kRotate_Flag            = 1 << 1,
    180     kBilerp_Flag            = 1 << 2,
    181     kBicubic_Flag           = 1 << 3,
    182 };
    183 
    184 static bool isBilerp(uint32_t flags) {
    185     return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag);
    186 }
    187 
    188 static bool isBicubic(uint32_t flags) {
    189     return (flags & (kBilerp_Flag | kBicubic_Flag)) == (kBilerp_Flag | kBicubic_Flag);
    190 }
    191 
    192 class FilterBitmapBench : public BitmapBench {
    193     uint32_t    fFlags;
    194     SkString    fFullName;
    195 public:
    196     FilterBitmapBench(SkColorType ct, SkAlphaType at,
    197                       bool forceUpdate, bool isVolitile, uint32_t flags)
    198         : INHERITED(ct, at, forceUpdate, isVolitile)
    199         , fFlags(flags) {
    200     }
    201 
    202 protected:
    203     virtual const char* onGetName() {
    204         fFullName.set(INHERITED::onGetName());
    205         if (fFlags & kScale_Flag) {
    206             fFullName.append("_scale");
    207         }
    208         if (fFlags & kRotate_Flag) {
    209             fFullName.append("_rotate");
    210         }
    211         if (isBilerp(fFlags)) {
    212             fFullName.append("_bilerp");
    213         } else if (isBicubic(fFlags)) {
    214             fFullName.append("_bicubic");
    215         }
    216 
    217         return fFullName.c_str();
    218     }
    219 
    220     virtual void onDraw(const int loops, SkCanvas* canvas) {
    221         SkISize dim = canvas->getDeviceSize();
    222         if (fFlags & kScale_Flag) {
    223             const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
    224             const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
    225 
    226             canvas->translate(x, y);
    227             // just enough so we can't take the sprite case
    228             canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100);
    229             canvas->translate(-x, -y);
    230         }
    231         if (fFlags & kRotate_Flag) {
    232             const SkScalar x = SkIntToScalar(dim.fWidth) / 2;
    233             const SkScalar y = SkIntToScalar(dim.fHeight) / 2;
    234 
    235             canvas->translate(x, y);
    236             canvas->rotate(SkIntToScalar(35));
    237             canvas->translate(-x, -y);
    238         }
    239         INHERITED::onDraw(loops, canvas);
    240     }
    241 
    242     virtual void setupPaint(SkPaint* paint) SK_OVERRIDE {
    243         this->INHERITED::setupPaint(paint);
    244 
    245         int index = 0;
    246         if (fFlags & kBilerp_Flag) {
    247             index |= 1;
    248         }
    249         if (fFlags & kBicubic_Flag) {
    250             index |= 2;
    251         }
    252         static const SkPaint::FilterLevel gLevels[] = {
    253             SkPaint::kNone_FilterLevel,
    254             SkPaint::kLow_FilterLevel,
    255             SkPaint::kMedium_FilterLevel,
    256             SkPaint::kHigh_FilterLevel
    257         };
    258         paint->setFilterLevel(gLevels[index]);
    259 }
    260 
    261 private:
    262     typedef BitmapBench INHERITED;
    263 };
    264 
    265 /** Verify optimizations that test source alpha values. */
    266 
    267 class SourceAlphaBitmapBench : public BitmapBench {
    268 public:
    269     enum SourceAlpha { kOpaque_SourceAlpha, kTransparent_SourceAlpha,
    270                        kTwoStripes_SourceAlpha, kThreeStripes_SourceAlpha};
    271 private:
    272     SkString    fFullName;
    273     SourceAlpha fSourceAlpha;
    274 public:
    275     SourceAlphaBitmapBench(SourceAlpha alpha, SkColorType ct,
    276                 bool forceUpdate = false, bool bitmapVolatile = false)
    277         : INHERITED(ct, kPremul_SkAlphaType, forceUpdate, bitmapVolatile)
    278         , fSourceAlpha(alpha) {
    279     }
    280 
    281 protected:
    282     virtual const char* onGetName() {
    283         fFullName.set(INHERITED::onGetName());
    284 
    285         if (fSourceAlpha == kOpaque_SourceAlpha) {
    286                 fFullName.append("_source_opaque");
    287         } else if (fSourceAlpha == kTransparent_SourceAlpha) {
    288                 fFullName.append("_source_transparent");
    289         } else if (fSourceAlpha == kTwoStripes_SourceAlpha) {
    290                 fFullName.append("_source_stripes_two");
    291         } else if (fSourceAlpha == kThreeStripes_SourceAlpha) {
    292                 fFullName.append("_source_stripes_three");
    293         }
    294 
    295         return fFullName.c_str();
    296     }
    297 
    298     virtual void onDrawIntoBitmap(const SkBitmap& bm) SK_OVERRIDE {
    299         const int w = bm.width();
    300         const int h = bm.height();
    301 
    302         if (kOpaque_SourceAlpha == fSourceAlpha) {
    303             bm.eraseColor(SK_ColorBLACK);
    304         } else if (kTransparent_SourceAlpha == fSourceAlpha) {
    305             bm.eraseColor(0);
    306         } else if (kTwoStripes_SourceAlpha == fSourceAlpha) {
    307             bm.eraseColor(0);
    308 
    309             SkCanvas canvas(bm);
    310             SkPaint p;
    311             p.setAntiAlias(false);
    312             p.setStyle(SkPaint::kFill_Style);
    313             p.setColor(SK_ColorRED);
    314 
    315             // Draw red vertical stripes on transparent background
    316             SkRect r;
    317             for (int x = 0; x < w; x+=2)
    318             {
    319                 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
    320                 canvas.drawRect(r, p);
    321             }
    322 
    323         } else if (kThreeStripes_SourceAlpha == fSourceAlpha) {
    324             bm.eraseColor(0);
    325 
    326             SkCanvas canvas(bm);
    327             SkPaint p;
    328             p.setAntiAlias(false);
    329             p.setStyle(SkPaint::kFill_Style);
    330 
    331             // Draw vertical stripes on transparent background with a pattern
    332             // where the first pixel is fully transparent, the next is semi-transparent
    333             // and the third is fully opaque.
    334             SkRect r;
    335             for (int x = 0; x < w; x++)
    336             {
    337                 if (x % 3 == 0) {
    338                     continue; // Keep transparent
    339                 } else if (x % 3 == 1) {
    340                     p.setColor(SkColorSetARGB(127, 127, 127, 127)); // Semi-transparent
    341                 } else if (x % 3 == 2) {
    342                     p.setColor(SK_ColorRED); // Opaque
    343                 }
    344                 r.set(SkIntToScalar(x), 0, SkIntToScalar(x+1), SkIntToScalar(h));
    345                 canvas.drawRect(r, p);
    346             }
    347         }
    348     }
    349 
    350 private:
    351     typedef BitmapBench INHERITED;
    352 };
    353 
    354 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kPremul_SkAlphaType); )
    355 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType); )
    356 DEF_BENCH( return new BitmapBench(kRGB_565_SkColorType, kOpaque_SkAlphaType); )
    357 DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kPremul_SkAlphaType); )
    358 DEF_BENCH( return new BitmapBench(kIndex_8_SkColorType, kOpaque_SkAlphaType); )
    359 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true); )
    360 DEF_BENCH( return new BitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false); )
    361 
    362 // scale filter -> S32_opaque_D32_filter_DX_{SSE2,SSSE3} and Fact9 is also for S32_D16_filter_DX_SSE2
    363 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
    364 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag); )
    365 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kBilerp_Flag); )
    366 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kBilerp_Flag); )
    367 
    368 // scale rotate filter -> S32_opaque_D32_filter_DXDY_{SSE2,SSSE3}
    369 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
    370 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
    371 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, true, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
    372 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kOpaque_SkAlphaType, true, false, kScale_Flag | kRotate_Flag | kBilerp_Flag); )
    373 
    374 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kBilerp_Flag | kBicubic_Flag); )
    375 DEF_BENCH( return new FilterBitmapBench(kN32_SkColorType, kPremul_SkAlphaType, false, false, kScale_Flag | kRotate_Flag | kBilerp_Flag | kBicubic_Flag); )
    376 
    377 // source alpha tests -> S32A_Opaque_BlitRow32_{arm,neon}
    378 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kOpaque_SourceAlpha, kN32_SkColorType); )
    379 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTransparent_SourceAlpha, kN32_SkColorType); )
    380 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kTwoStripes_SourceAlpha, kN32_SkColorType); )
    381 DEF_BENCH( return new SourceAlphaBitmapBench(SourceAlphaBitmapBench::kThreeStripes_SourceAlpha, kN32_SkColorType); )
    382