blob: 26d15911d11876b3bb5fb9d07a99cfe21897600d [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"
bsalomon682c2692015-05-22 14:01:46 -070011#if SK_SUPPORT_GPU
12#include "GrContextOptions.h"
13#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +000014#include "PictureRenderer.h"
15#include "picture_utils.h"
scroggo@google.comd9ba9a02013-03-21 19:43:15 +000016#include "SkCommandLineFlags.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000017#include "SkData.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000018#include "SkImage.h"
19#include "SkImageDecoder.h"
scroggo@google.combb281f72013-03-18 21:37:39 +000020#include "SkString.h"
scroggo@google.com161e1ba2013-03-04 16:41:06 +000021
22// Alphabetized list of flags used by this file or bench_ and render_pictures.
23DEFINE_string(bbh, "none", "bbhType [width height]: Set the bounding box hierarchy type to "
mtklein2a65a232014-08-26 14:07:04 -070024 "be used. Accepted values are: none, rtree, grid. "
scroggo@google.com161e1ba2013-03-04 16:41:06 +000025 "Not compatible with --pipe. With value "
26 "'grid', width and height must be specified. 'grid' can "
27 "only be used with modes tile, record, and "
28 "playbackCreation.");
robertphillips@google.com11e10e32014-01-06 19:09:29 +000029
30
31#if SK_SUPPORT_GPU
kkinnunen80549fc2014-06-30 06:36:31 -070032static const char kGpuAPINameGL[] = "gl";
33static const char kGpuAPINameGLES[] = "gles";
jvanverth4736e142014-11-07 07:12:46 -080034#define GPU_CONFIG_STRING "|gpu|msaa4|msaa16|nvprmsaa4|nvprmsaa16|gpudft"
robertphillips@google.com11e10e32014-01-06 19:09:29 +000035#else
36#define GPU_CONFIG_STRING ""
37#endif
38#if SK_ANGLE
39#define ANGLE_CONFIG_STRING "|angle"
40#else
41#define ANGLE_CONFIG_STRING ""
42#endif
43#if SK_MESA
44#define MESA_CONFIG_STRING "|mesa"
45#else
46#define MESA_CONFIG_STRING ""
47#endif
48
scroggo@google.com161e1ba2013-03-04 16:41:06 +000049// Although this config does not support all the same options as gm, the names should be kept
50// consistent.
rmistry@google.com6ab96732014-01-06 18:37:24 +000051DEFINE_string(config, "8888", "["
robertphillips@google.com11e10e32014-01-06 19:09:29 +000052 "8888" GPU_CONFIG_STRING ANGLE_CONFIG_STRING MESA_CONFIG_STRING
rmistry@google.com6ab96732014-01-06 18:37:24 +000053 "]: Use the corresponding config.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000054
55DEFINE_bool(deferImageDecoding, false, "Defer decoding until drawing images. "
56 "Has no effect if the provided skp does not have its images encoded.");
57DEFINE_string(mode, "simple", "Run in the corresponding mode:\n"
58 "simple: Simple rendering.\n"
59 "tile width height: Use tiles with the given dimensions or percentages.\n"
60 "pow2tile minWidth height: Use tiles with widths that are all a power\n"
61 "\tof two such that they minimize the amount of wasted tile space.\n"
62 "\tminWidth must be a power of two.\n"
63 "copyTile width height: Draw the picture, then copy into tiles. If the\n"
64 "\tpicture is large enough, it is broken into larger tiles to avoid\n"
65 "\tcreating a large canvas.\n"
66// TODO: If bench_pictures and render_pictures were two separate targets, we could use build flags
67// to determine which modes to display.
68 "record: (Only in bench_pictures) Time recording from a picture to a new\n"
69 "\tpicture.\n"
70 "playbackCreation: (Only in bench_pictures) Time creation of the \n"
71 "\tSkPicturePlayback.\n"
72 "rerecord: (Only in render_pictures) Record the picture as a new skp,\n"
73 "\twith the bitmaps PNG encoded.\n");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000074DEFINE_bool(pipe, false, "Use SkGPipe rendering. Currently incompatible with \"mode\".");
scroggo@google.com604e0c22013-04-09 21:25:46 +000075DEFINE_string2(readPath, r, "", "skp files or directories of skp files to process.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000076DEFINE_double(scale, 1, "Set the scale factor.");
77DEFINE_string(tiles, "", "Used with --mode copyTile to specify number of tiles per larger tile "
78 "in the x and y directions.");
79DEFINE_string(viewport, "", "width height: Set the viewport.");
kkinnunen80549fc2014-06-30 06:36:31 -070080#if SK_SUPPORT_GPU
81DEFINE_string(gpuAPI, "", "Force use of specific gpu API. Using \"gl\" "
82 "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
83 "Defaults to empty string, which selects the API native to the "
84 "system.");
krajcevskib1aded82014-08-18 07:52:17 -070085DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to "
86 "software path rendering.");
kkinnunen80549fc2014-06-30 06:36:31 -070087#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +000088
89sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
90 error.reset();
91
scroggo@google.com161e1ba2013-03-04 16:41:06 +000092 bool useTiles = false;
93 const char* widthString = NULL;
94 const char* heightString = NULL;
95 bool isPowerOf2Mode = false;
96 bool isCopyMode = false;
97 const char* mode = NULL;
scroggo@google.com161e1ba2013-03-04 16:41:06 +000098
krajcevskib1aded82014-08-18 07:52:17 -070099#if SK_SUPPORT_GPU
bsalomon682c2692015-05-22 14:01:46 -0700100 GrContextOptions grContextOpts;
krajcevskib1aded82014-08-18 07:52:17 -0700101 grContextOpts.fDrawPathToCompressedTexture = FLAGS_gpuCompressAlphaMasks;
102 #define RENDERER_ARGS (grContextOpts)
103#else
104 #define RENDERER_ARGS ()
105#endif
106
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000107 SkAutoTUnref<sk_tools::PictureRenderer> renderer;
108 if (FLAGS_mode.count() >= 1) {
109 mode = FLAGS_mode[0];
110 if (0 == strcmp(mode, "record")) {
krajcevskib1aded82014-08-18 07:52:17 -0700111 renderer.reset(SkNEW_ARGS(sk_tools::RecordPictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000112 } else if (0 == strcmp(mode, "tile") || 0 == strcmp(mode, "pow2tile")
113 || 0 == strcmp(mode, "copyTile")) {
114 useTiles = true;
115
116 if (0 == strcmp(mode, "pow2tile")) {
117 isPowerOf2Mode = true;
118 } else if (0 == strcmp(mode, "copyTile")) {
119 isCopyMode = true;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000120 }
121
122 if (FLAGS_mode.count() < 2) {
123 error.printf("Missing width for --mode %s\n", mode);
124 return NULL;
125 }
126
127 widthString = FLAGS_mode[1];
128 if (FLAGS_mode.count() < 3) {
129 error.printf("Missing height for --mode %s\n", mode);
130 return NULL;
131 }
132
133 heightString = FLAGS_mode[2];
134 } else if (0 == strcmp(mode, "playbackCreation") && kBench_PictureTool == tool) {
krajcevskib1aded82014-08-18 07:52:17 -0700135 renderer.reset(SkNEW_ARGS(sk_tools::PlaybackCreationRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000136 // undocumented
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000137 } else if (0 == strcmp(mode, "rerecord") && kRender_PictureTool == tool) {
krajcevskib1aded82014-08-18 07:52:17 -0700138 renderer.reset(SkNEW_ARGS(sk_tools::RecordPictureRenderer, RENDERER_ARGS));
mtklein963b8322015-01-13 10:51:36 -0800139 } else if (0 == strcmp(mode, "simple")) {
140 // Allow 'mode' to be set to 'simple', but do not create a renderer, so we can
141 // ensure that pipe does not override a mode besides simple. The renderer will
142 // be created below.
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000143 } else {
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000144 error.printf("%s is not a valid mode for --mode\n", mode);
145 return NULL;
146 }
147 }
148
149 if (useTiles) {
150 SkASSERT(NULL == renderer);
151 SkAutoTUnref<sk_tools::TiledPictureRenderer> tiledRenderer;
152 if (isCopyMode) {
153 int xTiles = -1;
154 int yTiles = -1;
155 if (FLAGS_tiles.count() > 0) {
156 if (FLAGS_tiles.count() != 2) {
157 error.printf("--tiles requires an x value and a y value.\n");
158 return NULL;
159 }
160 xTiles = atoi(FLAGS_tiles[0]);
161 yTiles = atoi(FLAGS_tiles[1]);
162 }
163
164 int x, y;
165 if (xTiles != -1 && yTiles != -1) {
166 x = xTiles;
167 y = yTiles;
168 if (x <= 0 || y <= 0) {
169 error.printf("--tiles must be given values > 0\n");
170 return NULL;
171 }
172 } else {
173 x = y = 4;
174 }
krajcevskib1aded82014-08-18 07:52:17 -0700175#if SK_SUPPORT_GPU
176 tiledRenderer.reset(SkNEW_ARGS(sk_tools::CopyTilesRenderer, (grContextOpts, x, y)));
177#else
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000178 tiledRenderer.reset(SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y)));
krajcevskib1aded82014-08-18 07:52:17 -0700179#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000180 } else {
krajcevskib1aded82014-08-18 07:52:17 -0700181 tiledRenderer.reset(SkNEW_ARGS(sk_tools::TiledPictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000182 }
183
184 if (isPowerOf2Mode) {
185 int minWidth = atoi(widthString);
186 if (!SkIsPow2(minWidth) || minWidth < 0) {
187 SkString err;
188 error.printf("-mode %s must be given a width"
189 " value that is a power of two\n", mode);
190 return NULL;
191 }
192 tiledRenderer->setTileMinPowerOf2Width(minWidth);
193 } else if (sk_tools::is_percentage(widthString)) {
194 if (isCopyMode) {
195 error.printf("--mode %s does not support percentages.\n", mode);
196 return NULL;
197 }
198 tiledRenderer->setTileWidthPercentage(atof(widthString));
199 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
200 error.printf("--mode %s must be given a width percentage > 0\n", mode);
201 return NULL;
202 }
203 } else {
204 tiledRenderer->setTileWidth(atoi(widthString));
205 if (!(tiledRenderer->getTileWidth() > 0)) {
206 error.printf("--mode %s must be given a width > 0\n", mode);
207 return NULL;
208 }
209 }
210
211 if (sk_tools::is_percentage(heightString)) {
212 if (isCopyMode) {
213 error.printf("--mode %s does not support percentages.\n", mode);
214 return NULL;
215 }
216 tiledRenderer->setTileHeightPercentage(atof(heightString));
217 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
218 error.printf("--mode %s must be given a height percentage > 0\n", mode);
219 return NULL;
220 }
221 } else {
222 tiledRenderer->setTileHeight(atoi(heightString));
223 if (!(tiledRenderer->getTileHeight() > 0)) {
224 SkString err;
225 error.printf("--mode %s must be given a height > 0\n", mode);
226 return NULL;
227 }
228 }
229
230 renderer.reset(tiledRenderer.detach());
231 if (FLAGS_pipe) {
232 error.printf("Pipe rendering is currently not compatible with tiling.\n"
233 "Turning off pipe.\n");
234 }
235
236 } else { // useTiles
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000237 if (FLAGS_pipe) {
238 if (renderer != NULL) {
239 error.printf("Pipe is incompatible with other modes.\n");
240 return NULL;
241 }
krajcevskib1aded82014-08-18 07:52:17 -0700242 renderer.reset(SkNEW_ARGS(sk_tools::PipePictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000243 }
244 }
245
246 if (NULL == renderer) {
krajcevskib1aded82014-08-18 07:52:17 -0700247 renderer.reset(SkNEW_ARGS(sk_tools::SimplePictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000248 }
249
250 if (FLAGS_viewport.count() > 0) {
251 if (FLAGS_viewport.count() != 2) {
252 error.printf("--viewport requires a width and a height.\n");
253 return NULL;
254 }
255 SkISize viewport;
256 viewport.fWidth = atoi(FLAGS_viewport[0]);
257 viewport.fHeight = atoi(FLAGS_viewport[1]);
258 renderer->setViewport(viewport);
259 }
260
261 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
262 sk_tools::PictureRenderer::kBitmap_DeviceType;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000263#if SK_SUPPORT_GPU
kkinnunen80549fc2014-06-30 06:36:31 -0700264 GrGLStandard gpuAPI = kNone_GrGLStandard;
265 if (1 == FLAGS_gpuAPI.count()) {
266 if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
267 gpuAPI = kGL_GrGLStandard;
268 } else if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
269 gpuAPI = kGLES_GrGLStandard;
270 } else {
271 error.printf("--gpuAPI invalid api value.\n");
272 return NULL;
273 }
274 } else if (FLAGS_gpuAPI.count() > 1) {
275 error.printf("--gpuAPI invalid api value.\n");
276 return NULL;
277 }
278
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000279 int sampleCount = 0;
jvanverth4736e142014-11-07 07:12:46 -0800280 bool useDFText = false;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000281#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000282 if (FLAGS_config.count() > 0) {
283 if (0 == strcmp(FLAGS_config[0], "8888")) {
284 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
285 }
286#if SK_SUPPORT_GPU
287 else if (0 == strcmp(FLAGS_config[0], "gpu")) {
288 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000289 }
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000290 else if (0 == strcmp(FLAGS_config[0], "msaa4")) {
291 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000292 sampleCount = 4;
293 }
294 else if (0 == strcmp(FLAGS_config[0], "msaa16")) {
295 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000296 sampleCount = 16;
297 }
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000298 else if (0 == strcmp(FLAGS_config[0], "nvprmsaa4")) {
299 deviceType = sk_tools::PictureRenderer::kNVPR_DeviceType;
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000300 sampleCount = 4;
301 }
302 else if (0 == strcmp(FLAGS_config[0], "nvprmsaa16")) {
303 deviceType = sk_tools::PictureRenderer::kNVPR_DeviceType;
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000304 sampleCount = 16;
305 }
jvanverth4736e142014-11-07 07:12:46 -0800306 else if (0 == strcmp(FLAGS_config[0], "gpudft")) {
307 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
308 useDFText = true;
309 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000310#if SK_ANGLE
311 else if (0 == strcmp(FLAGS_config[0], "angle")) {
312 deviceType = sk_tools::PictureRenderer::kAngle_DeviceType;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000313 }
314#endif
rmistry@google.com6ab96732014-01-06 18:37:24 +0000315#if SK_MESA
316 else if (0 == strcmp(FLAGS_config[0], "mesa")) {
317 deviceType = sk_tools::PictureRenderer::kMesa_DeviceType;
rmistry@google.com6ab96732014-01-06 18:37:24 +0000318 }
319#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000320#endif
321 else {
322 error.printf("%s is not a valid mode for --config\n", FLAGS_config[0]);
323 return NULL;
324 }
kkinnunen80549fc2014-06-30 06:36:31 -0700325#if SK_SUPPORT_GPU
326 if (!renderer->setDeviceType(deviceType, gpuAPI)) {
327#else
328 if (!renderer->setDeviceType(deviceType)) {
329#endif
330 error.printf("Could not create backend for --config %s\n", FLAGS_config[0]);
331 return NULL;
332 }
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000333#if SK_SUPPORT_GPU
334 renderer->setSampleCount(sampleCount);
jvanverth4736e142014-11-07 07:12:46 -0800335 renderer->setUseDFText(useDFText);
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000336#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000337 }
338
339
340 sk_tools::PictureRenderer::BBoxHierarchyType bbhType
341 = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
342 if (FLAGS_bbh.count() > 0) {
343 const char* type = FLAGS_bbh[0];
344 if (0 == strcmp(type, "none")) {
345 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
346 } else if (0 == strcmp(type, "rtree")) {
347 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000348 } else {
349 error.printf("%s is not a valid value for --bbhType\n", type);
350 return NULL;
351 }
352 if (FLAGS_pipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
353 error.printf("--pipe and --bbh cannot be used together\n");
354 return NULL;
355 }
356 }
357 renderer->setBBoxHierarchyType(bbhType);
358 renderer->setScaleFactor(SkDoubleToScalar(FLAGS_scale));
359
360 return renderer.detach();
361}