blob: 2aae77f9ac9cc4b47c0ffd5af7847055b08bc020 [file] [log] [blame]
scroggo@google.com161e1ba2013-03-04 16:41:06 +00001/*
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"
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000013#include "SkCommandLineFlags.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000014#include "SkData.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000015#include "SkImage.h"
16#include "SkImageDecoder.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000017#include "SkString.h"
scroggo@google.com161e1ba2013-03-04 16:41:06 +000018
19// Alphabetized list of flags used by this file or bench_ and render_pictures.
20DEFINE_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
jvanverth@google.comf6a90332013-05-02 12:39:37 +000030DEFINE_string(config, "8888", "[8888|gpu|msaa4|msaa16|angle]: Use the corresponding config.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000031#elif SK_SUPPORT_GPU
jvanverth@google.comf6a90332013-05-02 12:39:37 +000032DEFINE_string(config, "8888", "[8888|gpu|msaa4|msaa16]: Use the corresponding config.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000033#else
34DEFINE_string(config, "8888", "[8888]: Use the corresponding config.");
35#endif
36
37DEFINE_bool(deferImageDecoding, false, "Defer decoding until drawing images. "
38 "Has no effect if the provided skp does not have its images encoded.");
39DEFINE_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");
56DEFINE_int32(multi, 1, "Set the number of threads for multi threaded drawing. "
57 "If > 1, requires tiled rendering.");
58DEFINE_bool(pipe, false, "Use SkGPipe rendering. Currently incompatible with \"mode\".");
scroggo@google.com604e0c22013-04-09 21:25:46 +000059DEFINE_string2(readPath, r, "", "skp files or directories of skp files to process.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000060DEFINE_double(scale, 1, "Set the scale factor.");
61DEFINE_string(tiles, "", "Used with --mode copyTile to specify number of tiles per larger tile "
62 "in the x and y directions.");
63DEFINE_string(viewport, "", "width height: Set the viewport.");
64
65sk_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;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000248#if SK_SUPPORT_GPU
249 int sampleCount = 0;
250#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000251 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 }
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000263 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 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000279#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);
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000294#if SK_SUPPORT_GPU
295 renderer->setSampleCount(sampleCount);
296#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000297 }
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}