blob: 3ab5628e6cc7381b7d9edde7635885613509c094 [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
scroggo@google.com0556ea02013-02-08 19:38:21 +000043#if SK_ANGLE
44" | angle"
45#endif
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000046"]"
junov@chromium.org777442d2012-06-12 14:56:36 +000047, argv0);
keyar@chromium.org472b3792012-07-20 22:34:27 +000048 SkDebugf("\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000049 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000050" input: A list of directories and files to use as input. Files are\n"
51" expected to have the .skp extension.\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000052 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000053" outputDir: directory to write the rendered images.\n\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000054 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000055" --mode pow2tile minWidth height | copyTile width height | simple\n"
56" | tile width height | rerecord: Run in the corresponding mode.\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000057" Default is simple.\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000058 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000059" pow2tile minWidth height, Creates tiles with widths\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000060" that are all a power of two\n"
61" such that they minimize the\n"
62" amount of wasted tile space.\n"
63" minWidth is the minimum width\n"
64" of these tiles and must be a\n"
65" power of two. A simple render\n"
66" is done with these tiles.\n");
67 SkDebugf(
scroggo@google.coma9e3a362012-11-07 17:52:48 +000068" simple, Render using the default rendering method.\n"
69" rerecord, Record the picture as a new skp, with the bitmaps PNG encoded.\n"
70 );
keyar@chromium.org795cd472012-08-02 18:57:53 +000071 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000072" tile width height, Do a simple render using tiles\n"
73" with the given dimensions.\n"
74" copyTile width height, Draw the picture, then copy it into tiles.\n"
75" Does not support percentages.\n"
76" If the picture is large enough, breaks it into\n"
77" larger tiles (and draws the picture once per\n"
78" larger tile) to avoid creating a large canvas.\n"
79" Add --tiles x y to specify the number of tiles\n"
80" per larger tile in the x and y direction.\n"
81 );
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000082 SkDebugf("\n");
83 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000084" --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
85" than 1. Only works with tiled rendering.\n"
scroggo@google.comc0d5e542012-12-13 21:40:48 +000086" --viewport width height : Set the viewport.\n"
scroggo@google.com82ec0b02012-12-17 19:25:54 +000087" --scale sf : Scale drawing by sf.\n"
scroggo@google.coma62da2f2012-11-02 21:28:12 +000088" --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
scroggo@google.comb6e806b2012-10-03 17:32:33 +000089 SkDebugf(
edisonn@google.com84f548c2012-12-18 22:24:03 +000090" --validate: Verify that the rendered image contains the same pixels as "
91"the picture rendered in simple mode.\n"
edisonn@google.comca1b3ff2013-01-16 18:18:48 +000092" --maxComponentDiff: maximum diff on a component. Default is 256, "
93"which means we report but we do not generate an error.\n"
edisonn@google.com84f548c2012-12-18 22:24:03 +000094" --writeWholeImage: In tile mode, write the entire rendered image to a "
95"file, instead of an image for each tile.\n");
96 SkDebugf(
97" --clone n: Clone the picture n times before rendering.\n");
98 SkDebugf(
99" --bbh bbhType [width height]: Set the bounding box hierarchy type to\n"
100" be used. Accepted values are: none, rtree, grid. Default\n"
101" value is none. Not compatible with --pipe. With value\n"
102" 'grid', width and height must be specified. 'grid' can\n"
103" only be used with modes tile, record, and\n"
104" playbackCreation.");
105 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000106" --device bitmap"
107#if SK_SUPPORT_GPU
108" | gpu"
109#endif
110": Use the corresponding device. Default is bitmap.\n");
111 SkDebugf(
112" bitmap, Render to a bitmap.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000113#if SK_SUPPORT_GPU
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000114 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000115" gpu, Render to the GPU.\n");
116#endif
scroggo@google.com0556ea02013-02-08 19:38:21 +0000117#if SK_ANGLE
118 SkDebugf(
119" angle, Render using angle.\n");
120#endif
junov@chromium.org777442d2012-06-12 14:56:36 +0000121}
122
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000123static void make_output_filepath(SkString* path, const SkString& dir,
junov@chromium.org777442d2012-06-12 14:56:36 +0000124 const SkString& name) {
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000125 sk_tools::make_filepath(path, dir, name);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000126 // Remove ".skp"
127 path->remove(path->size() - 4, 4);
junov@chromium.org777442d2012-06-12 14:56:36 +0000128}
129
borenet@google.com070d3542012-10-26 13:26:55 +0000130static bool render_picture(const SkString& inputPath, const SkString* outputDir,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000131 sk_tools::PictureRenderer& renderer,
132 SkBitmap** out,
133 int clones) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000134 SkString inputFilename;
135 sk_tools::get_basename(&inputFilename, inputPath);
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000136
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000137 SkFILEStream inputStream;
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000138 inputStream.setPath(inputPath.c_str());
139 if (!inputStream.isValid()) {
140 SkDebugf("Could not open file %s\n", inputPath.c_str());
borenet@google.com66bcbd12012-09-17 18:26:06 +0000141 return false;
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000142 }
143
borenet@google.com66bcbd12012-09-17 18:26:06 +0000144 bool success = false;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000145 SkPicture* picture = SkNEW_ARGS(SkPicture,
146 (&inputStream, &success, &SkImageDecoder::DecodeStream));
borenet@google.com66bcbd12012-09-17 18:26:06 +0000147 if (!success) {
148 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
149 return false;
150 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000151
edisonn@google.com84f548c2012-12-18 22:24:03 +0000152 for (int i = 0; i < clones; ++i) {
153 SkPicture* clone = picture->clone();
154 SkDELETE(picture);
155 picture = clone;
156 }
157
158 SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(),
borenet@google.com03fcee82012-09-10 18:18:38 +0000159 inputPath.c_str());
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000160
edisonn@google.com84f548c2012-12-18 22:24:03 +0000161 renderer.init(picture);
scroggo@google.comb4773b42012-10-01 20:06:09 +0000162 renderer.setup();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000163
borenet@google.com070d3542012-10-26 13:26:55 +0000164 SkString* outputPath = NULL;
165 if (NULL != outputDir) {
166 outputPath = SkNEW(SkString);
167 make_output_filepath(outputPath, *outputDir, inputFilename);
168 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000169
170 success = renderer.render(outputPath, out);
borenet@google.com070d3542012-10-26 13:26:55 +0000171 if (outputPath) {
172 if (!success) {
173 SkDebugf("Could not write to file %s\n", outputPath->c_str());
174 }
175 SkDELETE(outputPath);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000176 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000177
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000178 renderer.end();
edisonn@google.com84f548c2012-12-18 22:24:03 +0000179
180 SkDELETE(picture);
borenet@google.com66bcbd12012-09-17 18:26:06 +0000181 return success;
junov@chromium.org777442d2012-06-12 14:56:36 +0000182}
183
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000184static inline int getByte(uint32_t value, int index) {
185 SkASSERT(0 <= index && index < 4);
186 return (value >> (index * 8)) & 0xFF;
187}
188
189static int MaxByteDiff(uint32_t v1, uint32_t v2) {
190 return SkMax32(SkMax32(abs(getByte(v1, 0) - getByte(v2, 0)), abs(getByte(v1, 1) - getByte(v2, 1))),
191 SkMax32(abs(getByte(v1, 2) - getByte(v2, 2)), abs(getByte(v1, 3) - getByte(v2, 3))));
192}
193
edisonn@google.com84f548c2012-12-18 22:24:03 +0000194static bool render_picture(const SkString& inputPath, const SkString* outputDir,
195 sk_tools::PictureRenderer& renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000196 bool validate, int maxComponentDiff,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000197 bool writeWholeImage,
198 int clones) {
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000199 int diffs[256] = {0};
edisonn@google.com84f548c2012-12-18 22:24:03 +0000200 SkBitmap* bitmap = NULL;
201 bool success = render_picture(inputPath,
202 writeWholeImage ? NULL : outputDir,
203 renderer,
204 validate || writeWholeImage ? &bitmap : NULL, clones);
205
206 if (!success || ((validate || writeWholeImage) && bitmap == NULL)) {
207 SkDebugf("Failed to draw the picture.\n");
208 SkDELETE(bitmap);
209 return false;
210 }
211
212 if (validate) {
213 SkBitmap* referenceBitmap = NULL;
214 sk_tools::SimplePictureRenderer referenceRenderer;
215 success = render_picture(inputPath, NULL, referenceRenderer,
216 &referenceBitmap, 0);
217
218 if (!success || !referenceBitmap) {
219 SkDebugf("Failed to draw the reference picture.\n");
220 SkDELETE(bitmap);
221 SkDELETE(referenceBitmap);
222 return false;
223 }
224
225 if (success && (bitmap->width() != referenceBitmap->width())) {
226 SkDebugf("Expected image width: %i, actual image width %i.\n",
227 referenceBitmap->width(), bitmap->width());
228 SkDELETE(bitmap);
229 SkDELETE(referenceBitmap);
230 return false;
231 }
232 if (success && (bitmap->height() != referenceBitmap->height())) {
233 SkDebugf("Expected image height: %i, actual image height %i",
234 referenceBitmap->height(), bitmap->height());
235 SkDELETE(bitmap);
236 SkDELETE(referenceBitmap);
237 return false;
238 }
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000239
edisonn@google.com84f548c2012-12-18 22:24:03 +0000240 for (int y = 0; success && y < bitmap->height(); y++) {
241 for (int x = 0; success && x < bitmap->width(); x++) {
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000242 int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y),
243 *bitmap->getAddr32(x, y));
244 SkASSERT(diff >= 0 && diff <= 255);
245 diffs[diff]++;
skia.committer@gmail.com4d28d982013-01-17 07:06:06 +0000246
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000247 if (diff > maxComponentDiff) {
248 SkDebugf("Expected pixel at (%i %i) exceedds maximum "
249 "component diff of %i: 0x%x, actual 0x%x\n",
250 x, y, maxComponentDiff,
edisonn@google.com01754bf2013-01-11 16:08:07 +0000251 *referenceBitmap->getAddr32(x, y),
edisonn@google.com84f548c2012-12-18 22:24:03 +0000252 *bitmap->getAddr32(x, y));
253 SkDELETE(bitmap);
254 SkDELETE(referenceBitmap);
255 return false;
256 }
257 }
258 }
259 SkDELETE(referenceBitmap);
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000260
261 for (int i = 1; i <= 255; ++i) {
262 if(diffs[i] > 0) {
263 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]);
264 }
265 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000266 }
267
268 if (writeWholeImage) {
269 sk_tools::force_all_opaque(*bitmap);
270 if (NULL != outputDir && writeWholeImage) {
271 SkString inputFilename;
272 sk_tools::get_basename(&inputFilename, inputPath);
273 SkString outputPath;
274 make_output_filepath(&outputPath, *outputDir, inputFilename);
275 outputPath.append(".png");
276 if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap,
277 SkImageEncoder::kPNG_Type, 100)) {
278 SkDebugf("Failed to draw the picture.\n");
279 success = false;
280 }
281 }
282 }
283 SkDELETE(bitmap);
284
285 return success;
286}
287
288
borenet@google.com070d3542012-10-26 13:26:55 +0000289static int process_input(const SkString& input, const SkString* outputDir,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000290 sk_tools::PictureRenderer& renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000291 bool validate, int maxComponentDiff,
292 bool writeWholeImage, int clones) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000293 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000294 SkString inputFilename;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000295 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000296 SkDebugf("process_input, %s\n", input.c_str());
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000297 if (iter.next(&inputFilename)) {
298 do {
299 SkString inputPath;
300 sk_tools::make_filepath(&inputPath, input, inputFilename);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000301 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000302 validate, maxComponentDiff,
303 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000304 ++failures;
305 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000306 } while(iter.next(&inputFilename));
borenet@google.com57837bf2012-09-19 17:28:29 +0000307 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000308 SkString inputPath(input);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000309 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000310 validate, maxComponentDiff,
311 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000312 ++failures;
313 }
314 } else {
315 SkString warning;
316 warning.printf("Warning: skipping %s\n", input.c_str());
317 SkDebugf(warning.c_str());
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000318 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000319 return failures;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000320}
321
322static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000323 sk_tools::PictureRenderer*& renderer, SkString*& outputDir,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000324 bool* validate, int* maxComponentDiff,
325 bool* writeWholeImage,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000326 int* clones){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000327 const char* argv0 = argv[0];
328 char* const* stop = argv + argc;
329
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000330 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
331 sk_tools::PictureRenderer::kBitmap_DeviceType;
332
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000333 bool usePipe = false;
334 int numThreads = 1;
335 bool useTiles = false;
336 const char* widthString = NULL;
337 const char* heightString = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000338 int gridWidth = 0;
339 int gridHeight = 0;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000340 bool isPowerOf2Mode = false;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000341 bool isCopyMode = false;
342 const char* xTilesString = NULL;
343 const char* yTilesString = NULL;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000344 const char* mode = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000345 bool gridSupported = false;
346 sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
347 sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
348 *validate = false;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000349 *maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000350 *writeWholeImage = false;
351 *clones = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000352 SkISize viewport;
353 viewport.setEmpty();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000354 SkScalar scaleFactor = SK_Scalar1;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000355
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000356 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000357 if (0 == strcmp(*argv, "--mode")) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000358 if (renderer != NULL) {
359 renderer->unref();
360 SkDebugf("Cannot combine modes.\n");
361 usage(argv0);
362 exit(-1);
363 }
keyar@chromium.org795cd472012-08-02 18:57:53 +0000364
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000365 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000366 if (argv >= stop) {
367 SkDebugf("Missing mode for --mode\n");
368 usage(argv0);
369 exit(-1);
370 }
371
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000372 if (0 == strcmp(*argv, "simple")) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000373 renderer = SkNEW(sk_tools::SimplePictureRenderer);
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000374 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))
375 || 0 == strcmp(*argv, "copyTile")) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000376 useTiles = true;
377 mode = *argv;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000378
379 if (0 == strcmp(*argv, "pow2tile")) {
380 isPowerOf2Mode = true;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000381 } else if (0 == strcmp(*argv, "copyTile")) {
382 isCopyMode = true;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000383 } else {
384 gridSupported = true;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000385 }
386
keyar@chromium.org795cd472012-08-02 18:57:53 +0000387 ++argv;
388 if (argv >= stop) {
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000389 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000390 usage(argv0);
391 exit(-1);
392 }
393
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000394 widthString = *argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000395 ++argv;
396 if (argv >= stop) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000397 SkDebugf("Missing height for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000398 usage(argv0);
399 exit(-1);
400 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000401 heightString = *argv;
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000402 } else if (0 == strcmp(*argv, "rerecord")) {
403 renderer = SkNEW(sk_tools::RecordPictureRenderer);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000404 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000405 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000406 usage(argv0);
407 exit(-1);
408 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000409 } else if (0 == strcmp(*argv, "--bbh")) {
410 ++argv;
411 if (argv >= stop) {
412 SkDebugf("Missing value for --bbh\n");
413 usage(argv0);
414 exit(-1);
415 }
416 if (0 == strcmp(*argv, "none")) {
417 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
418 } else if (0 == strcmp(*argv, "rtree")) {
419 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
420 } else if (0 == strcmp(*argv, "grid")) {
421 bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType;
422 ++argv;
423 if (argv >= stop) {
424 SkDebugf("Missing width for --bbh grid\n");
425 usage(argv0);
426 exit(-1);
427 }
428 gridWidth = atoi(*argv);
429 ++argv;
430 if (argv >= stop) {
431 SkDebugf("Missing height for --bbh grid\n");
432 usage(argv0);
433 exit(-1);
434 }
435 gridHeight = atoi(*argv);
436 } else {
437 SkDebugf("%s is not a valid value for --bbhType\n", *argv);
438 usage(argv0);
439 exit(-1);;
440 }
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000441 } else if (0 == strcmp(*argv, "--viewport")) {
442 ++argv;
443 if (argv >= stop) {
444 SkDebugf("Missing width for --viewport\n");
445 usage(argv0);
446 exit(-1);
447 }
448 viewport.fWidth = atoi(*argv);
449 ++argv;
450 if (argv >= stop) {
451 SkDebugf("Missing height for --viewport\n");
452 usage(argv0);
453 exit(-1);
454 }
455 viewport.fHeight = atoi(*argv);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000456 } else if (0 == strcmp(*argv, "--scale")) {
457 ++argv;
458 if (argv >= stop) {
459 SkDebugf("Missing scaleFactor for --scale\n");
460 usage(argv0);
461 exit(-1);
462 }
reed@google.com89d15a22013-01-07 22:26:05 +0000463 scaleFactor = SkDoubleToScalar(atof(*argv));
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000464 } else if (0 == strcmp(*argv, "--tiles")) {
465 ++argv;
466 if (argv >= stop) {
467 SkDebugf("Missing x for --tiles\n");
468 usage(argv0);
469 exit(-1);
470 }
471 xTilesString = *argv;
472 ++argv;
473 if (argv >= stop) {
474 SkDebugf("Missing y for --tiles\n");
475 usage(argv0);
476 exit(-1);
477 }
478 yTilesString = *argv;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000479 } else if (0 == strcmp(*argv, "--pipe")) {
480 usePipe = true;
481 } else if (0 == strcmp(*argv, "--multi")) {
482 ++argv;
483 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000484 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000485 SkDebugf("Missing arg for --multi\n");
486 usage(argv0);
487 exit(-1);
488 }
489 numThreads = atoi(*argv);
490 if (numThreads < 2) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000491 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000492 SkDebugf("Number of threads must be at least 2.\n");
493 usage(argv0);
494 exit(-1);
495 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000496 } else if (0 == strcmp(*argv, "--clone")) {
497 ++argv;
498 if (argv >= stop) {
499 SkSafeUnref(renderer);
500 SkDebugf("Missing arg for --clone\n");
501 usage(argv0);
502 exit(-1);
503 }
504 *clones = atoi(*argv);
505 if (*clones < 0) {
506 SkSafeUnref(renderer);
507 SkDebugf("Number of clones must be at least 0.\n");
508 usage(argv0);
509 exit(-1);
510 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000511 } else if (0 == strcmp(*argv, "--device")) {
512 ++argv;
513 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000514 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000515 SkDebugf("Missing mode for --device\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000516 usage(argv0);
517 exit(-1);
518 }
519
520 if (0 == strcmp(*argv, "bitmap")) {
521 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
522 }
523#if SK_SUPPORT_GPU
524 else if (0 == strcmp(*argv, "gpu")) {
525 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
526 }
527#endif
scroggo@google.com0556ea02013-02-08 19:38:21 +0000528#if SK_ANGLE
529 else if (0 == strcmp(*argv, "angle")) {
530 deviceType = sk_tools::PictureRenderer::kAngle_DeviceType;
531 }
532#endif
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000533 else {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000534 SkSafeUnref(renderer);
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000535 SkDebugf("%s is not a valid mode for --device\n", *argv);
536 usage(argv0);
537 exit(-1);
538 }
539
keyar@chromium.org472b3792012-07-20 22:34:27 +0000540 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000541 SkSafeUnref(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000542 usage(argv0);
543 exit(-1);
borenet@google.com070d3542012-10-26 13:26:55 +0000544 } else if (0 == strcmp(*argv, "-w")) {
545 ++argv;
546 if (argv >= stop) {
547 SkDebugf("Missing output directory for -w\n");
548 usage(argv0);
549 exit(-1);
550 }
551 outputDir = SkNEW_ARGS(SkString, (*argv));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000552 } else if (0 == strcmp(*argv, "--validate")) {
553 *validate = true;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000554 } else if (0 == strcmp(*argv, "--maxComponentDiff")) {
555 if (!*validate) {
556 SkDebugf("--maxComponentDiff must be used only with --validate\n");
557 usage(argv0);
558 exit(-1);
559 }
560 ++argv;
561 if (argv >= stop) {
562 SkDebugf("Missing arg for --maxComponentDiff\n");
563 usage(argv0);
564 exit(-1);
565 }
566 *maxComponentDiff = atoi(*argv);
567 if (*maxComponentDiff < 0 || *maxComponentDiff > 256) {
568 SkSafeUnref(renderer);
569 SkDebugf("maxComponentDiff: 0 - 256.\n");
570 usage(argv0);
571 exit(-1);
skia.committer@gmail.com4d28d982013-01-17 07:06:06 +0000572 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000573 } else if (0 == strcmp(*argv, "--writeWholeImage")) {
574 *writeWholeImage = true;
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000575 } else {
576 inputs->push_back(SkString(*argv));
577 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000578 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000579
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000580 if (numThreads > 1 && !useTiles) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000581 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000582 SkDebugf("Multithreaded drawing requires tiled rendering.\n");
583 usage(argv0);
584 exit(-1);
585 }
586
edisonn@google.com84f548c2012-12-18 22:24:03 +0000587 if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
588 SkDebugf("--pipe and --bbh cannot be used together\n");
589 usage(argv0);
590 exit(-1);
591 }
592
593 if (sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType == bbhType &&
594 !gridSupported) {
595 SkDebugf("'--bbh grid' is not compatible with specified --mode.\n");
596 usage(argv0);
597 exit(-1);
598 }
599
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000600 if (useTiles) {
601 SkASSERT(NULL == renderer);
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000602 sk_tools::TiledPictureRenderer* tiledRenderer;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000603 if (isCopyMode) {
604 int x, y;
605 if (xTilesString != NULL) {
606 SkASSERT(yTilesString != NULL);
607 x = atoi(xTilesString);
608 y = atoi(yTilesString);
609 if (x <= 0 || y <= 0) {
610 SkDebugf("--tiles must be given values > 0\n");
611 usage(argv0);
612 exit(-1);
613 }
614 } else {
615 x = y = 4;
616 }
617 tiledRenderer = SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y));
618 } else if (numThreads > 1) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000619 tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
620 } else {
621 tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
622 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000623 if (isPowerOf2Mode) {
624 int minWidth = atoi(widthString);
625 if (!SkIsPow2(minWidth) || minWidth < 0) {
626 tiledRenderer->unref();
627 SkString err;
628 err.printf("-mode %s must be given a width"
629 " value that is a power of two\n", mode);
630 SkDebugf(err.c_str());
631 usage(argv0);
632 exit(-1);
633 }
634 tiledRenderer->setTileMinPowerOf2Width(minWidth);
635 } else if (sk_tools::is_percentage(widthString)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000636 if (isCopyMode) {
637 tiledRenderer->unref();
638 SkString err;
639 err.printf("--mode %s does not support percentages.\n", mode);
640 SkDebugf(err.c_str());
641 usage(argv0);
642 exit(-1);
643 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000644 tiledRenderer->setTileWidthPercentage(atof(widthString));
645 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
646 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000647 SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000648 usage(argv0);
649 exit(-1);
650 }
651 } else {
652 tiledRenderer->setTileWidth(atoi(widthString));
653 if (!(tiledRenderer->getTileWidth() > 0)) {
654 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000655 SkDebugf("--mode %s must be given a width > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000656 usage(argv0);
657 exit(-1);
658 }
659 }
660
661 if (sk_tools::is_percentage(heightString)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000662 if (isCopyMode) {
663 tiledRenderer->unref();
664 SkString err;
665 err.printf("--mode %s does not support percentages.\n", mode);
666 SkDebugf(err.c_str());
667 usage(argv0);
668 exit(-1);
669 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000670 tiledRenderer->setTileHeightPercentage(atof(heightString));
671 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
672 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000673 SkDebugf("--mode %s must be given a height percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000674 usage(argv0);
675 exit(-1);
676 }
677 } else {
678 tiledRenderer->setTileHeight(atoi(heightString));
679 if (!(tiledRenderer->getTileHeight() > 0)) {
680 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000681 SkDebugf("--mode %s must be given a height > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000682 usage(argv0);
683 exit(-1);
684 }
685 }
686 if (numThreads > 1) {
scroggo@google.com0556ea02013-02-08 19:38:21 +0000687 switch (deviceType) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000688#if SK_SUPPORT_GPU
scroggo@google.com0556ea02013-02-08 19:38:21 +0000689 case sk_tools::PictureRenderer::kGPU_DeviceType:
690 // fall through
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000691#endif
scroggo@google.com0556ea02013-02-08 19:38:21 +0000692#if SK_ANGLE
693 case sk_tools::PictureRenderer::kAngle_DeviceType:
694#endif
695 tiledRenderer->unref();
696 SkDebugf("GPU not compatible with multithreaded tiling.\n");
697 usage(argv0);
698 exit(-1);
699 break;
700 default:
701 break;
702 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000703 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000704 renderer = tiledRenderer;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000705 if (usePipe) {
706 SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
707 "Turning off pipe.\n");
708 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000709 } else if (usePipe) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000710 if (renderer != NULL) {
711 renderer->unref();
712 SkDebugf("Pipe is incompatible with other modes.\n");
713 usage(argv0);
714 exit(-1);
715 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000716 renderer = SkNEW(sk_tools::PipePictureRenderer);
717 }
718
borenet@google.com070d3542012-10-26 13:26:55 +0000719 if (inputs->empty()) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000720 SkSafeUnref(renderer);
borenet@google.com070d3542012-10-26 13:26:55 +0000721 if (NULL != outputDir) {
722 SkDELETE(outputDir);
723 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000724 usage(argv0);
725 exit(-1);
726 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000727
728 if (NULL == renderer) {
729 renderer = SkNEW(sk_tools::SimplePictureRenderer);
730 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000731
edisonn@google.com84f548c2012-12-18 22:24:03 +0000732 renderer->setBBoxHierarchyType(bbhType);
733 renderer->setGridSize(gridWidth, gridHeight);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000734 renderer->setViewport(viewport);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000735 renderer->setScaleFactor(scaleFactor);
scroggo@google.com0556ea02013-02-08 19:38:21 +0000736 if (!renderer->setDeviceType(deviceType)) {
737 SkDebugf("Invalid device type.\n");
738 exit(-1);
739 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000740}
741
caryclark@google.com5987f582012-10-02 18:33:14 +0000742int tool_main(int argc, char** argv);
743int tool_main(int argc, char** argv) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000744 SkAutoGraphics ag;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000745 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000746 sk_tools::PictureRenderer* renderer = NULL;
borenet@google.com070d3542012-10-26 13:26:55 +0000747 SkString* outputDir = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000748 bool validate = false;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000749 int maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000750 bool writeWholeImage = false;
751 int clones = 0;
752 parse_commandline(argc, argv, &inputs, renderer, outputDir,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000753 &validate, &maxComponentDiff, &writeWholeImage, &clones);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000754 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000755
borenet@google.com66bcbd12012-09-17 18:26:06 +0000756 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000757 for (int i = 0; i < inputs.count(); i ++) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000758 failures += process_input(inputs[i], outputDir, *renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000759 validate, maxComponentDiff,
760 writeWholeImage, clones);
junov@chromium.org777442d2012-06-12 14:56:36 +0000761 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000762 if (failures != 0) {
763 SkDebugf("Failed to render %i pictures.\n", failures);
764 return 1;
765 }
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000766#if SK_SUPPORT_GPU
767#if GR_CACHE_STATS
768 if (renderer->isUsingGpuDevice()) {
769 GrContext* ctx = renderer->getGrContext();
770
771 ctx->printCacheStats();
772 }
773#endif
774#endif
borenet@google.com070d3542012-10-26 13:26:55 +0000775 if (NULL != outputDir) {
776 SkDELETE(outputDir);
777 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000778 SkDELETE(renderer);
caryclark@google.com868e1f62012-10-02 20:00:03 +0000779 return 0;
junov@chromium.org777442d2012-06-12 14:56:36 +0000780}
caryclark@google.com5987f582012-10-02 18:33:14 +0000781
782#if !defined SK_BUILD_FOR_IOS
783int main(int argc, char * const argv[]) {
784 return tool_main(argc, (char**) argv);
785}
786#endif