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