• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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