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