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, 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