blob: 7b9efc5f0f2995fbc08b3e6143c2f839ad1bf219 [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
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.comca1b3ff2013-01-16 18:18:48 +0000179static inline int getByte(uint32_t value, int index) {
180 SkASSERT(0 <= index && index < 4);
181 return (value >> (index * 8)) & 0xFF;
182}
183
184static int MaxByteDiff(uint32_t v1, uint32_t v2) {
185 return SkMax32(SkMax32(abs(getByte(v1, 0) - getByte(v2, 0)), abs(getByte(v1, 1) - getByte(v2, 1))),
186 SkMax32(abs(getByte(v1, 2) - getByte(v2, 2)), abs(getByte(v1, 3) - getByte(v2, 3))));
187}
188
edisonn@google.com84f548c2012-12-18 22:24:03 +0000189static bool render_picture(const SkString& inputPath, const SkString* outputDir,
190 sk_tools::PictureRenderer& renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000191 bool validate, int maxComponentDiff,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000192 bool writeWholeImage,
193 int clones) {
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000194 int diffs[256] = {0};
edisonn@google.com84f548c2012-12-18 22:24:03 +0000195 SkBitmap* bitmap = NULL;
196 bool success = render_picture(inputPath,
197 writeWholeImage ? NULL : outputDir,
198 renderer,
199 validate || writeWholeImage ? &bitmap : NULL, clones);
200
201 if (!success || ((validate || writeWholeImage) && bitmap == NULL)) {
202 SkDebugf("Failed to draw the picture.\n");
203 SkDELETE(bitmap);
204 return false;
205 }
206
207 if (validate) {
208 SkBitmap* referenceBitmap = NULL;
209 sk_tools::SimplePictureRenderer referenceRenderer;
210 success = render_picture(inputPath, NULL, referenceRenderer,
211 &referenceBitmap, 0);
212
213 if (!success || !referenceBitmap) {
214 SkDebugf("Failed to draw the reference picture.\n");
215 SkDELETE(bitmap);
216 SkDELETE(referenceBitmap);
217 return false;
218 }
219
220 if (success && (bitmap->width() != referenceBitmap->width())) {
221 SkDebugf("Expected image width: %i, actual image width %i.\n",
222 referenceBitmap->width(), bitmap->width());
223 SkDELETE(bitmap);
224 SkDELETE(referenceBitmap);
225 return false;
226 }
227 if (success && (bitmap->height() != referenceBitmap->height())) {
228 SkDebugf("Expected image height: %i, actual image height %i",
229 referenceBitmap->height(), bitmap->height());
230 SkDELETE(bitmap);
231 SkDELETE(referenceBitmap);
232 return false;
233 }
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000234
edisonn@google.com84f548c2012-12-18 22:24:03 +0000235 for (int y = 0; success && y < bitmap->height(); y++) {
236 for (int x = 0; success && x < bitmap->width(); x++) {
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000237 int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y),
238 *bitmap->getAddr32(x, y));
239 SkASSERT(diff >= 0 && diff <= 255);
240 diffs[diff]++;
skia.committer@gmail.com4d28d982013-01-17 07:06:06 +0000241
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000242 if (diff > maxComponentDiff) {
243 SkDebugf("Expected pixel at (%i %i) exceedds maximum "
244 "component diff of %i: 0x%x, actual 0x%x\n",
245 x, y, maxComponentDiff,
edisonn@google.com01754bf2013-01-11 16:08:07 +0000246 *referenceBitmap->getAddr32(x, y),
edisonn@google.com84f548c2012-12-18 22:24:03 +0000247 *bitmap->getAddr32(x, y));
248 SkDELETE(bitmap);
249 SkDELETE(referenceBitmap);
250 return false;
251 }
252 }
253 }
254 SkDELETE(referenceBitmap);
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000255
256 for (int i = 1; i <= 255; ++i) {
257 if(diffs[i] > 0) {
258 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]);
259 }
260 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000261 }
262
263 if (writeWholeImage) {
264 sk_tools::force_all_opaque(*bitmap);
265 if (NULL != outputDir && writeWholeImage) {
266 SkString inputFilename;
267 sk_tools::get_basename(&inputFilename, inputPath);
268 SkString outputPath;
269 make_output_filepath(&outputPath, *outputDir, inputFilename);
270 outputPath.append(".png");
271 if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap,
272 SkImageEncoder::kPNG_Type, 100)) {
273 SkDebugf("Failed to draw the picture.\n");
274 success = false;
275 }
276 }
277 }
278 SkDELETE(bitmap);
279
280 return success;
281}
282
283
borenet@google.com070d3542012-10-26 13:26:55 +0000284static int process_input(const SkString& input, const SkString* outputDir,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000285 sk_tools::PictureRenderer& renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000286 bool validate, int maxComponentDiff,
287 bool writeWholeImage, int clones) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000288 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000289 SkString inputFilename;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000290 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000291 SkDebugf("process_input, %s\n", input.c_str());
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000292 if (iter.next(&inputFilename)) {
293 do {
294 SkString inputPath;
295 sk_tools::make_filepath(&inputPath, input, inputFilename);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000296 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000297 validate, maxComponentDiff,
298 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000299 ++failures;
300 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000301 } while(iter.next(&inputFilename));
borenet@google.com57837bf2012-09-19 17:28:29 +0000302 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000303 SkString inputPath(input);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000304 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000305 validate, maxComponentDiff,
306 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000307 ++failures;
308 }
309 } else {
310 SkString warning;
311 warning.printf("Warning: skipping %s\n", input.c_str());
312 SkDebugf(warning.c_str());
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000313 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000314 return failures;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000315}
316
317static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000318 sk_tools::PictureRenderer*& renderer, SkString*& outputDir,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000319 bool* validate, int* maxComponentDiff,
320 bool* writeWholeImage,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000321 int* clones){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000322 const char* argv0 = argv[0];
323 char* const* stop = argv + argc;
324
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000325 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
326 sk_tools::PictureRenderer::kBitmap_DeviceType;
327
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000328 bool usePipe = false;
329 int numThreads = 1;
330 bool useTiles = false;
331 const char* widthString = NULL;
332 const char* heightString = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000333 int gridWidth = 0;
334 int gridHeight = 0;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000335 bool isPowerOf2Mode = false;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000336 bool isCopyMode = false;
337 const char* xTilesString = NULL;
338 const char* yTilesString = NULL;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000339 const char* mode = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000340 bool gridSupported = false;
341 sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
342 sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
343 *validate = false;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000344 *maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000345 *writeWholeImage = false;
346 *clones = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000347 SkISize viewport;
348 viewport.setEmpty();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000349 SkScalar scaleFactor = SK_Scalar1;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000350
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000351 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000352 if (0 == strcmp(*argv, "--mode")) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000353 if (renderer != NULL) {
354 renderer->unref();
355 SkDebugf("Cannot combine modes.\n");
356 usage(argv0);
357 exit(-1);
358 }
keyar@chromium.org795cd472012-08-02 18:57:53 +0000359
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000360 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000361 if (argv >= stop) {
362 SkDebugf("Missing mode for --mode\n");
363 usage(argv0);
364 exit(-1);
365 }
366
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000367 if (0 == strcmp(*argv, "simple")) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000368 renderer = SkNEW(sk_tools::SimplePictureRenderer);
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000369 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))
370 || 0 == strcmp(*argv, "copyTile")) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000371 useTiles = true;
372 mode = *argv;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000373
374 if (0 == strcmp(*argv, "pow2tile")) {
375 isPowerOf2Mode = true;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000376 } else if (0 == strcmp(*argv, "copyTile")) {
377 isCopyMode = true;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000378 } else {
379 gridSupported = true;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000380 }
381
keyar@chromium.org795cd472012-08-02 18:57:53 +0000382 ++argv;
383 if (argv >= stop) {
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000384 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000385 usage(argv0);
386 exit(-1);
387 }
388
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000389 widthString = *argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000390 ++argv;
391 if (argv >= stop) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000392 SkDebugf("Missing height for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000393 usage(argv0);
394 exit(-1);
395 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000396 heightString = *argv;
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000397 } else if (0 == strcmp(*argv, "rerecord")) {
398 renderer = SkNEW(sk_tools::RecordPictureRenderer);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000399 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000400 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000401 usage(argv0);
402 exit(-1);
403 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000404 } else if (0 == strcmp(*argv, "--bbh")) {
405 ++argv;
406 if (argv >= stop) {
407 SkDebugf("Missing value for --bbh\n");
408 usage(argv0);
409 exit(-1);
410 }
411 if (0 == strcmp(*argv, "none")) {
412 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
413 } else if (0 == strcmp(*argv, "rtree")) {
414 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
415 } else if (0 == strcmp(*argv, "grid")) {
416 bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType;
417 ++argv;
418 if (argv >= stop) {
419 SkDebugf("Missing width for --bbh grid\n");
420 usage(argv0);
421 exit(-1);
422 }
423 gridWidth = atoi(*argv);
424 ++argv;
425 if (argv >= stop) {
426 SkDebugf("Missing height for --bbh grid\n");
427 usage(argv0);
428 exit(-1);
429 }
430 gridHeight = atoi(*argv);
431 } else {
432 SkDebugf("%s is not a valid value for --bbhType\n", *argv);
433 usage(argv0);
434 exit(-1);;
435 }
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000436 } else if (0 == strcmp(*argv, "--viewport")) {
437 ++argv;
438 if (argv >= stop) {
439 SkDebugf("Missing width for --viewport\n");
440 usage(argv0);
441 exit(-1);
442 }
443 viewport.fWidth = atoi(*argv);
444 ++argv;
445 if (argv >= stop) {
446 SkDebugf("Missing height for --viewport\n");
447 usage(argv0);
448 exit(-1);
449 }
450 viewport.fHeight = atoi(*argv);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000451 } else if (0 == strcmp(*argv, "--scale")) {
452 ++argv;
453 if (argv >= stop) {
454 SkDebugf("Missing scaleFactor for --scale\n");
455 usage(argv0);
456 exit(-1);
457 }
reed@google.com89d15a22013-01-07 22:26:05 +0000458 scaleFactor = SkDoubleToScalar(atof(*argv));
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000459 } else if (0 == strcmp(*argv, "--tiles")) {
460 ++argv;
461 if (argv >= stop) {
462 SkDebugf("Missing x for --tiles\n");
463 usage(argv0);
464 exit(-1);
465 }
466 xTilesString = *argv;
467 ++argv;
468 if (argv >= stop) {
469 SkDebugf("Missing y for --tiles\n");
470 usage(argv0);
471 exit(-1);
472 }
473 yTilesString = *argv;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000474 } else if (0 == strcmp(*argv, "--pipe")) {
475 usePipe = true;
476 } else if (0 == strcmp(*argv, "--multi")) {
477 ++argv;
478 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000479 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000480 SkDebugf("Missing arg for --multi\n");
481 usage(argv0);
482 exit(-1);
483 }
484 numThreads = atoi(*argv);
485 if (numThreads < 2) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000486 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000487 SkDebugf("Number of threads must be at least 2.\n");
488 usage(argv0);
489 exit(-1);
490 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000491 } else if (0 == strcmp(*argv, "--clone")) {
492 ++argv;
493 if (argv >= stop) {
494 SkSafeUnref(renderer);
495 SkDebugf("Missing arg for --clone\n");
496 usage(argv0);
497 exit(-1);
498 }
499 *clones = atoi(*argv);
500 if (*clones < 0) {
501 SkSafeUnref(renderer);
502 SkDebugf("Number of clones must be at least 0.\n");
503 usage(argv0);
504 exit(-1);
505 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000506 } else if (0 == strcmp(*argv, "--device")) {
507 ++argv;
508 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000509 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000510 SkDebugf("Missing mode for --device\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000511 usage(argv0);
512 exit(-1);
513 }
514
515 if (0 == strcmp(*argv, "bitmap")) {
516 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
517 }
518#if SK_SUPPORT_GPU
519 else if (0 == strcmp(*argv, "gpu")) {
520 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
521 }
522#endif
523 else {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000524 SkSafeUnref(renderer);
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000525 SkDebugf("%s is not a valid mode for --device\n", *argv);
526 usage(argv0);
527 exit(-1);
528 }
529
keyar@chromium.org472b3792012-07-20 22:34:27 +0000530 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000531 SkSafeUnref(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000532 usage(argv0);
533 exit(-1);
borenet@google.com070d3542012-10-26 13:26:55 +0000534 } else if (0 == strcmp(*argv, "-w")) {
535 ++argv;
536 if (argv >= stop) {
537 SkDebugf("Missing output directory for -w\n");
538 usage(argv0);
539 exit(-1);
540 }
541 outputDir = SkNEW_ARGS(SkString, (*argv));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000542 } else if (0 == strcmp(*argv, "--validate")) {
543 *validate = true;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000544 } else if (0 == strcmp(*argv, "--maxComponentDiff")) {
545 if (!*validate) {
546 SkDebugf("--maxComponentDiff must be used only with --validate\n");
547 usage(argv0);
548 exit(-1);
549 }
550 ++argv;
551 if (argv >= stop) {
552 SkDebugf("Missing arg for --maxComponentDiff\n");
553 usage(argv0);
554 exit(-1);
555 }
556 *maxComponentDiff = atoi(*argv);
557 if (*maxComponentDiff < 0 || *maxComponentDiff > 256) {
558 SkSafeUnref(renderer);
559 SkDebugf("maxComponentDiff: 0 - 256.\n");
560 usage(argv0);
561 exit(-1);
skia.committer@gmail.com4d28d982013-01-17 07:06:06 +0000562 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000563 } else if (0 == strcmp(*argv, "--writeWholeImage")) {
564 *writeWholeImage = true;
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000565 } else {
566 inputs->push_back(SkString(*argv));
567 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000568 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000569
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000570 if (numThreads > 1 && !useTiles) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000571 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000572 SkDebugf("Multithreaded drawing requires tiled rendering.\n");
573 usage(argv0);
574 exit(-1);
575 }
576
edisonn@google.com84f548c2012-12-18 22:24:03 +0000577 if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
578 SkDebugf("--pipe and --bbh cannot be used together\n");
579 usage(argv0);
580 exit(-1);
581 }
582
583 if (sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType == bbhType &&
584 !gridSupported) {
585 SkDebugf("'--bbh grid' is not compatible with specified --mode.\n");
586 usage(argv0);
587 exit(-1);
588 }
589
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000590 if (useTiles) {
591 SkASSERT(NULL == renderer);
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000592 sk_tools::TiledPictureRenderer* tiledRenderer;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000593 if (isCopyMode) {
594 int x, y;
595 if (xTilesString != NULL) {
596 SkASSERT(yTilesString != NULL);
597 x = atoi(xTilesString);
598 y = atoi(yTilesString);
599 if (x <= 0 || y <= 0) {
600 SkDebugf("--tiles must be given values > 0\n");
601 usage(argv0);
602 exit(-1);
603 }
604 } else {
605 x = y = 4;
606 }
607 tiledRenderer = SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y));
608 } else if (numThreads > 1) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000609 tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
610 } else {
611 tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
612 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000613 if (isPowerOf2Mode) {
614 int minWidth = atoi(widthString);
615 if (!SkIsPow2(minWidth) || minWidth < 0) {
616 tiledRenderer->unref();
617 SkString err;
618 err.printf("-mode %s must be given a width"
619 " value that is a power of two\n", mode);
620 SkDebugf(err.c_str());
621 usage(argv0);
622 exit(-1);
623 }
624 tiledRenderer->setTileMinPowerOf2Width(minWidth);
625 } else if (sk_tools::is_percentage(widthString)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000626 if (isCopyMode) {
627 tiledRenderer->unref();
628 SkString err;
629 err.printf("--mode %s does not support percentages.\n", mode);
630 SkDebugf(err.c_str());
631 usage(argv0);
632 exit(-1);
633 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000634 tiledRenderer->setTileWidthPercentage(atof(widthString));
635 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
636 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000637 SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000638 usage(argv0);
639 exit(-1);
640 }
641 } else {
642 tiledRenderer->setTileWidth(atoi(widthString));
643 if (!(tiledRenderer->getTileWidth() > 0)) {
644 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000645 SkDebugf("--mode %s must be given a width > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000646 usage(argv0);
647 exit(-1);
648 }
649 }
650
651 if (sk_tools::is_percentage(heightString)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000652 if (isCopyMode) {
653 tiledRenderer->unref();
654 SkString err;
655 err.printf("--mode %s does not support percentages.\n", mode);
656 SkDebugf(err.c_str());
657 usage(argv0);
658 exit(-1);
659 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000660 tiledRenderer->setTileHeightPercentage(atof(heightString));
661 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
662 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000663 SkDebugf("--mode %s must be given a height percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000664 usage(argv0);
665 exit(-1);
666 }
667 } else {
668 tiledRenderer->setTileHeight(atoi(heightString));
669 if (!(tiledRenderer->getTileHeight() > 0)) {
670 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000671 SkDebugf("--mode %s must be given a height > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000672 usage(argv0);
673 exit(-1);
674 }
675 }
676 if (numThreads > 1) {
677#if SK_SUPPORT_GPU
678 if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) {
679 tiledRenderer->unref();
680 SkDebugf("GPU not compatible with multithreaded tiling.\n");
681 usage(argv0);
682 exit(-1);
683 }
684#endif
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000685 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000686 renderer = tiledRenderer;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000687 if (usePipe) {
688 SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
689 "Turning off pipe.\n");
690 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000691 } else if (usePipe) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000692 if (renderer != NULL) {
693 renderer->unref();
694 SkDebugf("Pipe is incompatible with other modes.\n");
695 usage(argv0);
696 exit(-1);
697 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000698 renderer = SkNEW(sk_tools::PipePictureRenderer);
699 }
700
borenet@google.com070d3542012-10-26 13:26:55 +0000701 if (inputs->empty()) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000702 SkSafeUnref(renderer);
borenet@google.com070d3542012-10-26 13:26:55 +0000703 if (NULL != outputDir) {
704 SkDELETE(outputDir);
705 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000706 usage(argv0);
707 exit(-1);
708 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000709
710 if (NULL == renderer) {
711 renderer = SkNEW(sk_tools::SimplePictureRenderer);
712 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000713
edisonn@google.com84f548c2012-12-18 22:24:03 +0000714 renderer->setBBoxHierarchyType(bbhType);
715 renderer->setGridSize(gridWidth, gridHeight);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000716 renderer->setViewport(viewport);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000717 renderer->setScaleFactor(scaleFactor);
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000718 renderer->setDeviceType(deviceType);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000719}
720
caryclark@google.com5987f582012-10-02 18:33:14 +0000721int tool_main(int argc, char** argv);
722int tool_main(int argc, char** argv) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000723 SkAutoGraphics ag;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000724 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000725 sk_tools::PictureRenderer* renderer = NULL;
borenet@google.com070d3542012-10-26 13:26:55 +0000726 SkString* outputDir = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000727 bool validate = false;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000728 int maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000729 bool writeWholeImage = false;
730 int clones = 0;
731 parse_commandline(argc, argv, &inputs, renderer, outputDir,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000732 &validate, &maxComponentDiff, &writeWholeImage, &clones);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000733 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000734
borenet@google.com66bcbd12012-09-17 18:26:06 +0000735 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000736 for (int i = 0; i < inputs.count(); i ++) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000737 failures += process_input(inputs[i], outputDir, *renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000738 validate, maxComponentDiff,
739 writeWholeImage, clones);
junov@chromium.org777442d2012-06-12 14:56:36 +0000740 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000741 if (failures != 0) {
742 SkDebugf("Failed to render %i pictures.\n", failures);
743 return 1;
744 }
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000745#if SK_SUPPORT_GPU
746#if GR_CACHE_STATS
747 if (renderer->isUsingGpuDevice()) {
748 GrContext* ctx = renderer->getGrContext();
749
750 ctx->printCacheStats();
751 }
752#endif
753#endif
borenet@google.com070d3542012-10-26 13:26:55 +0000754 if (NULL != outputDir) {
755 SkDELETE(outputDir);
756 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000757 SkDELETE(renderer);
caryclark@google.com868e1f62012-10-02 20:00:03 +0000758 return 0;
junov@chromium.org777442d2012-06-12 14:56:36 +0000759}
caryclark@google.com5987f582012-10-02 18:33:14 +0000760
761#if !defined SK_BUILD_FOR_IOS
762int main(int argc, char * const argv[]) {
763 return tool_main(argc, (char**) argv);
764}
765#endif