• 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 "CopyTilesRenderer.h"
9 #include "SkBitmap.h"
10 #include "SkCanvas.h"
11 #include "SkDevice.h"
12 #include "SkGraphics.h"
13 #include "SkImageDecoder.h"
14 #include "SkImageEncoder.h"
15 #include "SkMath.h"
16 #include "SkOSFile.h"
17 #include "SkPicture.h"
18 #include "SkStream.h"
19 #include "SkString.h"
20 #include "SkTArray.h"
21 #include "PictureRenderer.h"
22 #include "picture_utils.h"
23 
usage(const char * argv0)24 static void usage(const char* argv0) {
25     SkDebugf("SkPicture rendering tool\n");
26     SkDebugf("\n"
27 "Usage: \n"
28 "     %s <input>... \n"
29 "     [-w <outputDir>]\n"
30 "     [--mode pow2tile minWidth height | copyTile width height | simple\n"
31 "         | tile width height]\n"
32 "     [--pipe]\n"
33 "     [--bbh bbhType]\n"
34 "     [--multi count]\n"
35 "     [--validate [--maxComponentDiff n]]\n"
36 "     [--writeWholeImage]\n"
37 "     [--clone n]\n"
38 "     [--viewport width height][--scale sf]\n"
39 "     [--device bitmap"
40 #if SK_SUPPORT_GPU
41 " | gpu"
42 #endif
43 "]"
44 , argv0);
45     SkDebugf("\n\n");
46     SkDebugf(
47 "     input:     A list of directories and files to use as input. Files are\n"
48 "                expected to have the .skp extension.\n\n");
49     SkDebugf(
50 "     outputDir: directory to write the rendered images.\n\n");
51     SkDebugf(
52 "     --mode pow2tile minWidth height | copyTile width height | simple\n"
53 "          | tile width height | rerecord: Run in the corresponding mode.\n"
54 "                                     Default is simple.\n");
55     SkDebugf(
56 "                     pow2tile minWidth height, Creates tiles with widths\n"
57 "                                                  that are all a power of two\n"
58 "                                                  such that they minimize the\n"
59 "                                                  amount of wasted tile space.\n"
60 "                                                  minWidth is the minimum width\n"
61 "                                                  of these tiles and must be a\n"
62 "                                                  power of two. A simple render\n"
63 "                                                  is done with these tiles.\n");
64     SkDebugf(
65 "                     simple, Render using the default rendering method.\n"
66 "                     rerecord, Record the picture as a new skp, with the bitmaps PNG encoded.\n"
67              );
68     SkDebugf(
69 "                     tile width height, Do a simple render using tiles\n"
70 "                                              with the given dimensions.\n"
71 "                     copyTile width height, Draw the picture, then copy it into tiles.\n"
72 "                                                Does not support percentages.\n"
73 "                                                If the picture is large enough, breaks it into\n"
74 "                                                larger tiles (and draws the picture once per\n"
75 "                                                larger tile) to avoid creating a large canvas.\n"
76 "                                                Add --tiles x y to specify the number of tiles\n"
77 "                                                per larger tile in the x and y direction.\n"
78              );
79     SkDebugf("\n");
80     SkDebugf(
81 "     --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
82 "                     than 1. Only works with tiled rendering.\n"
83 "     --viewport width height : Set the viewport.\n"
84 "     --scale sf : Scale drawing by sf.\n"
85 "     --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
86     SkDebugf(
87 "     --validate: Verify that the rendered image contains the same pixels as "
88 "the picture rendered in simple mode.\n"
89 "     --maxComponentDiff: maximum diff on a component. Default is 256, "
90 "which means we report but we do not generate an error.\n"
91 "     --writeWholeImage: In tile mode, write the entire rendered image to a "
92 "file, instead of an image for each tile.\n");
93     SkDebugf(
94 "     --clone n: Clone the picture n times before rendering.\n");
95     SkDebugf(
96 "     --bbh bbhType [width height]: Set the bounding box hierarchy type to\n"
97 "                     be used. Accepted values are: none, rtree, grid. Default\n"
98 "                     value is none. Not compatible with --pipe. With value\n"
99 "                     'grid', width and height must be specified. 'grid' can\n"
100 "                     only be used with modes tile, record, and\n"
101 "                     playbackCreation.");
102     SkDebugf(
103 "     --device bitmap"
104 #if SK_SUPPORT_GPU
105 " | gpu"
106 #endif
107 ": Use the corresponding device. Default is bitmap.\n");
108     SkDebugf(
109 "                     bitmap, Render to a bitmap.\n");
110 #if SK_SUPPORT_GPU
111     SkDebugf(
112 "                     gpu, Render to the GPU.\n");
113 #endif
114 }
115 
make_output_filepath(SkString * path,const SkString & dir,const SkString & name)116 static void make_output_filepath(SkString* path, const SkString& dir,
117                                  const SkString& name) {
118     sk_tools::make_filepath(path, dir, name);
119     // Remove ".skp"
120     path->remove(path->size() - 4, 4);
121 }
122 
render_picture(const SkString & inputPath,const SkString * outputDir,sk_tools::PictureRenderer & renderer,SkBitmap ** out,int clones)123 static bool render_picture(const SkString& inputPath, const SkString* outputDir,
124                            sk_tools::PictureRenderer& renderer,
125                            SkBitmap** out,
126                            int clones) {
127     SkString inputFilename;
128     sk_tools::get_basename(&inputFilename, inputPath);
129 
130     SkFILEStream inputStream;
131     inputStream.setPath(inputPath.c_str());
132     if (!inputStream.isValid()) {
133         SkDebugf("Could not open file %s\n", inputPath.c_str());
134         return false;
135     }
136 
137     bool success = false;
138     SkPicture* picture = SkNEW_ARGS(SkPicture,
139             (&inputStream, &success, &SkImageDecoder::DecodeStream));
140     if (!success) {
141         SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
142         return false;
143     }
144 
145     for (int i = 0; i < clones; ++i) {
146         SkPicture* clone = picture->clone();
147         SkDELETE(picture);
148         picture = clone;
149     }
150 
151     SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(),
152              inputPath.c_str());
153 
154     renderer.init(picture);
155     renderer.setup();
156 
157     SkString* outputPath = NULL;
158     if (NULL != outputDir) {
159         outputPath = SkNEW(SkString);
160         make_output_filepath(outputPath, *outputDir, inputFilename);
161     }
162 
163     success = renderer.render(outputPath, out);
164     if (outputPath) {
165         if (!success) {
166             SkDebugf("Could not write to file %s\n", outputPath->c_str());
167         }
168         SkDELETE(outputPath);
169     }
170 
171     renderer.end();
172 
173     SkDELETE(picture);
174     return success;
175 }
176 
getByte(uint32_t value,int index)177 static inline int getByte(uint32_t value, int index) {
178     SkASSERT(0 <= index && index < 4);
179     return (value >> (index * 8)) & 0xFF;
180 }
181 
MaxByteDiff(uint32_t v1,uint32_t v2)182 static int MaxByteDiff(uint32_t v1, uint32_t v2) {
183     return SkMax32(SkMax32(abs(getByte(v1, 0) - getByte(v2, 0)), abs(getByte(v1, 1) - getByte(v2, 1))),
184                    SkMax32(abs(getByte(v1, 2) - getByte(v2, 2)), abs(getByte(v1, 3) - getByte(v2, 3))));
185 }
186 
render_picture(const SkString & inputPath,const SkString * outputDir,sk_tools::PictureRenderer & renderer,bool validate,int maxComponentDiff,bool writeWholeImage,int clones)187 static bool render_picture(const SkString& inputPath, const SkString* outputDir,
188                            sk_tools::PictureRenderer& renderer,
189                            bool validate, int maxComponentDiff,
190                            bool writeWholeImage,
191                            int clones) {
192     int diffs[256] = {0};
193     SkBitmap* bitmap = NULL;
194     bool success = render_picture(inputPath,
195         writeWholeImage ? NULL : outputDir,
196         renderer,
197         validate || writeWholeImage ? &bitmap : NULL, clones);
198 
199     if (!success || ((validate || writeWholeImage) && bitmap == NULL)) {
200         SkDebugf("Failed to draw the picture.\n");
201         SkDELETE(bitmap);
202         return false;
203     }
204 
205     if (validate) {
206         SkBitmap* referenceBitmap = NULL;
207         sk_tools::SimplePictureRenderer referenceRenderer;
208         success = render_picture(inputPath, NULL, referenceRenderer,
209                                  &referenceBitmap, 0);
210 
211         if (!success || !referenceBitmap) {
212             SkDebugf("Failed to draw the reference picture.\n");
213             SkDELETE(bitmap);
214             SkDELETE(referenceBitmap);
215             return false;
216         }
217 
218         if (success && (bitmap->width() != referenceBitmap->width())) {
219             SkDebugf("Expected image width: %i, actual image width %i.\n",
220                      referenceBitmap->width(), bitmap->width());
221             SkDELETE(bitmap);
222             SkDELETE(referenceBitmap);
223             return false;
224         }
225         if (success && (bitmap->height() != referenceBitmap->height())) {
226             SkDebugf("Expected image height: %i, actual image height %i",
227                      referenceBitmap->height(), bitmap->height());
228             SkDELETE(bitmap);
229             SkDELETE(referenceBitmap);
230             return false;
231         }
232 
233         for (int y = 0; success && y < bitmap->height(); y++) {
234             for (int x = 0; success && x < bitmap->width(); x++) {
235                 int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y),
236                                        *bitmap->getAddr32(x, y));
237                 SkASSERT(diff >= 0 && diff <= 255);
238                 diffs[diff]++;
239 
240                 if (diff > maxComponentDiff) {
241                     SkDebugf("Expected pixel at (%i %i) exceedds maximum "
242                                  "component diff of %i: 0x%x, actual 0x%x\n",
243                              x, y, maxComponentDiff,
244                              *referenceBitmap->getAddr32(x, y),
245                              *bitmap->getAddr32(x, y));
246                     SkDELETE(bitmap);
247                     SkDELETE(referenceBitmap);
248                     return false;
249                 }
250             }
251         }
252         SkDELETE(referenceBitmap);
253 
254         for (int i = 1; i <= 255; ++i) {
255             if(diffs[i] > 0) {
256                 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]);
257             }
258         }
259     }
260 
261     if (writeWholeImage) {
262         sk_tools::force_all_opaque(*bitmap);
263         if (NULL != outputDir && writeWholeImage) {
264             SkString inputFilename;
265             sk_tools::get_basename(&inputFilename, inputPath);
266             SkString outputPath;
267             make_output_filepath(&outputPath, *outputDir, inputFilename);
268             outputPath.append(".png");
269             if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap,
270                                             SkImageEncoder::kPNG_Type, 100)) {
271                 SkDebugf("Failed to draw the picture.\n");
272                 success = false;
273             }
274         }
275     }
276     SkDELETE(bitmap);
277 
278     return success;
279 }
280 
281 
process_input(const SkString & input,const SkString * outputDir,sk_tools::PictureRenderer & renderer,bool validate,int maxComponentDiff,bool writeWholeImage,int clones)282 static int process_input(const SkString& input, const SkString* outputDir,
283                          sk_tools::PictureRenderer& renderer,
284                          bool validate, int maxComponentDiff,
285                          bool writeWholeImage, int clones) {
286     SkOSFile::Iter iter(input.c_str(), "skp");
287     SkString inputFilename;
288     int failures = 0;
289     SkDebugf("process_input, %s\n", input.c_str());
290     if (iter.next(&inputFilename)) {
291         do {
292             SkString inputPath;
293             sk_tools::make_filepath(&inputPath, input, inputFilename);
294             if (!render_picture(inputPath, outputDir, renderer,
295                                 validate, maxComponentDiff,
296                                 writeWholeImage, clones)) {
297                 ++failures;
298             }
299         } while(iter.next(&inputFilename));
300     } else if (SkStrEndsWith(input.c_str(), ".skp")) {
301         SkString inputPath(input);
302         if (!render_picture(inputPath, outputDir, renderer,
303                             validate, maxComponentDiff,
304                             writeWholeImage, clones)) {
305             ++failures;
306         }
307     } else {
308         SkString warning;
309         warning.printf("Warning: skipping %s\n", input.c_str());
310         SkDebugf(warning.c_str());
311     }
312     return failures;
313 }
314 
parse_commandline(int argc,char * const argv[],SkTArray<SkString> * inputs,sk_tools::PictureRenderer * & renderer,SkString * & outputDir,bool * validate,int * maxComponentDiff,bool * writeWholeImage,int * clones)315 static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
316                               sk_tools::PictureRenderer*& renderer, SkString*& outputDir,
317                               bool* validate, int* maxComponentDiff,
318                               bool* writeWholeImage,
319                               int* clones){
320     const char* argv0 = argv[0];
321     char* const* stop = argv + argc;
322 
323     sk_tools::PictureRenderer::SkDeviceTypes deviceType =
324         sk_tools::PictureRenderer::kBitmap_DeviceType;
325 
326     bool usePipe = false;
327     int numThreads = 1;
328     bool useTiles = false;
329     const char* widthString = NULL;
330     const char* heightString = NULL;
331     int gridWidth = 0;
332     int gridHeight = 0;
333     bool isPowerOf2Mode = false;
334     bool isCopyMode = false;
335     const char* xTilesString = NULL;
336     const char* yTilesString = NULL;
337     const char* mode = NULL;
338     bool gridSupported = false;
339     sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
340         sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
341     *validate = false;
342     *maxComponentDiff = 256;
343     *writeWholeImage = false;
344     *clones = 0;
345     SkISize viewport;
346     viewport.setEmpty();
347     SkScalar scaleFactor = SK_Scalar1;
348 
349     for (++argv; argv < stop; ++argv) {
350         if (0 == strcmp(*argv, "--mode")) {
351             if (renderer != NULL) {
352                 renderer->unref();
353                 SkDebugf("Cannot combine modes.\n");
354                 usage(argv0);
355                 exit(-1);
356             }
357 
358             ++argv;
359             if (argv >= stop) {
360                 SkDebugf("Missing mode for --mode\n");
361                 usage(argv0);
362                 exit(-1);
363             }
364 
365             if (0 == strcmp(*argv, "simple")) {
366                 renderer = SkNEW(sk_tools::SimplePictureRenderer);
367             } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))
368                        || 0 == strcmp(*argv, "copyTile")) {
369                 useTiles = true;
370                 mode = *argv;
371 
372                 if (0 == strcmp(*argv, "pow2tile")) {
373                     isPowerOf2Mode = true;
374                 } else if (0 == strcmp(*argv, "copyTile")) {
375                     isCopyMode = true;
376                 } else {
377                     gridSupported = true;
378                 }
379 
380                 ++argv;
381                 if (argv >= stop) {
382                     SkDebugf("Missing width for --mode %s\n", mode);
383                     usage(argv0);
384                     exit(-1);
385                 }
386 
387                 widthString = *argv;
388                 ++argv;
389                 if (argv >= stop) {
390                     SkDebugf("Missing height for --mode %s\n", mode);
391                     usage(argv0);
392                     exit(-1);
393                 }
394                 heightString = *argv;
395             } else if (0 == strcmp(*argv, "rerecord")) {
396                 renderer = SkNEW(sk_tools::RecordPictureRenderer);
397             } else {
398                 SkDebugf("%s is not a valid mode for --mode\n", *argv);
399                 usage(argv0);
400                 exit(-1);
401             }
402         } else if (0 == strcmp(*argv, "--bbh")) {
403             ++argv;
404             if (argv >= stop) {
405                 SkDebugf("Missing value for --bbh\n");
406                 usage(argv0);
407                 exit(-1);
408             }
409             if (0 == strcmp(*argv, "none")) {
410                 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
411             } else if (0 == strcmp(*argv, "rtree")) {
412                 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
413             } else if (0 == strcmp(*argv, "grid")) {
414                 bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType;
415                 ++argv;
416                 if (argv >= stop) {
417                     SkDebugf("Missing width for --bbh grid\n");
418                     usage(argv0);
419                     exit(-1);
420                 }
421                 gridWidth = atoi(*argv);
422                 ++argv;
423                 if (argv >= stop) {
424                     SkDebugf("Missing height for --bbh grid\n");
425                     usage(argv0);
426                     exit(-1);
427                 }
428                 gridHeight = atoi(*argv);
429             } else {
430                 SkDebugf("%s is not a valid value for --bbhType\n", *argv);
431                 usage(argv0);
432                 exit(-1);;
433             }
434         } else if (0 == strcmp(*argv, "--viewport")) {
435             ++argv;
436             if (argv >= stop) {
437                 SkDebugf("Missing width for --viewport\n");
438                 usage(argv0);
439                 exit(-1);
440             }
441             viewport.fWidth = atoi(*argv);
442             ++argv;
443             if (argv >= stop) {
444                 SkDebugf("Missing height for --viewport\n");
445                 usage(argv0);
446                 exit(-1);
447             }
448             viewport.fHeight = atoi(*argv);
449         } else if (0 == strcmp(*argv, "--scale")) {
450             ++argv;
451             if (argv >= stop) {
452                 SkDebugf("Missing scaleFactor for --scale\n");
453                 usage(argv0);
454                 exit(-1);
455             }
456             scaleFactor = SkDoubleToScalar(atof(*argv));
457         } else if (0 == strcmp(*argv, "--tiles")) {
458             ++argv;
459             if (argv >= stop) {
460                 SkDebugf("Missing x for --tiles\n");
461                 usage(argv0);
462                 exit(-1);
463             }
464             xTilesString = *argv;
465             ++argv;
466             if (argv >= stop) {
467                 SkDebugf("Missing y for --tiles\n");
468                 usage(argv0);
469                 exit(-1);
470             }
471             yTilesString = *argv;
472         } else if (0 == strcmp(*argv, "--pipe")) {
473             usePipe = true;
474         } else if (0 == strcmp(*argv, "--multi")) {
475             ++argv;
476             if (argv >= stop) {
477                 SkSafeUnref(renderer);
478                 SkDebugf("Missing arg for --multi\n");
479                 usage(argv0);
480                 exit(-1);
481             }
482             numThreads = atoi(*argv);
483             if (numThreads < 2) {
484                 SkSafeUnref(renderer);
485                 SkDebugf("Number of threads must be at least 2.\n");
486                 usage(argv0);
487                 exit(-1);
488             }
489         } else if (0 == strcmp(*argv, "--clone")) {
490             ++argv;
491             if (argv >= stop) {
492                 SkSafeUnref(renderer);
493                 SkDebugf("Missing arg for --clone\n");
494                 usage(argv0);
495                 exit(-1);
496             }
497             *clones = atoi(*argv);
498             if (*clones < 0) {
499                 SkSafeUnref(renderer);
500                 SkDebugf("Number of clones must be at least 0.\n");
501                 usage(argv0);
502                 exit(-1);
503             }
504         } else if (0 == strcmp(*argv, "--device")) {
505             ++argv;
506             if (argv >= stop) {
507                 SkSafeUnref(renderer);
508                 SkDebugf("Missing mode for --device\n");
509                 usage(argv0);
510                 exit(-1);
511             }
512 
513             if (0 == strcmp(*argv, "bitmap")) {
514                 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
515             }
516 #if SK_SUPPORT_GPU
517             else if (0 == strcmp(*argv, "gpu")) {
518                 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
519             }
520 #endif
521             else {
522                 SkSafeUnref(renderer);
523                 SkDebugf("%s is not a valid mode for --device\n", *argv);
524                 usage(argv0);
525                 exit(-1);
526             }
527 
528         } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
529             SkSafeUnref(renderer);
530             usage(argv0);
531             exit(-1);
532         } else if (0 == strcmp(*argv, "-w")) {
533             ++argv;
534             if (argv >= stop) {
535                 SkDebugf("Missing output directory for -w\n");
536                 usage(argv0);
537                 exit(-1);
538             }
539             outputDir = SkNEW_ARGS(SkString, (*argv));
540         } else if (0 == strcmp(*argv, "--validate")) {
541             *validate = true;
542         } else if (0 == strcmp(*argv, "--maxComponentDiff")) {
543             if (!*validate) {
544                 SkDebugf("--maxComponentDiff must be used only with --validate\n");
545                 usage(argv0);
546                 exit(-1);
547             }
548             ++argv;
549             if (argv >= stop) {
550                 SkDebugf("Missing arg for --maxComponentDiff\n");
551                 usage(argv0);
552                 exit(-1);
553             }
554             *maxComponentDiff = atoi(*argv);
555             if (*maxComponentDiff < 0 || *maxComponentDiff > 256) {
556                 SkSafeUnref(renderer);
557                 SkDebugf("maxComponentDiff: 0 - 256.\n");
558                 usage(argv0);
559                 exit(-1);
560             }
561         } else if (0 == strcmp(*argv, "--writeWholeImage")) {
562             *writeWholeImage = true;
563         } else {
564             inputs->push_back(SkString(*argv));
565         }
566     }
567 
568     if (numThreads > 1 && !useTiles) {
569         SkSafeUnref(renderer);
570         SkDebugf("Multithreaded drawing requires tiled rendering.\n");
571         usage(argv0);
572         exit(-1);
573     }
574 
575     if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
576         SkDebugf("--pipe and --bbh cannot be used together\n");
577         usage(argv0);
578         exit(-1);
579     }
580 
581     if (sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType == bbhType &&
582         !gridSupported) {
583         SkDebugf("'--bbh grid' is not compatible with specified --mode.\n");
584         usage(argv0);
585         exit(-1);
586     }
587 
588     if (useTiles) {
589         SkASSERT(NULL == renderer);
590         sk_tools::TiledPictureRenderer* tiledRenderer;
591         if (isCopyMode) {
592             int x, y;
593             if (xTilesString != NULL) {
594                 SkASSERT(yTilesString != NULL);
595                 x = atoi(xTilesString);
596                 y = atoi(yTilesString);
597                 if (x <= 0 || y <= 0) {
598                     SkDebugf("--tiles must be given values > 0\n");
599                     usage(argv0);
600                     exit(-1);
601                 }
602             } else {
603                 x = y = 4;
604             }
605             tiledRenderer = SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y));
606         } else if (numThreads > 1) {
607             tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
608         } else {
609             tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
610         }
611         if (isPowerOf2Mode) {
612             int minWidth = atoi(widthString);
613             if (!SkIsPow2(minWidth) || minWidth < 0) {
614                 tiledRenderer->unref();
615                 SkString err;
616                 err.printf("-mode %s must be given a width"
617                            " value that is a power of two\n", mode);
618                 SkDebugf(err.c_str());
619                 usage(argv0);
620                 exit(-1);
621             }
622             tiledRenderer->setTileMinPowerOf2Width(minWidth);
623         } else if (sk_tools::is_percentage(widthString)) {
624             if (isCopyMode) {
625                 tiledRenderer->unref();
626                 SkString err;
627                 err.printf("--mode %s does not support percentages.\n", mode);
628                 SkDebugf(err.c_str());
629                 usage(argv0);
630                 exit(-1);
631             }
632             tiledRenderer->setTileWidthPercentage(atof(widthString));
633             if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
634                 tiledRenderer->unref();
635                 SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
636                 usage(argv0);
637                 exit(-1);
638             }
639         } else {
640             tiledRenderer->setTileWidth(atoi(widthString));
641             if (!(tiledRenderer->getTileWidth() > 0)) {
642                 tiledRenderer->unref();
643                 SkDebugf("--mode %s must be given a width > 0\n", mode);
644                 usage(argv0);
645                 exit(-1);
646             }
647         }
648 
649         if (sk_tools::is_percentage(heightString)) {
650             if (isCopyMode) {
651                 tiledRenderer->unref();
652                 SkString err;
653                 err.printf("--mode %s does not support percentages.\n", mode);
654                 SkDebugf(err.c_str());
655                 usage(argv0);
656                 exit(-1);
657             }
658             tiledRenderer->setTileHeightPercentage(atof(heightString));
659             if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
660                 tiledRenderer->unref();
661                 SkDebugf("--mode %s must be given a height percentage > 0\n", mode);
662                 usage(argv0);
663                 exit(-1);
664             }
665         } else {
666             tiledRenderer->setTileHeight(atoi(heightString));
667             if (!(tiledRenderer->getTileHeight() > 0)) {
668                 tiledRenderer->unref();
669                 SkDebugf("--mode %s must be given a height > 0\n", mode);
670                 usage(argv0);
671                 exit(-1);
672             }
673         }
674         if (numThreads > 1) {
675 #if SK_SUPPORT_GPU
676             if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) {
677                 tiledRenderer->unref();
678                 SkDebugf("GPU not compatible with multithreaded tiling.\n");
679                 usage(argv0);
680                 exit(-1);
681             }
682 #endif
683         }
684         renderer = tiledRenderer;
685         if (usePipe) {
686             SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
687                      "Turning off pipe.\n");
688         }
689     } else if (usePipe) {
690         if (renderer != NULL) {
691             renderer->unref();
692             SkDebugf("Pipe is incompatible with other modes.\n");
693             usage(argv0);
694             exit(-1);
695         }
696         renderer = SkNEW(sk_tools::PipePictureRenderer);
697     }
698 
699     if (inputs->empty()) {
700         SkSafeUnref(renderer);
701         if (NULL != outputDir) {
702             SkDELETE(outputDir);
703         }
704         usage(argv0);
705         exit(-1);
706     }
707 
708     if (NULL == renderer) {
709         renderer = SkNEW(sk_tools::SimplePictureRenderer);
710     }
711 
712     renderer->setBBoxHierarchyType(bbhType);
713     renderer->setGridSize(gridWidth, gridHeight);
714     renderer->setViewport(viewport);
715     renderer->setScaleFactor(scaleFactor);
716     renderer->setDeviceType(deviceType);
717 }
718 
719 int tool_main(int argc, char** argv);
tool_main(int argc,char ** argv)720 int tool_main(int argc, char** argv) {
721     SkAutoGraphics ag;
722     SkTArray<SkString> inputs;
723     sk_tools::PictureRenderer* renderer = NULL;
724     SkString* outputDir = NULL;
725     bool validate = false;
726     int maxComponentDiff = 256;
727     bool writeWholeImage = false;
728     int clones = 0;
729     parse_commandline(argc, argv, &inputs, renderer, outputDir,
730                       &validate, &maxComponentDiff, &writeWholeImage, &clones);
731     SkASSERT(renderer);
732 
733     int failures = 0;
734     for (int i = 0; i < inputs.count(); i ++) {
735         failures += process_input(inputs[i], outputDir, *renderer,
736                                   validate, maxComponentDiff,
737                                   writeWholeImage, clones);
738     }
739     if (failures != 0) {
740         SkDebugf("Failed to render %i pictures.\n", failures);
741         return 1;
742     }
743 #if SK_SUPPORT_GPU
744 #if GR_CACHE_STATS
745     if (renderer->isUsingGpuDevice()) {
746         GrContext* ctx = renderer->getGrContext();
747 
748         ctx->printCacheStats();
749     }
750 #endif
751 #endif
752     if (NULL != outputDir) {
753         SkDELETE(outputDir);
754     }
755     SkDELETE(renderer);
756     return 0;
757 }
758 
759 #if !defined SK_BUILD_FOR_IOS
main(int argc,char * const argv[])760 int main(int argc, char * const argv[]) {
761     return tool_main(argc, (char**) argv);
762 }
763 #endif
764