blob: 1539b56b57fe05cab70670b8ed2c8fdd46beead7 [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.comd17c8652013-01-16 14:47:06 +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.comd17c8652013-01-16 14:47:06 +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
171 renderer.resetState();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000172
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000173 renderer.end();
edisonn@google.com84f548c2012-12-18 22:24:03 +0000174
175 SkDELETE(picture);
borenet@google.com66bcbd12012-09-17 18:26:06 +0000176 return success;
junov@chromium.org777442d2012-06-12 14:56:36 +0000177}
178
edisonn@google.comd17c8652013-01-16 14:47:06 +0000179static 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
edisonn@google.com84f548c2012-12-18 22:24:03 +0000184static bool render_picture(const SkString& inputPath, const SkString* outputDir,
185 sk_tools::PictureRenderer& renderer,
edisonn@google.comd17c8652013-01-16 14:47:06 +0000186 bool validate, int maxComponentDiff,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000187 bool writeWholeImage,
188 int clones) {
edisonn@google.comd17c8652013-01-16 14:47:06 +0000189 int diffs[256];
190 memset(diffs, 0x00, sizeof(diffs));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000191 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 }
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000230
edisonn@google.com84f548c2012-12-18 22:24:03 +0000231 for (int y = 0; success && y < bitmap->height(); y++) {
232 for (int x = 0; success && x < bitmap->width(); x++) {
edisonn@google.comd17c8652013-01-16 14:47:06 +0000233 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,
edisonn@google.com01754bf2013-01-11 16:08:07 +0000242 *referenceBitmap->getAddr32(x, y),
edisonn@google.com84f548c2012-12-18 22:24:03 +0000243 *bitmap->getAddr32(x, y));
244 SkDELETE(bitmap);
245 SkDELETE(referenceBitmap);
246 return false;
247 }
248 }
249 }
250 SkDELETE(referenceBitmap);
edisonn@google.comd17c8652013-01-16 14:47:06 +0000251
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 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000257 }
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
borenet@google.com070d3542012-10-26 13:26:55 +0000280static int process_input(const SkString& input, const SkString* outputDir,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000281 sk_tools::PictureRenderer& renderer,
edisonn@google.comd17c8652013-01-16 14:47:06 +0000282 bool validate, int maxComponentDiff,
283 bool writeWholeImage, int clones) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000284 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000285 SkString inputFilename;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000286 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000287 SkDebugf("process_input, %s\n", input.c_str());
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000288 if (iter.next(&inputFilename)) {
289 do {
290 SkString inputPath;
291 sk_tools::make_filepath(&inputPath, input, inputFilename);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000292 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comd17c8652013-01-16 14:47:06 +0000293 validate, maxComponentDiff,
294 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000295 ++failures;
296 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000297 } while(iter.next(&inputFilename));
borenet@google.com57837bf2012-09-19 17:28:29 +0000298 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000299 SkString inputPath(input);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000300 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comd17c8652013-01-16 14:47:06 +0000301 validate, maxComponentDiff,
302 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000303 ++failures;
304 }
305 } else {
306 SkString warning;
307 warning.printf("Warning: skipping %s\n", input.c_str());
308 SkDebugf(warning.c_str());
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000309 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000310 return failures;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000311}
312
313static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000314 sk_tools::PictureRenderer*& renderer, SkString*& outputDir,
edisonn@google.comd17c8652013-01-16 14:47:06 +0000315 bool* validate, int* maxComponentDiff,
316 bool* writeWholeImage,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000317 int* clones){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000318 const char* argv0 = argv[0];
319 char* const* stop = argv + argc;
320
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000321 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
322 sk_tools::PictureRenderer::kBitmap_DeviceType;
323
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000324 bool usePipe = false;
325 int numThreads = 1;
326 bool useTiles = false;
327 const char* widthString = NULL;
328 const char* heightString = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000329 int gridWidth = 0;
330 int gridHeight = 0;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000331 bool isPowerOf2Mode = false;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000332 bool isCopyMode = false;
333 const char* xTilesString = NULL;
334 const char* yTilesString = NULL;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000335 const char* mode = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000336 bool gridSupported = false;
337 sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
338 sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
339 *validate = false;
edisonn@google.comd17c8652013-01-16 14:47:06 +0000340 *maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000341 *writeWholeImage = false;
342 *clones = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000343 SkISize viewport;
344 viewport.setEmpty();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000345 SkScalar scaleFactor = SK_Scalar1;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000346
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000347 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000348 if (0 == strcmp(*argv, "--mode")) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000349 if (renderer != NULL) {
350 renderer->unref();
351 SkDebugf("Cannot combine modes.\n");
352 usage(argv0);
353 exit(-1);
354 }
keyar@chromium.org795cd472012-08-02 18:57:53 +0000355
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000356 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000357 if (argv >= stop) {
358 SkDebugf("Missing mode for --mode\n");
359 usage(argv0);
360 exit(-1);
361 }
362
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000363 if (0 == strcmp(*argv, "simple")) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000364 renderer = SkNEW(sk_tools::SimplePictureRenderer);
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000365 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))
366 || 0 == strcmp(*argv, "copyTile")) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000367 useTiles = true;
368 mode = *argv;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000369
370 if (0 == strcmp(*argv, "pow2tile")) {
371 isPowerOf2Mode = true;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000372 } else if (0 == strcmp(*argv, "copyTile")) {
373 isCopyMode = true;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000374 } else {
375 gridSupported = true;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000376 }
377
keyar@chromium.org795cd472012-08-02 18:57:53 +0000378 ++argv;
379 if (argv >= stop) {
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000380 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000381 usage(argv0);
382 exit(-1);
383 }
384
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000385 widthString = *argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000386 ++argv;
387 if (argv >= stop) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000388 SkDebugf("Missing height for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000389 usage(argv0);
390 exit(-1);
391 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000392 heightString = *argv;
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000393 } else if (0 == strcmp(*argv, "rerecord")) {
394 renderer = SkNEW(sk_tools::RecordPictureRenderer);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000395 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000396 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000397 usage(argv0);
398 exit(-1);
399 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000400 } 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 }
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000432 } 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);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000447 } 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 }
reed@google.com89d15a22013-01-07 22:26:05 +0000454 scaleFactor = SkDoubleToScalar(atof(*argv));
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000455 } 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;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000470 } else if (0 == strcmp(*argv, "--pipe")) {
471 usePipe = true;
472 } else if (0 == strcmp(*argv, "--multi")) {
473 ++argv;
474 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000475 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000476 SkDebugf("Missing arg for --multi\n");
477 usage(argv0);
478 exit(-1);
479 }
480 numThreads = atoi(*argv);
481 if (numThreads < 2) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000482 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000483 SkDebugf("Number of threads must be at least 2.\n");
484 usage(argv0);
485 exit(-1);
486 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000487 } 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 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000502 } else if (0 == strcmp(*argv, "--device")) {
503 ++argv;
504 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000505 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000506 SkDebugf("Missing mode for --device\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000507 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 {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000520 SkSafeUnref(renderer);
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000521 SkDebugf("%s is not a valid mode for --device\n", *argv);
522 usage(argv0);
523 exit(-1);
524 }
525
keyar@chromium.org472b3792012-07-20 22:34:27 +0000526 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000527 SkSafeUnref(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000528 usage(argv0);
529 exit(-1);
borenet@google.com070d3542012-10-26 13:26:55 +0000530 } 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));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000538 } else if (0 == strcmp(*argv, "--validate")) {
539 *validate = true;
edisonn@google.comd17c8652013-01-16 14:47:06 +0000540 } 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 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000559 } else if (0 == strcmp(*argv, "--writeWholeImage")) {
560 *writeWholeImage = true;
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000561 } else {
562 inputs->push_back(SkString(*argv));
563 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000564 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000565
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000566 if (numThreads > 1 && !useTiles) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000567 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000568 SkDebugf("Multithreaded drawing requires tiled rendering.\n");
569 usage(argv0);
570 exit(-1);
571 }
572
edisonn@google.com84f548c2012-12-18 22:24:03 +0000573 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
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000586 if (useTiles) {
587 SkASSERT(NULL == renderer);
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000588 sk_tools::TiledPictureRenderer* tiledRenderer;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000589 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) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000605 tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
606 } else {
607 tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
608 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000609 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)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000622 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 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000630 tiledRenderer->setTileWidthPercentage(atof(widthString));
631 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
632 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000633 SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000634 usage(argv0);
635 exit(-1);
636 }
637 } else {
638 tiledRenderer->setTileWidth(atoi(widthString));
639 if (!(tiledRenderer->getTileWidth() > 0)) {
640 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000641 SkDebugf("--mode %s must be given a width > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000642 usage(argv0);
643 exit(-1);
644 }
645 }
646
647 if (sk_tools::is_percentage(heightString)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000648 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 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000656 tiledRenderer->setTileHeightPercentage(atof(heightString));
657 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
658 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000659 SkDebugf("--mode %s must be given a height percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000660 usage(argv0);
661 exit(-1);
662 }
663 } else {
664 tiledRenderer->setTileHeight(atoi(heightString));
665 if (!(tiledRenderer->getTileHeight() > 0)) {
666 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000667 SkDebugf("--mode %s must be given a height > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000668 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
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000681 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000682 renderer = tiledRenderer;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000683 if (usePipe) {
684 SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
685 "Turning off pipe.\n");
686 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000687 } else if (usePipe) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000688 if (renderer != NULL) {
689 renderer->unref();
690 SkDebugf("Pipe is incompatible with other modes.\n");
691 usage(argv0);
692 exit(-1);
693 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000694 renderer = SkNEW(sk_tools::PipePictureRenderer);
695 }
696
borenet@google.com070d3542012-10-26 13:26:55 +0000697 if (inputs->empty()) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000698 SkSafeUnref(renderer);
borenet@google.com070d3542012-10-26 13:26:55 +0000699 if (NULL != outputDir) {
700 SkDELETE(outputDir);
701 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000702 usage(argv0);
703 exit(-1);
704 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000705
706 if (NULL == renderer) {
707 renderer = SkNEW(sk_tools::SimplePictureRenderer);
708 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000709
edisonn@google.com84f548c2012-12-18 22:24:03 +0000710 renderer->setBBoxHierarchyType(bbhType);
711 renderer->setGridSize(gridWidth, gridHeight);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000712 renderer->setViewport(viewport);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000713 renderer->setScaleFactor(scaleFactor);
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000714 renderer->setDeviceType(deviceType);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000715}
716
caryclark@google.com5987f582012-10-02 18:33:14 +0000717int tool_main(int argc, char** argv);
718int tool_main(int argc, char** argv) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000719 SkAutoGraphics ag;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000720 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000721 sk_tools::PictureRenderer* renderer = NULL;
borenet@google.com070d3542012-10-26 13:26:55 +0000722 SkString* outputDir = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000723 bool validate = false;
edisonn@google.comd17c8652013-01-16 14:47:06 +0000724 int maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000725 bool writeWholeImage = false;
726 int clones = 0;
727 parse_commandline(argc, argv, &inputs, renderer, outputDir,
edisonn@google.comd17c8652013-01-16 14:47:06 +0000728 &validate, &maxComponentDiff, &writeWholeImage, &clones);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000729 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000730
borenet@google.com66bcbd12012-09-17 18:26:06 +0000731 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000732 for (int i = 0; i < inputs.count(); i ++) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000733 failures += process_input(inputs[i], outputDir, *renderer,
edisonn@google.comd17c8652013-01-16 14:47:06 +0000734 validate, maxComponentDiff,
735 writeWholeImage, clones);
junov@chromium.org777442d2012-06-12 14:56:36 +0000736 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000737 if (failures != 0) {
738 SkDebugf("Failed to render %i pictures.\n", failures);
739 return 1;
740 }
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000741#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
borenet@google.com070d3542012-10-26 13:26:55 +0000750 if (NULL != outputDir) {
751 SkDELETE(outputDir);
752 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000753 SkDELETE(renderer);
caryclark@google.com868e1f62012-10-02 20:00:03 +0000754 return 0;
junov@chromium.org777442d2012-06-12 14:56:36 +0000755}
caryclark@google.com5987f582012-10-02 18:33:14 +0000756
757#if !defined SK_BUILD_FOR_IOS
758int main(int argc, char * const argv[]) {
759 return tool_main(argc, (char**) argv);
760}
761#endif