1 /*
2 * Copyright 2012 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 "BenchTimer.h"
9 #include "CopyTilesRenderer.h"
10 #include "PictureBenchmark.h"
11 #include "SkBenchLogger.h"
12 #include "SkCanvas.h"
13 #include "SkGraphics.h"
14 #include "SkImageDecoder.h"
15 #include "SkMath.h"
16 #include "SkOSFile.h"
17 #include "SkPicture.h"
18 #include "SkStream.h"
19 #include "SkTArray.h"
20 #include "picture_utils.h"
21
22 const int DEFAULT_REPEATS = 1;
23
24 static char const * const gFilterTypes[] = {
25 "paint",
26 "point",
27 "line",
28 "bitmap",
29 "rect",
30 "oval",
31 "path",
32 "text",
33 "all",
34 };
35
36 static const size_t kFilterTypesCount = sizeof(gFilterTypes) / sizeof(gFilterTypes[0]);
37
38 static char const * const gFilterFlags[] = {
39 "antiAlias",
40 "filterBitmap",
41 "dither",
42 "underlineText",
43 "strikeThruText",
44 "fakeBoldText",
45 "linearText",
46 "subpixelText",
47 "devKernText",
48 "LCDRenderText",
49 "embeddedBitmapText",
50 "autoHinting",
51 "verticalText",
52 "genA8FromLCD",
53 "blur",
54 "hinting",
55 "slightHinting",
56 "AAClip",
57 };
58
59 static const size_t kFilterFlagsCount = sizeof(gFilterFlags) / sizeof(gFilterFlags[0]);
60
filtersName(sk_tools::PictureRenderer::DrawFilterFlags * drawFilters)61 static SkString filtersName(sk_tools::PictureRenderer::DrawFilterFlags* drawFilters) {
62 int all = drawFilters[0];
63 size_t tIndex;
64 for (tIndex = 1; tIndex < SkDrawFilter::kTypeCount; ++tIndex) {
65 all &= drawFilters[tIndex];
66 }
67 SkString result;
68 for (size_t fIndex = 0; fIndex < kFilterFlagsCount; ++fIndex) {
69 SkString types;
70 if (all & (1 << fIndex)) {
71 types = gFilterTypes[SkDrawFilter::kTypeCount];
72 } else {
73 for (tIndex = 0; tIndex < SkDrawFilter::kTypeCount; ++tIndex) {
74 if (drawFilters[tIndex] & (1 << fIndex)) {
75 types += gFilterTypes[tIndex];
76 }
77 }
78 }
79 if (!types.size()) {
80 continue;
81 }
82 result += "_";
83 result += types;
84 result += ".";
85 result += gFilterFlags[fIndex];
86 }
87 return result;
88 }
89
filterTypesUsage()90 static SkString filterTypesUsage() {
91 SkString result;
92 for (size_t index = 0; index < kFilterTypesCount; ++index) {
93 result += gFilterTypes[index];
94 if (index < kFilterTypesCount - 1) {
95 result += " | ";
96 }
97 }
98 return result;
99 }
100
filterFlagsUsage()101 static SkString filterFlagsUsage() {
102 SkString result;
103 size_t len = 0;
104 for (size_t index = 0; index < kFilterFlagsCount; ++index) {
105 result += gFilterFlags[index];
106 if (result.size() - len >= 72) {
107 result += "\n ";
108 len = result.size();
109 }
110 if (index < kFilterFlagsCount - 1) {
111 result += " | ";
112 }
113 }
114 return result;
115 }
116
usage(const char * argv0)117 static void usage(const char* argv0) {
118 SkDebugf("SkPicture benchmarking tool\n");
119 SkDebugf("\n"
120 "Usage: \n"
121 " %s <inputDir>...\n"
122 " [--logFile filename][--timers [wcgWC]*][--logPerIter 1|0][--min]\n"
123 " [--repeat][--timeIndividualTiles] \n"
124 " [--mode pow2tile minWidth height | record | simple\n"
125 " | tile width height | playbackCreation]\n"
126 " [--pipe]\n"
127 " [--bbh bbhType]\n"
128 " [--multi numThreads]\n"
129 " [--viewport width height][--scale sf]\n"
130 " [--device bitmap"
131 #if SK_SUPPORT_GPU
132 " | gpu"
133 #endif
134 "]\n"
135 " [--filter [%s]:\n [%s]]\n"
136 , argv0, filterTypesUsage().c_str(), filterFlagsUsage().c_str());
137 SkDebugf("\n");
138 SkDebugf(
139 " inputDir: A list of directories and files to use as input. Files are\n"
140 " expected to have the .skp extension.\n\n"
141 " --logFile filename : destination for writing log output, in addition to stdout.\n");
142 SkDebugf(" --logPerIter 1|0 : "
143 "Log each repeat timer instead of mean, default is disabled.\n");
144 SkDebugf(" --min : Print the minimum times (instead of average).\n");
145 SkDebugf(" --timers [wcgWC]* : "
146 "Display wall, cpu, gpu, truncated wall or truncated cpu time for each picture.\n");
147 SkDebugf(" --timeIndividualTiles : Report times for drawing individual tiles, rather than\n"
148 " times for drawing the whole page.\n"
149 " Requires --mode tile\n");
150 SkDebugf(
151 " --mode pow2tile minWidth height | copyTile width height | record | simple\n"
152 " | tile width height | playbackCreation:\n"
153 " Run in the corresponding mode.\n"
154 " Default is simple.\n");
155 SkDebugf(
156 " pow2tile minWidth height, Creates tiles with widths\n"
157 " that are all a power of two\n"
158 " such that they minimize the\n"
159 " amount of wasted tile space.\n"
160 " minWidth is the minimum width\n"
161 " of these tiles and must be a\n"
162 " power of two. Simple\n"
163 " rendering using these tiles\n"
164 " is benchmarked.\n");
165 SkDebugf(
166 " record, Benchmark picture to picture recording.\n");
167 SkDebugf(
168 " simple, Benchmark a simple rendering.\n");
169 SkDebugf(
170 " tile width height, Benchmark simple rendering using\n"
171 " tiles with the given dimensions.\n"
172 " copyTile width height, Draw the picture, then copy it into tiles.\n"
173 " Does not support percentages.\n"
174 " If the picture is large enough, breaks it into\n"
175 " larger tiles (and draws the picture once per\n"
176 " larger tile) to avoid creating a large canvas.\n"
177 " Add --tiles x y to specify the number of tiles\n"
178 " per larger tile in the x and y direction.\n"
179 );
180 SkDebugf(
181 " playbackCreation, Benchmark creation of the SkPicturePlayback.\n");
182 SkDebugf("\n");
183 SkDebugf(
184 " --multi numThreads : Set the number of threads for multi threaded drawing. Must be greater\n"
185 " than 1. Only works with tiled rendering.\n"
186 " --viewport width height : Set the viewport.\n"
187 " --scale sf : Scale drawing by sf.\n"
188 " --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
189 SkDebugf(
190 " --bbh bbhType [width height]: Set the bounding box hierarchy type to\n"
191 " be used. Accepted values are: none, rtree, grid. Default\n"
192 " value is none. Not compatible with --pipe. With value\n"
193 " 'grid', width and height must be specified. 'grid' can\n"
194 " only be used with modes tile, record, and\n"
195 " playbackCreation.");
196 SkDebugf(
197 " --device bitmap"
198 #if SK_SUPPORT_GPU
199 " | gpu"
200 #endif
201 ": Use the corresponding device. Default is bitmap.\n");
202 SkDebugf(
203 " bitmap, Render to a bitmap.\n");
204 #if SK_SUPPORT_GPU
205 SkDebugf(
206 " gpu, Render to the GPU.\n");
207 #endif
208 SkDebugf("\n");
209 SkDebugf(
210 " --repeat: "
211 "Set the number of times to repeat each test."
212 " Default is %i.\n", DEFAULT_REPEATS);
213 SkDebugf(
214 " --filter type:flag : Enable canvas filtering to disable a paint flag,\n"
215 " use no blur or low quality blur, or use no hinting or\n"
216 " slight hinting. For all flags except AAClip, specify the\n"
217 " type of primitive to effect, or choose all. for AAClip\n"
218 " alone, the filter affects all clips independent of type.\n");
219 }
220
221 SkBenchLogger gLogger;
222
run_single_benchmark(const SkString & inputPath,sk_tools::PictureBenchmark & benchmark)223 static bool run_single_benchmark(const SkString& inputPath,
224 sk_tools::PictureBenchmark& benchmark) {
225 SkFILEStream inputStream;
226
227 inputStream.setPath(inputPath.c_str());
228 if (!inputStream.isValid()) {
229 SkString err;
230 err.printf("Could not open file %s\n", inputPath.c_str());
231 gLogger.logError(err);
232 return false;
233 }
234
235 bool success = false;
236 SkPicture picture(&inputStream, &success, &SkImageDecoder::DecodeStream);
237 if (!success) {
238 SkString err;
239 err.printf("Could not read an SkPicture from %s\n", inputPath.c_str());
240 gLogger.logError(err);
241 return false;
242 }
243
244 SkString filename;
245 sk_tools::get_basename(&filename, inputPath);
246
247 SkString result;
248 result.printf("running bench [%i %i] %s ", picture.width(),
249 picture.height(), filename.c_str());
250 gLogger.logProgress(result);
251
252 benchmark.run(&picture);
253 return true;
254 }
255
256 #define PRINT_USAGE_AND_EXIT \
257 do { \
258 usage(argv0); \
259 exit(-1); \
260 } while (0)
261
parse_commandline(int argc,char * const argv[],SkTArray<SkString> * inputs,sk_tools::PictureBenchmark * benchmark)262 static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
263 sk_tools::PictureBenchmark* benchmark) {
264 const char* argv0 = argv[0];
265 char* const* stop = argv + argc;
266
267 int repeats = DEFAULT_REPEATS;
268 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
269 sk_tools::PictureRenderer::kBitmap_DeviceType;
270
271 SkAutoTUnref<sk_tools::PictureRenderer> renderer(NULL);
272
273 // Create a string to show our current settings.
274 // TODO: Make it prettier. Currently it just repeats the command line.
275 SkString commandLine("bench_pictures:");
276 for (int i = 1; i < argc; i++) {
277 commandLine.appendf(" %s", *(argv+i));
278 }
279 commandLine.append("\n");
280
281 bool usePipe = false;
282 int numThreads = 1;
283 bool useTiles = false;
284 const char* widthString = NULL;
285 const char* heightString = NULL;
286 int gridWidth = 0;
287 int gridHeight = 0;
288 bool isPowerOf2Mode = false;
289 bool isCopyMode = false;
290 const char* xTilesString = NULL;
291 const char* yTilesString = NULL;
292 const char* mode = NULL;
293 bool gridSupported = false;
294 sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
295 sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
296 sk_tools::PictureRenderer::DrawFilterFlags drawFilters[SkDrawFilter::kTypeCount];
297 sk_bzero(drawFilters, sizeof(drawFilters));
298 SkISize viewport;
299 viewport.setEmpty();
300 SkScalar scaleFactor = SK_Scalar1;
301 for (++argv; argv < stop; ++argv) {
302 if (0 == strcmp(*argv, "--repeat")) {
303 ++argv;
304 if (argv < stop) {
305 repeats = atoi(*argv);
306 if (repeats < 1) {
307 gLogger.logError("--repeat must be given a value > 0\n");
308 PRINT_USAGE_AND_EXIT;
309 }
310 } else {
311 gLogger.logError("Missing arg for --repeat\n");
312 PRINT_USAGE_AND_EXIT;
313 }
314 } else if (0 == strcmp(*argv, "--pipe")) {
315 usePipe = true;
316 } else if (0 == strcmp(*argv, "--logFile")) {
317 argv++;
318 if (argv < stop) {
319 if (!gLogger.SetLogFile(*argv)) {
320 SkString str;
321 str.printf("Could not open %s for writing.", *argv);
322 gLogger.logError(str);
323 usage(argv0);
324 // TODO(borenet): We're disabling this for now, due to
325 // write-protected Android devices. The very short-term
326 // solution is to ignore the fact that we have no log file.
327 //exit(-1);
328 }
329 } else {
330 gLogger.logError("Missing arg for --logFile\n");
331 PRINT_USAGE_AND_EXIT;
332 }
333 } else if (0 == strcmp(*argv, "--multi")) {
334 ++argv;
335 if (argv >= stop) {
336 gLogger.logError("Missing arg for --multi\n");
337 PRINT_USAGE_AND_EXIT;
338 }
339 numThreads = atoi(*argv);
340 if (numThreads < 2) {
341 gLogger.logError("Number of threads must be at least 2.\n");
342 PRINT_USAGE_AND_EXIT;
343 }
344 } else if (0 == strcmp(*argv, "--bbh")) {
345 ++argv;
346 if (argv >= stop) {
347 gLogger.logError("Missing value for --bbh\n");
348 PRINT_USAGE_AND_EXIT;
349 }
350 if (0 == strcmp(*argv, "none")) {
351 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
352 } else if (0 == strcmp(*argv, "rtree")) {
353 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
354 } else if (0 == strcmp(*argv, "grid")) {
355 bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType;
356 ++argv;
357 if (argv >= stop) {
358 gLogger.logError("Missing width for --bbh grid\n");
359 PRINT_USAGE_AND_EXIT;
360 }
361 gridWidth = atoi(*argv);
362 ++argv;
363 if (argv >= stop) {
364 gLogger.logError("Missing height for --bbh grid\n");
365 PRINT_USAGE_AND_EXIT;
366 }
367 gridHeight = atoi(*argv);
368 } else {
369 SkString err;
370 err.printf("%s is not a valid value for --bbhType\n", *argv);
371 gLogger.logError(err);
372 PRINT_USAGE_AND_EXIT;
373 }
374
375 } else if (0 == strcmp(*argv, "--mode")) {
376 if (renderer.get() != NULL) {
377 SkDebugf("Cannot combine modes.\n");
378 PRINT_USAGE_AND_EXIT;
379 }
380
381 ++argv;
382 if (argv >= stop) {
383 gLogger.logError("Missing mode for --mode\n");
384 PRINT_USAGE_AND_EXIT;
385 }
386
387 if (0 == strcmp(*argv, "record")) {
388 renderer.reset(SkNEW(sk_tools::RecordPictureRenderer));
389 gridSupported = true;
390 } else if (0 == strcmp(*argv, "clone")) {
391 renderer.reset(sk_tools::CreatePictureCloneRenderer());
392 } else if (0 == strcmp(*argv, "simple")) {
393 renderer.reset(SkNEW(sk_tools::SimplePictureRenderer));
394 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))
395 || 0 == strcmp(*argv, "copyTile")) {
396 useTiles = true;
397 mode = *argv;
398
399 if (0 == strcmp(*argv, "pow2tile")) {
400 isPowerOf2Mode = true;
401 } else if (0 == strcmp(*argv, "copyTile")) {
402 isCopyMode = true;
403 } else {
404 gridSupported = true;
405 }
406
407 ++argv;
408 if (argv >= stop) {
409 SkString err;
410 err.printf("Missing width for --mode %s\n", mode);
411 gLogger.logError(err);
412 PRINT_USAGE_AND_EXIT;
413 }
414
415 widthString = *argv;
416 ++argv;
417 if (argv >= stop) {
418 SkString err;
419 err.appendf("Missing height for --mode %s\n", mode);
420 gLogger.logError(err);
421 PRINT_USAGE_AND_EXIT;
422 }
423 heightString = *argv;
424 } else if (0 == strcmp(*argv, "playbackCreation")) {
425 renderer.reset(SkNEW(sk_tools::PlaybackCreationRenderer));
426 gridSupported = true;
427 } else if (0 == strcmp(*argv, "gatherPixelRefs")) {
428 renderer.reset(sk_tools::CreateGatherPixelRefsRenderer());
429 } else {
430 SkString err;
431 err.printf("%s is not a valid mode for --mode\n", *argv);
432 gLogger.logError(err);
433 PRINT_USAGE_AND_EXIT;
434 }
435 } else if (0 == strcmp(*argv, "--viewport")) {
436 ++argv;
437 if (argv >= stop) {
438 gLogger.logError("Missing width for --viewport\n");
439 PRINT_USAGE_AND_EXIT;
440 }
441 viewport.fWidth = atoi(*argv);
442 ++argv;
443 if (argv >= stop) {
444 gLogger.logError("Missing height for --viewport\n");
445 PRINT_USAGE_AND_EXIT;
446 }
447 viewport.fHeight = atoi(*argv);
448 } else if (0 == strcmp(*argv, "--scale")) {
449 ++argv;
450 if (argv >= stop) {
451 gLogger.logError("Missing scaleFactor for --scale\n");
452 PRINT_USAGE_AND_EXIT;
453 }
454 scaleFactor = SkDoubleToScalar(atof(*argv));
455 } else if (0 == strcmp(*argv, "--tiles")) {
456 ++argv;
457 if (argv >= stop) {
458 gLogger.logError("Missing x for --tiles\n");
459 PRINT_USAGE_AND_EXIT;
460 }
461 xTilesString = *argv;
462 ++argv;
463 if (argv >= stop) {
464 gLogger.logError("Missing y for --tiles\n");
465 PRINT_USAGE_AND_EXIT;
466 }
467 yTilesString = *argv;
468 } else if (0 == strcmp(*argv, "--device")) {
469 ++argv;
470 if (argv >= stop) {
471 gLogger.logError("Missing mode for --device\n");
472 PRINT_USAGE_AND_EXIT;
473 }
474
475 if (0 == strcmp(*argv, "bitmap")) {
476 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
477 }
478 #if SK_SUPPORT_GPU
479 else if (0 == strcmp(*argv, "gpu")) {
480 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
481 }
482 #endif
483 else {
484 SkString err;
485 err.printf("%s is not a valid mode for --device\n", *argv);
486 gLogger.logError(err);
487 PRINT_USAGE_AND_EXIT;
488 }
489 } else if (0 == strcmp(*argv, "--timers")) {
490 ++argv;
491 if (argv < stop) {
492 bool timerWall = false;
493 bool truncatedTimerWall = false;
494 bool timerCpu = false;
495 bool truncatedTimerCpu = false;
496 bool timerGpu = false;
497 for (char* t = *argv; *t; ++t) {
498 switch (*t) {
499 case 'w':
500 timerWall = true;
501 break;
502 case 'c':
503 timerCpu = true;
504 break;
505 case 'W':
506 truncatedTimerWall = true;
507 break;
508 case 'C':
509 truncatedTimerCpu = true;
510 break;
511 case 'g':
512 timerGpu = true;
513 break;
514 default: {
515 break;
516 }
517 }
518 }
519 benchmark->setTimersToShow(timerWall, truncatedTimerWall, timerCpu,
520 truncatedTimerCpu, timerGpu);
521 } else {
522 gLogger.logError("Missing arg for --timers\n");
523 PRINT_USAGE_AND_EXIT;
524 }
525 } else if (0 == strcmp(*argv, "--timeIndividualTiles")) {
526 benchmark->setTimeIndividualTiles(true);
527 } else if (0 == strcmp(*argv, "--min")) {
528 benchmark->setPrintMin(true);
529 } else if (0 == strcmp(*argv, "--logPerIter")) {
530 ++argv;
531 if (argv < stop) {
532 bool log = atoi(*argv) != 0;
533 benchmark->setLogPerIter(log);
534 } else {
535 gLogger.logError("Missing arg for --logPerIter\n");
536 PRINT_USAGE_AND_EXIT;
537 }
538 } else if (0 == strcmp(*argv, "--filter")) {
539 ++argv;
540 if (argv < stop) {
541 const char* colon = strchr(*argv, ':');
542 if (colon) {
543 int type = -1;
544 size_t typeLen = colon - *argv;
545 for (size_t tIndex = 0; tIndex < kFilterTypesCount; ++tIndex) {
546 if (typeLen == strlen(gFilterTypes[tIndex])
547 && !strncmp(*argv, gFilterTypes[tIndex], typeLen)) {
548 type = tIndex;
549 break;
550 }
551 }
552 if (type < 0) {
553 SkString err;
554 err.printf("Unknown type for --filter %s\n", *argv);
555 gLogger.logError(err);
556 PRINT_USAGE_AND_EXIT;
557 }
558 int flag = -1;
559 size_t flagLen = strlen(*argv) - typeLen - 1;
560 for (size_t fIndex = 0; fIndex < kFilterFlagsCount; ++fIndex) {
561 if (flagLen == strlen(gFilterFlags[fIndex])
562 && !strncmp(colon + 1, gFilterFlags[fIndex], flagLen)) {
563 flag = 1 << fIndex;
564 break;
565 }
566 }
567 if (flag < 0) {
568 SkString err;
569 err.printf("Unknown flag for --filter %s\n", *argv);
570 gLogger.logError(err);
571 PRINT_USAGE_AND_EXIT;
572 }
573 for (int index = 0; index < SkDrawFilter::kTypeCount; ++index) {
574 if (type != SkDrawFilter::kTypeCount && index != type) {
575 continue;
576 }
577 drawFilters[index] = (sk_tools::PictureRenderer::DrawFilterFlags)
578 (drawFilters[index] | flag);
579 }
580 } else {
581 SkString err;
582 err.printf("Unknown arg for --filter %s : missing colon\n", *argv);
583 gLogger.logError(err);
584 PRINT_USAGE_AND_EXIT;
585 }
586 } else {
587 gLogger.logError("Missing arg for --filter\n");
588 PRINT_USAGE_AND_EXIT;
589 }
590 } else if (0 == strcmp(*argv, "--help") || 0 == strcmp(*argv, "-h")) {
591 PRINT_USAGE_AND_EXIT;
592 } else {
593 inputs->push_back(SkString(*argv));
594 }
595 }
596
597 if (numThreads > 1 && !useTiles) {
598 gLogger.logError("Multithreaded drawing requires tiled rendering.\n");
599 PRINT_USAGE_AND_EXIT;
600 }
601
602 if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
603 gLogger.logError("--pipe and --bbh cannot be used together\n");
604 PRINT_USAGE_AND_EXIT;
605 }
606
607 if (sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType == bbhType &&
608 !gridSupported) {
609 gLogger.logError("'--bbh grid' is not compatible with specified --mode.\n");
610 PRINT_USAGE_AND_EXIT;
611 }
612
613 if (useTiles) {
614 SkASSERT(NULL == renderer);
615 sk_tools::TiledPictureRenderer* tiledRenderer;
616 if (isCopyMode) {
617 int x, y;
618 if (xTilesString != NULL) {
619 SkASSERT(yTilesString != NULL);
620 x = atoi(xTilesString);
621 y = atoi(yTilesString);
622 if (x <= 0 || y <= 0) {
623 gLogger.logError("--tiles must be given values > 0\n");
624 PRINT_USAGE_AND_EXIT;
625 }
626 } else {
627 x = y = 4;
628 }
629 tiledRenderer = SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y));
630 if (benchmark->timeIndividualTiles()) {
631 gLogger.logError("timeIndividualTiles is not compatible with copyTile\n");
632 PRINT_USAGE_AND_EXIT;
633 }
634 } else if (numThreads > 1) {
635 tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
636 } else {
637 tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
638 }
639 if (isPowerOf2Mode) {
640 int minWidth = atoi(widthString);
641 if (!SkIsPow2(minWidth) || minWidth < 0) {
642 tiledRenderer->unref();
643 SkString err;
644 err.printf("-mode %s must be given a width"
645 " value that is a power of two\n", mode);
646 gLogger.logError(err);
647 PRINT_USAGE_AND_EXIT;
648 }
649 tiledRenderer->setTileMinPowerOf2Width(minWidth);
650 } else if (sk_tools::is_percentage(widthString)) {
651 if (isCopyMode) {
652 tiledRenderer->unref();
653 SkString err;
654 err.printf("--mode %s does not support percentages.\n", mode);
655 gLogger.logError(err.c_str());
656 PRINT_USAGE_AND_EXIT;
657 }
658 tiledRenderer->setTileWidthPercentage(atof(widthString));
659 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
660 tiledRenderer->unref();
661 SkString err;
662 err.appendf("--mode %s must be given a width percentage > 0\n", mode);
663 gLogger.logError(err);
664 PRINT_USAGE_AND_EXIT;
665 }
666 } else {
667 tiledRenderer->setTileWidth(atoi(widthString));
668 if (!(tiledRenderer->getTileWidth() > 0)) {
669 tiledRenderer->unref();
670 SkString err;
671 err.appendf("--mode %s must be given a width > 0\n", mode);
672 gLogger.logError(err);
673 PRINT_USAGE_AND_EXIT;
674 }
675 }
676
677 if (sk_tools::is_percentage(heightString)) {
678 if (isCopyMode) {
679 tiledRenderer->unref();
680 SkString err;
681 err.printf("--mode %s does not support percentages.\n", mode);
682 gLogger.logError(err.c_str());
683 PRINT_USAGE_AND_EXIT;
684 }
685 tiledRenderer->setTileHeightPercentage(atof(heightString));
686 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
687 tiledRenderer->unref();
688 SkString err;
689 err.appendf("--mode %s must be given a height percentage > 0\n", mode);
690 gLogger.logError(err);
691 PRINT_USAGE_AND_EXIT;
692 }
693 } else {
694 tiledRenderer->setTileHeight(atoi(heightString));
695 if (!(tiledRenderer->getTileHeight() > 0)) {
696 tiledRenderer->unref();
697 SkString err;
698 err.appendf("--mode %s must be given a height > 0\n", mode);
699 gLogger.logError(err);
700 PRINT_USAGE_AND_EXIT;
701 }
702 }
703 if (numThreads > 1) {
704 #if SK_SUPPORT_GPU
705 if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) {
706 tiledRenderer->unref();
707 gLogger.logError("GPU not compatible with multithreaded tiling.\n");
708 PRINT_USAGE_AND_EXIT;
709 }
710 #endif
711 }
712 renderer.reset(tiledRenderer);
713 if (usePipe) {
714 gLogger.logError("Pipe rendering is currently not compatible with tiling.\n"
715 "Turning off pipe.\n");
716 }
717 } else {
718 if (benchmark->timeIndividualTiles()) {
719 gLogger.logError("timeIndividualTiles requires tiled rendering.\n");
720 PRINT_USAGE_AND_EXIT;
721 }
722 if (usePipe) {
723 if (renderer.get() != NULL) {
724 gLogger.logError("Pipe is incompatible with other modes.\n");
725 PRINT_USAGE_AND_EXIT;
726 }
727 renderer.reset(SkNEW(sk_tools::PipePictureRenderer));
728 }
729 }
730 if (inputs->count() < 1) {
731 PRINT_USAGE_AND_EXIT;
732 }
733
734 if (NULL == renderer) {
735 renderer.reset(SkNEW(sk_tools::SimplePictureRenderer));
736 }
737
738 renderer->setBBoxHierarchyType(bbhType);
739 renderer->setDrawFilters(drawFilters, filtersName(drawFilters));
740 renderer->setGridSize(gridWidth, gridHeight);
741 renderer->setViewport(viewport);
742 renderer->setScaleFactor(scaleFactor);
743 benchmark->setRenderer(renderer);
744 benchmark->setRepeats(repeats);
745 benchmark->setDeviceType(deviceType);
746 benchmark->setLogger(&gLogger);
747 // Report current settings:
748 gLogger.logProgress(commandLine);
749 }
750
process_input(const SkString & input,sk_tools::PictureBenchmark & benchmark)751 static int process_input(const SkString& input,
752 sk_tools::PictureBenchmark& benchmark) {
753 SkOSFile::Iter iter(input.c_str(), "skp");
754 SkString inputFilename;
755 int failures = 0;
756 if (iter.next(&inputFilename)) {
757 do {
758 SkString inputPath;
759 sk_tools::make_filepath(&inputPath, input, inputFilename);
760 if (!run_single_benchmark(inputPath, benchmark)) {
761 ++failures;
762 }
763 } while(iter.next(&inputFilename));
764 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
765 if (!run_single_benchmark(input, benchmark)) {
766 ++failures;
767 }
768 } else {
769 SkString warning;
770 warning.printf("Warning: skipping %s\n", input.c_str());
771 gLogger.logError(warning);
772 }
773 return failures;
774 }
775
776 int tool_main(int argc, char** argv);
tool_main(int argc,char ** argv)777 int tool_main(int argc, char** argv) {
778 #if SK_ENABLE_INST_COUNT
779 gPrintInstCount = true;
780 #endif
781 SkAutoGraphics ag;
782
783 SkTArray<SkString> inputs;
784 sk_tools::PictureBenchmark benchmark;
785
786 parse_commandline(argc, argv, &inputs, &benchmark);
787
788 int failures = 0;
789 for (int i = 0; i < inputs.count(); ++i) {
790 failures += process_input(inputs[i], benchmark);
791 }
792
793 if (failures != 0) {
794 SkString err;
795 err.printf("Failed to run %i benchmarks.\n", failures);
796 gLogger.logError(err);
797 return 1;
798 }
799 return 0;
800 }
801
802 #if !defined SK_BUILD_FOR_IOS
main(int argc,char * const argv[])803 int main(int argc, char * const argv[]) {
804 return tool_main(argc, (char**) argv);
805 }
806 #endif
807