blob: a459bf20a95d83f99abe8042eb8a71afe8cfa6ec [file] [log] [blame]
junov@chromium.org777442d2012-06-12 14:56:36 +00001/*
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
scroggo@google.com4a26d9d2012-11-07 18:01:46 +00008#include "CopyTilesRenderer.h"
junov@chromium.org777442d2012-06-12 14:56:36 +00009#include "SkBitmap.h"
10#include "SkCanvas.h"
keyar@chromium.org472b3792012-07-20 22:34:27 +000011#include "SkDevice.h"
borenet@google.com10ef79e2012-09-10 17:19:06 +000012#include "SkGraphics.h"
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000013#include "SkImageDecoder.h"
edisonn@google.com84f548c2012-12-18 22:24:03 +000014#include "SkImageEncoder.h"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000015#include "SkMath.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000016#include "SkOSFile.h"
17#include "SkPicture.h"
18#include "SkStream.h"
19#include "SkString.h"
senorblanco@chromium.org3cbbb542012-07-13 18:55:53 +000020#include "SkTArray.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000021#include "PictureRenderer.h"
twiz@google.coma31b8bb2012-06-22 18:24:56 +000022#include "picture_utils.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000023
junov@chromium.org777442d2012-06-12 14:56:36 +000024static void usage(const char* argv0) {
25 SkDebugf("SkPicture rendering tool\n");
26 SkDebugf("\n"
27"Usage: \n"
borenet@google.com070d3542012-10-26 13:26:55 +000028" %s <input>... \n"
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000029" [-w <outputDir>]\n"
30" [--mode pow2tile minWidth height | copyTile width height | simple\n"
31" | tile width height]\n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000032" [--pipe]\n"
edisonn@google.com84f548c2012-12-18 22:24:03 +000033" [--bbh bbhType]\n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000034" [--multi count]\n"
edisonn@google.comca1b3ff2013-01-16 18:18:48 +000035" [--validate [--maxComponentDiff n]]\n"
edisonn@google.com84f548c2012-12-18 22:24:03 +000036" [--writeWholeImage]\n"
37" [--clone n]\n"
scroggo@google.com82ec0b02012-12-17 19:25:54 +000038" [--viewport width height][--scale sf]\n"
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000039" [--device bitmap"
40#if SK_SUPPORT_GPU
41" | gpu"
42#endif
43"]"
junov@chromium.org777442d2012-06-12 14:56:36 +000044, argv0);
keyar@chromium.org472b3792012-07-20 22:34:27 +000045 SkDebugf("\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000046 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000047" input: A list of directories and files to use as input. Files are\n"
48" expected to have the .skp extension.\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000049 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000050" outputDir: directory to write the rendered images.\n\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000051 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000052" --mode pow2tile minWidth height | copyTile width height | simple\n"
53" | tile width height | rerecord: Run in the corresponding mode.\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000054" Default is simple.\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000055 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000056" pow2tile minWidth height, Creates tiles with widths\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000057" 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(
scroggo@google.coma9e3a362012-11-07 17:52:48 +000065" simple, Render using the default rendering method.\n"
66" rerecord, Record the picture as a new skp, with the bitmaps PNG encoded.\n"
67 );
keyar@chromium.org795cd472012-08-02 18:57:53 +000068 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000069" 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 );
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000079 SkDebugf("\n");
80 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000081" --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
82" than 1. Only works with tiled rendering.\n"
scroggo@google.comc0d5e542012-12-13 21:40:48 +000083" --viewport width height : Set the viewport.\n"
scroggo@google.com82ec0b02012-12-17 19:25:54 +000084" --scale sf : Scale drawing by sf.\n"
scroggo@google.coma62da2f2012-11-02 21:28:12 +000085" --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
scroggo@google.comb6e806b2012-10-03 17:32:33 +000086 SkDebugf(
edisonn@google.com84f548c2012-12-18 22:24:03 +000087" --validate: Verify that the rendered image contains the same pixels as "
88"the picture rendered in simple mode.\n"
edisonn@google.comca1b3ff2013-01-16 18:18:48 +000089" --maxComponentDiff: maximum diff on a component. Default is 256, "
90"which means we report but we do not generate an error.\n"
edisonn@google.com84f548c2012-12-18 22:24:03 +000091" --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(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000103" --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");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000110#if SK_SUPPORT_GPU
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000111 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000112" gpu, Render to the GPU.\n");
113#endif
junov@chromium.org777442d2012-06-12 14:56:36 +0000114}
115
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000116static void make_output_filepath(SkString* path, const SkString& dir,
junov@chromium.org777442d2012-06-12 14:56:36 +0000117 const SkString& name) {
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000118 sk_tools::make_filepath(path, dir, name);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000119 // Remove ".skp"
120 path->remove(path->size() - 4, 4);
junov@chromium.org777442d2012-06-12 14:56:36 +0000121}
122
borenet@google.com070d3542012-10-26 13:26:55 +0000123static bool render_picture(const SkString& inputPath, const SkString* outputDir,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000124 sk_tools::PictureRenderer& renderer,
125 SkBitmap** out,
126 int clones) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000127 SkString inputFilename;
128 sk_tools::get_basename(&inputFilename, inputPath);
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000129
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000130 SkFILEStream inputStream;
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000131 inputStream.setPath(inputPath.c_str());
132 if (!inputStream.isValid()) {
133 SkDebugf("Could not open file %s\n", inputPath.c_str());
borenet@google.com66bcbd12012-09-17 18:26:06 +0000134 return false;
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000135 }
136
borenet@google.com66bcbd12012-09-17 18:26:06 +0000137 bool success = false;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000138 SkPicture* picture = SkNEW_ARGS(SkPicture,
139 (&inputStream, &success, &SkImageDecoder::DecodeStream));
borenet@google.com66bcbd12012-09-17 18:26:06 +0000140 if (!success) {
141 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
142 return false;
143 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000144
edisonn@google.com84f548c2012-12-18 22:24:03 +0000145 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(),
borenet@google.com03fcee82012-09-10 18:18:38 +0000152 inputPath.c_str());
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000153
edisonn@google.com84f548c2012-12-18 22:24:03 +0000154 renderer.init(picture);
scroggo@google.comb4773b42012-10-01 20:06:09 +0000155 renderer.setup();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000156
borenet@google.com070d3542012-10-26 13:26:55 +0000157 SkString* outputPath = NULL;
158 if (NULL != outputDir) {
159 outputPath = SkNEW(SkString);
160 make_output_filepath(outputPath, *outputDir, inputFilename);
161 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000162
163 success = renderer.render(outputPath, out);
borenet@google.com070d3542012-10-26 13:26:55 +0000164 if (outputPath) {
165 if (!success) {
166 SkDebugf("Could not write to file %s\n", outputPath->c_str());
167 }
168 SkDELETE(outputPath);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000169 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000170
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000171 renderer.end();
edisonn@google.com84f548c2012-12-18 22:24:03 +0000172
173 SkDELETE(picture);
borenet@google.com66bcbd12012-09-17 18:26:06 +0000174 return success;
junov@chromium.org777442d2012-06-12 14:56:36 +0000175}
176
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000177static inline int getByte(uint32_t value, int index) {
178 SkASSERT(0 <= index && index < 4);
179 return (value >> (index * 8)) & 0xFF;
180}
181
182static 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
edisonn@google.com84f548c2012-12-18 22:24:03 +0000187static bool render_picture(const SkString& inputPath, const SkString* outputDir,
188 sk_tools::PictureRenderer& renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000189 bool validate, int maxComponentDiff,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000190 bool writeWholeImage,
191 int clones) {
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000192 int diffs[256] = {0};
edisonn@google.com84f548c2012-12-18 22:24:03 +0000193 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 }
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000232
edisonn@google.com84f548c2012-12-18 22:24:03 +0000233 for (int y = 0; success && y < bitmap->height(); y++) {
234 for (int x = 0; success && x < bitmap->width(); x++) {
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000235 int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y),
236 *bitmap->getAddr32(x, y));
237 SkASSERT(diff >= 0 && diff <= 255);
238 diffs[diff]++;
skia.committer@gmail.com4d28d982013-01-17 07:06:06 +0000239
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000240 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,
edisonn@google.com01754bf2013-01-11 16:08:07 +0000244 *referenceBitmap->getAddr32(x, y),
edisonn@google.com84f548c2012-12-18 22:24:03 +0000245 *bitmap->getAddr32(x, y));
246 SkDELETE(bitmap);
247 SkDELETE(referenceBitmap);
248 return false;
249 }
250 }
251 }
252 SkDELETE(referenceBitmap);
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000253
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 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000259 }
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
borenet@google.com070d3542012-10-26 13:26:55 +0000282static int process_input(const SkString& input, const SkString* outputDir,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000283 sk_tools::PictureRenderer& renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000284 bool validate, int maxComponentDiff,
285 bool writeWholeImage, int clones) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000286 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000287 SkString inputFilename;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000288 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000289 SkDebugf("process_input, %s\n", input.c_str());
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000290 if (iter.next(&inputFilename)) {
291 do {
292 SkString inputPath;
293 sk_tools::make_filepath(&inputPath, input, inputFilename);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000294 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000295 validate, maxComponentDiff,
296 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000297 ++failures;
298 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000299 } while(iter.next(&inputFilename));
borenet@google.com57837bf2012-09-19 17:28:29 +0000300 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000301 SkString inputPath(input);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000302 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000303 validate, maxComponentDiff,
304 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000305 ++failures;
306 }
307 } else {
308 SkString warning;
309 warning.printf("Warning: skipping %s\n", input.c_str());
310 SkDebugf(warning.c_str());
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000311 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000312 return failures;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000313}
314
315static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000316 sk_tools::PictureRenderer*& renderer, SkString*& outputDir,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000317 bool* validate, int* maxComponentDiff,
318 bool* writeWholeImage,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000319 int* clones){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000320 const char* argv0 = argv[0];
321 char* const* stop = argv + argc;
322
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000323 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
324 sk_tools::PictureRenderer::kBitmap_DeviceType;
325
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000326 bool usePipe = false;
327 int numThreads = 1;
328 bool useTiles = false;
329 const char* widthString = NULL;
330 const char* heightString = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000331 int gridWidth = 0;
332 int gridHeight = 0;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000333 bool isPowerOf2Mode = false;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000334 bool isCopyMode = false;
335 const char* xTilesString = NULL;
336 const char* yTilesString = NULL;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000337 const char* mode = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000338 bool gridSupported = false;
339 sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
340 sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
341 *validate = false;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000342 *maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000343 *writeWholeImage = false;
344 *clones = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000345 SkISize viewport;
346 viewport.setEmpty();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000347 SkScalar scaleFactor = SK_Scalar1;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000348
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000349 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000350 if (0 == strcmp(*argv, "--mode")) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000351 if (renderer != NULL) {
352 renderer->unref();
353 SkDebugf("Cannot combine modes.\n");
354 usage(argv0);
355 exit(-1);
356 }
keyar@chromium.org795cd472012-08-02 18:57:53 +0000357
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000358 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000359 if (argv >= stop) {
360 SkDebugf("Missing mode for --mode\n");
361 usage(argv0);
362 exit(-1);
363 }
364
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000365 if (0 == strcmp(*argv, "simple")) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000366 renderer = SkNEW(sk_tools::SimplePictureRenderer);
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000367 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))
368 || 0 == strcmp(*argv, "copyTile")) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000369 useTiles = true;
370 mode = *argv;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000371
372 if (0 == strcmp(*argv, "pow2tile")) {
373 isPowerOf2Mode = true;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000374 } else if (0 == strcmp(*argv, "copyTile")) {
375 isCopyMode = true;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000376 } else {
377 gridSupported = true;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000378 }
379
keyar@chromium.org795cd472012-08-02 18:57:53 +0000380 ++argv;
381 if (argv >= stop) {
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000382 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000383 usage(argv0);
384 exit(-1);
385 }
386
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000387 widthString = *argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000388 ++argv;
389 if (argv >= stop) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000390 SkDebugf("Missing height for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000391 usage(argv0);
392 exit(-1);
393 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000394 heightString = *argv;
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000395 } else if (0 == strcmp(*argv, "rerecord")) {
396 renderer = SkNEW(sk_tools::RecordPictureRenderer);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000397 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000398 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000399 usage(argv0);
400 exit(-1);
401 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000402 } 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 }
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000434 } 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);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000449 } 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 }
reed@google.com89d15a22013-01-07 22:26:05 +0000456 scaleFactor = SkDoubleToScalar(atof(*argv));
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000457 } 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;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000472 } else if (0 == strcmp(*argv, "--pipe")) {
473 usePipe = true;
474 } else if (0 == strcmp(*argv, "--multi")) {
475 ++argv;
476 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000477 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000478 SkDebugf("Missing arg for --multi\n");
479 usage(argv0);
480 exit(-1);
481 }
482 numThreads = atoi(*argv);
483 if (numThreads < 2) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000484 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000485 SkDebugf("Number of threads must be at least 2.\n");
486 usage(argv0);
487 exit(-1);
488 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000489 } 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 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000504 } else if (0 == strcmp(*argv, "--device")) {
505 ++argv;
506 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000507 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000508 SkDebugf("Missing mode for --device\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000509 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 {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000522 SkSafeUnref(renderer);
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000523 SkDebugf("%s is not a valid mode for --device\n", *argv);
524 usage(argv0);
525 exit(-1);
526 }
527
keyar@chromium.org472b3792012-07-20 22:34:27 +0000528 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000529 SkSafeUnref(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000530 usage(argv0);
531 exit(-1);
borenet@google.com070d3542012-10-26 13:26:55 +0000532 } 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));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000540 } else if (0 == strcmp(*argv, "--validate")) {
541 *validate = true;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000542 } 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);
skia.committer@gmail.com4d28d982013-01-17 07:06:06 +0000560 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000561 } else if (0 == strcmp(*argv, "--writeWholeImage")) {
562 *writeWholeImage = true;
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000563 } else {
564 inputs->push_back(SkString(*argv));
565 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000566 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000567
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000568 if (numThreads > 1 && !useTiles) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000569 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000570 SkDebugf("Multithreaded drawing requires tiled rendering.\n");
571 usage(argv0);
572 exit(-1);
573 }
574
edisonn@google.com84f548c2012-12-18 22:24:03 +0000575 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
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000588 if (useTiles) {
589 SkASSERT(NULL == renderer);
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000590 sk_tools::TiledPictureRenderer* tiledRenderer;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000591 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) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000607 tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
608 } else {
609 tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
610 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000611 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)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000624 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 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000632 tiledRenderer->setTileWidthPercentage(atof(widthString));
633 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
634 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000635 SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000636 usage(argv0);
637 exit(-1);
638 }
639 } else {
640 tiledRenderer->setTileWidth(atoi(widthString));
641 if (!(tiledRenderer->getTileWidth() > 0)) {
642 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000643 SkDebugf("--mode %s must be given a width > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000644 usage(argv0);
645 exit(-1);
646 }
647 }
648
649 if (sk_tools::is_percentage(heightString)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000650 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 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000658 tiledRenderer->setTileHeightPercentage(atof(heightString));
659 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
660 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000661 SkDebugf("--mode %s must be given a height percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000662 usage(argv0);
663 exit(-1);
664 }
665 } else {
666 tiledRenderer->setTileHeight(atoi(heightString));
667 if (!(tiledRenderer->getTileHeight() > 0)) {
668 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000669 SkDebugf("--mode %s must be given a height > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000670 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
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000683 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000684 renderer = tiledRenderer;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000685 if (usePipe) {
686 SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
687 "Turning off pipe.\n");
688 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000689 } else if (usePipe) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000690 if (renderer != NULL) {
691 renderer->unref();
692 SkDebugf("Pipe is incompatible with other modes.\n");
693 usage(argv0);
694 exit(-1);
695 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000696 renderer = SkNEW(sk_tools::PipePictureRenderer);
697 }
698
borenet@google.com070d3542012-10-26 13:26:55 +0000699 if (inputs->empty()) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000700 SkSafeUnref(renderer);
borenet@google.com070d3542012-10-26 13:26:55 +0000701 if (NULL != outputDir) {
702 SkDELETE(outputDir);
703 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000704 usage(argv0);
705 exit(-1);
706 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000707
708 if (NULL == renderer) {
709 renderer = SkNEW(sk_tools::SimplePictureRenderer);
710 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000711
edisonn@google.com84f548c2012-12-18 22:24:03 +0000712 renderer->setBBoxHierarchyType(bbhType);
713 renderer->setGridSize(gridWidth, gridHeight);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000714 renderer->setViewport(viewport);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000715 renderer->setScaleFactor(scaleFactor);
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000716 renderer->setDeviceType(deviceType);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000717}
718
caryclark@google.com5987f582012-10-02 18:33:14 +0000719int tool_main(int argc, char** argv);
720int tool_main(int argc, char** argv) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000721 SkAutoGraphics ag;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000722 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000723 sk_tools::PictureRenderer* renderer = NULL;
borenet@google.com070d3542012-10-26 13:26:55 +0000724 SkString* outputDir = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000725 bool validate = false;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000726 int maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000727 bool writeWholeImage = false;
728 int clones = 0;
729 parse_commandline(argc, argv, &inputs, renderer, outputDir,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000730 &validate, &maxComponentDiff, &writeWholeImage, &clones);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000731 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000732
borenet@google.com66bcbd12012-09-17 18:26:06 +0000733 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000734 for (int i = 0; i < inputs.count(); i ++) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000735 failures += process_input(inputs[i], outputDir, *renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000736 validate, maxComponentDiff,
737 writeWholeImage, clones);
junov@chromium.org777442d2012-06-12 14:56:36 +0000738 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000739 if (failures != 0) {
740 SkDebugf("Failed to render %i pictures.\n", failures);
741 return 1;
742 }
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000743#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
borenet@google.com070d3542012-10-26 13:26:55 +0000752 if (NULL != outputDir) {
753 SkDELETE(outputDir);
754 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000755 SkDELETE(renderer);
caryclark@google.com868e1f62012-10-02 20:00:03 +0000756 return 0;
junov@chromium.org777442d2012-06-12 14:56:36 +0000757}
caryclark@google.com5987f582012-10-02 18:33:14 +0000758
759#if !defined SK_BUILD_FOR_IOS
760int main(int argc, char * const argv[]) {
761 return tool_main(argc, (char**) argv);
762}
763#endif