blob: 477272df2531421fad5665f111445a67bcf90749 [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"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000012#include "SkMath.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000013#include "SkOSFile.h"
14#include "SkPicture.h"
15#include "SkStream.h"
16#include "SkString.h"
senorblanco@chromium.org3cbbb542012-07-13 18:55:53 +000017#include "SkTArray.h"
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000018#include "PictureRenderer.h"
twiz@google.coma31b8bb2012-06-22 18:24:56 +000019#include "picture_utils.h"
junov@chromium.org777442d2012-06-12 14:56:36 +000020
junov@chromium.org777442d2012-06-12 14:56:36 +000021static void usage(const char* argv0) {
22 SkDebugf("SkPicture rendering tool\n");
23 SkDebugf("\n"
24"Usage: \n"
keyar@chromium.org472b3792012-07-20 22:34:27 +000025" %s <input>... <outputDir> \n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000026" [--mode pow2tile minWidth height[%] | simple\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000027" | tile width[%] height[%]]\n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000028" [--pipe]\n"
29" [--multi count]\n"
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000030" [--device bitmap"
31#if SK_SUPPORT_GPU
32" | gpu"
33#endif
34"]"
junov@chromium.org777442d2012-06-12 14:56:36 +000035, argv0);
keyar@chromium.org472b3792012-07-20 22:34:27 +000036 SkDebugf("\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000037 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000038" input: A list of directories and files to use as input. Files are\n"
39" expected to have the .skp extension.\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000040 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000041" outputDir: directory to write the rendered images.\n\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000042 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000043" --mode pow2tile minWidth height[%] | simple\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000044" | tile width[%] height[%]: Run in the corresponding mode.\n"
45" Default is simple.\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000046 SkDebugf(
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000047" pow2tile minWidth height[%], Creates tiles with widths\n"
48" that are all a power of two\n"
49" such that they minimize the\n"
50" amount of wasted tile space.\n"
51" minWidth is the minimum width\n"
52" of these tiles and must be a\n"
53" power of two. A simple render\n"
54" is done with these tiles.\n");
55 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000056" simple, Render using the default rendering method.\n");
57 SkDebugf(
58" tile width[%] height[%], Do a simple render using tiles\n"
59" with the given dimensions.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000060 SkDebugf("\n");
61 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000062" --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
63" than 1. Only works with tiled rendering.\n"
64" --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n");
65 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000066" --device bitmap"
67#if SK_SUPPORT_GPU
68" | gpu"
69#endif
70": Use the corresponding device. Default is bitmap.\n");
71 SkDebugf(
72" bitmap, Render to a bitmap.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000073#if SK_SUPPORT_GPU
keyar@chromium.orga40c20d2012-08-20 15:04:12 +000074 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000075" gpu, Render to the GPU.\n");
76#endif
junov@chromium.org777442d2012-06-12 14:56:36 +000077}
78
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +000079static void make_output_filepath(SkString* path, const SkString& dir,
junov@chromium.org777442d2012-06-12 14:56:36 +000080 const SkString& name) {
twiz@google.coma31b8bb2012-06-22 18:24:56 +000081 sk_tools::make_filepath(path, dir, name);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +000082 // Remove ".skp"
83 path->remove(path->size() - 4, 4);
junov@chromium.org777442d2012-06-12 14:56:36 +000084}
85
borenet@google.com66bcbd12012-09-17 18:26:06 +000086static bool render_picture(const SkString& inputPath, const SkString& outputDir,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000087 sk_tools::PictureRenderer& renderer) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +000088 SkString inputFilename;
89 sk_tools::get_basename(&inputFilename, inputPath);
twiz@google.coma31b8bb2012-06-22 18:24:56 +000090
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +000091 SkFILEStream inputStream;
twiz@google.coma31b8bb2012-06-22 18:24:56 +000092 inputStream.setPath(inputPath.c_str());
93 if (!inputStream.isValid()) {
94 SkDebugf("Could not open file %s\n", inputPath.c_str());
borenet@google.com66bcbd12012-09-17 18:26:06 +000095 return false;
twiz@google.coma31b8bb2012-06-22 18:24:56 +000096 }
97
borenet@google.com66bcbd12012-09-17 18:26:06 +000098 bool success = false;
borenet@google.com2d2b9a02012-09-20 18:54:04 +000099 SkPicture picture(&inputStream, &success);
borenet@google.com66bcbd12012-09-17 18:26:06 +0000100 if (!success) {
101 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
102 return false;
103 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000104
borenet@google.com2d2b9a02012-09-20 18:54:04 +0000105 SkDebugf("drawing... [%i %i] %s\n", picture.width(), picture.height(),
borenet@google.com03fcee82012-09-10 18:18:38 +0000106 inputPath.c_str());
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000107
borenet@google.com2d2b9a02012-09-20 18:54:04 +0000108 renderer.init(&picture);
scroggo@google.comb4773b42012-10-01 20:06:09 +0000109 renderer.setup();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000110
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000111 SkString outputPath;
112 make_output_filepath(&outputPath, outputDir, inputFilename);
113
114 success = renderer.render(&outputPath);
115 if (!success) {
116 SkDebugf("Could not write to file %s\n", outputPath.c_str());
117 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000118
119 renderer.resetState();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000120
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000121 renderer.end();
borenet@google.com66bcbd12012-09-17 18:26:06 +0000122 return success;
junov@chromium.org777442d2012-06-12 14:56:36 +0000123}
124
borenet@google.com66bcbd12012-09-17 18:26:06 +0000125static int process_input(const SkString& input, const SkString& outputDir,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000126 sk_tools::PictureRenderer& renderer) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000127 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000128 SkString inputFilename;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000129 int failures = 0;
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000130 if (iter.next(&inputFilename)) {
131 do {
132 SkString inputPath;
133 sk_tools::make_filepath(&inputPath, input, inputFilename);
borenet@google.com57837bf2012-09-19 17:28:29 +0000134 if (!render_picture(inputPath, outputDir, renderer)) {
135 ++failures;
136 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000137 } while(iter.next(&inputFilename));
borenet@google.com57837bf2012-09-19 17:28:29 +0000138 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000139 SkString inputPath(input);
borenet@google.com57837bf2012-09-19 17:28:29 +0000140 if (!render_picture(inputPath, outputDir, renderer)) {
141 ++failures;
142 }
143 } else {
144 SkString warning;
145 warning.printf("Warning: skipping %s\n", input.c_str());
146 SkDebugf(warning.c_str());
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000147 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000148 return failures;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000149}
150
151static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000152 sk_tools::PictureRenderer*& renderer){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000153 const char* argv0 = argv[0];
154 char* const* stop = argv + argc;
155
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000156 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
157 sk_tools::PictureRenderer::kBitmap_DeviceType;
158
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000159 bool usePipe = false;
160 int numThreads = 1;
161 bool useTiles = false;
162 const char* widthString = NULL;
163 const char* heightString = NULL;
164 bool isPowerOf2Mode = false;
165 const char* mode = NULL;
166
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000167 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000168 if (0 == strcmp(*argv, "--mode")) {
169 SkDELETE(renderer);
170
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000171 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000172 if (argv >= stop) {
173 SkDebugf("Missing mode for --mode\n");
174 usage(argv0);
175 exit(-1);
176 }
177
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000178 if (0 == strcmp(*argv, "simple")) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000179 renderer = SkNEW(sk_tools::SimplePictureRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000180 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000181 useTiles = true;
182 mode = *argv;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000183
184 if (0 == strcmp(*argv, "pow2tile")) {
185 isPowerOf2Mode = true;
186 }
187
keyar@chromium.org795cd472012-08-02 18:57:53 +0000188 ++argv;
189 if (argv >= stop) {
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000190 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000191 usage(argv0);
192 exit(-1);
193 }
194
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000195 widthString = *argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000196 ++argv;
197 if (argv >= stop) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000198 SkDebugf("Missing height for --mode tile\n");
keyar@chromium.org795cd472012-08-02 18:57:53 +0000199 usage(argv0);
200 exit(-1);
201 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000202 heightString = *argv;
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000203 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000204 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000205 usage(argv0);
206 exit(-1);
207 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000208 } else if (0 == strcmp(*argv, "--pipe")) {
209 usePipe = true;
210 } else if (0 == strcmp(*argv, "--multi")) {
211 ++argv;
212 if (argv >= stop) {
213 SkDebugf("Missing arg for --multi\n");
214 usage(argv0);
215 exit(-1);
216 }
217 numThreads = atoi(*argv);
218 if (numThreads < 2) {
219 SkDebugf("Number of threads must be at least 2.\n");
220 usage(argv0);
221 exit(-1);
222 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000223 } else if (0 == strcmp(*argv, "--device")) {
224 ++argv;
225 if (argv >= stop) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000226 SkDebugf("Missing mode for --device\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000227 usage(argv0);
228 exit(-1);
229 }
230
231 if (0 == strcmp(*argv, "bitmap")) {
232 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
233 }
234#if SK_SUPPORT_GPU
235 else if (0 == strcmp(*argv, "gpu")) {
236 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
237 }
238#endif
239 else {
240 SkDebugf("%s is not a valid mode for --device\n", *argv);
241 usage(argv0);
242 exit(-1);
243 }
244
keyar@chromium.org472b3792012-07-20 22:34:27 +0000245 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000246 SkDELETE(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000247 usage(argv0);
248 exit(-1);
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000249 } else {
250 inputs->push_back(SkString(*argv));
251 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000252 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000253
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000254 if (numThreads > 1 && !useTiles) {
255 SkDebugf("Multithreaded drawing requires tiled rendering.\n");
256 usage(argv0);
257 exit(-1);
258 }
259
260 if (useTiles) {
261 SkASSERT(NULL == renderer);
262 sk_tools::TiledPictureRenderer* tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
263 if (isPowerOf2Mode) {
264 int minWidth = atoi(widthString);
265 if (!SkIsPow2(minWidth) || minWidth < 0) {
266 tiledRenderer->unref();
267 SkString err;
268 err.printf("-mode %s must be given a width"
269 " value that is a power of two\n", mode);
270 SkDebugf(err.c_str());
271 usage(argv0);
272 exit(-1);
273 }
274 tiledRenderer->setTileMinPowerOf2Width(minWidth);
275 } else if (sk_tools::is_percentage(widthString)) {
276 tiledRenderer->setTileWidthPercentage(atof(widthString));
277 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
278 tiledRenderer->unref();
279 SkDebugf("--mode tile must be given a width percentage > 0\n");
280 usage(argv0);
281 exit(-1);
282 }
283 } else {
284 tiledRenderer->setTileWidth(atoi(widthString));
285 if (!(tiledRenderer->getTileWidth() > 0)) {
286 tiledRenderer->unref();
287 SkDebugf("--mode tile must be given a width > 0\n");
288 usage(argv0);
289 exit(-1);
290 }
291 }
292
293 if (sk_tools::is_percentage(heightString)) {
294 tiledRenderer->setTileHeightPercentage(atof(heightString));
295 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
296 tiledRenderer->unref();
297 SkDebugf("--mode tile must be given a height percentage > 0\n");
298 usage(argv0);
299 exit(-1);
300 }
301 } else {
302 tiledRenderer->setTileHeight(atoi(heightString));
303 if (!(tiledRenderer->getTileHeight() > 0)) {
304 tiledRenderer->unref();
305 SkDebugf("--mode tile must be given a height > 0\n");
306 usage(argv0);
307 exit(-1);
308 }
309 }
310 if (numThreads > 1) {
311#if SK_SUPPORT_GPU
312 if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) {
313 tiledRenderer->unref();
314 SkDebugf("GPU not compatible with multithreaded tiling.\n");
315 usage(argv0);
316 exit(-1);
317 }
318#endif
319 tiledRenderer->setNumberOfThreads(numThreads);
320 }
321 tiledRenderer->setUsePipe(usePipe);
322 renderer = tiledRenderer;
323 } else if (usePipe) {
324 renderer = SkNEW(sk_tools::PipePictureRenderer);
325 }
326
keyar@chromium.org472b3792012-07-20 22:34:27 +0000327 if (inputs->count() < 2) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000328 SkDELETE(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000329 usage(argv0);
330 exit(-1);
331 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000332
333 if (NULL == renderer) {
334 renderer = SkNEW(sk_tools::SimplePictureRenderer);
335 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000336
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000337 renderer->setDeviceType(deviceType);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000338}
339
caryclark@google.com5987f582012-10-02 18:33:14 +0000340int tool_main(int argc, char** argv);
341int tool_main(int argc, char** argv) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000342 SkAutoGraphics ag;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000343 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000344 sk_tools::PictureRenderer* renderer = NULL;
keyar@chromium.org472b3792012-07-20 22:34:27 +0000345
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000346 parse_commandline(argc, argv, &inputs, renderer);
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000347 SkString outputDir = inputs[inputs.count() - 1];
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000348 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000349
borenet@google.com66bcbd12012-09-17 18:26:06 +0000350 int failures = 0;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000351 for (int i = 0; i < inputs.count() - 1; i ++) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000352 failures += process_input(inputs[i], outputDir, *renderer);
junov@chromium.org777442d2012-06-12 14:56:36 +0000353 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000354 if (failures != 0) {
355 SkDebugf("Failed to render %i pictures.\n", failures);
356 return 1;
357 }
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000358#if SK_SUPPORT_GPU
359#if GR_CACHE_STATS
360 if (renderer->isUsingGpuDevice()) {
361 GrContext* ctx = renderer->getGrContext();
362
363 ctx->printCacheStats();
364 }
365#endif
366#endif
367
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000368 SkDELETE(renderer);
caryclark@google.com868e1f62012-10-02 20:00:03 +0000369 return 0;
junov@chromium.org777442d2012-06-12 14:56:36 +0000370}
caryclark@google.com5987f582012-10-02 18:33:14 +0000371
372#if !defined SK_BUILD_FOR_IOS
373int main(int argc, char * const argv[]) {
374 return tool_main(argc, (char**) argv);
375}
376#endif