benchmain.cpp revision d34658a5f1b961e2852c2272ac8b47701a42e50d
1#include "SkCanvas.h" 2#include "SkColorPriv.h" 3#include "SkGraphics.h" 4#include "SkImageEncoder.h" 5#include "SkNWayCanvas.h" 6#include "SkPicture.h" 7#include "SkString.h" 8#include "SkTime.h" 9 10#include "SkBenchmark.h" 11 12#ifdef ANDROID 13static void log_error(const char msg[]) { SkDebugf("%s", msg); } 14static void log_progress(const char msg[]) { SkDebugf("%s", msg); } 15#else 16static void log_error(const char msg[]) { fprintf(stderr, "%s", msg); } 17static void log_progress(const char msg[]) { printf("%s", msg); } 18#endif 19 20static void log_error(const SkString& str) { log_error(str.c_str()); } 21static void log_progress(const SkString& str) { log_progress(str.c_str()); } 22 23/////////////////////////////////////////////////////////////////////////////// 24 25static void erase(SkBitmap& bm) { 26 if (bm.config() == SkBitmap::kA8_Config) { 27 bm.eraseColor(0); 28 } else { 29 bm.eraseColor(SK_ColorWHITE); 30 } 31} 32 33static bool equal(const SkBitmap& bm1, const SkBitmap& bm2) { 34 if (bm1.width() != bm2.width() || 35 bm1.height() != bm2.height() || 36 bm1.config() != bm2.config()) { 37 return false; 38 } 39 40 size_t pixelBytes = bm1.width() * bm1.bytesPerPixel(); 41 for (int y = 0; y < bm1.height(); y++) { 42 if (memcmp(bm1.getAddr(0, y), bm2.getAddr(0, y), pixelBytes)) { 43 return false; 44 } 45 } 46 47 return true; 48} 49 50class Iter { 51public: 52 Iter(void* param) { 53 fBench = BenchRegistry::Head(); 54 fParam = param; 55 } 56 57 SkBenchmark* next() { 58 if (fBench) { 59 BenchRegistry::Factory f = fBench->factory(); 60 fBench = fBench->next(); 61 return f(fParam); 62 } 63 return NULL; 64 } 65 66private: 67 const BenchRegistry* fBench; 68 void* fParam; 69}; 70 71static void make_filename(const char name[], SkString* path) { 72 path->set(name); 73 for (int i = 0; name[i]; i++) { 74 switch (name[i]) { 75 case '/': 76 case '\\': 77 case ' ': 78 case ':': 79 path->writable_str()[i] = '-'; 80 break; 81 default: 82 break; 83 } 84 } 85} 86 87static void saveFile(const char name[], const char config[], const char dir[], 88 const SkBitmap& bm) { 89 SkBitmap copy; 90 if (!bm.copyTo(©, SkBitmap::kARGB_8888_Config)) { 91 return; 92 } 93 94 if (bm.config() == SkBitmap::kA8_Config) { 95 // turn alpha into gray-scale 96 size_t size = copy.getSize() >> 2; 97 SkPMColor* p = copy.getAddr32(0, 0); 98 for (size_t i = 0; i < size; i++) { 99 int c = (*p >> SK_A32_SHIFT) & 0xFF; 100 c = 255 - c; 101 c |= (c << 24) | (c << 16) | (c << 8); 102 *p++ = c | (SK_A32_MASK << SK_A32_SHIFT); 103 } 104 } 105 106 SkString str; 107 make_filename(name, &str); 108 str.appendf("_%s.png", config); 109 str.prepend(dir); 110 ::remove(str.c_str()); 111 SkImageEncoder::EncodeFile(str.c_str(), copy, SkImageEncoder::kPNG_Type, 112 100); 113} 114 115static void performClip(SkCanvas* canvas, int w, int h) { 116 SkRect r; 117 118 r.set(SkIntToScalar(10), SkIntToScalar(10), 119 SkIntToScalar(w*2/3), SkIntToScalar(h*2/3)); 120 canvas->clipRect(r, SkRegion::kIntersect_Op); 121 122 r.set(SkIntToScalar(w/3), SkIntToScalar(h/3), 123 SkIntToScalar(w-10), SkIntToScalar(h-10)); 124 canvas->clipRect(r, SkRegion::kXOR_Op); 125} 126 127static void performRotate(SkCanvas* canvas, int w, int h) { 128 const SkScalar x = SkIntToScalar(w) / 2; 129 const SkScalar y = SkIntToScalar(h) / 2; 130 131 canvas->translate(x, y); 132 canvas->rotate(SkIntToScalar(35)); 133 canvas->translate(-x, -y); 134} 135 136static void performScale(SkCanvas* canvas, int w, int h) { 137 const SkScalar x = SkIntToScalar(w) / 2; 138 const SkScalar y = SkIntToScalar(h) / 2; 139 140 canvas->translate(x, y); 141 // just enough so we can't take the sprite case 142 canvas->scale(SK_Scalar1 * 99/100, SK_Scalar1 * 99/100); 143 canvas->translate(-x, -y); 144} 145 146static void compare_pict_to_bitmap(SkPicture* pict, const SkBitmap& bm) { 147 SkBitmap bm2; 148 149 bm2.setConfig(bm.config(), bm.width(), bm.height()); 150 bm2.allocPixels(); 151 erase(bm2); 152 153 SkCanvas canvas(bm2); 154 canvas.drawPicture(*pict); 155 156 if (!equal(bm, bm2)) { 157 SkDebugf("----- compare_pict_to_bitmap failed\n"); 158 } 159} 160 161static bool parse_bool_arg(char * const* argv, char* const* stop, bool* var) { 162 if (argv < stop) { 163 *var = atoi(*argv) != 0; 164 return true; 165 } 166 return false; 167} 168 169static const struct { 170 SkBitmap::Config fConfig; 171 const char* fName; 172} gConfigs[] = { 173 { SkBitmap::kARGB_8888_Config, "8888" }, 174 { SkBitmap::kRGB_565_Config, "565", }, 175#if 0 176 { SkBitmap::kARGB_4444_Config, "4444", }, 177 { SkBitmap::kA8_Config, "A8", } 178#endif 179}; 180 181static int findConfig(const char config[]) { 182 for (size_t i = 0; i < SK_ARRAY_COUNT(gConfigs); i++) { 183 if (!strcmp(config, gConfigs[i].fName)) { 184 return i; 185 } 186 } 187 return -1; 188} 189 190int main (int argc, char * const argv[]) { 191 SkAutoGraphics ag; 192 193 SkTDict<const char*> defineDict(1024); 194 int repeatDraw = 1; 195 int forceAlpha = 0xFF; 196 bool forceAA = true; 197 bool forceFilter = false; 198 SkTriState::State forceDither = SkTriState::kDefault; 199 bool doScale = false; 200 bool doRotate = false; 201 bool doClip = false; 202 bool doPict = false; 203 const char* matchStr = NULL; 204 bool hasStrokeWidth = false; 205 float strokeWidth; 206 207 SkString outDir; 208 SkBitmap::Config outConfig = SkBitmap::kNo_Config; 209 const char* configName = ""; 210 int configCount = SK_ARRAY_COUNT(gConfigs); 211 212 char* const* stop = argv + argc; 213 for (++argv; argv < stop; ++argv) { 214 if (strcmp(*argv, "-o") == 0) { 215 argv++; 216 if (argv < stop && **argv) { 217 outDir.set(*argv); 218 if (outDir.c_str()[outDir.size() - 1] != '/') { 219 outDir.append("/"); 220 } 221 } 222 } else if (strcmp(*argv, "-pict") == 0) { 223 doPict = true; 224 } else if (strcmp(*argv, "-repeat") == 0) { 225 argv++; 226 if (argv < stop) { 227 repeatDraw = atoi(*argv); 228 if (repeatDraw < 1) { 229 repeatDraw = 1; 230 } 231 } else { 232 log_error("missing arg for -repeat\n"); 233 return -1; 234 } 235 } else if (!strcmp(*argv, "-rotate")) { 236 doRotate = true; 237 } else if (!strcmp(*argv, "-scale")) { 238 doScale = true; 239 } else if (!strcmp(*argv, "-clip")) { 240 doClip = true; 241 } else if (strcmp(*argv, "-forceAA") == 0) { 242 if (!parse_bool_arg(++argv, stop, &forceAA)) { 243 log_error("missing arg for -forceAA\n"); 244 return -1; 245 } 246 } else if (strcmp(*argv, "-forceFilter") == 0) { 247 if (!parse_bool_arg(++argv, stop, &forceFilter)) { 248 log_error("missing arg for -forceFilter\n"); 249 return -1; 250 } 251 } else if (strcmp(*argv, "-forceDither") == 0) { 252 bool tmp; 253 if (!parse_bool_arg(++argv, stop, &tmp)) { 254 log_error("missing arg for -forceDither\n"); 255 return -1; 256 } 257 forceDither = tmp ? SkTriState::kTrue : SkTriState::kFalse; 258 } else if (strcmp(*argv, "-forceBlend") == 0) { 259 bool wantAlpha = false; 260 if (!parse_bool_arg(++argv, stop, &wantAlpha)) { 261 log_error("missing arg for -forceBlend\n"); 262 return -1; 263 } 264 forceAlpha = wantAlpha ? 0x80 : 0xFF; 265 } else if (strcmp(*argv, "-strokeWidth") == 0) { 266 argv++; 267 if (argv < stop) { 268 const char *strokeWidthStr = *argv; 269 if (sscanf(strokeWidthStr, "%f", &strokeWidth) != 1) { 270 log_error("bad arg for -strokeWidth\n"); 271 return -1; 272 } 273 hasStrokeWidth = true; 274 } else { 275 log_error("missing arg for -strokeWidth\n"); 276 return -1; 277 } 278 } else if (strcmp(*argv, "-match") == 0) { 279 argv++; 280 if (argv < stop) { 281 matchStr = *argv; 282 } else { 283 log_error("missing arg for -match\n"); 284 return -1; 285 } 286 } else if (strcmp(*argv, "-config") == 0) { 287 argv++; 288 if (argv < stop) { 289 int index = findConfig(*argv); 290 if (index >= 0) { 291 outConfig = gConfigs[index].fConfig; 292 configName = gConfigs[index].fName; 293 configCount = 1; 294 } else { 295 SkString str; 296 str.printf("unrecognized config %s\n", *argv); 297 log_error(str); 298 return -1; 299 } 300 } else { 301 log_error("missing arg for -config\n"); 302 return -1; 303 } 304 } else if (strlen(*argv) > 2 && strncmp(*argv, "-D", 2) == 0) { 305 argv++; 306 if (argv < stop) { 307 defineDict.set(argv[-1] + 2, *argv); 308 } else { 309 log_error("incomplete '-Dfoo bar' definition\n"); 310 return -1; 311 } 312 } else { 313 SkString str; 314 str.printf("unrecognized arg %s\n", *argv); 315 log_error(str); 316 return -1; 317 } 318 } 319 320 // report our current settings 321 { 322 SkString str; 323 str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d\n", 324 forceAlpha, forceAA, forceFilter); 325 log_progress(str); 326 } 327 328 Iter iter(&defineDict); 329 SkBenchmark* bench; 330 while ((bench = iter.next()) != NULL) { 331 SkIPoint dim = bench->getSize(); 332 if (dim.fX <= 0 || dim.fY <= 0) { 333 continue; 334 } 335 336 bench->setForceAlpha(forceAlpha); 337 bench->setForceAA(forceAA); 338 bench->setForceFilter(forceFilter); 339 bench->setDither(forceDither); 340 if (hasStrokeWidth) { 341 bench->setStrokeWidth(strokeWidth); 342 } 343 344 // only run benchmarks if their name contains matchStr 345 if (matchStr && strstr(bench->getName(), matchStr) == NULL) { 346 continue; 347 } 348 349 { 350 SkString str; 351 str.printf("running bench [%d %d] %28s", dim.fX, dim.fY, 352 bench->getName()); 353 log_progress(str); 354 } 355 356 for (int configIndex = 0; configIndex < configCount; configIndex++) { 357 if (configCount > 1) { 358 outConfig = gConfigs[configIndex].fConfig; 359 configName = gConfigs[configIndex].fName; 360 } 361 362 SkBitmap bm; 363 bm.setConfig(outConfig, dim.fX, dim.fY); 364 bm.allocPixels(); 365 erase(bm); 366 367 SkCanvas canvas(bm); 368 369 if (doClip) { 370 performClip(&canvas, dim.fX, dim.fY); 371 } 372 if (doScale) { 373 performScale(&canvas, dim.fX, dim.fY); 374 } 375 if (doRotate) { 376 performRotate(&canvas, dim.fX, dim.fY); 377 } 378 379 if (repeatDraw > 1) { 380 SkAutoCanvasRestore acr(&canvas, true); 381 bench->draw(&canvas); 382 } 383 384 SkMSec now = SkTime::GetMSecs(); 385 for (int i = 0; i < repeatDraw; i++) { 386 SkCanvas* c = &canvas; 387 388 SkNWayCanvas nway; 389 SkPicture* pict = NULL; 390 if (doPict) { 391 pict = new SkPicture; 392 nway.addCanvas(pict->beginRecording(bm.width(), bm.height())); 393 nway.addCanvas(&canvas); 394 c = &nway; 395 } 396 397 SkAutoCanvasRestore acr(c, true); 398 bench->draw(c); 399 400 if (pict) { 401 compare_pict_to_bitmap(pict, bm); 402 pict->unref(); 403 } 404 } 405 if (repeatDraw > 1) { 406 double duration = SkTime::GetMSecs() - now; 407 SkString str; 408 str.printf(" %4s: msecs = %5.2f", configName, duration / repeatDraw); 409 log_progress(str); 410 } 411 if (outDir.size() > 0) { 412 saveFile(bench->getName(), configName, outDir.c_str(), bm); 413 } 414 } 415 log_progress("\n"); 416 } 417 418 return 0; 419} 420