render_pictures_main.cpp revision d17c8656342422447e4c40e4113052ddce4aaf38
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
24static 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
116static 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
123static 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.resetState();
172
173    renderer.end();
174
175    SkDELETE(picture);
176    return success;
177}
178
179static int MaxDiff(uint32_t v1, uint32_t v2) {
180    return MAX(MAX(abs(SkColorGetA(v1) - SkColorGetA(v2)), abs(SkColorGetR(v1) - SkColorGetR(v2))),
181               MAX(abs(SkColorGetG(v1) - SkColorGetG(v2)), abs(SkColorGetB(v1) - SkColorGetB(v2))));
182}
183
184static bool render_picture(const SkString& inputPath, const SkString* outputDir,
185                           sk_tools::PictureRenderer& renderer,
186                           bool validate, int maxComponentDiff,
187                           bool writeWholeImage,
188                           int clones) {
189    int diffs[256];
190    memset(diffs, 0x00, sizeof(diffs));
191    SkBitmap* bitmap = NULL;
192    bool success = render_picture(inputPath,
193        writeWholeImage ? NULL : outputDir,
194        renderer,
195        validate || writeWholeImage ? &bitmap : NULL, clones);
196
197    if (!success || ((validate || writeWholeImage) && bitmap == NULL)) {
198        SkDebugf("Failed to draw the picture.\n");
199        SkDELETE(bitmap);
200        return false;
201    }
202
203    if (validate) {
204        SkBitmap* referenceBitmap = NULL;
205        sk_tools::SimplePictureRenderer referenceRenderer;
206        success = render_picture(inputPath, NULL, referenceRenderer,
207                                 &referenceBitmap, 0);
208
209        if (!success || !referenceBitmap) {
210            SkDebugf("Failed to draw the reference picture.\n");
211            SkDELETE(bitmap);
212            SkDELETE(referenceBitmap);
213            return false;
214        }
215
216        if (success && (bitmap->width() != referenceBitmap->width())) {
217            SkDebugf("Expected image width: %i, actual image width %i.\n",
218                     referenceBitmap->width(), bitmap->width());
219            SkDELETE(bitmap);
220            SkDELETE(referenceBitmap);
221            return false;
222        }
223        if (success && (bitmap->height() != referenceBitmap->height())) {
224            SkDebugf("Expected image height: %i, actual image height %i",
225                     referenceBitmap->height(), bitmap->height());
226            SkDELETE(bitmap);
227            SkDELETE(referenceBitmap);
228            return false;
229        }
230
231        for (int y = 0; success && y < bitmap->height(); y++) {
232            for (int x = 0; success && x < bitmap->width(); x++) {
233                int diff = MaxDiff(*referenceBitmap->getAddr32(x, y),
234                                   *bitmap->getAddr32(x, y));
235                SkASSERT(diff >= 0 && diff <= 255);
236                diffs[diff]++;
237
238                if (diff > maxComponentDiff) {
239                    SkDebugf("Expected pixel at (%i %i) exceedds maximum "
240                                 "component diff of %i: 0x%x, actual 0x%x\n",
241                             x, y, maxComponentDiff,
242                             *referenceBitmap->getAddr32(x, y),
243                             *bitmap->getAddr32(x, y));
244                    SkDELETE(bitmap);
245                    SkDELETE(referenceBitmap);
246                    return false;
247                }
248            }
249        }
250        SkDELETE(referenceBitmap);
251
252        for (int i = 1; i <= 255; ++i) {
253            if(diffs[i] > 0) {
254                SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]);
255            }
256        }
257    }
258
259    if (writeWholeImage) {
260        sk_tools::force_all_opaque(*bitmap);
261        if (NULL != outputDir && writeWholeImage) {
262            SkString inputFilename;
263            sk_tools::get_basename(&inputFilename, inputPath);
264            SkString outputPath;
265            make_output_filepath(&outputPath, *outputDir, inputFilename);
266            outputPath.append(".png");
267            if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap,
268                                            SkImageEncoder::kPNG_Type, 100)) {
269                SkDebugf("Failed to draw the picture.\n");
270                success = false;
271            }
272        }
273    }
274    SkDELETE(bitmap);
275
276    return success;
277}
278
279
280static int process_input(const SkString& input, const SkString* outputDir,
281                         sk_tools::PictureRenderer& renderer,
282                         bool validate, int maxComponentDiff,
283                         bool writeWholeImage, int clones) {
284    SkOSFile::Iter iter(input.c_str(), "skp");
285    SkString inputFilename;
286    int failures = 0;
287    SkDebugf("process_input, %s\n", input.c_str());
288    if (iter.next(&inputFilename)) {
289        do {
290            SkString inputPath;
291            sk_tools::make_filepath(&inputPath, input, inputFilename);
292            if (!render_picture(inputPath, outputDir, renderer,
293                                validate, maxComponentDiff,
294                                writeWholeImage, clones)) {
295                ++failures;
296            }
297        } while(iter.next(&inputFilename));
298    } else if (SkStrEndsWith(input.c_str(), ".skp")) {
299        SkString inputPath(input);
300        if (!render_picture(inputPath, outputDir, renderer,
301                            validate, maxComponentDiff,
302                            writeWholeImage, clones)) {
303            ++failures;
304        }
305    } else {
306        SkString warning;
307        warning.printf("Warning: skipping %s\n", input.c_str());
308        SkDebugf(warning.c_str());
309    }
310    return failures;
311}
312
313static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
314                              sk_tools::PictureRenderer*& renderer, SkString*& outputDir,
315                              bool* validate, int* maxComponentDiff,
316                              bool* writeWholeImage,
317                              int* clones){
318    const char* argv0 = argv[0];
319    char* const* stop = argv + argc;
320
321    sk_tools::PictureRenderer::SkDeviceTypes deviceType =
322        sk_tools::PictureRenderer::kBitmap_DeviceType;
323
324    bool usePipe = false;
325    int numThreads = 1;
326    bool useTiles = false;
327    const char* widthString = NULL;
328    const char* heightString = NULL;
329    int gridWidth = 0;
330    int gridHeight = 0;
331    bool isPowerOf2Mode = false;
332    bool isCopyMode = false;
333    const char* xTilesString = NULL;
334    const char* yTilesString = NULL;
335    const char* mode = NULL;
336    bool gridSupported = false;
337    sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
338        sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
339    *validate = false;
340    *maxComponentDiff = 256;
341    *writeWholeImage = false;
342    *clones = 0;
343    SkISize viewport;
344    viewport.setEmpty();
345    SkScalar scaleFactor = SK_Scalar1;
346
347    for (++argv; argv < stop; ++argv) {
348        if (0 == strcmp(*argv, "--mode")) {
349            if (renderer != NULL) {
350                renderer->unref();
351                SkDebugf("Cannot combine modes.\n");
352                usage(argv0);
353                exit(-1);
354            }
355
356            ++argv;
357            if (argv >= stop) {
358                SkDebugf("Missing mode for --mode\n");
359                usage(argv0);
360                exit(-1);
361            }
362
363            if (0 == strcmp(*argv, "simple")) {
364                renderer = SkNEW(sk_tools::SimplePictureRenderer);
365            } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))
366                       || 0 == strcmp(*argv, "copyTile")) {
367                useTiles = true;
368                mode = *argv;
369
370                if (0 == strcmp(*argv, "pow2tile")) {
371                    isPowerOf2Mode = true;
372                } else if (0 == strcmp(*argv, "copyTile")) {
373                    isCopyMode = true;
374                } else {
375                    gridSupported = true;
376                }
377
378                ++argv;
379                if (argv >= stop) {
380                    SkDebugf("Missing width for --mode %s\n", mode);
381                    usage(argv0);
382                    exit(-1);
383                }
384
385                widthString = *argv;
386                ++argv;
387                if (argv >= stop) {
388                    SkDebugf("Missing height for --mode %s\n", mode);
389                    usage(argv0);
390                    exit(-1);
391                }
392                heightString = *argv;
393            } else if (0 == strcmp(*argv, "rerecord")) {
394                renderer = SkNEW(sk_tools::RecordPictureRenderer);
395            } else {
396                SkDebugf("%s is not a valid mode for --mode\n", *argv);
397                usage(argv0);
398                exit(-1);
399            }
400        } else if (0 == strcmp(*argv, "--bbh")) {
401            ++argv;
402            if (argv >= stop) {
403                SkDebugf("Missing value for --bbh\n");
404                usage(argv0);
405                exit(-1);
406            }
407            if (0 == strcmp(*argv, "none")) {
408                bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
409            } else if (0 == strcmp(*argv, "rtree")) {
410                bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
411            } else if (0 == strcmp(*argv, "grid")) {
412                bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType;
413                ++argv;
414                if (argv >= stop) {
415                    SkDebugf("Missing width for --bbh grid\n");
416                    usage(argv0);
417                    exit(-1);
418                }
419                gridWidth = atoi(*argv);
420                ++argv;
421                if (argv >= stop) {
422                    SkDebugf("Missing height for --bbh grid\n");
423                    usage(argv0);
424                    exit(-1);
425                }
426                gridHeight = atoi(*argv);
427            } else {
428                SkDebugf("%s is not a valid value for --bbhType\n", *argv);
429                usage(argv0);
430                exit(-1);;
431            }
432        } else if (0 == strcmp(*argv, "--viewport")) {
433            ++argv;
434            if (argv >= stop) {
435                SkDebugf("Missing width for --viewport\n");
436                usage(argv0);
437                exit(-1);
438            }
439            viewport.fWidth = atoi(*argv);
440            ++argv;
441            if (argv >= stop) {
442                SkDebugf("Missing height for --viewport\n");
443                usage(argv0);
444                exit(-1);
445            }
446            viewport.fHeight = atoi(*argv);
447        } else if (0 == strcmp(*argv, "--scale")) {
448            ++argv;
449            if (argv >= stop) {
450                SkDebugf("Missing scaleFactor for --scale\n");
451                usage(argv0);
452                exit(-1);
453            }
454            scaleFactor = SkDoubleToScalar(atof(*argv));
455        } else if (0 == strcmp(*argv, "--tiles")) {
456            ++argv;
457            if (argv >= stop) {
458                SkDebugf("Missing x for --tiles\n");
459                usage(argv0);
460                exit(-1);
461            }
462            xTilesString = *argv;
463            ++argv;
464            if (argv >= stop) {
465                SkDebugf("Missing y for --tiles\n");
466                usage(argv0);
467                exit(-1);
468            }
469            yTilesString = *argv;
470        } else if (0 == strcmp(*argv, "--pipe")) {
471            usePipe = true;
472        } else if (0 == strcmp(*argv, "--multi")) {
473            ++argv;
474            if (argv >= stop) {
475                SkSafeUnref(renderer);
476                SkDebugf("Missing arg for --multi\n");
477                usage(argv0);
478                exit(-1);
479            }
480            numThreads = atoi(*argv);
481            if (numThreads < 2) {
482                SkSafeUnref(renderer);
483                SkDebugf("Number of threads must be at least 2.\n");
484                usage(argv0);
485                exit(-1);
486            }
487        } else if (0 == strcmp(*argv, "--clone")) {
488            ++argv;
489            if (argv >= stop) {
490                SkSafeUnref(renderer);
491                SkDebugf("Missing arg for --clone\n");
492                usage(argv0);
493                exit(-1);
494            }
495            *clones = atoi(*argv);
496            if (*clones < 0) {
497                SkSafeUnref(renderer);
498                SkDebugf("Number of clones must be at least 0.\n");
499                usage(argv0);
500                exit(-1);
501            }
502        } else if (0 == strcmp(*argv, "--device")) {
503            ++argv;
504            if (argv >= stop) {
505                SkSafeUnref(renderer);
506                SkDebugf("Missing mode for --device\n");
507                usage(argv0);
508                exit(-1);
509            }
510
511            if (0 == strcmp(*argv, "bitmap")) {
512                deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
513            }
514#if SK_SUPPORT_GPU
515            else if (0 == strcmp(*argv, "gpu")) {
516                deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
517            }
518#endif
519            else {
520                SkSafeUnref(renderer);
521                SkDebugf("%s is not a valid mode for --device\n", *argv);
522                usage(argv0);
523                exit(-1);
524            }
525
526        } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
527            SkSafeUnref(renderer);
528            usage(argv0);
529            exit(-1);
530        } else if (0 == strcmp(*argv, "-w")) {
531            ++argv;
532            if (argv >= stop) {
533                SkDebugf("Missing output directory for -w\n");
534                usage(argv0);
535                exit(-1);
536            }
537            outputDir = SkNEW_ARGS(SkString, (*argv));
538        } else if (0 == strcmp(*argv, "--validate")) {
539            *validate = true;
540        } else if (0 == strcmp(*argv, "--maxComponentDiff")) {
541            if (!*validate) {
542                SkDebugf("--maxComponentDiff must be used only with --validate\n");
543                usage(argv0);
544                exit(-1);
545            }
546            ++argv;
547            if (argv >= stop) {
548                SkDebugf("Missing arg for --maxComponentDiff\n");
549                usage(argv0);
550                exit(-1);
551            }
552            *maxComponentDiff = atoi(*argv);
553            if (*maxComponentDiff < 0 || *maxComponentDiff > 256) {
554                SkSafeUnref(renderer);
555                SkDebugf("maxComponentDiff: 0 - 256.\n");
556                usage(argv0);
557                exit(-1);
558            }
559        } else if (0 == strcmp(*argv, "--writeWholeImage")) {
560            *writeWholeImage = true;
561        } else {
562            inputs->push_back(SkString(*argv));
563        }
564    }
565
566    if (numThreads > 1 && !useTiles) {
567        SkSafeUnref(renderer);
568        SkDebugf("Multithreaded drawing requires tiled rendering.\n");
569        usage(argv0);
570        exit(-1);
571    }
572
573    if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
574        SkDebugf("--pipe and --bbh cannot be used together\n");
575        usage(argv0);
576        exit(-1);
577    }
578
579    if (sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType == bbhType &&
580        !gridSupported) {
581        SkDebugf("'--bbh grid' is not compatible with specified --mode.\n");
582        usage(argv0);
583        exit(-1);
584    }
585
586    if (useTiles) {
587        SkASSERT(NULL == renderer);
588        sk_tools::TiledPictureRenderer* tiledRenderer;
589        if (isCopyMode) {
590            int x, y;
591            if (xTilesString != NULL) {
592                SkASSERT(yTilesString != NULL);
593                x = atoi(xTilesString);
594                y = atoi(yTilesString);
595                if (x <= 0 || y <= 0) {
596                    SkDebugf("--tiles must be given values > 0\n");
597                    usage(argv0);
598                    exit(-1);
599                }
600            } else {
601                x = y = 4;
602            }
603            tiledRenderer = SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y));
604        } else if (numThreads > 1) {
605            tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
606        } else {
607            tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
608        }
609        if (isPowerOf2Mode) {
610            int minWidth = atoi(widthString);
611            if (!SkIsPow2(minWidth) || minWidth < 0) {
612                tiledRenderer->unref();
613                SkString err;
614                err.printf("-mode %s must be given a width"
615                           " value that is a power of two\n", mode);
616                SkDebugf(err.c_str());
617                usage(argv0);
618                exit(-1);
619            }
620            tiledRenderer->setTileMinPowerOf2Width(minWidth);
621        } else if (sk_tools::is_percentage(widthString)) {
622            if (isCopyMode) {
623                tiledRenderer->unref();
624                SkString err;
625                err.printf("--mode %s does not support percentages.\n", mode);
626                SkDebugf(err.c_str());
627                usage(argv0);
628                exit(-1);
629            }
630            tiledRenderer->setTileWidthPercentage(atof(widthString));
631            if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
632                tiledRenderer->unref();
633                SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
634                usage(argv0);
635                exit(-1);
636            }
637        } else {
638            tiledRenderer->setTileWidth(atoi(widthString));
639            if (!(tiledRenderer->getTileWidth() > 0)) {
640                tiledRenderer->unref();
641                SkDebugf("--mode %s must be given a width > 0\n", mode);
642                usage(argv0);
643                exit(-1);
644            }
645        }
646
647        if (sk_tools::is_percentage(heightString)) {
648            if (isCopyMode) {
649                tiledRenderer->unref();
650                SkString err;
651                err.printf("--mode %s does not support percentages.\n", mode);
652                SkDebugf(err.c_str());
653                usage(argv0);
654                exit(-1);
655            }
656            tiledRenderer->setTileHeightPercentage(atof(heightString));
657            if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
658                tiledRenderer->unref();
659                SkDebugf("--mode %s must be given a height percentage > 0\n", mode);
660                usage(argv0);
661                exit(-1);
662            }
663        } else {
664            tiledRenderer->setTileHeight(atoi(heightString));
665            if (!(tiledRenderer->getTileHeight() > 0)) {
666                tiledRenderer->unref();
667                SkDebugf("--mode %s must be given a height > 0\n", mode);
668                usage(argv0);
669                exit(-1);
670            }
671        }
672        if (numThreads > 1) {
673#if SK_SUPPORT_GPU
674            if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) {
675                tiledRenderer->unref();
676                SkDebugf("GPU not compatible with multithreaded tiling.\n");
677                usage(argv0);
678                exit(-1);
679            }
680#endif
681        }
682        renderer = tiledRenderer;
683        if (usePipe) {
684            SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
685                     "Turning off pipe.\n");
686        }
687    } else if (usePipe) {
688        if (renderer != NULL) {
689            renderer->unref();
690            SkDebugf("Pipe is incompatible with other modes.\n");
691            usage(argv0);
692            exit(-1);
693        }
694        renderer = SkNEW(sk_tools::PipePictureRenderer);
695    }
696
697    if (inputs->empty()) {
698        SkSafeUnref(renderer);
699        if (NULL != outputDir) {
700            SkDELETE(outputDir);
701        }
702        usage(argv0);
703        exit(-1);
704    }
705
706    if (NULL == renderer) {
707        renderer = SkNEW(sk_tools::SimplePictureRenderer);
708    }
709
710    renderer->setBBoxHierarchyType(bbhType);
711    renderer->setGridSize(gridWidth, gridHeight);
712    renderer->setViewport(viewport);
713    renderer->setScaleFactor(scaleFactor);
714    renderer->setDeviceType(deviceType);
715}
716
717int tool_main(int argc, char** argv);
718int tool_main(int argc, char** argv) {
719    SkAutoGraphics ag;
720    SkTArray<SkString> inputs;
721    sk_tools::PictureRenderer* renderer = NULL;
722    SkString* outputDir = NULL;
723    bool validate = false;
724    int maxComponentDiff = 256;
725    bool writeWholeImage = false;
726    int clones = 0;
727    parse_commandline(argc, argv, &inputs, renderer, outputDir,
728                      &validate, &maxComponentDiff, &writeWholeImage, &clones);
729    SkASSERT(renderer);
730
731    int failures = 0;
732    for (int i = 0; i < inputs.count(); i ++) {
733        failures += process_input(inputs[i], outputDir, *renderer,
734                                  validate, maxComponentDiff,
735                                  writeWholeImage, clones);
736    }
737    if (failures != 0) {
738        SkDebugf("Failed to render %i pictures.\n", failures);
739        return 1;
740    }
741#if SK_SUPPORT_GPU
742#if GR_CACHE_STATS
743    if (renderer->isUsingGpuDevice()) {
744        GrContext* ctx = renderer->getGrContext();
745
746        ctx->printCacheStats();
747    }
748#endif
749#endif
750    if (NULL != outputDir) {
751        SkDELETE(outputDir);
752    }
753    SkDELETE(renderer);
754    return 0;
755}
756
757#if !defined SK_BUILD_FOR_IOS
758int main(int argc, char * const argv[]) {
759    return tool_main(argc, (char**) argv);
760}
761#endif
762