blob: 7424d5078671256868c1fdcf516fea2d72b9aed1 [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 "
mtklein2a65a232014-08-26 14:07:04 -070021 "be used. Accepted values are: none, rtree, 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
kkinnunen80549fc2014-06-30 06:36:31 -070029static const char kGpuAPINameGL[] = "gl";
30static const char kGpuAPINameGLES[] = "gles";
jvanverth4736e142014-11-07 07:12:46 -080031#define GPU_CONFIG_STRING "|gpu|msaa4|msaa16|nvprmsaa4|nvprmsaa16|gpudft"
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");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000071DEFINE_bool(pipe, false, "Use SkGPipe rendering. Currently incompatible with \"mode\".");
scroggo@google.com604e0c22013-04-09 21:25:46 +000072DEFINE_string2(readPath, r, "", "skp files or directories of skp files to process.");
scroggo@google.com161e1ba2013-03-04 16:41:06 +000073DEFINE_double(scale, 1, "Set the scale factor.");
74DEFINE_string(tiles, "", "Used with --mode copyTile to specify number of tiles per larger tile "
75 "in the x and y directions.");
76DEFINE_string(viewport, "", "width height: Set the viewport.");
kkinnunen80549fc2014-06-30 06:36:31 -070077#if SK_SUPPORT_GPU
78DEFINE_string(gpuAPI, "", "Force use of specific gpu API. Using \"gl\" "
79 "forces OpenGL API. Using \"gles\" forces OpenGL ES API. "
80 "Defaults to empty string, which selects the API native to the "
81 "system.");
krajcevskib1aded82014-08-18 07:52:17 -070082DEFINE_bool(gpuCompressAlphaMasks, false, "Compress masks generated from falling back to "
83 "software path rendering.");
kkinnunen80549fc2014-06-30 06:36:31 -070084#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +000085
86sk_tools::PictureRenderer* parseRenderer(SkString& error, PictureTool tool) {
87 error.reset();
88
scroggo@google.com161e1ba2013-03-04 16:41:06 +000089 bool useTiles = false;
90 const char* widthString = NULL;
91 const char* heightString = NULL;
92 bool isPowerOf2Mode = false;
93 bool isCopyMode = false;
94 const char* mode = NULL;
scroggo@google.com161e1ba2013-03-04 16:41:06 +000095
krajcevskib1aded82014-08-18 07:52:17 -070096#if SK_SUPPORT_GPU
97 GrContext::Options grContextOpts;
98 grContextOpts.fDrawPathToCompressedTexture = FLAGS_gpuCompressAlphaMasks;
99 #define RENDERER_ARGS (grContextOpts)
100#else
101 #define RENDERER_ARGS ()
102#endif
103
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000104 SkAutoTUnref<sk_tools::PictureRenderer> renderer;
105 if (FLAGS_mode.count() >= 1) {
106 mode = FLAGS_mode[0];
107 if (0 == strcmp(mode, "record")) {
krajcevskib1aded82014-08-18 07:52:17 -0700108 renderer.reset(SkNEW_ARGS(sk_tools::RecordPictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000109 } else if (0 == strcmp(mode, "tile") || 0 == strcmp(mode, "pow2tile")
110 || 0 == strcmp(mode, "copyTile")) {
111 useTiles = true;
112
113 if (0 == strcmp(mode, "pow2tile")) {
114 isPowerOf2Mode = true;
115 } else if (0 == strcmp(mode, "copyTile")) {
116 isCopyMode = true;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000117 }
118
119 if (FLAGS_mode.count() < 2) {
120 error.printf("Missing width for --mode %s\n", mode);
121 return NULL;
122 }
123
124 widthString = FLAGS_mode[1];
125 if (FLAGS_mode.count() < 3) {
126 error.printf("Missing height for --mode %s\n", mode);
127 return NULL;
128 }
129
130 heightString = FLAGS_mode[2];
131 } else if (0 == strcmp(mode, "playbackCreation") && kBench_PictureTool == tool) {
krajcevskib1aded82014-08-18 07:52:17 -0700132 renderer.reset(SkNEW_ARGS(sk_tools::PlaybackCreationRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000133 // undocumented
134 } else if (0 == strcmp(mode, "gatherPixelRefs") && kBench_PictureTool == tool) {
krajcevskib1aded82014-08-18 07:52:17 -0700135#if SK_SUPPORT_GPU
136 renderer.reset(sk_tools::CreateGatherPixelRefsRenderer(grContextOpts));
137#else
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000138 renderer.reset(sk_tools::CreateGatherPixelRefsRenderer());
krajcevskib1aded82014-08-18 07:52:17 -0700139#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000140 } else if (0 == strcmp(mode, "rerecord") && kRender_PictureTool == tool) {
krajcevskib1aded82014-08-18 07:52:17 -0700141 renderer.reset(SkNEW_ARGS(sk_tools::RecordPictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000142 // Allow 'mode' to be set to 'simple', but do not create a renderer, so we can
143 // ensure that pipe does not override a mode besides simple. The renderer will
144 // be created below.
commit-bot@chromium.org5fb2ce32014-04-17 23:35:06 +0000145 } else {
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000146 error.printf("%s is not a valid mode for --mode\n", mode);
147 return NULL;
148 }
149 }
150
151 if (useTiles) {
152 SkASSERT(NULL == renderer);
153 SkAutoTUnref<sk_tools::TiledPictureRenderer> tiledRenderer;
154 if (isCopyMode) {
155 int xTiles = -1;
156 int yTiles = -1;
157 if (FLAGS_tiles.count() > 0) {
158 if (FLAGS_tiles.count() != 2) {
159 error.printf("--tiles requires an x value and a y value.\n");
160 return NULL;
161 }
162 xTiles = atoi(FLAGS_tiles[0]);
163 yTiles = atoi(FLAGS_tiles[1]);
164 }
165
166 int x, y;
167 if (xTiles != -1 && yTiles != -1) {
168 x = xTiles;
169 y = yTiles;
170 if (x <= 0 || y <= 0) {
171 error.printf("--tiles must be given values > 0\n");
172 return NULL;
173 }
174 } else {
175 x = y = 4;
176 }
krajcevskib1aded82014-08-18 07:52:17 -0700177#if SK_SUPPORT_GPU
178 tiledRenderer.reset(SkNEW_ARGS(sk_tools::CopyTilesRenderer, (grContextOpts, x, y)));
179#else
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000180 tiledRenderer.reset(SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y)));
krajcevskib1aded82014-08-18 07:52:17 -0700181#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000182 } else {
krajcevskib1aded82014-08-18 07:52:17 -0700183 tiledRenderer.reset(SkNEW_ARGS(sk_tools::TiledPictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000184 }
185
186 if (isPowerOf2Mode) {
187 int minWidth = atoi(widthString);
188 if (!SkIsPow2(minWidth) || minWidth < 0) {
189 SkString err;
190 error.printf("-mode %s must be given a width"
191 " value that is a power of two\n", mode);
192 return NULL;
193 }
194 tiledRenderer->setTileMinPowerOf2Width(minWidth);
195 } else if (sk_tools::is_percentage(widthString)) {
196 if (isCopyMode) {
197 error.printf("--mode %s does not support percentages.\n", mode);
198 return NULL;
199 }
200 tiledRenderer->setTileWidthPercentage(atof(widthString));
201 if (!(tiledRenderer->getTileWidthPercentage() > 0)) {
202 error.printf("--mode %s must be given a width percentage > 0\n", mode);
203 return NULL;
204 }
205 } else {
206 tiledRenderer->setTileWidth(atoi(widthString));
207 if (!(tiledRenderer->getTileWidth() > 0)) {
208 error.printf("--mode %s must be given a width > 0\n", mode);
209 return NULL;
210 }
211 }
212
213 if (sk_tools::is_percentage(heightString)) {
214 if (isCopyMode) {
215 error.printf("--mode %s does not support percentages.\n", mode);
216 return NULL;
217 }
218 tiledRenderer->setTileHeightPercentage(atof(heightString));
219 if (!(tiledRenderer->getTileHeightPercentage() > 0)) {
220 error.printf("--mode %s must be given a height percentage > 0\n", mode);
221 return NULL;
222 }
223 } else {
224 tiledRenderer->setTileHeight(atoi(heightString));
225 if (!(tiledRenderer->getTileHeight() > 0)) {
226 SkString err;
227 error.printf("--mode %s must be given a height > 0\n", mode);
228 return NULL;
229 }
230 }
231
232 renderer.reset(tiledRenderer.detach());
233 if (FLAGS_pipe) {
234 error.printf("Pipe rendering is currently not compatible with tiling.\n"
235 "Turning off pipe.\n");
236 }
237
238 } else { // useTiles
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000239 if (FLAGS_pipe) {
240 if (renderer != NULL) {
241 error.printf("Pipe is incompatible with other modes.\n");
242 return NULL;
243 }
krajcevskib1aded82014-08-18 07:52:17 -0700244 renderer.reset(SkNEW_ARGS(sk_tools::PipePictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000245 }
246 }
247
248 if (NULL == renderer) {
krajcevskib1aded82014-08-18 07:52:17 -0700249 renderer.reset(SkNEW_ARGS(sk_tools::SimplePictureRenderer, RENDERER_ARGS));
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000250 }
251
252 if (FLAGS_viewport.count() > 0) {
253 if (FLAGS_viewport.count() != 2) {
254 error.printf("--viewport requires a width and a height.\n");
255 return NULL;
256 }
257 SkISize viewport;
258 viewport.fWidth = atoi(FLAGS_viewport[0]);
259 viewport.fHeight = atoi(FLAGS_viewport[1]);
260 renderer->setViewport(viewport);
261 }
262
263 sk_tools::PictureRenderer::SkDeviceTypes deviceType =
264 sk_tools::PictureRenderer::kBitmap_DeviceType;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000265#if SK_SUPPORT_GPU
kkinnunen80549fc2014-06-30 06:36:31 -0700266 GrGLStandard gpuAPI = kNone_GrGLStandard;
267 if (1 == FLAGS_gpuAPI.count()) {
268 if (FLAGS_gpuAPI.contains(kGpuAPINameGL)) {
269 gpuAPI = kGL_GrGLStandard;
270 } else if (FLAGS_gpuAPI.contains(kGpuAPINameGLES)) {
271 gpuAPI = kGLES_GrGLStandard;
272 } else {
273 error.printf("--gpuAPI invalid api value.\n");
274 return NULL;
275 }
276 } else if (FLAGS_gpuAPI.count() > 1) {
277 error.printf("--gpuAPI invalid api value.\n");
278 return NULL;
279 }
280
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000281 int sampleCount = 0;
jvanverth4736e142014-11-07 07:12:46 -0800282 bool useDFText = false;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000283#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000284 if (FLAGS_config.count() > 0) {
285 if (0 == strcmp(FLAGS_config[0], "8888")) {
286 deviceType = sk_tools::PictureRenderer::kBitmap_DeviceType;
287 }
288#if SK_SUPPORT_GPU
289 else if (0 == strcmp(FLAGS_config[0], "gpu")) {
290 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000291 }
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000292 else if (0 == strcmp(FLAGS_config[0], "msaa4")) {
293 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000294 sampleCount = 4;
295 }
296 else if (0 == strcmp(FLAGS_config[0], "msaa16")) {
297 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000298 sampleCount = 16;
299 }
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000300 else if (0 == strcmp(FLAGS_config[0], "nvprmsaa4")) {
301 deviceType = sk_tools::PictureRenderer::kNVPR_DeviceType;
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000302 sampleCount = 4;
303 }
304 else if (0 == strcmp(FLAGS_config[0], "nvprmsaa16")) {
305 deviceType = sk_tools::PictureRenderer::kNVPR_DeviceType;
commit-bot@chromium.org0fd52702014-03-07 18:41:14 +0000306 sampleCount = 16;
307 }
jvanverth4736e142014-11-07 07:12:46 -0800308 else if (0 == strcmp(FLAGS_config[0], "gpudft")) {
309 deviceType = sk_tools::PictureRenderer::kGPU_DeviceType;
310 useDFText = true;
311 }
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000312#if SK_ANGLE
313 else if (0 == strcmp(FLAGS_config[0], "angle")) {
314 deviceType = sk_tools::PictureRenderer::kAngle_DeviceType;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000315 }
316#endif
rmistry@google.com6ab96732014-01-06 18:37:24 +0000317#if SK_MESA
318 else if (0 == strcmp(FLAGS_config[0], "mesa")) {
319 deviceType = sk_tools::PictureRenderer::kMesa_DeviceType;
rmistry@google.com6ab96732014-01-06 18:37:24 +0000320 }
321#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000322#endif
323 else {
324 error.printf("%s is not a valid mode for --config\n", FLAGS_config[0]);
325 return NULL;
326 }
kkinnunen80549fc2014-06-30 06:36:31 -0700327#if SK_SUPPORT_GPU
328 if (!renderer->setDeviceType(deviceType, gpuAPI)) {
329#else
330 if (!renderer->setDeviceType(deviceType)) {
331#endif
332 error.printf("Could not create backend for --config %s\n", FLAGS_config[0]);
333 return NULL;
334 }
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000335#if SK_SUPPORT_GPU
336 renderer->setSampleCount(sampleCount);
jvanverth4736e142014-11-07 07:12:46 -0800337 renderer->setUseDFText(useDFText);
jvanverth@google.comf6a90332013-05-02 12:39:37 +0000338#endif
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000339 }
340
341
342 sk_tools::PictureRenderer::BBoxHierarchyType bbhType
343 = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
344 if (FLAGS_bbh.count() > 0) {
345 const char* type = FLAGS_bbh[0];
346 if (0 == strcmp(type, "none")) {
347 bbhType = sk_tools::PictureRenderer::kNone_BBoxHierarchyType;
348 } else if (0 == strcmp(type, "rtree")) {
349 bbhType = sk_tools::PictureRenderer::kRTree_BBoxHierarchyType;
scroggo@google.com161e1ba2013-03-04 16:41:06 +0000350 } else {
351 error.printf("%s is not a valid value for --bbhType\n", type);
352 return NULL;
353 }
354 if (FLAGS_pipe && sk_tools::PictureRenderer::kNone_BBoxHierarchyType != bbhType) {
355 error.printf("--pipe and --bbh cannot be used together\n");
356 return NULL;
357 }
358 }
359 renderer->setBBoxHierarchyType(bbhType);
360 renderer->setScaleFactor(SkDoubleToScalar(FLAGS_scale));
361
362 return renderer.detach();
363}