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