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