Home | History | Annotate | Download | only in tools
      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 // 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
     30 DEFINE_string(config, "8888", "[8888|gpu|msaa4|msaa16|angle]: Use the corresponding config.");
     31 #elif SK_SUPPORT_GPU
     32 DEFINE_string(config, "8888", "[8888|gpu|msaa4|msaa16]: Use the corresponding config.");
     33 #else
     34 DEFINE_string(config, "8888", "[8888]: Use the corresponding config.");
     35 #endif
     36 
     37 DEFINE_bool(deferImageDecoding, false, "Defer decoding until drawing images. "
     38             "Has no effect if the provided skp does not have its images encoded.");
     39 DEFINE_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");
     56 DEFINE_int32(multi, 1, "Set the number of threads for multi threaded drawing. "
     57              "If > 1, requires tiled rendering.");
     58 DEFINE_bool(pipe, false, "Use SkGPipe rendering. Currently incompatible with \"mode\".");
     59 DEFINE_string2(readPath, r, "", "skp files or directories of skp files to process.");
     60 DEFINE_double(scale, 1, "Set the scale factor.");
     61 DEFINE_string(tiles, "", "Used with --mode copyTile to specify number of tiles per larger tile "
     62               "in the x and y directions.");
     63 DEFINE_string(viewport, "", "width height: Set the viewport.");
     64 
     65 sk_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