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