blob: 146b04552f4353cf078f90c47e0b4944941435b3 [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"
scroggo@google.comf8d7d272013-02-22 21:38:35 +000010#include "SkBitmapFactory.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000011#include "SkCanvas.h"
keyar@chromium.org472b3792012-07-20 22:34:27 +000012#include "SkDevice.h"
borenet@google.com10ef79e2012-09-10 17:19:06 +000013#include "SkGraphics.h"
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000014#include "SkImageDecoder.h"
edisonn@google.com84f548c2012-12-18 22:24:03 +000015#include "SkImageEncoder.h"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000016#include "SkMath.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000017#include "SkOSFile.h"
18#include "SkPicture.h"
19#include "SkStream.h"
20#include "SkString.h"
senorblanco@chromium.org3cbbb542012-07-13 18:55:53 +000021#include "SkTArray.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000022#include "PictureRenderer.h"
twiz@google.coma31b8bb2012-06-22 18:24:56 +000023#include "picture_utils.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000024
junov@chromium.org777442d2012-06-12 14:56:36 +000025static void usage(const char* argv0) {
26 SkDebugf("SkPicture rendering tool\n");
27 SkDebugf("\n"
28"Usage: \n"
borenet@google.com070d3542012-10-26 13:26:55 +000029" %s <input>... \n"
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000030" [-w <outputDir>]\n"
31" [--mode pow2tile minWidth height | copyTile width height | simple\n"
32" | tile width height]\n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000033" [--pipe]\n"
edisonn@google.com84f548c2012-12-18 22:24:03 +000034" [--bbh bbhType]\n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000035" [--multi count]\n"
edisonn@google.comca1b3ff2013-01-16 18:18:48 +000036" [--validate [--maxComponentDiff n]]\n"
edisonn@google.com84f548c2012-12-18 22:24:03 +000037" [--writeWholeImage]\n"
38" [--clone n]\n"
scroggo@google.comf8d7d272013-02-22 21:38:35 +000039" [--enable-deferred-image-decoding]\n"
scroggo@google.com82ec0b02012-12-17 19:25:54 +000040" [--viewport width height][--scale sf]\n"
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000041" [--device bitmap"
42#if SK_SUPPORT_GPU
43" | gpu"
44#endif
scroggo@google.com0556ea02013-02-08 19:38:21 +000045#if SK_ANGLE
46" | angle"
47#endif
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000048"]"
junov@chromium.org777442d2012-06-12 14:56:36 +000049, argv0);
keyar@chromium.org472b3792012-07-20 22:34:27 +000050 SkDebugf("\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000051 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000052" input: A list of directories and files to use as input. Files are\n"
53" expected to have the .skp extension.\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000054 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000055" outputDir: directory to write the rendered images.\n\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000056 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000057" --mode pow2tile minWidth height | copyTile width height | simple\n"
58" | tile width height | rerecord: Run in the corresponding mode.\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000059" Default is simple.\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000060 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000061" pow2tile minWidth height, Creates tiles with widths\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000062" that are all a power of two\n"
63" such that they minimize the\n"
64" amount of wasted tile space.\n"
65" minWidth is the minimum width\n"
66" of these tiles and must be a\n"
67" power of two. A simple render\n"
68" is done with these tiles.\n");
69 SkDebugf(
scroggo@google.coma9e3a362012-11-07 17:52:48 +000070" simple, Render using the default rendering method.\n"
71" rerecord, Record the picture as a new skp, with the bitmaps PNG encoded.\n"
72 );
keyar@chromium.org795cd472012-08-02 18:57:53 +000073 SkDebugf(
scroggo@google.com4a26d9d2012-11-07 18:01:46 +000074" tile width height, Do a simple render using tiles\n"
75" with the given dimensions.\n"
76" copyTile width height, Draw the picture, then copy it into tiles.\n"
77" Does not support percentages.\n"
78" If the picture is large enough, breaks it into\n"
79" larger tiles (and draws the picture once per\n"
80" larger tile) to avoid creating a large canvas.\n"
81" Add --tiles x y to specify the number of tiles\n"
82" per larger tile in the x and y direction.\n"
83 );
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000084 SkDebugf("\n");
85 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000086" --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
87" than 1. Only works with tiled rendering.\n"
scroggo@google.comf8d7d272013-02-22 21:38:35 +000088" --enable-deferred-image-decoding : Defer decoding until drawing images. Has no effect if\n"
89" the provided skp does not have its images encoded.\n"
scroggo@google.comc0d5e542012-12-13 21:40:48 +000090" --viewport width height : Set the viewport.\n"
scroggo@google.com82ec0b02012-12-17 19:25:54 +000091" --scale sf : Scale drawing by sf.\n"
scroggo@google.coma62da2f2012-11-02 21:28:12 +000092" --pipe: Benchmark SkGPipe rendering. Currently incompatible with \"mode\".\n");
scroggo@google.comb6e806b2012-10-03 17:32:33 +000093 SkDebugf(
edisonn@google.com84f548c2012-12-18 22:24:03 +000094" --validate: Verify that the rendered image contains the same pixels as "
95"the picture rendered in simple mode.\n"
edisonn@google.comca1b3ff2013-01-16 18:18:48 +000096" --maxComponentDiff: maximum diff on a component. Default is 256, "
97"which means we report but we do not generate an error.\n"
edisonn@google.com84f548c2012-12-18 22:24:03 +000098" --writeWholeImage: In tile mode, write the entire rendered image to a "
99"file, instead of an image for each tile.\n");
100 SkDebugf(
101" --clone n: Clone the picture n times before rendering.\n");
102 SkDebugf(
103" --bbh bbhType [width height]: Set the bounding box hierarchy type to\n"
104" be used. Accepted values are: none, rtree, grid. Default\n"
105" value is none. Not compatible with --pipe. With value\n"
106" 'grid', width and height must be specified. 'grid' can\n"
107" only be used with modes tile, record, and\n"
108" playbackCreation.");
109 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000110" --device bitmap"
111#if SK_SUPPORT_GPU
112" | gpu"
113#endif
114": Use the corresponding device. Default is bitmap.\n");
115 SkDebugf(
116" bitmap, Render to a bitmap.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000117#if SK_SUPPORT_GPU
keyar@chromium.orga40c20d2012-08-20 15:04:12 +0000118 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000119" gpu, Render to the GPU.\n");
120#endif
scroggo@google.com0556ea02013-02-08 19:38:21 +0000121#if SK_ANGLE
122 SkDebugf(
123" angle, Render using angle.\n");
124#endif
junov@chromium.org777442d2012-06-12 14:56:36 +0000125}
126
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000127static void make_output_filepath(SkString* path, const SkString& dir,
junov@chromium.org777442d2012-06-12 14:56:36 +0000128 const SkString& name) {
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000129 sk_tools::make_filepath(path, dir, name);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000130 // Remove ".skp"
131 path->remove(path->size() - 4, 4);
junov@chromium.org777442d2012-06-12 14:56:36 +0000132}
133
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000134bool lazy_decode = false;
135
136#include "SkData.h"
137#include "SkLruImageCache.h"
138
139static SkLruImageCache gLruImageCache(1024*1024);
140
141#ifdef SK_BUILD_FOR_ANDROID
142#include "SkAshmemImageCache.h"
143#include "SkImage.h"
144
145static SkImageCache* cache_selector(const SkImage::Info& info) {
146 if (info.fWidth * info.fHeight > 32 * 1024) {
147 return SkAshmemImageCache::GetAshmemImageCache();
148 }
149 return &gLruImageCache;
150}
151
152#endif
153
154static bool lazy_decode_bitmap(const void* buffer, size_t size, SkBitmap* bitmap) {
155 void* copiedBuffer = sk_malloc_throw(size);
156 memcpy(copiedBuffer, buffer, size);
157 SkAutoDataUnref data(SkData::NewFromMalloc(copiedBuffer, size));
158 SkBitmapFactory factory(&SkImageDecoder::DecodeMemoryToTarget);
159#ifdef SK_BUILD_FOR_ANDROID
160 factory.setCacheSelector(&cache_selector);
161#else
162 factory.setImageCache(&gLruImageCache);
163#endif
164 return factory.installPixelRef(data, bitmap);
165}
166
borenet@google.com070d3542012-10-26 13:26:55 +0000167static bool render_picture(const SkString& inputPath, const SkString* outputDir,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000168 sk_tools::PictureRenderer& renderer,
169 SkBitmap** out,
170 int clones) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000171 SkString inputFilename;
172 sk_tools::get_basename(&inputFilename, inputPath);
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000173
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000174 SkFILEStream inputStream;
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000175 inputStream.setPath(inputPath.c_str());
176 if (!inputStream.isValid()) {
177 SkDebugf("Could not open file %s\n", inputPath.c_str());
borenet@google.com66bcbd12012-09-17 18:26:06 +0000178 return false;
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000179 }
180
borenet@google.com66bcbd12012-09-17 18:26:06 +0000181 bool success = false;
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000182 SkPicture* picture;
183 if (lazy_decode) {
184 picture = SkNEW_ARGS(SkPicture, (&inputStream, &success, &lazy_decode_bitmap));
185 } else {
186 picture = SkNEW_ARGS(SkPicture, (&inputStream, &success, &SkImageDecoder::DecodeMemory));
187 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000188 if (!success) {
189 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
190 return false;
191 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000192
edisonn@google.com84f548c2012-12-18 22:24:03 +0000193 for (int i = 0; i < clones; ++i) {
194 SkPicture* clone = picture->clone();
195 SkDELETE(picture);
196 picture = clone;
197 }
198
199 SkDebugf("drawing... [%i %i] %s\n", picture->width(), picture->height(),
borenet@google.com03fcee82012-09-10 18:18:38 +0000200 inputPath.c_str());
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000201
edisonn@google.com84f548c2012-12-18 22:24:03 +0000202 renderer.init(picture);
scroggo@google.comb4773b42012-10-01 20:06:09 +0000203 renderer.setup();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000204
borenet@google.com070d3542012-10-26 13:26:55 +0000205 SkString* outputPath = NULL;
206 if (NULL != outputDir) {
207 outputPath = SkNEW(SkString);
208 make_output_filepath(outputPath, *outputDir, inputFilename);
209 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000210
211 success = renderer.render(outputPath, out);
borenet@google.com070d3542012-10-26 13:26:55 +0000212 if (outputPath) {
213 if (!success) {
214 SkDebugf("Could not write to file %s\n", outputPath->c_str());
215 }
216 SkDELETE(outputPath);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000217 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000218
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000219 renderer.end();
edisonn@google.com84f548c2012-12-18 22:24:03 +0000220
221 SkDELETE(picture);
borenet@google.com66bcbd12012-09-17 18:26:06 +0000222 return success;
junov@chromium.org777442d2012-06-12 14:56:36 +0000223}
224
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000225static inline int getByte(uint32_t value, int index) {
226 SkASSERT(0 <= index && index < 4);
227 return (value >> (index * 8)) & 0xFF;
228}
229
230static int MaxByteDiff(uint32_t v1, uint32_t v2) {
231 return SkMax32(SkMax32(abs(getByte(v1, 0) - getByte(v2, 0)), abs(getByte(v1, 1) - getByte(v2, 1))),
232 SkMax32(abs(getByte(v1, 2) - getByte(v2, 2)), abs(getByte(v1, 3) - getByte(v2, 3))));
233}
234
edisonn@google.com84f548c2012-12-18 22:24:03 +0000235static bool render_picture(const SkString& inputPath, const SkString* outputDir,
236 sk_tools::PictureRenderer& renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000237 bool validate, int maxComponentDiff,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000238 bool writeWholeImage,
239 int clones) {
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000240 int diffs[256] = {0};
edisonn@google.com84f548c2012-12-18 22:24:03 +0000241 SkBitmap* bitmap = NULL;
242 bool success = render_picture(inputPath,
243 writeWholeImage ? NULL : outputDir,
244 renderer,
245 validate || writeWholeImage ? &bitmap : NULL, clones);
246
247 if (!success || ((validate || writeWholeImage) && bitmap == NULL)) {
248 SkDebugf("Failed to draw the picture.\n");
249 SkDELETE(bitmap);
250 return false;
251 }
252
253 if (validate) {
254 SkBitmap* referenceBitmap = NULL;
255 sk_tools::SimplePictureRenderer referenceRenderer;
256 success = render_picture(inputPath, NULL, referenceRenderer,
257 &referenceBitmap, 0);
258
259 if (!success || !referenceBitmap) {
260 SkDebugf("Failed to draw the reference picture.\n");
261 SkDELETE(bitmap);
262 SkDELETE(referenceBitmap);
263 return false;
264 }
265
266 if (success && (bitmap->width() != referenceBitmap->width())) {
267 SkDebugf("Expected image width: %i, actual image width %i.\n",
268 referenceBitmap->width(), bitmap->width());
269 SkDELETE(bitmap);
270 SkDELETE(referenceBitmap);
271 return false;
272 }
273 if (success && (bitmap->height() != referenceBitmap->height())) {
274 SkDebugf("Expected image height: %i, actual image height %i",
275 referenceBitmap->height(), bitmap->height());
276 SkDELETE(bitmap);
277 SkDELETE(referenceBitmap);
278 return false;
279 }
skia.committer@gmail.coma7d8e3e2012-12-19 02:01:38 +0000280
edisonn@google.com84f548c2012-12-18 22:24:03 +0000281 for (int y = 0; success && y < bitmap->height(); y++) {
282 for (int x = 0; success && x < bitmap->width(); x++) {
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000283 int diff = MaxByteDiff(*referenceBitmap->getAddr32(x, y),
284 *bitmap->getAddr32(x, y));
285 SkASSERT(diff >= 0 && diff <= 255);
286 diffs[diff]++;
skia.committer@gmail.com4d28d982013-01-17 07:06:06 +0000287
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000288 if (diff > maxComponentDiff) {
289 SkDebugf("Expected pixel at (%i %i) exceedds maximum "
290 "component diff of %i: 0x%x, actual 0x%x\n",
291 x, y, maxComponentDiff,
edisonn@google.com01754bf2013-01-11 16:08:07 +0000292 *referenceBitmap->getAddr32(x, y),
edisonn@google.com84f548c2012-12-18 22:24:03 +0000293 *bitmap->getAddr32(x, y));
294 SkDELETE(bitmap);
295 SkDELETE(referenceBitmap);
296 return false;
297 }
298 }
299 }
300 SkDELETE(referenceBitmap);
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000301
302 for (int i = 1; i <= 255; ++i) {
303 if(diffs[i] > 0) {
304 SkDebugf("Number of pixels with max diff of %i is %i\n", i, diffs[i]);
305 }
306 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000307 }
308
309 if (writeWholeImage) {
310 sk_tools::force_all_opaque(*bitmap);
311 if (NULL != outputDir && writeWholeImage) {
312 SkString inputFilename;
313 sk_tools::get_basename(&inputFilename, inputPath);
314 SkString outputPath;
315 make_output_filepath(&outputPath, *outputDir, inputFilename);
316 outputPath.append(".png");
317 if (!SkImageEncoder::EncodeFile(outputPath.c_str(), *bitmap,
318 SkImageEncoder::kPNG_Type, 100)) {
319 SkDebugf("Failed to draw the picture.\n");
320 success = false;
321 }
322 }
323 }
324 SkDELETE(bitmap);
325
326 return success;
327}
328
329
borenet@google.com070d3542012-10-26 13:26:55 +0000330static int process_input(const SkString& input, const SkString* outputDir,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000331 sk_tools::PictureRenderer& renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000332 bool validate, int maxComponentDiff,
333 bool writeWholeImage, int clones) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000334 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000335 SkString inputFilename;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000336 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000337 SkDebugf("process_input, %s\n", input.c_str());
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000338 if (iter.next(&inputFilename)) {
339 do {
340 SkString inputPath;
341 sk_tools::make_filepath(&inputPath, input, inputFilename);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000342 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000343 validate, maxComponentDiff,
344 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000345 ++failures;
346 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000347 } while(iter.next(&inputFilename));
borenet@google.com57837bf2012-09-19 17:28:29 +0000348 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000349 SkString inputPath(input);
edisonn@google.com84f548c2012-12-18 22:24:03 +0000350 if (!render_picture(inputPath, outputDir, renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000351 validate, maxComponentDiff,
352 writeWholeImage, clones)) {
borenet@google.com57837bf2012-09-19 17:28:29 +0000353 ++failures;
354 }
355 } else {
356 SkString warning;
357 warning.printf("Warning: skipping %s\n", input.c_str());
358 SkDebugf(warning.c_str());
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000359 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000360 return failures;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000361}
362
363static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000364 sk_tools::PictureRenderer*& renderer, SkString*& outputDir,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000365 bool* validate, int* maxComponentDiff,
366 bool* writeWholeImage,
edisonn@google.com84f548c2012-12-18 22:24:03 +0000367 int* clones){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000368 const char* argv0 = argv[0];
369 char* const* stop = argv + argc;
370
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000371 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
372 sk_tools::PictureRenderer::kBitmap_DeviceType;
373
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000374 bool usePipe = false;
375 int numThreads = 1;
376 bool useTiles = false;
377 const char* widthString = NULL;
378 const char* heightString = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000379 int gridWidth = 0;
380 int gridHeight = 0;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000381 bool isPowerOf2Mode = false;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000382 bool isCopyMode = false;
383 const char* xTilesString = NULL;
384 const char* yTilesString = NULL;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000385 const char* mode = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000386 bool gridSupported = false;
387 sk_tools::PictureRenderer::BBoxHierarchyType bbhType =
388 sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
389 *validate = false;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000390 *maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000391 *writeWholeImage = false;
392 *clones = 0;
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000393 SkISize viewport;
394 viewport.setEmpty();
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000395 SkScalar scaleFactor = SK_Scalar1;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000396
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000397 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000398 if (0 == strcmp(*argv, "--mode")) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000399 if (renderer != NULL) {
400 renderer->unref();
401 SkDebugf("Cannot combine modes.\n");
402 usage(argv0);
403 exit(-1);
404 }
keyar@chromium.org795cd472012-08-02 18:57:53 +0000405
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000406 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000407 if (argv >= stop) {
408 SkDebugf("Missing mode for --mode\n");
409 usage(argv0);
410 exit(-1);
411 }
412
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000413 if (0 == strcmp(*argv, "simple")) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000414 renderer = SkNEW(sk_tools::SimplePictureRenderer);
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000415 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))
416 || 0 == strcmp(*argv, "copyTile")) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000417 useTiles = true;
418 mode = *argv;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000419
420 if (0 == strcmp(*argv, "pow2tile")) {
421 isPowerOf2Mode = true;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000422 } else if (0 == strcmp(*argv, "copyTile")) {
423 isCopyMode = true;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000424 } else {
425 gridSupported = true;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000426 }
427
keyar@chromium.org795cd472012-08-02 18:57:53 +0000428 ++argv;
429 if (argv >= stop) {
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000430 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000431 usage(argv0);
432 exit(-1);
433 }
434
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000435 widthString = *argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000436 ++argv;
437 if (argv >= stop) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000438 SkDebugf("Missing height for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000439 usage(argv0);
440 exit(-1);
441 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000442 heightString = *argv;
scroggo@google.coma9e3a362012-11-07 17:52:48 +0000443 } else if (0 == strcmp(*argv, "rerecord")) {
444 renderer = SkNEW(sk_tools::RecordPictureRenderer);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000445 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000446 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000447 usage(argv0);
448 exit(-1);
449 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000450 } else if (0 == strcmp(*argv, "--bbh")) {
451 ++argv;
452 if (argv >= stop) {
453 SkDebugf("Missing value for --bbh\n");
454 usage(argv0);
455 exit(-1);
456 }
457 if (0 == strcmp(*argv, "none")) {
458 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
459 } else if (0 == strcmp(*argv, "rtree")) {
460 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
461 } else if (0 == strcmp(*argv, "grid")) {
462 bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType;
463 ++argv;
464 if (argv >= stop) {
465 SkDebugf("Missing width for --bbh grid\n");
466 usage(argv0);
467 exit(-1);
468 }
469 gridWidth = atoi(*argv);
470 ++argv;
471 if (argv >= stop) {
472 SkDebugf("Missing height for --bbh grid\n");
473 usage(argv0);
474 exit(-1);
475 }
476 gridHeight = atoi(*argv);
477 } else {
478 SkDebugf("%s is not a valid value for --bbhType\n", *argv);
479 usage(argv0);
480 exit(-1);;
481 }
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000482 } else if (0 == strcmp(*argv, "--viewport")) {
483 ++argv;
484 if (argv >= stop) {
485 SkDebugf("Missing width for --viewport\n");
486 usage(argv0);
487 exit(-1);
488 }
489 viewport.fWidth = atoi(*argv);
490 ++argv;
491 if (argv >= stop) {
492 SkDebugf("Missing height for --viewport\n");
493 usage(argv0);
494 exit(-1);
495 }
496 viewport.fHeight = atoi(*argv);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000497 } else if (0 == strcmp(*argv, "--scale")) {
498 ++argv;
499 if (argv >= stop) {
500 SkDebugf("Missing scaleFactor for --scale\n");
501 usage(argv0);
502 exit(-1);
503 }
reed@google.com89d15a22013-01-07 22:26:05 +0000504 scaleFactor = SkDoubleToScalar(atof(*argv));
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000505 } else if (0 == strcmp(*argv, "--tiles")) {
506 ++argv;
507 if (argv >= stop) {
508 SkDebugf("Missing x for --tiles\n");
509 usage(argv0);
510 exit(-1);
511 }
512 xTilesString = *argv;
513 ++argv;
514 if (argv >= stop) {
515 SkDebugf("Missing y for --tiles\n");
516 usage(argv0);
517 exit(-1);
518 }
519 yTilesString = *argv;
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000520 } else if (0 == strcmp(*argv, "--pipe")) {
521 usePipe = true;
522 } else if (0 == strcmp(*argv, "--multi")) {
523 ++argv;
524 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000525 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000526 SkDebugf("Missing arg for --multi\n");
527 usage(argv0);
528 exit(-1);
529 }
530 numThreads = atoi(*argv);
531 if (numThreads < 2) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000532 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000533 SkDebugf("Number of threads must be at least 2.\n");
534 usage(argv0);
535 exit(-1);
536 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000537 } else if (0 == strcmp(*argv, "--clone")) {
538 ++argv;
539 if (argv >= stop) {
540 SkSafeUnref(renderer);
541 SkDebugf("Missing arg for --clone\n");
542 usage(argv0);
543 exit(-1);
544 }
545 *clones = atoi(*argv);
546 if (*clones < 0) {
547 SkSafeUnref(renderer);
548 SkDebugf("Number of clones must be at least 0.\n");
549 usage(argv0);
550 exit(-1);
551 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000552 } else if (0 == strcmp(*argv, "--device")) {
553 ++argv;
554 if (argv >= stop) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000555 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000556 SkDebugf("Missing mode for --device\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000557 usage(argv0);
558 exit(-1);
559 }
560
561 if (0 == strcmp(*argv, "bitmap")) {
562 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
563 }
564#if SK_SUPPORT_GPU
565 else if (0 == strcmp(*argv, "gpu")) {
566 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
567 }
568#endif
scroggo@google.com0556ea02013-02-08 19:38:21 +0000569#if SK_ANGLE
570 else if (0 == strcmp(*argv, "angle")) {
571 deviceType = sk_tools::PictureRenderer::kAngle_DeviceType;
572 }
573#endif
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000574 else {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000575 SkSafeUnref(renderer);
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000576 SkDebugf("%s is not a valid mode for --device\n", *argv);
577 usage(argv0);
578 exit(-1);
579 }
scroggo@google.comf8d7d272013-02-22 21:38:35 +0000580 } else if (0 == strcmp(*argv, "--enable-deferred-image-decoding")) {
581 lazy_decode = true;
keyar@chromium.org472b3792012-07-20 22:34:27 +0000582 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000583 SkSafeUnref(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000584 usage(argv0);
585 exit(-1);
borenet@google.com070d3542012-10-26 13:26:55 +0000586 } else if (0 == strcmp(*argv, "-w")) {
587 ++argv;
588 if (argv >= stop) {
589 SkDebugf("Missing output directory for -w\n");
590 usage(argv0);
591 exit(-1);
592 }
593 outputDir = SkNEW_ARGS(SkString, (*argv));
edisonn@google.com84f548c2012-12-18 22:24:03 +0000594 } else if (0 == strcmp(*argv, "--validate")) {
595 *validate = true;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000596 } else if (0 == strcmp(*argv, "--maxComponentDiff")) {
597 if (!*validate) {
598 SkDebugf("--maxComponentDiff must be used only with --validate\n");
599 usage(argv0);
600 exit(-1);
601 }
602 ++argv;
603 if (argv >= stop) {
604 SkDebugf("Missing arg for --maxComponentDiff\n");
605 usage(argv0);
606 exit(-1);
607 }
608 *maxComponentDiff = atoi(*argv);
609 if (*maxComponentDiff < 0 || *maxComponentDiff > 256) {
610 SkSafeUnref(renderer);
611 SkDebugf("maxComponentDiff: 0 - 256.\n");
612 usage(argv0);
613 exit(-1);
skia.committer@gmail.com4d28d982013-01-17 07:06:06 +0000614 }
edisonn@google.com84f548c2012-12-18 22:24:03 +0000615 } else if (0 == strcmp(*argv, "--writeWholeImage")) {
616 *writeWholeImage = true;
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000617 } else {
618 inputs->push_back(SkString(*argv));
619 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000620 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000621
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000622 if (numThreads > 1 && !useTiles) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000623 SkSafeUnref(renderer);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000624 SkDebugf("Multithreaded drawing requires tiled rendering.\n");
625 usage(argv0);
626 exit(-1);
627 }
628
edisonn@google.com84f548c2012-12-18 22:24:03 +0000629 if (usePipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
630 SkDebugf("--pipe and --bbh cannot be used together\n");
631 usage(argv0);
632 exit(-1);
633 }
634
635 if (sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType == bbhType &&
636 !gridSupported) {
637 SkDebugf("'--bbh grid' is not compatible with specified --mode.\n");
638 usage(argv0);
639 exit(-1);
640 }
641
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000642 if (useTiles) {
643 SkASSERT(NULL == renderer);
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000644 sk_tools::TiledPictureRenderer* tiledRenderer;
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000645 if (isCopyMode) {
646 int x, y;
647 if (xTilesString != NULL) {
648 SkASSERT(yTilesString != NULL);
649 x = atoi(xTilesString);
650 y = atoi(yTilesString);
651 if (x <= 0 || y <= 0) {
652 SkDebugf("--tiles must be given values > 0\n");
653 usage(argv0);
654 exit(-1);
655 }
656 } else {
657 x = y = 4;
658 }
659 tiledRenderer = SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y));
660 } else if (numThreads > 1) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000661 tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
662 } else {
663 tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
664 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000665 if (isPowerOf2Mode) {
666 int minWidth = atoi(widthString);
667 if (!SkIsPow2(minWidth) || minWidth < 0) {
668 tiledRenderer->unref();
669 SkString err;
670 err.printf("-mode %s must be given a width"
671 " value that is a power of two\n", mode);
672 SkDebugf(err.c_str());
673 usage(argv0);
674 exit(-1);
675 }
676 tiledRenderer->setTileMinPowerOf2Width(minWidth);
677 } else if (sk_tools::is_percentage(widthString)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000678 if (isCopyMode) {
679 tiledRenderer->unref();
680 SkString err;
681 err.printf("--mode %s does not support percentages.\n", mode);
682 SkDebugf(err.c_str());
683 usage(argv0);
684 exit(-1);
685 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000686 tiledRenderer->setTileWidthPercentage(atof(widthString));
687 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
688 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000689 SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000690 usage(argv0);
691 exit(-1);
692 }
693 } else {
694 tiledRenderer->setTileWidth(atoi(widthString));
695 if (!(tiledRenderer->getTileWidth() > 0)) {
696 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000697 SkDebugf("--mode %s must be given a width > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000698 usage(argv0);
699 exit(-1);
700 }
701 }
702
703 if (sk_tools::is_percentage(heightString)) {
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000704 if (isCopyMode) {
705 tiledRenderer->unref();
706 SkString err;
707 err.printf("--mode %s does not support percentages.\n", mode);
708 SkDebugf(err.c_str());
709 usage(argv0);
710 exit(-1);
711 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000712 tiledRenderer->setTileHeightPercentage(atof(heightString));
713 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
714 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000715 SkDebugf("--mode %s must be given a height percentage > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000716 usage(argv0);
717 exit(-1);
718 }
719 } else {
720 tiledRenderer->setTileHeight(atoi(heightString));
721 if (!(tiledRenderer->getTileHeight() > 0)) {
722 tiledRenderer->unref();
scroggo@google.com4a26d9d2012-11-07 18:01:46 +0000723 SkDebugf("--mode %s must be given a height > 0\n", mode);
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000724 usage(argv0);
725 exit(-1);
726 }
727 }
728 if (numThreads > 1) {
scroggo@google.com0556ea02013-02-08 19:38:21 +0000729 switch (deviceType) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000730#if SK_SUPPORT_GPU
scroggo@google.com0556ea02013-02-08 19:38:21 +0000731 case sk_tools::PictureRenderer::kGPU_DeviceType:
732 // fall through
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000733#endif
scroggo@google.com0556ea02013-02-08 19:38:21 +0000734#if SK_ANGLE
735 case sk_tools::PictureRenderer::kAngle_DeviceType:
736#endif
737 tiledRenderer->unref();
738 SkDebugf("GPU not compatible with multithreaded tiling.\n");
739 usage(argv0);
740 exit(-1);
741 break;
742 default:
743 break;
744 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000745 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000746 renderer = tiledRenderer;
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000747 if (usePipe) {
748 SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
749 "Turning off pipe.\n");
750 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000751 } else if (usePipe) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000752 if (renderer != NULL) {
753 renderer->unref();
754 SkDebugf("Pipe is incompatible with other modes.\n");
755 usage(argv0);
756 exit(-1);
757 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000758 renderer = SkNEW(sk_tools::PipePictureRenderer);
759 }
760
borenet@google.com070d3542012-10-26 13:26:55 +0000761 if (inputs->empty()) {
scroggo@google.coma62da2f2012-11-02 21:28:12 +0000762 SkSafeUnref(renderer);
borenet@google.com070d3542012-10-26 13:26:55 +0000763 if (NULL != outputDir) {
764 SkDELETE(outputDir);
765 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000766 usage(argv0);
767 exit(-1);
768 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000769
770 if (NULL == renderer) {
771 renderer = SkNEW(sk_tools::SimplePictureRenderer);
772 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000773
edisonn@google.com84f548c2012-12-18 22:24:03 +0000774 renderer->setBBoxHierarchyType(bbhType);
775 renderer->setGridSize(gridWidth, gridHeight);
scroggo@google.comc0d5e542012-12-13 21:40:48 +0000776 renderer->setViewport(viewport);
scroggo@google.com82ec0b02012-12-17 19:25:54 +0000777 renderer->setScaleFactor(scaleFactor);
scroggo@google.com0556ea02013-02-08 19:38:21 +0000778 if (!renderer->setDeviceType(deviceType)) {
779 SkDebugf("Invalid device type.\n");
780 exit(-1);
781 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000782}
783
caryclark@google.com5987f582012-10-02 18:33:14 +0000784int tool_main(int argc, char** argv);
785int tool_main(int argc, char** argv) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000786 SkAutoGraphics ag;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000787 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000788 sk_tools::PictureRenderer* renderer = NULL;
borenet@google.com070d3542012-10-26 13:26:55 +0000789 SkString* outputDir = NULL;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000790 bool validate = false;
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000791 int maxComponentDiff = 256;
edisonn@google.com84f548c2012-12-18 22:24:03 +0000792 bool writeWholeImage = false;
793 int clones = 0;
794 parse_commandline(argc, argv, &inputs, renderer, outputDir,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000795 &validate, &maxComponentDiff, &writeWholeImage, &clones);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000796 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000797
borenet@google.com66bcbd12012-09-17 18:26:06 +0000798 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000799 for (int i = 0; i < inputs.count(); i ++) {
edisonn@google.com84f548c2012-12-18 22:24:03 +0000800 failures += process_input(inputs[i], outputDir, *renderer,
edisonn@google.comca1b3ff2013-01-16 18:18:48 +0000801 validate, maxComponentDiff,
802 writeWholeImage, clones);
junov@chromium.org777442d2012-06-12 14:56:36 +0000803 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000804 if (failures != 0) {
805 SkDebugf("Failed to render %i pictures.\n", failures);
806 return 1;
807 }
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000808#if SK_SUPPORT_GPU
809#if GR_CACHE_STATS
810 if (renderer->isUsingGpuDevice()) {
811 GrContext* ctx = renderer->getGrContext();
812
813 ctx->printCacheStats();
814 }
815#endif
816#endif
borenet@google.com070d3542012-10-26 13:26:55 +0000817 if (NULL != outputDir) {
818 SkDELETE(outputDir);
819 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000820 SkDELETE(renderer);
caryclark@google.com868e1f62012-10-02 20:00:03 +0000821 return 0;
junov@chromium.org777442d2012-06-12 14:56:36 +0000822}
caryclark@google.com5987f582012-10-02 18:33:14 +0000823
824#if !defined SK_BUILD_FOR_IOS
825int main(int argc, char * const argv[]) {
826 return tool_main(argc, (char**) argv);
827}
828#endif