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