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