blob: ae9e94d4cc1b7dd364c4ee3996600a0c17650eea [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
junov@chromium.org777442d2012-06-12 14:56:36 +00008#include "SkBitmap.h"
9#include "SkCanvas.h"
keyar@chromium.org472b3792012-07-20 22:34:27 +000010#include "SkDevice.h"
borenet@google.com10ef79e2012-09-10 17:19:06 +000011#include "SkGraphics.h"
scroggo@google.com5a7c6be2012-10-04 21:46:08 +000012#include "SkImageDecoder.h"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000013#include "SkMath.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000014#include "SkOSFile.h"
15#include "SkPicture.h"
16#include "SkStream.h"
17#include "SkString.h"
senorblanco@chromium.org3cbbb542012-07-13 18:55:53 +000018#include "SkTArray.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000019#include "PictureRenderer.h"
twiz@google.coma31b8bb2012-06-22 18:24:56 +000020#include "picture_utils.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000021
junov@chromium.org777442d2012-06-12 14:56:36 +000022static void usage(const char* argv0) {
23 SkDebugf("SkPicture rendering tool\n");
24 SkDebugf("\n"
25"Usage: \n"
borenet@google.com070d3542012-10-26 13:26:55 +000026" %s <input>... \n"
27" [-w <outputDir>]"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000028" [--mode pow2tile minWidth height[%] | simple\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000029" | tile width[%] height[%]]\n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000030" [--pipe]\n"
31" [--multi count]\n"
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000032" [--device bitmap"
33#if SK_SUPPORT_GPU
34" | gpu"
35#endif
36"]"
junov@chromium.org777442d2012-06-12 14:56:36 +000037, argv0);
keyar@chromium.org472b3792012-07-20 22:34:27 +000038 SkDebugf("\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000039 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000040" input: A list of directories and files to use as input. Files are\n"
41" expected to have the .skp extension.\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000042 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000043" outputDir: directory to write the rendered images.\n\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000044 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000045" --mode pow2tile minWidth height[%] | simple\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000046" | tile width[%] height[%]: Run in the corresponding mode.\n"
47" Default is simple.\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000048 SkDebugf(
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000049" pow2tile minWidth height[%], Creates tiles with widths\n"
50" that are all a power of two\n"
51" such that they minimize the\n"
52" amount of wasted tile space.\n"
53" minWidth is the minimum width\n"
54" of these tiles and must be a\n"
55" power of two. A simple render\n"
56" is done with these tiles.\n");
57 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000058" simple, Render using the default rendering method.\n");
59 SkDebugf(
60" tile width[%] height[%], Do a simple render using tiles\n"
61" with the given dimensions.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000062 SkDebugf("\n");
63 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000064" --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
65" than 1. Only works with tiled rendering.\n"
66" --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n");
67 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000068" --device bitmap"
69#if SK_SUPPORT_GPU
70" | gpu"
71#endif
72": Use the corresponding device. Default is bitmap.\n");
73 SkDebugf(
74" bitmap, Render to a bitmap.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000075#if SK_SUPPORT_GPU
keyar@chromium.orga40c20d2012-08-20 15:04:12 +000076 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000077" gpu, Render to the GPU.\n");
78#endif
junov@chromium.org777442d2012-06-12 14:56:36 +000079}
80
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +000081static void make_output_filepath(SkString* path, const SkString& dir,
junov@chromium.org777442d2012-06-12 14:56:36 +000082 const SkString& name) {
twiz@google.coma31b8bb2012-06-22 18:24:56 +000083 sk_tools::make_filepath(path, dir, name);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +000084 // Remove ".skp"
85 path->remove(path->size() - 4, 4);
junov@chromium.org777442d2012-06-12 14:56:36 +000086}
87
borenet@google.com070d3542012-10-26 13:26:55 +000088static bool render_picture(const SkString& inputPath, const SkString* outputDir,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000089 sk_tools::PictureRenderer& renderer) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +000090 SkString inputFilename;
91 sk_tools::get_basename(&inputFilename, inputPath);
twiz@google.coma31b8bb2012-06-22 18:24:56 +000092
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +000093 SkFILEStream inputStream;
twiz@google.coma31b8bb2012-06-22 18:24:56 +000094 inputStream.setPath(inputPath.c_str());
95 if (!inputStream.isValid()) {
96 SkDebugf("Could not open file %s\n", inputPath.c_str());
borenet@google.com66bcbd12012-09-17 18:26:06 +000097 return false;
twiz@google.coma31b8bb2012-06-22 18:24:56 +000098 }
99
borenet@google.com66bcbd12012-09-17 18:26:06 +0000100 bool success = false;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000101 SkPicture picture(&inputStream, &success, &SkImageDecoder::DecodeStream);
borenet@google.com66bcbd12012-09-17 18:26:06 +0000102 if (!success) {
103 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
104 return false;
105 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000106
borenet@google.com2d2b9a02012-09-20 18:54:04 +0000107 SkDebugf("drawing... [%i %i] %s\n", picture.width(), picture.height(),
borenet@google.com03fcee82012-09-10 18:18:38 +0000108 inputPath.c_str());
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000109
borenet@google.com2d2b9a02012-09-20 18:54:04 +0000110 renderer.init(&picture);
scroggo@google.comb4773b42012-10-01 20:06:09 +0000111 renderer.setup();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000112
borenet@google.com070d3542012-10-26 13:26:55 +0000113 SkString* outputPath = NULL;
114 if (NULL != outputDir) {
115 outputPath = SkNEW(SkString);
116 make_output_filepath(outputPath, *outputDir, inputFilename);
117 }
118 success = renderer.render(outputPath);
119 if (outputPath) {
120 if (!success) {
121 SkDebugf("Could not write to file %s\n", outputPath->c_str());
122 }
123 SkDELETE(outputPath);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000124 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000125
126 renderer.resetState();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000127
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000128 renderer.end();
borenet@google.com66bcbd12012-09-17 18:26:06 +0000129 return success;
junov@chromium.org777442d2012-06-12 14:56:36 +0000130}
131
borenet@google.com070d3542012-10-26 13:26:55 +0000132static int process_input(const SkString& input, const SkString* outputDir,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000133 sk_tools::PictureRenderer& renderer) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000134 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000135 SkString inputFilename;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000136 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000137 SkDebugf("process_input, %s\n", input.c_str());
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000138 if (iter.next(&inputFilename)) {
139 do {
140 SkString inputPath;
141 sk_tools::make_filepath(&inputPath, input, inputFilename);
borenet@google.com57837bf2012-09-19 17:28:29 +0000142 if (!render_picture(inputPath, outputDir, renderer)) {
143 ++failures;
144 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000145 } while(iter.next(&inputFilename));
borenet@google.com57837bf2012-09-19 17:28:29 +0000146 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000147 SkString inputPath(input);
borenet@google.com57837bf2012-09-19 17:28:29 +0000148 if (!render_picture(inputPath, outputDir, renderer)) {
149 ++failures;
150 }
151 } else {
152 SkString warning;
153 warning.printf("Warning: skipping %s\n", input.c_str());
154 SkDebugf(warning.c_str());
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000155 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000156 return failures;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000157}
158
159static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
borenet@google.com070d3542012-10-26 13:26:55 +0000160 sk_tools::PictureRenderer*& renderer, SkString*& outputDir){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000161 const char* argv0 = argv[0];
162 char* const* stop = argv + argc;
163
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000164 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
165 sk_tools::PictureRenderer::kBitmap_DeviceType;
166
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000167 bool usePipe = false;
168 int numThreads = 1;
169 bool useTiles = false;
170 const char* widthString = NULL;
171 const char* heightString = NULL;
172 bool isPowerOf2Mode = false;
173 const char* mode = NULL;
174
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000175 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000176 if (0 == strcmp(*argv, "--mode")) {
177 SkDELETE(renderer);
178
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000179 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000180 if (argv >= stop) {
181 SkDebugf("Missing mode for --mode\n");
182 usage(argv0);
183 exit(-1);
184 }
185
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000186 if (0 == strcmp(*argv, "simple")) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000187 renderer = SkNEW(sk_tools::SimplePictureRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000188 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000189 useTiles = true;
190 mode = *argv;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000191
192 if (0 == strcmp(*argv, "pow2tile")) {
193 isPowerOf2Mode = true;
194 }
195
keyar@chromium.org795cd472012-08-02 18:57:53 +0000196 ++argv;
197 if (argv >= stop) {
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000198 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000199 usage(argv0);
200 exit(-1);
201 }
202
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000203 widthString = *argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000204 ++argv;
205 if (argv >= stop) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000206 SkDebugf("Missing height for --mode tile\n");
keyar@chromium.org795cd472012-08-02 18:57:53 +0000207 usage(argv0);
208 exit(-1);
209 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000210 heightString = *argv;
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000211 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000212 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000213 usage(argv0);
214 exit(-1);
215 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000216 } else if (0 == strcmp(*argv, "--pipe")) {
217 usePipe = true;
218 } else if (0 == strcmp(*argv, "--multi")) {
219 ++argv;
220 if (argv >= stop) {
221 SkDebugf("Missing arg for --multi\n");
222 usage(argv0);
223 exit(-1);
224 }
225 numThreads = atoi(*argv);
226 if (numThreads < 2) {
227 SkDebugf("Number of threads must be at least 2.\n");
228 usage(argv0);
229 exit(-1);
230 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000231 } else if (0 == strcmp(*argv, "--device")) {
232 ++argv;
233 if (argv >= stop) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000234 SkDebugf("Missing mode for --device\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000235 usage(argv0);
236 exit(-1);
237 }
238
239 if (0 == strcmp(*argv, "bitmap")) {
240 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
241 }
242#if SK_SUPPORT_GPU
243 else if (0 == strcmp(*argv, "gpu")) {
244 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
245 }
246#endif
247 else {
248 SkDebugf("%s is not a valid mode for --device\n", *argv);
249 usage(argv0);
250 exit(-1);
251 }
252
keyar@chromium.org472b3792012-07-20 22:34:27 +0000253 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000254 SkDELETE(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000255 usage(argv0);
256 exit(-1);
borenet@google.com070d3542012-10-26 13:26:55 +0000257 } else if (0 == strcmp(*argv, "-w")) {
258 ++argv;
259 if (argv >= stop) {
260 SkDebugf("Missing output directory for -w\n");
261 usage(argv0);
262 exit(-1);
263 }
264 outputDir = SkNEW_ARGS(SkString, (*argv));
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000265 } else {
266 inputs->push_back(SkString(*argv));
267 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000268 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000269
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000270 if (numThreads > 1 && !useTiles) {
271 SkDebugf("Multithreaded drawing requires tiled rendering.\n");
272 usage(argv0);
273 exit(-1);
274 }
275
276 if (useTiles) {
277 SkASSERT(NULL == renderer);
278 sk_tools::TiledPictureRenderer* tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
279 if (isPowerOf2Mode) {
280 int minWidth = atoi(widthString);
281 if (!SkIsPow2(minWidth) || minWidth < 0) {
282 tiledRenderer->unref();
283 SkString err;
284 err.printf("-mode %s must be given a width"
285 " value that is a power of two\n", mode);
286 SkDebugf(err.c_str());
287 usage(argv0);
288 exit(-1);
289 }
290 tiledRenderer->setTileMinPowerOf2Width(minWidth);
291 } else if (sk_tools::is_percentage(widthString)) {
292 tiledRenderer->setTileWidthPercentage(atof(widthString));
293 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
294 tiledRenderer->unref();
295 SkDebugf("--mode tile must be given a width percentage > 0\n");
296 usage(argv0);
297 exit(-1);
298 }
299 } else {
300 tiledRenderer->setTileWidth(atoi(widthString));
301 if (!(tiledRenderer->getTileWidth() > 0)) {
302 tiledRenderer->unref();
303 SkDebugf("--mode tile must be given a width > 0\n");
304 usage(argv0);
305 exit(-1);
306 }
307 }
308
309 if (sk_tools::is_percentage(heightString)) {
310 tiledRenderer->setTileHeightPercentage(atof(heightString));
311 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
312 tiledRenderer->unref();
313 SkDebugf("--mode tile must be given a height percentage > 0\n");
314 usage(argv0);
315 exit(-1);
316 }
317 } else {
318 tiledRenderer->setTileHeight(atoi(heightString));
319 if (!(tiledRenderer->getTileHeight() > 0)) {
320 tiledRenderer->unref();
321 SkDebugf("--mode tile must be given a height > 0\n");
322 usage(argv0);
323 exit(-1);
324 }
325 }
326 if (numThreads > 1) {
327#if SK_SUPPORT_GPU
328 if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) {
329 tiledRenderer->unref();
330 SkDebugf("GPU not compatible with multithreaded tiling.\n");
331 usage(argv0);
332 exit(-1);
333 }
334#endif
335 tiledRenderer->setNumberOfThreads(numThreads);
336 }
337 tiledRenderer->setUsePipe(usePipe);
338 renderer = tiledRenderer;
339 } else if (usePipe) {
340 renderer = SkNEW(sk_tools::PipePictureRenderer);
341 }
342
borenet@google.com070d3542012-10-26 13:26:55 +0000343 if (inputs->empty()) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000344 SkDELETE(renderer);
borenet@google.com070d3542012-10-26 13:26:55 +0000345 if (NULL != outputDir) {
346 SkDELETE(outputDir);
347 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000348 usage(argv0);
349 exit(-1);
350 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000351
352 if (NULL == renderer) {
353 renderer = SkNEW(sk_tools::SimplePictureRenderer);
354 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000355
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000356 renderer->setDeviceType(deviceType);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000357}
358
caryclark@google.com5987f582012-10-02 18:33:14 +0000359int tool_main(int argc, char** argv);
360int tool_main(int argc, char** argv) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000361 SkAutoGraphics ag;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000362 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000363 sk_tools::PictureRenderer* renderer = NULL;
borenet@google.com070d3542012-10-26 13:26:55 +0000364 SkString* outputDir = NULL;
365 parse_commandline(argc, argv, &inputs, renderer, outputDir);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000366 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000367
borenet@google.com66bcbd12012-09-17 18:26:06 +0000368 int failures = 0;
borenet@google.com070d3542012-10-26 13:26:55 +0000369 for (int i = 0; i < inputs.count(); i ++) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000370 failures += process_input(inputs[i], outputDir, *renderer);
junov@chromium.org777442d2012-06-12 14:56:36 +0000371 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000372 if (failures != 0) {
373 SkDebugf("Failed to render %i pictures.\n", failures);
374 return 1;
375 }
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000376#if SK_SUPPORT_GPU
377#if GR_CACHE_STATS
378 if (renderer->isUsingGpuDevice()) {
379 GrContext* ctx = renderer->getGrContext();
380
381 ctx->printCacheStats();
382 }
383#endif
384#endif
borenet@google.com070d3542012-10-26 13:26:55 +0000385 if (NULL != outputDir) {
386 SkDELETE(outputDir);
387 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000388 SkDELETE(renderer);
caryclark@google.com868e1f62012-10-02 20:00:03 +0000389 return 0;
junov@chromium.org777442d2012-06-12 14:56:36 +0000390}
caryclark@google.com5987f582012-10-02 18:33:14 +0000391
392#if !defined SK_BUILD_FOR_IOS
393int main(int argc, char * const argv[]) {
394 return tool_main(argc, (char**) argv);
395}
396#endif