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