blob: 6d6e8db19a68d27a96036f450189d1f70157565c [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"
keyar@chromium.org472b3792012-07-20 22:34:27 +000026" %s <input>... <outputDir> \n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000027" [--mode pow2tile minWidth height[%] | simple\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000028" | tile width[%] height[%]]\n"
scroggo@google.comb6e806b2012-10-03 17:32:33 +000029" [--pipe]\n"
30" [--multi count]\n"
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000031" [--device bitmap"
32#if SK_SUPPORT_GPU
33" | gpu"
34#endif
35"]"
junov@chromium.org777442d2012-06-12 14:56:36 +000036, argv0);
keyar@chromium.org472b3792012-07-20 22:34:27 +000037 SkDebugf("\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000038 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000039" input: A list of directories and files to use as input. Files are\n"
40" expected to have the .skp extension.\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000041 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000042" outputDir: directory to write the rendered images.\n\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000043 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000044" --mode pow2tile minWidth height[%] | simple\n"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000045" | tile width[%] height[%]: Run in the corresponding mode.\n"
46" Default is simple.\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000047 SkDebugf(
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000048" pow2tile minWidth height[%], Creates tiles with widths\n"
49" that are all a power of two\n"
50" such that they minimize the\n"
51" amount of wasted tile space.\n"
52" minWidth is the minimum width\n"
53" of these tiles and must be a\n"
54" power of two. A simple render\n"
55" is done with these tiles.\n");
56 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000057" simple, Render using the default rendering method.\n");
58 SkDebugf(
59" tile width[%] height[%], Do a simple render using tiles\n"
60" with the given dimensions.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000061 SkDebugf("\n");
62 SkDebugf(
scroggo@google.comb6e806b2012-10-03 17:32:33 +000063" --multi count : Set the number of threads for multi threaded drawing. Must be greater\n"
64" than 1. Only works with tiled rendering.\n"
65" --pipe: Benchmark SkGPipe rendering. Compatible with tiled, multithreaded rendering.\n");
66 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000067" --device bitmap"
68#if SK_SUPPORT_GPU
69" | gpu"
70#endif
71": Use the corresponding device. Default is bitmap.\n");
72 SkDebugf(
73" bitmap, Render to a bitmap.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000074#if SK_SUPPORT_GPU
keyar@chromium.orga40c20d2012-08-20 15:04:12 +000075 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000076" gpu, Render to the GPU.\n");
77#endif
junov@chromium.org777442d2012-06-12 14:56:36 +000078}
79
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +000080static void make_output_filepath(SkString* path, const SkString& dir,
junov@chromium.org777442d2012-06-12 14:56:36 +000081 const SkString& name) {
twiz@google.coma31b8bb2012-06-22 18:24:56 +000082 sk_tools::make_filepath(path, dir, name);
scroggo@google.com81f9d2e2012-09-20 14:54:21 +000083 // Remove ".skp"
84 path->remove(path->size() - 4, 4);
junov@chromium.org777442d2012-06-12 14:56:36 +000085}
86
borenet@google.com66bcbd12012-09-17 18:26:06 +000087static bool render_picture(const SkString& inputPath, const SkString& outputDir,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +000088 sk_tools::PictureRenderer& renderer) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +000089 SkString inputFilename;
90 sk_tools::get_basename(&inputFilename, inputPath);
twiz@google.coma31b8bb2012-06-22 18:24:56 +000091
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +000092 SkFILEStream inputStream;
twiz@google.coma31b8bb2012-06-22 18:24:56 +000093 inputStream.setPath(inputPath.c_str());
94 if (!inputStream.isValid()) {
95 SkDebugf("Could not open file %s\n", inputPath.c_str());
borenet@google.com66bcbd12012-09-17 18:26:06 +000096 return false;
twiz@google.coma31b8bb2012-06-22 18:24:56 +000097 }
98
borenet@google.com66bcbd12012-09-17 18:26:06 +000099 bool success = false;
scroggo@google.com5a7c6be2012-10-04 21:46:08 +0000100 SkPicture picture(&inputStream, &success, &SkImageDecoder::DecodeStream);
borenet@google.com66bcbd12012-09-17 18:26:06 +0000101 if (!success) {
102 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str());
103 return false;
104 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000105
borenet@google.com2d2b9a02012-09-20 18:54:04 +0000106 SkDebugf("drawing... [%i %i] %s\n", picture.width(), picture.height(),
borenet@google.com03fcee82012-09-10 18:18:38 +0000107 inputPath.c_str());
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000108
borenet@google.com2d2b9a02012-09-20 18:54:04 +0000109 renderer.init(&picture);
scroggo@google.comb4773b42012-10-01 20:06:09 +0000110 renderer.setup();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000111
scroggo@google.com81f9d2e2012-09-20 14:54:21 +0000112 SkString outputPath;
113 make_output_filepath(&outputPath, outputDir, inputFilename);
114
115 success = renderer.render(&outputPath);
116 if (!success) {
117 SkDebugf("Could not write to file %s\n", outputPath.c_str());
118 }
scroggo@google.com9a412522012-09-07 15:21:18 +0000119
120 renderer.resetState();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000121
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000122 renderer.end();
borenet@google.com66bcbd12012-09-17 18:26:06 +0000123 return success;
junov@chromium.org777442d2012-06-12 14:56:36 +0000124}
125
borenet@google.com66bcbd12012-09-17 18:26:06 +0000126static int process_input(const SkString& input, const SkString& outputDir,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000127 sk_tools::PictureRenderer& renderer) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000128 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000129 SkString inputFilename;
borenet@google.com66bcbd12012-09-17 18:26:06 +0000130 int failures = 0;
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000131 if (iter.next(&inputFilename)) {
132 do {
133 SkString inputPath;
134 sk_tools::make_filepath(&inputPath, input, inputFilename);
borenet@google.com57837bf2012-09-19 17:28:29 +0000135 if (!render_picture(inputPath, outputDir, renderer)) {
136 ++failures;
137 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000138 } while(iter.next(&inputFilename));
borenet@google.com57837bf2012-09-19 17:28:29 +0000139 } else if (SkStrEndsWith(input.c_str(), ".skp")) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000140 SkString inputPath(input);
borenet@google.com57837bf2012-09-19 17:28:29 +0000141 if (!render_picture(inputPath, outputDir, renderer)) {
142 ++failures;
143 }
144 } else {
145 SkString warning;
146 warning.printf("Warning: skipping %s\n", input.c_str());
147 SkDebugf(warning.c_str());
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000148 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000149 return failures;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000150}
151
152static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000153 sk_tools::PictureRenderer*& renderer){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000154 const char* argv0 = argv[0];
155 char* const* stop = argv + argc;
156
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000157 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
158 sk_tools::PictureRenderer::kBitmap_DeviceType;
159
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000160 bool usePipe = false;
161 int numThreads = 1;
162 bool useTiles = false;
163 const char* widthString = NULL;
164 const char* heightString = NULL;
165 bool isPowerOf2Mode = false;
166 const char* mode = NULL;
167
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000168 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000169 if (0 == strcmp(*argv, "--mode")) {
170 SkDELETE(renderer);
171
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000172 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000173 if (argv >= stop) {
174 SkDebugf("Missing mode for --mode\n");
175 usage(argv0);
176 exit(-1);
177 }
178
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000179 if (0 == strcmp(*argv, "simple")) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000180 renderer = SkNEW(sk_tools::SimplePictureRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000181 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000182 useTiles = true;
183 mode = *argv;
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000184
185 if (0 == strcmp(*argv, "pow2tile")) {
186 isPowerOf2Mode = true;
187 }
188
keyar@chromium.org795cd472012-08-02 18:57:53 +0000189 ++argv;
190 if (argv >= stop) {
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000191 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000192 usage(argv0);
193 exit(-1);
194 }
195
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000196 widthString = *argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000197 ++argv;
198 if (argv >= stop) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000199 SkDebugf("Missing height for --mode tile\n");
keyar@chromium.org795cd472012-08-02 18:57:53 +0000200 usage(argv0);
201 exit(-1);
202 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000203 heightString = *argv;
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000204 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000205 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000206 usage(argv0);
207 exit(-1);
208 }
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000209 } else if (0 == strcmp(*argv, "--pipe")) {
210 usePipe = true;
211 } else if (0 == strcmp(*argv, "--multi")) {
212 ++argv;
213 if (argv >= stop) {
214 SkDebugf("Missing arg for --multi\n");
215 usage(argv0);
216 exit(-1);
217 }
218 numThreads = atoi(*argv);
219 if (numThreads < 2) {
220 SkDebugf("Number of threads must be at least 2.\n");
221 usage(argv0);
222 exit(-1);
223 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000224 } else if (0 == strcmp(*argv, "--device")) {
225 ++argv;
226 if (argv >= stop) {
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000227 SkDebugf("Missing mode for --device\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000228 usage(argv0);
229 exit(-1);
230 }
231
232 if (0 == strcmp(*argv, "bitmap")) {
233 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
234 }
235#if SK_SUPPORT_GPU
236 else if (0 == strcmp(*argv, "gpu")) {
237 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
238 }
239#endif
240 else {
241 SkDebugf("%s is not a valid mode for --device\n", *argv);
242 usage(argv0);
243 exit(-1);
244 }
245
keyar@chromium.org472b3792012-07-20 22:34:27 +0000246 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000247 SkDELETE(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000248 usage(argv0);
249 exit(-1);
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000250 } else {
251 inputs->push_back(SkString(*argv));
252 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000253 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000254
scroggo@google.comb6e806b2012-10-03 17:32:33 +0000255 if (numThreads > 1 && !useTiles) {
256 SkDebugf("Multithreaded drawing requires tiled rendering.\n");
257 usage(argv0);
258 exit(-1);
259 }
260
261 if (useTiles) {
262 SkASSERT(NULL == renderer);
263 sk_tools::TiledPictureRenderer* tiledRenderer = SkNEW(sk_tools::TiledPictureRenderer);
264 if (isPowerOf2Mode) {
265 int minWidth = atoi(widthString);
266 if (!SkIsPow2(minWidth) || minWidth < 0) {
267 tiledRenderer->unref();
268 SkString err;
269 err.printf("-mode %s must be given a width"
270 " value that is a power of two\n", mode);
271 SkDebugf(err.c_str());
272 usage(argv0);
273 exit(-1);
274 }
275 tiledRenderer->setTileMinPowerOf2Width(minWidth);
276 } else if (sk_tools::is_percentage(widthString)) {
277 tiledRenderer->setTileWidthPercentage(atof(widthString));
278 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
279 tiledRenderer->unref();
280 SkDebugf("--mode tile must be given a width percentage > 0\n");
281 usage(argv0);
282 exit(-1);
283 }
284 } else {
285 tiledRenderer->setTileWidth(atoi(widthString));
286 if (!(tiledRenderer->getTileWidth() > 0)) {
287 tiledRenderer->unref();
288 SkDebugf("--mode tile must be given a width > 0\n");
289 usage(argv0);
290 exit(-1);
291 }
292 }
293
294 if (sk_tools::is_percentage(heightString)) {
295 tiledRenderer->setTileHeightPercentage(atof(heightString));
296 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
297 tiledRenderer->unref();
298 SkDebugf("--mode tile must be given a height percentage > 0\n");
299 usage(argv0);
300 exit(-1);
301 }
302 } else {
303 tiledRenderer->setTileHeight(atoi(heightString));
304 if (!(tiledRenderer->getTileHeight() > 0)) {
305 tiledRenderer->unref();
306 SkDebugf("--mode tile must be given a height > 0\n");
307 usage(argv0);
308 exit(-1);
309 }
310 }
311 if (numThreads > 1) {
312#if SK_SUPPORT_GPU
313 if (sk_tools::PictureRenderer::kGPU_DeviceType == deviceType) {
314 tiledRenderer->unref();
315 SkDebugf("GPU not compatible with multithreaded tiling.\n");
316 usage(argv0);
317 exit(-1);
318 }
319#endif
320 tiledRenderer->setNumberOfThreads(numThreads);
321 }
322 tiledRenderer->setUsePipe(usePipe);
323 renderer = tiledRenderer;
324 } else if (usePipe) {
325 renderer = SkNEW(sk_tools::PipePictureRenderer);
326 }
327
keyar@chromium.org472b3792012-07-20 22:34:27 +0000328 if (inputs->count() < 2) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000329 SkDELETE(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000330 usage(argv0);
331 exit(-1);
332 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000333
334 if (NULL == renderer) {
335 renderer = SkNEW(sk_tools::SimplePictureRenderer);
336 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000337
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000338 renderer->setDeviceType(deviceType);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000339}
340
caryclark@google.com5987f582012-10-02 18:33:14 +0000341int tool_main(int argc, char** argv);
342int tool_main(int argc, char** argv) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000343 SkAutoGraphics ag;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000344 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000345 sk_tools::PictureRenderer* renderer = NULL;
keyar@chromium.org472b3792012-07-20 22:34:27 +0000346
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000347 parse_commandline(argc, argv, &inputs, renderer);
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000348 SkString outputDir = inputs[inputs.count() - 1];
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000349 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000350
borenet@google.com66bcbd12012-09-17 18:26:06 +0000351 int failures = 0;
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000352 for (int i = 0; i < inputs.count() - 1; i ++) {
borenet@google.com66bcbd12012-09-17 18:26:06 +0000353 failures += process_input(inputs[i], outputDir, *renderer);
junov@chromium.org777442d2012-06-12 14:56:36 +0000354 }
borenet@google.com66bcbd12012-09-17 18:26:06 +0000355 if (failures != 0) {
356 SkDebugf("Failed to render %i pictures.\n", failures);
357 return 1;
358 }
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000359#if SK_SUPPORT_GPU
360#if GR_CACHE_STATS
361 if (renderer->isUsingGpuDevice()) {
362 GrContext* ctx = renderer->getGrContext();
363
364 ctx->printCacheStats();
365 }
366#endif
367#endif
368
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000369 SkDELETE(renderer);
caryclark@google.com868e1f62012-10-02 20:00:03 +0000370 return 0;
junov@chromium.org777442d2012-06-12 14:56:36 +0000371}
caryclark@google.com5987f582012-10-02 18:33:14 +0000372
373#if !defined SK_BUILD_FOR_IOS
374int main(int argc, char * const argv[]) {
375 return tool_main(argc, (char**) argv);
376}
377#endif