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