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