• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
parseRenderer(SkString & error,PictureTool tool)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