blob: 4ffa16f12b80f0a57efdbf59a8c0cf30f54146a2 [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 "
commit-bot@chromium.orgc22d1392014-02-03 18:08:33 +000021 "be used. Accepted values are: none, rtree, quadtree, grid. "
scroggo@google.com161e1ba2013-03-04 16:41:06 +000022 "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.");
robertphillips@google.com11e10e32014-01-06 19:09:29 +000026
27
28#if SK_SUPPORT_GPU
kkinnunen74fc7272014-06-22 22:56:53 -070029static const char kGpuAPINameGL[] = "gl";
30static const char kGpuAPINameGLES[] = "gles";
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +000031#define GPU_CONFIG_STRING "|gpu|msaa4|msaa16|nvprmsaa4|nvprmsaa16"
robertphillips@google.com11e10e32014-01-06 19:09:29 +000032#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
scroggo@google.com161e1ba2013-03-04 16:41:06 +000046// Although this config does not support all the same options as gm, the names should be kept
47// consistent.
rmistry@google.com6ab96732014-01-06 18:37:24 +000048DEFINE_string(config, "8888", "["
robertphillips@google.com11e10e32014-01-06 19:09:29 +000049 "8888" GPU_CONFIG_STRING ANGLE_CONFIG_STRING MESA_CONFIG_STRING
rmistry@google.com6ab96732014-01-06 18:37:24 +000050 "]: Use the corresponding config.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000051
52DEFINE_bool(deferImageDecoding, false, "Defer decoding until drawing images. "
53 "Has no effect if the provided skp does not have its images encoded.");
54DEFINE_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");
71DEFINE_int32(multi, 1, "Set the number of threads for multi threaded drawing. "
72 "If > 1, requires tiled rendering.");
73DEFINE_bool(pipe, false, "Use SkGPipe rendering. Currently incompatible with \"mode\".");
scroggo@google.com604e0c22013-04-09 21:25:46 +000074DEFINE_string2(readPath, r, "", "skp files or directories of skp files to process.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000075DEFINE_double(scale, 1, "Set the scale factor.");
76DEFINE_string(tiles, "", "Used with --mode copyTile to specify number of tiles per larger tile "
77 "in the x and y directions.");
78DEFINE_string(viewport, "", "width height: Set the viewport.");
kkinnunen74fc7272014-06-22 22:56:53 -070079#if SK_SUPPORT_GPU
80DEFINE_string(gpuAPI, "", "Force use of specific gpu API. Using \"gl\" "
81 "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
82 "Defaults to empty string, which selects the API native to the "
83 "system.");
84#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +000085
86sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
87 error.reset();
88
89 if (FLAGS_multi <= 0) {
90 error.printf("--multi must be > 0, was %i", FLAGS_multi);
91 return NULL;
92 }
93
94 bool useTiles = false;
95 const char* widthString = NULL;
96 const char* heightString = NULL;
97 bool isPowerOf2Mode = false;
98 bool isCopyMode = false;
99 const char* mode = NULL;
100 bool gridSupported = false;
101
102 SkAutoTUnref<sk_tools::PictureRenderer> renderer;
103 if (FLAGS_mode.count() >= 1) {
104 mode = FLAGS_mode[0];
105 if (0 == strcmp(mode, "record")) {
106 renderer.reset(SkNEW(sk_tools::RecordPictureRenderer));
107 gridSupported = true;
108 // undocumented
109 } else if (0 == strcmp(mode, "clone")) {
110 renderer.reset(sk_tools::CreatePictureCloneRenderer());
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(sk_tools::PlaybackCreationRenderer));
137 gridSupported = true;
138 // undocumented
139 } else if (0 == strcmp(mode, "gatherPixelRefs") && kBench_PictureTool == tool) {
140 renderer.reset(sk_tools::CreateGatherPixelRefsRenderer());
141 } else if (0 == strcmp(mode, "rerecord") && kRender_PictureTool == tool) {
142 renderer.reset(SkNEW(sk_tools::RecordPictureRenderer));
143 // Allow 'mode' to be set to 'simple', but do not create a renderer, so we can
144 // ensure that pipe does not override a mode besides simple. The renderer will
145 // be created below.
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000146 } else if (0 == strcmp(mode, "simple")) {
147 gridSupported = true;
148 } else {
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000149 error.printf("%s is not a valid mode for --mode\n", mode);
150 return NULL;
151 }
152 }
153
154 if (useTiles) {
155 SkASSERT(NULL == renderer);
156 SkAutoTUnref<sk_tools::TiledPictureRenderer> tiledRenderer;
157 if (isCopyMode) {
158 int xTiles = -1;
159 int yTiles = -1;
160 if (FLAGS_tiles.count() > 0) {
161 if (FLAGS_tiles.count() != 2) {
162 error.printf("--tiles requires an x value and a y value.\n");
163 return NULL;
164 }
165 xTiles = atoi(FLAGS_tiles[0]);
166 yTiles = atoi(FLAGS_tiles[1]);
167 }
168
169 int x, y;
170 if (xTiles != -1 && yTiles != -1) {
171 x = xTiles;
172 y = yTiles;
173 if (x <= 0 || y <= 0) {
174 error.printf("--tiles must be given values > 0\n");
175 return NULL;
176 }
177 } else {
178 x = y = 4;
179 }
180 tiledRenderer.reset(SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y)));
181 } else if (FLAGS_multi > 1) {
182 tiledRenderer.reset(SkNEW_ARGS(sk_tools::MultiCorePictureRenderer,
183 (FLAGS_multi)));
184 } else {
185 tiledRenderer.reset(SkNEW(sk_tools::TiledPictureRenderer));
186 }
187
188 if (isPowerOf2Mode) {
189 int minWidth = atoi(widthString);
190 if (!SkIsPow2(minWidth) || minWidth < 0) {
191 SkString err;
192 error.printf("-mode %s must be given a width"
193 " value that is a power of two\n", mode);
194 return NULL;
195 }
196 tiledRenderer->setTileMinPowerOf2Width(minWidth);
197 } else if (sk_tools::is_percentage(widthString)) {
198 if (isCopyMode) {
199 error.printf("--mode %s does not support percentages.\n", mode);
200 return NULL;
201 }
202 tiledRenderer->setTileWidthPercentage(atof(widthString));
203 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
204 error.printf("--mode %s must be given a width percentage > 0\n", mode);
205 return NULL;
206 }
207 } else {
208 tiledRenderer->setTileWidth(atoi(widthString));
209 if (!(tiledRenderer->getTileWidth() > 0)) {
210 error.printf("--mode %s must be given a width > 0\n", mode);
211 return NULL;
212 }
213 }
214
215 if (sk_tools::is_percentage(heightString)) {
216 if (isCopyMode) {
217 error.printf("--mode %s does not support percentages.\n", mode);
218 return NULL;
219 }
220 tiledRenderer->setTileHeightPercentage(atof(heightString));
221 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
222 error.printf("--mode %s must be given a height percentage > 0\n", mode);
223 return NULL;
224 }
225 } else {
226 tiledRenderer->setTileHeight(atoi(heightString));
227 if (!(tiledRenderer->getTileHeight() > 0)) {
228 SkString err;
229 error.printf("--mode %s must be given a height > 0\n", mode);
230 return NULL;
231 }
232 }
233
234 renderer.reset(tiledRenderer.detach());
235 if (FLAGS_pipe) {
236 error.printf("Pipe rendering is currently not compatible with tiling.\n"
237 "Turning off pipe.\n");
238 }
239
240 } else { // useTiles
241 if (FLAGS_multi > 1) {
242 error.printf("Multithreaded drawing requires tiled rendering.\n");
243 return NULL;
244 }
245 if (FLAGS_pipe) {
246 if (renderer != NULL) {
247 error.printf("Pipe is incompatible with other modes.\n");
248 return NULL;
249 }
250 renderer.reset(SkNEW(sk_tools::PipePictureRenderer));
251 }
252 }
253
254 if (NULL == renderer) {
255 renderer.reset(SkNEW(sk_tools::SimplePictureRenderer));
256 }
257
258 if (FLAGS_viewport.count() > 0) {
259 if (FLAGS_viewport.count() != 2) {
260 error.printf("--viewport requires a width and a height.\n");
261 return NULL;
262 }
263 SkISize viewport;
264 viewport.fWidth = atoi(FLAGS_viewport[0]);
265 viewport.fHeight = atoi(FLAGS_viewport[1]);
266 renderer->setViewport(viewport);
267 }
268
269 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
270 sk_tools::PictureRenderer::kBitmap_DeviceType;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000271#if SK_SUPPORT_GPU
kkinnunen74fc7272014-06-22 22:56:53 -0700272 GrGLStandard gpuAPI = kNone_GrGLStandard;
273 if (1 == FLAGS_gpuAPI.count()) {
274 if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
275 gpuAPI = kGL_GrGLStandard;
276 } else if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
277 gpuAPI = kGLES_GrGLStandard;
278 } else {
279 error.printf("--gpuAPI invalid api value.\n");
280 return NULL;
281 }
282 } else if (FLAGS_gpuAPI.count() > 1) {
283 error.printf("--gpuAPI invalid api value.\n");
284 return NULL;
285 }
286
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000287 int sampleCount = 0;
288#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000289 if (FLAGS_config.count() > 0) {
290 if (0 == strcmp(FLAGS_config[0], "8888")) {
291 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
292 }
293#if SK_SUPPORT_GPU
294 else if (0 == strcmp(FLAGS_config[0], "gpu")) {
295 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
296 if (FLAGS_multi > 1) {
297 error.printf("GPU not compatible with multithreaded tiling.\n");
298 return NULL;
299 }
300 }
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000301 else if (0 == strcmp(FLAGS_config[0], "msaa4")) {
302 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
303 if (FLAGS_multi > 1) {
304 error.printf("GPU not compatible with multithreaded tiling.\n");
305 return NULL;
306 }
307 sampleCount = 4;
308 }
309 else if (0 == strcmp(FLAGS_config[0], "msaa16")) {
310 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
311 if (FLAGS_multi > 1) {
312 error.printf("GPU not compatible with multithreaded tiling.\n");
313 return NULL;
314 }
315 sampleCount = 16;
316 }
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000317 else if (0 == strcmp(FLAGS_config[0], "nvprmsaa4")) {
318 deviceType = sk_tools::PictureRenderer::kNVPR_DeviceType;
319 if (FLAGS_multi > 1) {
320 error.printf("GPU not compatible with multithreaded tiling.\n");
321 return NULL;
322 }
323 sampleCount = 4;
324 }
325 else if (0 == strcmp(FLAGS_config[0], "nvprmsaa16")) {
326 deviceType = sk_tools::PictureRenderer::kNVPR_DeviceType;
327 if (FLAGS_multi > 1) {
328 error.printf("GPU not compatible with multithreaded tiling.\n");
329 return NULL;
330 }
331 sampleCount = 16;
332 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000333#if SK_ANGLE
334 else if (0 == strcmp(FLAGS_config[0], "angle")) {
335 deviceType = sk_tools::PictureRenderer::kAngle_DeviceType;
336 if (FLAGS_multi > 1) {
337 error.printf("Angle not compatible with multithreaded tiling.\n");
338 return NULL;
339 }
340 }
341#endif
rmistry@google.com6ab96732014-01-06 18:37:24 +0000342#if SK_MESA
343 else if (0 == strcmp(FLAGS_config[0], "mesa")) {
344 deviceType = sk_tools::PictureRenderer::kMesa_DeviceType;
345 if (FLAGS_multi > 1) {
346 error.printf("Mesa not compatible with multithreaded tiling.\n");
347 return NULL;
348 }
349 }
350#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000351#endif
352 else {
353 error.printf("%s is not a valid mode for --config\n", FLAGS_config[0]);
354 return NULL;
355 }
kkinnunen74fc7272014-06-22 22:56:53 -0700356#if SK_SUPPORT_GPU
357 if (!renderer->setDeviceType(deviceType, gpuAPI)) {
358#else
359 if (!renderer->setDeviceType(deviceType)) {
360#endif
361 error.printf("Could not create backend for --config %s\n", FLAGS_config[0]);
362 return NULL;
363 }
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000364#if SK_SUPPORT_GPU
365 renderer->setSampleCount(sampleCount);
366#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000367 }
368
369
370 sk_tools::PictureRenderer::BBoxHierarchyType bbhType
371 = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
372 if (FLAGS_bbh.count() > 0) {
373 const char* type = FLAGS_bbh[0];
374 if (0 == strcmp(type, "none")) {
375 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
commit-bot@chromium.orgc22d1392014-02-03 18:08:33 +0000376 } else if (0 == strcmp(type, "quadtree")) {
377 bbhType = sk_tools::PictureRenderer::kQuadTree_BBoxHierarchyType;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000378 } else if (0 == strcmp(type, "rtree")) {
379 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
380 } else if (0 == strcmp(type, "grid")) {
381 if (!gridSupported) {
382 error.printf("'--bbh grid' is not compatible with --mode=%s.\n", mode);
383 return NULL;
384 }
385 bbhType = sk_tools::PictureRenderer::kTileGrid_BBoxHierarchyType;
386 if (FLAGS_bbh.count() != 3) {
387 error.printf("--bbh grid requires a width and a height.\n");
388 return NULL;
389 }
390 int gridWidth = atoi(FLAGS_bbh[1]);
391 int gridHeight = atoi(FLAGS_bbh[2]);
392 renderer->setGridSize(gridWidth, gridHeight);
393
394 } else {
395 error.printf("%s is not a valid value for --bbhType\n", type);
396 return NULL;
397 }
398 if (FLAGS_pipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
399 error.printf("--pipe and --bbh cannot be used together\n");
400 return NULL;
401 }
402 }
403 renderer->setBBoxHierarchyType(bbhType);
404 renderer->setScaleFactor(SkDoubleToScalar(FLAGS_scale));
405
406 return renderer.detach();
407}