blob: 67a6a3d0aa806b1c777b8a0df0893a53d759c301 [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.combb281f72013-03-18 21:37:39 +000013#include "SkBitmapFactory.h"
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000014#include "SkCommandLineFlags.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000015#include "SkData.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000016#include "SkImage.h"
17#include "SkImageDecoder.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000018#include "SkString.h"
scroggo@google.com161e1ba2013-03-04 16:41:06 +000019
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
jvanverth@google.comf6a90332013-05-02 12:39:37 +000031DEFINE_string(config, "8888", "[8888|gpu|msaa4|msaa16|angle]: Use the corresponding config.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000032#elif SK_SUPPORT_GPU
jvanverth@google.comf6a90332013-05-02 12:39:37 +000033DEFINE_string(config, "8888", "[8888|gpu|msaa4|msaa16]: Use the corresponding config.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000034#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\".");
scroggo@google.com604e0c22013-04-09 21:25:46 +000060DEFINE_string2(readPath, r, "", "skp files or directories of skp files to process.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000061DEFINE_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;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000249#if SK_SUPPORT_GPU
250 int sampleCount = 0;
251#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000252 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 }
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000264 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 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000280#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);
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000295#if SK_SUPPORT_GPU
296 renderer->setSampleCount(sampleCount);
297#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000298 }
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}