render_pictures_main.cpp revision 5a7c6be72b940dde8ff6ad2485a09aecd56a2660
1/* 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 8#include "SkBitmap.h" 9#include "SkCanvas.h" 10#include "SkDevice.h" 11#include "SkGraphics.h" 12#include "SkImageDecoder.h" 13#include "SkMath.h" 14#include "SkOSFile.h" 15#include "SkPicture.h" 16#include "SkStream.h" 17#include "SkString.h" 18#include "SkTArray.h" 19#include "PictureRenderer.h" 20#include "picture_utils.h" 21 22static void usage(const char* argv0) { 23 SkDebugf("SkPicture rendering tool\n"); 24 SkDebugf("\n" 25"Usage: \n" 26" %s <input>... <outputDir> \n" 27" [--mode pow2tile minWidth height[%] | simple\n" 28" | tile width[%] height[%]]\n" 29" [--pipe]\n" 30" [--multi count]\n" 31" [--device bitmap" 32#if SK_SUPPORT_GPU 33" | gpu" 34#endif 35"]" 36, argv0); 37 SkDebugf("\n\n"); 38 SkDebugf( 39" input: A list of directories and files to use as input. Files are\n" 40" expected to have the .skp extension.\n\n"); 41 SkDebugf( 42" outputDir: directory to write the rendered images.\n\n"); 43 SkDebugf( 44" --mode pow2tile minWidth height[%] | simple\n" 45" | tile width[%] height[%]: Run in the corresponding mode.\n" 46" Default is simple.\n"); 47 SkDebugf( 48" 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( 57" 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"); 61 SkDebugf("\n"); 62 SkDebugf( 63" --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( 67" --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"); 74#if SK_SUPPORT_GPU 75 SkDebugf( 76" gpu, Render to the GPU.\n"); 77#endif 78} 79 80static void make_output_filepath(SkString* path, const SkString& dir, 81 const SkString& name) { 82 sk_tools::make_filepath(path, dir, name); 83 // Remove ".skp" 84 path->remove(path->size() - 4, 4); 85} 86 87static bool render_picture(const SkString& inputPath, const SkString& outputDir, 88 sk_tools::PictureRenderer& renderer) { 89 SkString inputFilename; 90 sk_tools::get_basename(&inputFilename, inputPath); 91 92 SkFILEStream inputStream; 93 inputStream.setPath(inputPath.c_str()); 94 if (!inputStream.isValid()) { 95 SkDebugf("Could not open file %s\n", inputPath.c_str()); 96 return false; 97 } 98 99 bool success = false; 100 SkPicture picture(&inputStream, &success, &SkImageDecoder::DecodeStream); 101 if (!success) { 102 SkDebugf("Could not read an SkPicture from %s\n", inputPath.c_str()); 103 return false; 104 } 105 106 SkDebugf("drawing... [%i %i] %s\n", picture.width(), picture.height(), 107 inputPath.c_str()); 108 109 renderer.init(&picture); 110 renderer.setup(); 111 112 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 } 119 120 renderer.resetState(); 121 122 renderer.end(); 123 return success; 124} 125 126static int process_input(const SkString& input, const SkString& outputDir, 127 sk_tools::PictureRenderer& renderer) { 128 SkOSFile::Iter iter(input.c_str(), "skp"); 129 SkString inputFilename; 130 int failures = 0; 131 if (iter.next(&inputFilename)) { 132 do { 133 SkString inputPath; 134 sk_tools::make_filepath(&inputPath, input, inputFilename); 135 if (!render_picture(inputPath, outputDir, renderer)) { 136 ++failures; 137 } 138 } while(iter.next(&inputFilename)); 139 } else if (SkStrEndsWith(input.c_str(), ".skp")) { 140 SkString inputPath(input); 141 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()); 148 } 149 return failures; 150} 151 152static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>* inputs, 153 sk_tools::PictureRenderer*& renderer){ 154 const char* argv0 = argv[0]; 155 char* const* stop = argv + argc; 156 157 sk_tools::PictureRenderer::SkDeviceTypes deviceType = 158 sk_tools::PictureRenderer::kBitmap_DeviceType; 159 160 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 168 for (++argv; argv < stop; ++argv) { 169 if (0 == strcmp(*argv, "--mode")) { 170 SkDELETE(renderer); 171 172 ++argv; 173 if (argv >= stop) { 174 SkDebugf("Missing mode for --mode\n"); 175 usage(argv0); 176 exit(-1); 177 } 178 179 if (0 == strcmp(*argv, "simple")) { 180 renderer = SkNEW(sk_tools::SimplePictureRenderer); 181 } else if ((0 == strcmp(*argv, "tile")) || (0 == strcmp(*argv, "pow2tile"))) { 182 useTiles = true; 183 mode = *argv; 184 185 if (0 == strcmp(*argv, "pow2tile")) { 186 isPowerOf2Mode = true; 187 } 188 189 ++argv; 190 if (argv >= stop) { 191 SkDebugf("Missing width for --mode %s\n", mode); 192 usage(argv0); 193 exit(-1); 194 } 195 196 widthString = *argv; 197 ++argv; 198 if (argv >= stop) { 199 SkDebugf("Missing height for --mode tile\n"); 200 usage(argv0); 201 exit(-1); 202 } 203 heightString = *argv; 204 } else { 205 SkDebugf("%s is not a valid mode for --mode\n", *argv); 206 usage(argv0); 207 exit(-1); 208 } 209 } 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 } 224 } else if (0 == strcmp(*argv, "--device")) { 225 ++argv; 226 if (argv >= stop) { 227 SkDebugf("Missing mode for --device\n"); 228 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 246 } else if ((0 == strcmp(*argv, "-h")) || (0 == strcmp(*argv, "--help"))) { 247 SkDELETE(renderer); 248 usage(argv0); 249 exit(-1); 250 } else { 251 inputs->push_back(SkString(*argv)); 252 } 253 } 254 255 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 328 if (inputs->count() < 2) { 329 SkDELETE(renderer); 330 usage(argv0); 331 exit(-1); 332 } 333 334 if (NULL == renderer) { 335 renderer = SkNEW(sk_tools::SimplePictureRenderer); 336 } 337 338 renderer->setDeviceType(deviceType); 339} 340 341int tool_main(int argc, char** argv); 342int tool_main(int argc, char** argv) { 343 SkAutoGraphics ag; 344 SkTArray<SkString> inputs; 345 sk_tools::PictureRenderer* renderer = NULL; 346 347 parse_commandline(argc, argv, &inputs, renderer); 348 SkString outputDir = inputs[inputs.count() - 1]; 349 SkASSERT(renderer); 350 351 int failures = 0; 352 for (int i = 0; i < inputs.count() - 1; i ++) { 353 failures += process_input(inputs[i], outputDir, *renderer); 354 } 355 if (failures != 0) { 356 SkDebugf("Failed to render %i pictures.\n", failures); 357 return 1; 358 } 359#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 369 SkDELETE(renderer); 370 return 0; 371} 372 373#if !defined SK_BUILD_FOR_IOS 374int main(int argc, char * const argv[]) { 375 return tool_main(argc, (char**) argv); 376} 377#endif 378