PictureRenderingFlags.cpp revision 58190644c30e1c4aa8e527f3503c58f841e0fcf3
1/* 2 * Copyright 2013 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 "PictureRenderingFlags.h" 9 10#include "CopyTilesRenderer.h" 11#include "PictureRenderer.h" 12#include "picture_utils.h" 13#include "SkBitmapFactory.h" 14#include "SkCommandLineFlags.h" 15#include "SkData.h" 16#include "SkImage.h" 17#include "SkImageDecoder.h" 18#include "SkString.h" 19 20// Alphabetized list of flags used by this file or bench_ and render_pictures. 21DEFINE_string(bbh, "none", "bbhType [width height]: Set the bounding box hierarchy type to " 22 "be used. Accepted values are: none, rtree, grid. " 23 "Not compatible with --pipe. With value " 24 "'grid', width and height must be specified. 'grid' can " 25 "only be used with modes tile, record, and " 26 "playbackCreation."); 27// Although this config does not support all the same options as gm, the names should be kept 28// consistent. 29#if SK_ANGLE 30// ANGLE assumes GPU 31DEFINE_string(config, "8888", "[8888|gpu|msaa4|msaa16|angle]: Use the corresponding config."); 32#elif SK_SUPPORT_GPU 33DEFINE_string(config, "8888", "[8888|gpu|msaa4|msaa16]: Use the corresponding config."); 34#else 35DEFINE_string(config, "8888", "[8888]: Use the corresponding config."); 36#endif 37 38DEFINE_bool(deferImageDecoding, false, "Defer decoding until drawing images. " 39 "Has no effect if the provided skp does not have its images encoded."); 40DEFINE_string(mode, "simple", "Run in the corresponding mode:\n" 41 "simple: Simple rendering.\n" 42 "tile width height: Use tiles with the given dimensions or percentages.\n" 43 "pow2tile minWidth height: Use tiles with widths that are all a power\n" 44 "\tof two such that they minimize the amount of wasted tile space.\n" 45 "\tminWidth must be a power of two.\n" 46 "copyTile width height: Draw the picture, then copy into tiles. If the\n" 47 "\tpicture is large enough, it is broken into larger tiles to avoid\n" 48 "\tcreating a large canvas.\n" 49// TODO: If bench_pictures and render_pictures were two separate targets, we could use build flags 50// to determine which modes to display. 51 "record: (Only in bench_pictures) Time recording from a picture to a new\n" 52 "\tpicture.\n" 53 "playbackCreation: (Only in bench_pictures) Time creation of the \n" 54 "\tSkPicturePlayback.\n" 55 "rerecord: (Only in render_pictures) Record the picture as a new skp,\n" 56 "\twith the bitmaps PNG encoded.\n"); 57DEFINE_int32(multi, 1, "Set the number of threads for multi threaded drawing. " 58 "If > 1, requires tiled rendering."); 59DEFINE_bool(pipe, false, "Use SkGPipe rendering. Currently incompatible with \"mode\"."); 60DEFINE_string2(readPath, r, "", "skp files or directories of skp files to process."); 61DEFINE_double(scale, 1, "Set the scale factor."); 62DEFINE_string(tiles, "", "Used with --mode copyTile to specify number of tiles per larger tile " 63 "in the x and y directions."); 64DEFINE_string(viewport, "", "width height: Set the viewport."); 65 66sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) { 67 error.reset(); 68 69 if (FLAGS_multi <= 0) { 70 error.printf("--multi must be > 0, was %i", FLAGS_multi); 71 return NULL; 72 } 73 74 bool useTiles = false; 75 const char* widthString = NULL; 76 const char* heightString = NULL; 77 bool isPowerOf2Mode = false; 78 bool isCopyMode = false; 79 const char* mode = NULL; 80 bool gridSupported = false; 81 82 SkAutoTUnref<sk_tools::PictureRenderer> renderer; 83 if (FLAGS_mode.count() >= 1) { 84 mode = FLAGS_mode[0]; 85 if (0 == strcmp(mode, "record")) { 86 renderer.reset(SkNEW(sk_tools::RecordPictureRenderer)); 87 gridSupported = true; 88 // undocumented 89 } else if (0 == strcmp(mode, "clone")) { 90 renderer.reset(sk_tools::CreatePictureCloneRenderer()); 91 } else if (0 == strcmp(mode, "tile") || 0 == strcmp(mode, "pow2tile") 92 || 0 == strcmp(mode, "copyTile")) { 93 useTiles = true; 94 95 if (0 == strcmp(mode, "pow2tile")) { 96 isPowerOf2Mode = true; 97 } else if (0 == strcmp(mode, "copyTile")) { 98 isCopyMode = true; 99 } else { 100 gridSupported = true; 101 } 102 103 if (FLAGS_mode.count() < 2) { 104 error.printf("Missing width for --mode %s\n", mode); 105 return NULL; 106 } 107 108 widthString = FLAGS_mode[1]; 109 if (FLAGS_mode.count() < 3) { 110 error.printf("Missing height for --mode %s\n", mode); 111 return NULL; 112 } 113 114 heightString = FLAGS_mode[2]; 115 } else if (0 == strcmp(mode, "playbackCreation") && kBench_PictureTool == tool) { 116 renderer.reset(SkNEW(sk_tools::PlaybackCreationRenderer)); 117 gridSupported = true; 118 // undocumented 119 } else if (0 == strcmp(mode, "gatherPixelRefs") && kBench_PictureTool == tool) { 120 renderer.reset(sk_tools::CreateGatherPixelRefsRenderer()); 121 } else if (0 == strcmp(mode, "rerecord") && kRender_PictureTool == tool) { 122 renderer.reset(SkNEW(sk_tools::RecordPictureRenderer)); 123 // Allow 'mode' to be set to 'simple', but do not create a renderer, so we can 124 // ensure that pipe does not override a mode besides simple. The renderer will 125 // be created below. 126 } else if (0 != strcmp(mode, "simple")) { 127 error.printf("%s is not a valid mode for --mode\n", mode); 128 return NULL; 129 } 130 } 131 132 if (useTiles) { 133 SkASSERT(NULL == renderer); 134 SkAutoTUnref<sk_tools::TiledPictureRenderer> tiledRenderer; 135 if (isCopyMode) { 136 int xTiles = -1; 137 int yTiles = -1; 138 if (FLAGS_tiles.count() > 0) { 139 if (FLAGS_tiles.count() != 2) { 140 error.printf("--tiles requires an x value and a y value.\n"); 141 return NULL; 142 } 143 xTiles = atoi(FLAGS_tiles[0]); 144 yTiles = atoi(FLAGS_tiles[1]); 145 } 146 147 int x, y; 148 if (xTiles != -1 && yTiles != -1) { 149 x = xTiles; 150 y = yTiles; 151 if (x <= 0 || y <= 0) { 152 error.printf("--tiles must be given values > 0\n"); 153 return NULL; 154 } 155 } else { 156 x = y = 4; 157 } 158 tiledRenderer.reset(SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y))); 159 } else if (FLAGS_multi > 1) { 160 tiledRenderer.reset(SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, 161 (FLAGS_multi))); 162 } else { 163 tiledRenderer.reset(SkNEW(sk_tools::TiledPictureRenderer)); 164 } 165 166 if (isPowerOf2Mode) { 167 int minWidth = atoi(widthString); 168 if (!SkIsPow2(minWidth) || minWidth < 0) { 169 SkString err; 170 error.printf("-mode %s must be given a width" 171 " value that is a power of two\n", mode); 172 return NULL; 173 } 174 tiledRenderer->setTileMinPowerOf2Width(minWidth); 175 } else if (sk_tools::is_percentage(widthString)) { 176 if (isCopyMode) { 177 error.printf("--mode %s does not support percentages.\n", mode); 178 return NULL; 179 } 180 tiledRenderer->setTileWidthPercentage(atof(widthString)); 181 if (!(tiledRenderer->getTileWidthPercentage() > 0)) { 182 error.printf("--mode %s must be given a width percentage > 0\n", mode); 183 return NULL; 184 } 185 } else { 186 tiledRenderer->setTileWidth(atoi(widthString)); 187 if (!(tiledRenderer->getTileWidth() > 0)) { 188 error.printf("--mode %s must be given a width > 0\n", mode); 189 return NULL; 190 } 191 } 192 193 if (sk_tools::is_percentage(heightString)) { 194 if (isCopyMode) { 195 error.printf("--mode %s does not support percentages.\n", mode); 196 return NULL; 197 } 198 tiledRenderer->setTileHeightPercentage(atof(heightString)); 199 if (!(tiledRenderer->getTileHeightPercentage() > 0)) { 200 error.printf("--mode %s must be given a height percentage > 0\n", mode); 201 return NULL; 202 } 203 } else { 204 tiledRenderer->setTileHeight(atoi(heightString)); 205 if (!(tiledRenderer->getTileHeight() > 0)) { 206 SkString err; 207 error.printf("--mode %s must be given a height > 0\n", mode); 208 return NULL; 209 } 210 } 211 212 renderer.reset(tiledRenderer.detach()); 213 if (FLAGS_pipe) { 214 error.printf("Pipe rendering is currently not compatible with tiling.\n" 215 "Turning off pipe.\n"); 216 } 217 218 } else { // useTiles 219 if (FLAGS_multi > 1) { 220 error.printf("Multithreaded drawing requires tiled rendering.\n"); 221 return NULL; 222 } 223 if (FLAGS_pipe) { 224 if (renderer != NULL) { 225 error.printf("Pipe is incompatible with other modes.\n"); 226 return NULL; 227 } 228 renderer.reset(SkNEW(sk_tools::PipePictureRenderer)); 229 } 230 } 231 232 if (NULL == renderer) { 233 renderer.reset(SkNEW(sk_tools::SimplePictureRenderer)); 234 } 235 236 if (FLAGS_viewport.count() > 0) { 237 if (FLAGS_viewport.count() != 2) { 238 error.printf("--viewport requires a width and a height.\n"); 239 return NULL; 240 } 241 SkISize viewport; 242 viewport.fWidth = atoi(FLAGS_viewport[0]); 243 viewport.fHeight = atoi(FLAGS_viewport[1]); 244 renderer->setViewport(viewport); 245 } 246 247 sk_tools::PictureRenderer::SkDeviceTypes deviceType = 248 sk_tools::PictureRenderer::kBitmap_DeviceType; 249#if SK_SUPPORT_GPU 250 int sampleCount = 0; 251#endif 252 if (FLAGS_config.count() > 0) { 253 if (0 == strcmp(FLAGS_config[0], "8888")) { 254 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType; 255 } 256#if SK_SUPPORT_GPU 257 else if (0 == strcmp(FLAGS_config[0], "gpu")) { 258 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType; 259 if (FLAGS_multi > 1) { 260 error.printf("GPU not compatible with multithreaded tiling.\n"); 261 return NULL; 262 } 263 } 264 else if (0 == strcmp(FLAGS_config[0], "msaa4")) { 265 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType; 266 if (FLAGS_multi > 1) { 267 error.printf("GPU not compatible with multithreaded tiling.\n"); 268 return NULL; 269 } 270 sampleCount = 4; 271 } 272 else if (0 == strcmp(FLAGS_config[0], "msaa16")) { 273 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType; 274 if (FLAGS_multi > 1) { 275 error.printf("GPU not compatible with multithreaded tiling.\n"); 276 return NULL; 277 } 278 sampleCount = 16; 279 } 280#if SK_ANGLE 281 else if (0 == strcmp(FLAGS_config[0], "angle")) { 282 deviceType = sk_tools::PictureRenderer::kAngle_DeviceType; 283 if (FLAGS_multi > 1) { 284 error.printf("Angle not compatible with multithreaded tiling.\n"); 285 return NULL; 286 } 287 } 288#endif 289#endif 290 else { 291 error.printf("%s is not a valid mode for --config\n", FLAGS_config[0]); 292 return NULL; 293 } 294 renderer->setDeviceType(deviceType); 295#if SK_SUPPORT_GPU 296 renderer->setSampleCount(sampleCount); 297#endif 298 } 299 300 301 sk_tools::PictureRenderer::BBoxHierarchyType bbhType 302 = sk_tools::PictureRenderer::kNone_BBoxHierarchyType; 303 if (FLAGS_bbh.count() > 0) { 304 const char* type = FLAGS_bbh[0]; 305 if (0 == strcmp(type, "none")) { 306 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType; 307 } else if (0 == strcmp(type, "rtree")) { 308 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType; 309 } else if (0 == strcmp(type, "grid")) { 310 if (!gridSupported) { 311 error.printf("'--bbh grid' is not compatible with --mode=%s.\n", mode); 312 return NULL; 313 } 314 bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType; 315 if (FLAGS_bbh.count() != 3) { 316 error.printf("--bbh grid requires a width and a height.\n"); 317 return NULL; 318 } 319 int gridWidth = atoi(FLAGS_bbh[1]); 320 int gridHeight = atoi(FLAGS_bbh[2]); 321 renderer->setGridSize(gridWidth, gridHeight); 322 323 } else { 324 error.printf("%s is not a valid value for --bbhType\n", type); 325 return NULL; 326 } 327 if (FLAGS_pipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) { 328 error.printf("--pipe and --bbh cannot be used together\n"); 329 return NULL; 330 } 331 } 332 renderer->setBBoxHierarchyType(bbhType); 333 renderer->setScaleFactor(SkDoubleToScalar(FLAGS_scale)); 334 335 return renderer.detach(); 336} 337