blob: 87d5d4b79e4cfe88d7650974a63a2bcaf20e2133 [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"
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000026" [--mode pipe | pow2tile minWidth height[%] | simple\n"
27" | tile width[%] height[%]]\n"
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000028" [--device bitmap"
29#if SK_SUPPORT_GPU
30" | gpu"
31#endif
32"]"
junov@chromium.org777442d2012-06-12 14:56:36 +000033, argv0);
keyar@chromium.org472b3792012-07-20 22:34:27 +000034 SkDebugf("\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000035 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000036" input: A list of directories and files to use as input. Files are\n"
37" expected to have the .skp extension.\n\n");
junov@chromium.org777442d2012-06-12 14:56:36 +000038 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000039" outputDir: directory to write the rendered images.\n\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000040 SkDebugf(
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +000041" --mode pipe | pow2tile minWidth height[%] | simple\n"
42" | tile width[%] height[%]: Run in the corresponding mode.\n"
43" Default is simple.\n");
keyar@chromium.org472b3792012-07-20 22:34:27 +000044 SkDebugf(
keyar@chromium.org795cd472012-08-02 18:57:53 +000045" pipe, Render using a SkGPipe.\n");
46 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(
62" --device bitmap"
63#if SK_SUPPORT_GPU
64" | gpu"
65#endif
66": Use the corresponding device. Default is bitmap.\n");
67 SkDebugf(
68" bitmap, Render to a bitmap.\n");
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000069#if SK_SUPPORT_GPU
keyar@chromium.orga40c20d2012-08-20 15:04:12 +000070 SkDebugf(
keyar@chromium.orgc81686c2012-08-20 15:04:04 +000071" gpu, Render to the GPU.\n");
72#endif
junov@chromium.org777442d2012-06-12 14:56:36 +000073}
74
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +000075static void make_output_filepath(SkString* path, const SkString& dir,
junov@chromium.org777442d2012-06-12 14:56:36 +000076 const SkString& name) {
twiz@google.coma31b8bb2012-06-22 18:24:56 +000077 sk_tools::make_filepath(path, dir, name);
junov@chromium.org777442d2012-06-12 14:56:36 +000078 path->remove(path->size() - 3, 3);
79 path->append("png");
80}
81
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +000082static void write_output(const SkString& outputDir, const SkString& inputFilename,
keyar@chromium.org9299ede2012-08-21 19:05:08 +000083 const sk_tools::PictureRenderer& renderer) {
junov@chromium.org777442d2012-06-12 14:56:36 +000084 SkString outputPath;
85 make_output_filepath(&outputPath, outputDir, inputFilename);
keyar@chromium.org9299ede2012-08-21 19:05:08 +000086 bool isWritten = renderer.write(outputPath);
junov@chromium.org777442d2012-06-12 14:56:36 +000087 if (!isWritten) {
88 SkDebugf("Could not write to file %s\n", outputPath.c_str());
89 }
90}
91
reed@google.come04e92b2012-09-13 17:44:32 +000092static bool area_too_big(int w, int h, SkISize* newSize) {
93 // just a guess, based on what seems to fail on smaller android devices
94 static const int64_t kMaxAreaForMemory = 16 * 1024 * 1024;
95
96 if ((int64_t)w * h > kMaxAreaForMemory) {
97 do {
98 w >>= 1;
99 h >>= 1;
100 } while ((int64_t)w * h > kMaxAreaForMemory);
101 if (0 == w) {
102 w = 1;
103 }
104 if (0 == h) {
105 h = 1;
106 }
107 newSize->set(w, h);
108 return true;
109 }
110 return false;
111}
112
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000113static void render_picture(const SkString& inputPath, const SkString& outputDir,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000114 sk_tools::PictureRenderer& renderer) {
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000115 SkString inputFilename;
116 sk_tools::get_basename(&inputFilename, inputPath);
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000117
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000118 SkFILEStream inputStream;
twiz@google.coma31b8bb2012-06-22 18:24:56 +0000119 inputStream.setPath(inputPath.c_str());
120 if (!inputStream.isValid()) {
121 SkDebugf("Could not open file %s\n", inputPath.c_str());
122 return;
123 }
124
junov@chromium.org777442d2012-06-12 14:56:36 +0000125 SkPicture picture(&inputStream);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000126
borenet@google.com03fcee82012-09-10 18:18:38 +0000127 SkDebugf("drawing... [%i %i] %s\n", picture.width(), picture.height(),
128 inputPath.c_str());
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000129
reed@google.come04e92b2012-09-13 17:44:32 +0000130
131 // rescale to avoid memory issues allcoating a very large offscreen
132 SkPicture* pic = &picture;
133 SkISize newSize;
134 SkAutoUnref aur(NULL);
135
136 if (area_too_big(picture.width(), picture.height(), &newSize)) {
137 pic = new SkPicture;
138 aur.reset(pic);
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000139
reed@google.come04e92b2012-09-13 17:44:32 +0000140 SkCanvas* canvas = pic->beginRecording(newSize.width(), newSize.height());
141 SkScalar scale = SkIntToScalar(newSize.width()) / picture.width();
142 canvas->scale(scale, scale);
143 canvas->drawPicture(picture);
144 pic->endRecording();
skia.committer@gmail.com1d225f22012-09-14 02:01:10 +0000145
reed@google.come04e92b2012-09-13 17:44:32 +0000146 SkDebugf("... rescaling to [%d %d] to avoid overly large allocations\n",
147 newSize.width(), newSize.height());
148 }
149
150 renderer.init(pic);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000151
scroggo@google.com9a412522012-09-07 15:21:18 +0000152 renderer.render(true);
153
154 renderer.resetState();
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000155
keyar@chromium.org9299ede2012-08-21 19:05:08 +0000156 write_output(outputDir, inputFilename, renderer);
keyar@chromium.org9d696c02012-08-07 17:11:33 +0000157
158 renderer.end();
junov@chromium.org777442d2012-06-12 14:56:36 +0000159}
160
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000161static void process_input(const SkString& input, const SkString& outputDir,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000162 sk_tools::PictureRenderer& renderer) {
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000163 SkOSFile::Iter iter(input.c_str(), "skp");
junov@chromium.org777442d2012-06-12 14:56:36 +0000164 SkString inputFilename;
165
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000166 if (iter.next(&inputFilename)) {
167 do {
168 SkString inputPath;
169 sk_tools::make_filepath(&inputPath, input, inputFilename);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000170 render_picture(inputPath, outputDir, renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000171 } while(iter.next(&inputFilename));
172 } else {
173 SkString inputPath(input);
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000174 render_picture(inputPath, outputDir, renderer);
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000175 }
176}
177
178static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs,
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000179 sk_tools::PictureRenderer*& renderer){
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000180 const char* argv0 = argv[0];
181 char* const* stop = argv + argc;
182
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000183 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
184 sk_tools::PictureRenderer::kBitmap_DeviceType;
185
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000186 for (++argv; argv < stop; ++argv) {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000187 if (0 == strcmp(*argv, "--mode")) {
188 SkDELETE(renderer);
189
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000190 ++argv;
keyar@chromium.org795cd472012-08-02 18:57:53 +0000191 if (argv >= stop) {
192 SkDebugf("Missing mode for --mode\n");
193 usage(argv0);
194 exit(-1);
195 }
196
197 if (0 == strcmp(*argv, "pipe")) {
198 renderer = SkNEW(sk_tools::PipePictureRenderer);
199 } else if (0 == strcmp(*argv, "simple")) {
200 renderer = SkNEW(sk_tools::SimplePictureRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000201 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) {
202 char* mode = *argv;
203 bool isPowerOf2Mode = false;
204
205 if (0 == strcmp(*argv, "pow2tile")) {
206 isPowerOf2Mode = true;
207 }
208
keyar@chromium.org795cd472012-08-02 18:57:53 +0000209 sk_tools::TiledPictureRenderer* tileRenderer =
210 SkNEW(sk_tools::TiledPictureRenderer);
211 ++argv;
212 if (argv >= stop) {
213 SkDELETE(tileRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000214 SkDebugf("Missing width for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000215 usage(argv0);
216 exit(-1);
217 }
218
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000219 if (isPowerOf2Mode) {
220 int minWidth = atoi(*argv);
221
222 if (!SkIsPow2(minWidth) || minWidth <= 0) {
223 SkDELETE(tileRenderer);
224 SkDebugf("--mode %s must be given a width"
225 " value that is a power of two\n", mode);
226 exit(-1);
227 }
228
229 tileRenderer->setTileMinPowerOf2Width(minWidth);
230 } else if (sk_tools::is_percentage(*argv)) {
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000231 tileRenderer->setTileWidthPercentage(atof(*argv));
232 if (!(tileRenderer->getTileWidthPercentage() > 0)) {
233 SkDELETE(tileRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000234 SkDebugf("--mode %s must be given a width percentage > 0\n", mode);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000235 exit(-1);
236 }
237 } else {
238 tileRenderer->setTileWidth(atoi(*argv));
239 if (!(tileRenderer->getTileWidth() > 0)) {
240 SkDELETE(tileRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000241 SkDebugf("--mode %s must be given a width > 0\n", mode);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000242 exit(-1);
243 }
244 }
keyar@chromium.org795cd472012-08-02 18:57:53 +0000245
246 ++argv;
247 if (argv >= stop) {
248 SkDELETE(tileRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000249 SkDebugf("Missing height for --mode %s\n", mode);
keyar@chromium.org795cd472012-08-02 18:57:53 +0000250 usage(argv0);
251 exit(-1);
252 }
253
keyar@chromium.org163b5672012-08-01 17:53:29 +0000254 if (sk_tools::is_percentage(*argv)) {
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000255 tileRenderer->setTileHeightPercentage(atof(*argv));
256 if (!(tileRenderer->getTileHeightPercentage() > 0)) {
257 SkDELETE(tileRenderer);
258 SkDebugf(
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000259 "--mode %s must be given a height percentage > 0\n", mode);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000260 exit(-1);
261 }
262 } else {
263 tileRenderer->setTileHeight(atoi(*argv));
264 if (!(tileRenderer->getTileHeight() > 0)) {
265 SkDELETE(tileRenderer);
keyar@chromium.orgf4959ab2012-08-23 20:53:25 +0000266 SkDebugf("--mode %s must be given a height > 0\n", mode);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000267 exit(-1);
268 }
269 }
keyar@chromium.org795cd472012-08-02 18:57:53 +0000270
271 renderer = tileRenderer;
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000272 } else {
keyar@chromium.org795cd472012-08-02 18:57:53 +0000273 SkDebugf("%s is not a valid mode for --mode\n", *argv);
keyar@chromium.orgcc6e5ef2012-07-27 20:09:26 +0000274 usage(argv0);
275 exit(-1);
276 }
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000277 } else if (0 == strcmp(*argv, "--device")) {
278 ++argv;
279 if (argv >= stop) {
280 SkDebugf("Missing mode for --deivce\n");
281 usage(argv0);
282 exit(-1);
283 }
284
285 if (0 == strcmp(*argv, "bitmap")) {
286 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
287 }
288#if SK_SUPPORT_GPU
289 else if (0 == strcmp(*argv, "gpu")) {
290 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
291 }
292#endif
293 else {
294 SkDebugf("%s is not a valid mode for --device\n", *argv);
295 usage(argv0);
296 exit(-1);
297 }
298
keyar@chromium.org472b3792012-07-20 22:34:27 +0000299 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000300 SkDELETE(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000301 usage(argv0);
302 exit(-1);
keyar@chromium.orga2333d92012-07-16 17:29:16 +0000303 } else {
304 inputs->push_back(SkString(*argv));
305 }
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000306 }
keyar@chromium.org472b3792012-07-20 22:34:27 +0000307
308 if (inputs->count() < 2) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000309 SkDELETE(renderer);
keyar@chromium.org472b3792012-07-20 22:34:27 +0000310 usage(argv0);
311 exit(-1);
312 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000313
314 if (NULL == renderer) {
315 renderer = SkNEW(sk_tools::SimplePictureRenderer);
316 }
keyar@chromium.org4ea96c52012-08-20 15:03:29 +0000317
keyar@chromium.orgc81686c2012-08-20 15:04:04 +0000318 renderer->setDeviceType(deviceType);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000319}
320
321int main(int argc, char* const argv[]) {
borenet@google.com10ef79e2012-09-10 17:19:06 +0000322 SkGraphics::Init();
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000323 SkTArray<SkString> inputs;
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000324 sk_tools::PictureRenderer* renderer = NULL;
keyar@chromium.org472b3792012-07-20 22:34:27 +0000325
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000326 parse_commandline(argc, argv, &inputs, renderer);
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000327 SkString outputDir = inputs[inputs.count() - 1];
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000328 SkASSERT(renderer);
keyar@chromium.orgd1dc9202012-07-09 18:32:08 +0000329
keyar@chromium.org1cbd47c2012-07-13 18:22:59 +0000330 for (int i = 0; i < inputs.count() - 1; i ++) {
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000331 process_input(inputs[i], outputDir, *renderer);
junov@chromium.org777442d2012-06-12 14:56:36 +0000332 }
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000333
robertphillips@google.com163c84b2012-09-13 15:40:37 +0000334#if SK_SUPPORT_GPU
335#if GR_CACHE_STATS
336 if (renderer->isUsingGpuDevice()) {
337 GrContext* ctx = renderer->getGrContext();
338
339 ctx->printCacheStats();
340 }
341#endif
342#endif
343
keyar@chromium.org451bb9f2012-07-26 17:27:57 +0000344 SkDELETE(renderer);
borenet@google.com10ef79e2012-09-10 17:19:06 +0000345 SkGraphics::Term();
junov@chromium.org777442d2012-06-12 14:56:36 +0000346}