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