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