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