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