1 /*
2 * Copyright 2015 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 "tools/flags/CommonFlagsConfig.h"
9
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkStringView.h"
12 #include "include/core/SkSurfaceProps.h"
13 #include "include/private/SkTHash.h"
14 #include "src/core/SkColorSpacePriv.h"
15 #include "src/core/SkSurfacePriv.h"
16
17 #include <stdlib.h>
18 #include <unordered_map>
19
20 using sk_gpu_test::GrContextFactory;
21
22 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
23 #define DEFAULT_GPU_CONFIG "gles"
24 #else
25 #define DEFAULT_GPU_CONFIG "gl"
26 #endif
27
28 static const char defaultConfigs[] = "8888 " DEFAULT_GPU_CONFIG
29 " nonrendering "
30 #if SK_ANGLE && defined(SK_BUILD_FOR_WIN)
31 " angle_d3d11_es2"
32 #endif
33 ;
34
35 #undef DEFAULT_GPU_CONFIG
36
37 // clang-format off
38 static const struct {
39 const char* predefinedConfig;
40 const char* backend;
41 const char* options;
42 } gPredefinedConfigs[] = {
43 { "gl", "gpu", "api=gl" },
44 { "gles", "gpu", "api=gles" },
45 { "glesfakev2", "gpu", "api=glesfakev2" },
46 { "gldmsaa", "gpu", "api=gl,dmsaa=true" },
47 { "glesdmsaa", "gpu", "api=gles,dmsaa=true" },
48 { "glmsaa4", "gpu", "api=gl,samples=4" },
49 { "glmsaa8" , "gpu", "api=gl,samples=8" },
50 { "glesmsaa4", "gpu", "api=gles,samples=4" },
51 { "glbetex", "gpu", "api=gl,surf=betex" },
52 { "glesbetex", "gpu", "api=gles,surf=betex" },
53 { "glbert", "gpu", "api=gl,surf=bert" },
54 { "glesbert", "gpu", "api=gles,surf=bert" },
55 { "gl4444", "gpu", "api=gl,color=4444" },
56 { "gles4444", "gpu", "api=gles,color=4444" },
57 { "gl565", "gpu", "api=gl,color=565" },
58 { "gl888x", "gpu", "api=gl,color=888x" },
59 { "gles888x", "gpu", "api=gles,color=888x" },
60 { "gl1010102", "gpu", "api=gl,color=1010102" },
61 { "gles1010102", "gpu", "api=gles,color=1010102" },
62 { "glf16", "gpu", "api=gl,color=f16" },
63 { "glf16norm", "gpu", "api=gl,color=f16norm" },
64 { "glsrgba", "gpu", "api=gl,color=srgba" },
65 { "glesf16", "gpu", "api=gles,color=f16" },
66 { "glessrgba", "gpu", "api=gles,color=srgba" },
67 { "glnostencils", "gpu", "api=gl,stencils=false" },
68 { "gldft", "gpu", "api=gl,dit=true" },
69 { "glesdft", "gpu", "api=gles,dit=true" },
70 { "gltestthreading", "gpu", "api=gl,testThreading=true" },
71 { "gltestpersistentcache", "gpu", "api=gl,testPersistentCache=1" },
72 { "gltestglslcache", "gpu", "api=gl,testPersistentCache=2" },
73 { "gltestprecompile", "gpu", "api=gl,testPrecompile=true" },
74 { "glestestprecompile", "gpu", "api=gles,testPrecompile=true" },
75 { "glddl", "gpu", "api=gl,useDDLSink=true" },
76 { "glooprddl", "gpu", "api=gl,OOPRish=true" },
77 { "glreducedshaders", "gpu", "api=gl,reducedShaders=true" },
78 { "glesreducedshaders", "gpu", "api=gles,reducedShaders=true" },
79 { "angle_d3d11_es2", "gpu", "api=angle_d3d11_es2" },
80 { "angle_d3d11_es3", "gpu", "api=angle_d3d11_es3" },
81 { "angle_d3d9_es2", "gpu", "api=angle_d3d9_es2" },
82 { "angle_d3d11_es2_msaa4", "gpu", "api=angle_d3d11_es2,samples=4" },
83 { "angle_d3d11_es2_msaa8", "gpu", "api=angle_d3d11_es2,samples=8" },
84 { "angle_d3d11_es2_dmsaa", "gpu", "api=angle_d3d11_es2,dmsaa=true" },
85 { "angle_d3d11_es3_msaa4", "gpu", "api=angle_d3d11_es3,samples=4" },
86 { "angle_d3d11_es3_msaa8", "gpu", "api=angle_d3d11_es3,samples=8" },
87 { "angle_d3d11_es3_dmsaa", "gpu", "api=angle_d3d11_es3,dmsaa=true" },
88 { "angle_gl_es2", "gpu", "api=angle_gl_es2" },
89 { "angle_gl_es3", "gpu", "api=angle_gl_es3" },
90 { "angle_gl_es2_msaa4", "gpu", "api=angle_gl_es2,samples=4" },
91 { "angle_gl_es2_msaa8", "gpu", "api=angle_gl_es2,samples=8" },
92 { "angle_gl_es2_dmsaa", "gpu", "api=angle_gl_es2,dmsaa=true" },
93 { "angle_gl_es3_msaa4", "gpu", "api=angle_gl_es3,samples=4" },
94 { "angle_gl_es3_msaa8", "gpu", "api=angle_gl_es3,samples=8" },
95 { "angle_gl_es3_dmsaa", "gpu", "api=angle_gl_es3,dmsaa=true" },
96 { "cmdbuffer_es2", "gpu", "api=cmdbuffer_es2" },
97 { "cmdbuffer_es2_dmsaa", "gpu", "api=cmdbuffer_es2,dmsaa=true" },
98 { "cmdbuffer_es3", "gpu", "api=cmdbuffer_es3" },
99 { "mock", "gpu", "api=mock" },
100 #ifdef SK_DAWN
101 { "dawn", "gpu", "api=dawn" },
102 #endif
103 #ifdef SK_VULKAN
104 { "vk", "gpu", "api=vulkan" },
105 { "vkdmsaa", "gpu", "api=vulkan,dmsaa=true" },
106 { "vknostencils", "gpu", "api=vulkan,stencils=false" },
107 { "vk1010102", "gpu", "api=vulkan,color=1010102" },
108 { "vkf16", "gpu", "api=vulkan,color=f16" },
109 { "vkmsaa4", "gpu", "api=vulkan,samples=4" },
110 { "vkmsaa8", "gpu", "api=vulkan,samples=8" },
111 { "vkbetex", "gpu", "api=vulkan,surf=betex" },
112 { "vkbert", "gpu", "api=vulkan,surf=bert" },
113 { "vktestpersistentcache", "gpu", "api=vulkan,testPersistentCache=1" },
114 { "vkddl", "gpu", "api=vulkan,useDDLSink=true" },
115 { "vkooprddl", "gpu", "api=vulkan,OOPRish=true" },
116 #endif
117 #ifdef SK_METAL
118 { "mtl", "gpu", "api=metal" },
119 { "mtl1010102", "gpu", "api=metal,color=1010102" },
120 { "mtlmsaa4", "gpu", "api=metal,samples=4" },
121 { "mtlmsaa8", "gpu", "api=metal,samples=8" },
122 { "mtlddl", "gpu", "api=metal,useDDLSink=true" },
123 { "mtlooprddl", "gpu", "api=metal,OOPRish=true" },
124 { "mtltestprecompile", "gpu", "api=metal,testPrecompile=true" },
125 { "mtlreducedshaders", "gpu", "api=metal,reducedShaders=true" },
126 #endif
127 #ifdef SK_DIRECT3D
128 { "d3d", "gpu", "api=direct3d" },
129 { "d3dmsaa4", "gpu", "api=direct3d,samples=4" },
130 { "d3dmsaa8", "gpu", "api=direct3d,samples=8" },
131 #endif
132
133 #ifdef SK_GRAPHITE_ENABLED
134 #ifdef SK_DIRECT3D
135 { "grd3d", "graphite", "api=direct3d" },
136 #endif
137 #ifdef SK_METAL
138 { "grmtl", "graphite", "api=metal,testPrecompile=true" },
139 #endif
140 #ifdef SK_VULKAN
141 { "grvk", "graphite", "api=vulkan" },
142 #endif
143 #endif
144
145 };
146 // clang-format on
147
148 static const char configHelp[] =
149 "Options: 565 4444 8888 rgba bgra rgbx 1010102 101010x bgra1010102 bgr101010x f16 f16norm "
150 "f32 nonrendering null pdf pdfa pdf300 skp svg xps";
151
config_help_fn()152 static const char* config_help_fn() {
153 static SkString helpString;
154 helpString.set(configHelp);
155 for (const auto& config : gPredefinedConfigs) {
156 helpString.appendf(" %s", config.predefinedConfig);
157 }
158 helpString.append(" or use extended form 'backend[option=value,...]'.\n");
159 return helpString.c_str();
160 }
161
162 static const char configExtendedHelp[] =
163 "Extended form: 'backend(option=value,...)'\n\n"
164 "Possible backends and options:\n"
165 "\n"
166 "gpu[api=string,color=string,dit=bool,dmsaa=bool,samples=int]\n"
167 "\tapi\ttype: string\trequired\n"
168 "\t Select graphics API to use with gpu backend.\n"
169 "\t Options:\n"
170 "\t\tgl \t\t\tUse OpenGL.\n"
171 "\t\tgles \t\t\tUse OpenGL ES.\n"
172 "\t\tglesfakev2 \t\t\tUse OpenGL ES with version faked as 2.0.\n"
173 "\t\tnullgl \t\t\tUse null OpenGL.\n"
174 "\t\tangle_d3d9_es2\t\tUse OpenGL ES2 on the ANGLE Direct3D9 backend.\n"
175 "\t\tangle_d3d11_es2\t\tUse OpenGL ES2 on the ANGLE Direct3D11 backend.\n"
176 "\t\tangle_d3d11_es3\t\tUse OpenGL ES3 on the ANGLE Direct3D11 backend.\n"
177 "\t\tangle_gl_es2\t\tUse OpenGL ES2 on the ANGLE OpenGL backend.\n"
178 "\t\tangle_gl_es3\t\tUse OpenGL ES3 on the ANGLE OpenGL backend.\n"
179 "\t\tcommandbuffer\t\tUse command buffer.\n"
180 "\t\tmock\t\t\tUse mock context.\n"
181 #ifdef SK_VULKAN
182 "\t\tvulkan\t\t\tUse Vulkan.\n"
183 #endif
184 #ifdef SK_METAL
185 "\t\tmetal\t\t\tUse Metal.\n"
186 #endif
187 "\tcolor\ttype: string\tdefault: 8888.\n"
188 "\t Select framebuffer color format.\n"
189 "\t Options:\n"
190 "\t\t8888\t\t\tLinear 8888.\n"
191 "\t\t888x\t\t\tLinear 888x.\n"
192 "\t\t4444\t\t\tLinear 4444.\n"
193 "\t\t565\t\t\tLinear 565.\n"
194 "\t\t1010102\t\t\tLinear 1010102.\n"
195 "\t\tf16\t\t\t16-bit floating point.\n"
196 "\tdit\ttype: bool\tdefault: false.\n"
197 "\t Use device independent text.\n"
198 "\tdmsaa\ttype: bool\tdefault: false.\n"
199 "\t Use internal MSAA to render to non-MSAA surfaces.\n"
200 "\tsamples\ttype: int\tdefault: 0.\n"
201 "\t Use multisampling with N samples.\n"
202 "\tstencils\ttype: bool\tdefault: true.\n"
203 "\t Allow the use of stencil buffers.\n"
204 "\ttestThreading\ttype: bool\tdefault: false.\n"
205 "\t Run with and without worker threads, check that results match.\n"
206 "\ttestPersistentCache\ttype: int\tdefault: 0.\n"
207 "\t 1: Run using a pre-warmed binary GrContextOptions::fPersistentCache.\n"
208 "\t 2: Run using a pre-warmed GLSL GrContextOptions::fPersistentCache.\n"
209 "\tsurf\ttype: string\tdefault: default.\n"
210 "\t Controls the type of backing store for SkSurfaces.\n"
211 "\t Options:\n"
212 "\t\tdefault\t\t\tA renderable texture created in Skia's resource cache.\n"
213 "\t\tbetex\t\t\tA wrapped backend texture.\n"
214 "\t\tbert\t\t\tA wrapped backend render target\n"
215 "\n"
216 "Predefined configs:\n\n"
217 // Help text for pre-defined configs is auto-generated from gPredefinedConfigs
218 ;
219
config_extended_help_fn()220 static const char* config_extended_help_fn() {
221 static SkString helpString;
222 helpString.set(configExtendedHelp);
223 for (const auto& config : gPredefinedConfigs) {
224 helpString.appendf("\t%-10s\t= gpu(%s)\n", config.predefinedConfig, config.options);
225 }
226 return helpString.c_str();
227 }
228
229 DEFINE_extended_string(config, defaultConfigs, config_help_fn(), config_extended_help_fn());
230
SkCommandLineConfig(const SkString & tag,const SkString & backend,const SkTArray<SkString> & viaParts)231 SkCommandLineConfig::SkCommandLineConfig(const SkString& tag,
232 const SkString& backend,
233 const SkTArray<SkString>& viaParts)
234 : fTag(tag), fBackend(backend) {
235
236 static std::unordered_map<skstd::string_view, sk_sp<SkColorSpace>> kColorSpaces = {
237 // 'narrow' has a gamut narrower than sRGB, and different transfer function.
238 { "narrow", SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gNarrow_toXYZD50) },
239 { "srgb", SkColorSpace::MakeSRGB() },
240 { "linear", SkColorSpace::MakeSRGBLinear() },
241 { "p3", SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3) },
242 { "spin", SkColorSpace::MakeSRGB()->makeColorSpin() },
243 { "rec2020", SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020) },
244 };
245
246 // Strip off any via parts that refer to color spaces (and remember the last one we see)
247 for (const SkString& via : viaParts) {
248 auto it = kColorSpaces.find(via.c_str());
249 if (it == kColorSpaces.end()) {
250 fViaParts.push_back(via);
251 } else {
252 fColorSpace = it->second;
253 }
254 }
255 }
256
~SkCommandLineConfig()257 SkCommandLineConfig::~SkCommandLineConfig() {}
258
parse_option_int(const SkString & value,int * outInt)259 static bool parse_option_int(const SkString& value, int* outInt) {
260 if (value.isEmpty()) {
261 return false;
262 }
263 char* endptr = nullptr;
264 long intValue = strtol(value.c_str(), &endptr, 10);
265 if (*endptr != '\0') {
266 return false;
267 }
268 *outInt = static_cast<int>(intValue);
269 return true;
270 }
parse_option_bool(const SkString & value,bool * outBool)271 static bool parse_option_bool(const SkString& value, bool* outBool) {
272 if (value.equals("true")) {
273 *outBool = true;
274 return true;
275 }
276 if (value.equals("false")) {
277 *outBool = false;
278 return true;
279 }
280 return false;
281 }
parse_option_gpu_api(const SkString & value,SkCommandLineConfigGpu::ContextType * outContextType,bool * outFakeGLESVersion2)282 static bool parse_option_gpu_api(const SkString& value,
283 SkCommandLineConfigGpu::ContextType* outContextType,
284 bool* outFakeGLESVersion2) {
285 *outFakeGLESVersion2 = false;
286 if (value.equals("gl")) {
287 *outContextType = GrContextFactory::kGL_ContextType;
288 return true;
289 }
290 if (value.equals("gles")) {
291 *outContextType = GrContextFactory::kGLES_ContextType;
292 return true;
293 }
294 if (value.equals("glesfakev2")) {
295 *outContextType = GrContextFactory::kGLES_ContextType;
296 *outFakeGLESVersion2 = true;
297 return true;
298 }
299 if (value.equals("angle_d3d9_es2")) {
300 *outContextType = GrContextFactory::kANGLE_D3D9_ES2_ContextType;
301 return true;
302 }
303 if (value.equals("angle_d3d11_es2")) {
304 *outContextType = GrContextFactory::kANGLE_D3D11_ES2_ContextType;
305 return true;
306 }
307 if (value.equals("angle_d3d11_es3")) {
308 *outContextType = GrContextFactory::kANGLE_D3D11_ES3_ContextType;
309 return true;
310 }
311 if (value.equals("angle_gl_es2")) {
312 *outContextType = GrContextFactory::kANGLE_GL_ES2_ContextType;
313 return true;
314 }
315 if (value.equals("angle_gl_es3")) {
316 *outContextType = GrContextFactory::kANGLE_GL_ES3_ContextType;
317 return true;
318 }
319 if (value.equals("cmdbuffer_es2")) {
320 *outContextType = GrContextFactory::kCommandBuffer_ES2_ContextType;
321 return true;
322 }
323 if (value.equals("cmdbuffer_es3")) {
324 *outContextType = GrContextFactory::kCommandBuffer_ES3_ContextType;
325 return true;
326 }
327 if (value.equals("mock")) {
328 *outContextType = GrContextFactory::kMock_ContextType;
329 return true;
330 }
331 #ifdef SK_VULKAN
332 if (value.equals("vulkan")) {
333 *outContextType = GrContextFactory::kVulkan_ContextType;
334 return true;
335 }
336 #endif
337 #ifdef SK_METAL
338 if (value.equals("metal")) {
339 *outContextType = GrContextFactory::kMetal_ContextType;
340 return true;
341 }
342 #endif
343 #ifdef SK_DIRECT3D
344 if (value.equals("direct3d")) {
345 *outContextType = GrContextFactory::kDirect3D_ContextType;
346 return true;
347 }
348 #endif
349 #ifdef SK_DAWN
350 if (value.equals("dawn")) {
351 *outContextType = GrContextFactory::kDawn_ContextType;
352 return true;
353 }
354 #endif
355 return false;
356 }
357
parse_option_gpu_color(const SkString & value,SkColorType * outColorType,SkAlphaType * alphaType)358 static bool parse_option_gpu_color(const SkString& value,
359 SkColorType* outColorType,
360 SkAlphaType* alphaType) {
361 // We always use premul unless the color type is 565.
362 *alphaType = kPremul_SkAlphaType;
363
364 if (value.equals("8888")) {
365 *outColorType = kRGBA_8888_SkColorType;
366 } else if (value.equals("888x")) {
367 *outColorType = kRGB_888x_SkColorType;
368 } else if (value.equals("bgra8")) {
369 *outColorType = kBGRA_8888_SkColorType;
370 } else if (value.equals("4444")) {
371 *outColorType = kARGB_4444_SkColorType;
372 } else if (value.equals("565")) {
373 *outColorType = kRGB_565_SkColorType;
374 *alphaType = kOpaque_SkAlphaType;
375 } else if (value.equals("1010102")) {
376 *outColorType = kRGBA_1010102_SkColorType;
377 } else if (value.equals("f16")) {
378 *outColorType = kRGBA_F16_SkColorType;
379 } else if (value.equals("f16norm")) {
380 *outColorType = kRGBA_F16Norm_SkColorType;
381 } else if (value.equals("srgba")) {
382 *outColorType = kSRGBA_8888_SkColorType;
383 } else {
384 return false;
385 }
386 return true;
387 }
388
parse_option_gpu_surf_type(const SkString & value,SkCommandLineConfigGpu::SurfType * surfType)389 static bool parse_option_gpu_surf_type(const SkString& value,
390 SkCommandLineConfigGpu::SurfType* surfType) {
391 if (value.equals("default")) {
392 *surfType = SkCommandLineConfigGpu::SurfType::kDefault;
393 return true;
394 }
395 if (value.equals("betex")) {
396 *surfType = SkCommandLineConfigGpu::SurfType::kBackendTexture;
397 return true;
398 }
399 if (value.equals("bert")) {
400 *surfType = SkCommandLineConfigGpu::SurfType::kBackendRenderTarget;
401 return true;
402 }
403 return false;
404 }
405
406 // Extended options take form --config item[key1=value1,key2=value2,...]
407 // Example: --config gpu[api=gl,color=8888]
408 class ExtendedOptions {
409 public:
ExtendedOptions(const SkString & optionsString,bool * outParseSucceeded)410 ExtendedOptions(const SkString& optionsString, bool* outParseSucceeded) {
411 SkTArray<SkString> optionParts;
412 SkStrSplit(optionsString.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
413 for (int i = 0; i < optionParts.count(); ++i) {
414 SkTArray<SkString> keyValueParts;
415 SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts);
416 if (keyValueParts.count() != 2) {
417 *outParseSucceeded = false;
418 return;
419 }
420 const SkString& key = keyValueParts[0];
421 const SkString& value = keyValueParts[1];
422 if (fOptionsMap.find(key) == nullptr) {
423 fOptionsMap.set(key, value);
424 } else {
425 // Duplicate values are not allowed.
426 *outParseSucceeded = false;
427 return;
428 }
429 }
430 *outParseSucceeded = true;
431 }
432
get_option_gpu_color(const char * optionKey,SkColorType * outColorType,SkAlphaType * alphaType,bool optional=true) const433 bool get_option_gpu_color(const char* optionKey,
434 SkColorType* outColorType,
435 SkAlphaType* alphaType,
436 bool optional = true) const {
437 SkString* optionValue = fOptionsMap.find(SkString(optionKey));
438 if (optionValue == nullptr) {
439 return optional;
440 }
441 return parse_option_gpu_color(*optionValue, outColorType, alphaType);
442 }
443
get_option_gpu_api(const char * optionKey,SkCommandLineConfigGpu::ContextType * outContextType,bool * outFakeGLESVersion2,bool optional=true) const444 bool get_option_gpu_api(const char* optionKey,
445 SkCommandLineConfigGpu::ContextType* outContextType,
446 bool* outFakeGLESVersion2,
447 bool optional = true) const {
448 SkString* optionValue = fOptionsMap.find(SkString(optionKey));
449 if (optionValue == nullptr) {
450 return optional;
451 }
452 return parse_option_gpu_api(*optionValue, outContextType, outFakeGLESVersion2);
453 }
454
455 #ifdef SK_GRAPHITE_ENABLED
get_option_graphite_api(const char * optionKey,SkCommandLineConfigGraphite::ContextType * outContextType) const456 bool get_option_graphite_api(const char* optionKey,
457 SkCommandLineConfigGraphite::ContextType* outContextType) const {
458 using ContextType = skiatest::graphite::ContextFactory::ContextType;
459
460 SkString* optionValue = fOptionsMap.find(SkString(optionKey));
461 if (optionValue == nullptr) {
462 return false;
463 }
464 #ifdef SK_VULKAN
465 if (optionValue->equals("vulkan")) {
466 *outContextType = ContextType::kVulkan;
467 return true;
468 }
469 #endif
470 #ifdef SK_METAL
471 if (optionValue->equals("metal")) {
472 *outContextType = ContextType::kMetal;
473 return true;
474 }
475 #endif
476 #ifdef SK_DIRECT3D
477 if (optionValue->equals("direct3d")) {
478 *outContextType = ContextType::kDirect3D;
479 return true;
480 }
481 #endif
482 return false;
483 }
484 #endif
485
get_option_gpu_surf_type(const char * optionKey,SkCommandLineConfigGpu::SurfType * outSurfType,bool optional=true) const486 bool get_option_gpu_surf_type(const char* optionKey,
487 SkCommandLineConfigGpu::SurfType* outSurfType,
488 bool optional = true) const {
489 SkString* optionValue = fOptionsMap.find(SkString(optionKey));
490 if (optionValue == nullptr) {
491 return optional;
492 }
493 return parse_option_gpu_surf_type(*optionValue, outSurfType);
494 }
495
get_option_int(const char * optionKey,int * outInt,bool optional=true) const496 bool get_option_int(const char* optionKey, int* outInt, bool optional = true) const {
497 SkString* optionValue = fOptionsMap.find(SkString(optionKey));
498 if (optionValue == nullptr) {
499 return optional;
500 }
501 return parse_option_int(*optionValue, outInt);
502 }
503
get_option_bool(const char * optionKey,bool * outBool,bool optional=true) const504 bool get_option_bool(const char* optionKey, bool* outBool, bool optional = true) const {
505 SkString* optionValue = fOptionsMap.find(SkString(optionKey));
506 if (optionValue == nullptr) {
507 return optional;
508 }
509 return parse_option_bool(*optionValue, outBool);
510 }
511
512 private:
513 SkTHashMap<SkString, SkString> fOptionsMap;
514 };
515
SkCommandLineConfigGpu(const SkString & tag,const SkTArray<SkString> & viaParts,ContextType contextType,bool fakeGLESVersion2,uint32_t surfaceFlags,int samples,SkColorType colorType,SkAlphaType alphaType,bool useStencilBuffers,bool testThreading,int testPersistentCache,bool testPrecompile,bool useDDLSink,bool OOPRish,bool reducedShaders,SurfType surfType)516 SkCommandLineConfigGpu::SkCommandLineConfigGpu(const SkString& tag,
517 const SkTArray<SkString>& viaParts,
518 ContextType contextType,
519 bool fakeGLESVersion2,
520 uint32_t surfaceFlags,
521 int samples,
522 SkColorType colorType,
523 SkAlphaType alphaType,
524 bool useStencilBuffers,
525 bool testThreading,
526 int testPersistentCache,
527 bool testPrecompile,
528 bool useDDLSink,
529 bool OOPRish,
530 bool reducedShaders,
531 SurfType surfType)
532 : SkCommandLineConfig(tag, SkString("gpu"), viaParts)
533 , fContextType(contextType)
534 , fContextOverrides(ContextOverrides::kNone)
535 , fSurfaceFlags(surfaceFlags)
536 , fSamples(samples)
537 , fColorType(colorType)
538 , fAlphaType(alphaType)
539 , fTestThreading(testThreading)
540 , fTestPersistentCache(testPersistentCache)
541 , fTestPrecompile(testPrecompile)
542 , fUseDDLSink(useDDLSink)
543 , fOOPRish(OOPRish)
544 , fReducedShaders(reducedShaders)
545 , fSurfType(surfType) {
546 if (!useStencilBuffers) {
547 fContextOverrides |= ContextOverrides::kAvoidStencilBuffers;
548 }
549 if (fakeGLESVersion2) {
550 fContextOverrides |= ContextOverrides::kFakeGLESVersionAs2;
551 }
552 if (reducedShaders) {
553 fContextOverrides |= ContextOverrides ::kReducedShaders;
554 }
555 }
556
parse_command_line_config_gpu(const SkString & tag,const SkTArray<SkString> & vias,const SkString & options)557 SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString& tag,
558 const SkTArray<SkString>& vias,
559 const SkString& options) {
560 // Defaults for GPU backend.
561 SkCommandLineConfigGpu::ContextType contextType = GrContextFactory::kGL_ContextType;
562 bool useDIText = false;
563 bool useDMSAA = false;
564 int samples = 1;
565 SkColorType colorType = kRGBA_8888_SkColorType;
566 SkAlphaType alphaType = kPremul_SkAlphaType;
567 bool useStencils = true;
568 bool testThreading = false;
569 int testPersistentCache = 0;
570 bool testPrecompile = false;
571 bool useDDLs = false;
572 bool ooprish = false;
573 bool reducedShaders = false;
574 bool fakeGLESVersion2 = false;
575 SkCommandLineConfigGpu::SurfType surfType = SkCommandLineConfigGpu::SurfType::kDefault;
576
577 bool parseSucceeded = false;
578 ExtendedOptions extendedOptions(options, &parseSucceeded);
579 if (!parseSucceeded) {
580 return nullptr;
581 }
582
583 bool validOptions =
584 extendedOptions.get_option_gpu_api("api", &contextType, &fakeGLESVersion2, false) &&
585 extendedOptions.get_option_bool("dit", &useDIText) &&
586 extendedOptions.get_option_int("samples", &samples) &&
587 extendedOptions.get_option_bool("dmsaa", &useDMSAA) &&
588 extendedOptions.get_option_gpu_color("color", &colorType, &alphaType) &&
589 extendedOptions.get_option_bool("stencils", &useStencils) &&
590 extendedOptions.get_option_bool("testThreading", &testThreading) &&
591 extendedOptions.get_option_int("testPersistentCache", &testPersistentCache) &&
592 extendedOptions.get_option_bool("testPrecompile", &testPrecompile) &&
593 extendedOptions.get_option_bool("useDDLSink", &useDDLs) &&
594 extendedOptions.get_option_bool("OOPRish", &ooprish) &&
595 extendedOptions.get_option_bool("reducedShaders", &reducedShaders) &&
596 extendedOptions.get_option_gpu_surf_type("surf", &surfType);
597
598 // testing threading and the persistent cache are mutually exclusive.
599 if (!validOptions || (testThreading && (testPersistentCache != 0))) {
600 return nullptr;
601 }
602
603 uint32_t surfaceFlags = 0;
604 if (useDIText) {
605 surfaceFlags |= SkSurfaceProps::kUseDeviceIndependentFonts_Flag;
606 }
607 if (useDMSAA) {
608 surfaceFlags |= SkSurfaceProps::kDynamicMSAA_Flag;
609 }
610
611 return new SkCommandLineConfigGpu(tag,
612 vias,
613 contextType,
614 fakeGLESVersion2,
615 surfaceFlags,
616 samples,
617 colorType,
618 alphaType,
619 useStencils,
620 testThreading,
621 testPersistentCache,
622 testPrecompile,
623 useDDLs,
624 ooprish,
625 reducedShaders,
626 surfType);
627 }
628
629 #ifdef SK_GRAPHITE_ENABLED
630
parse_command_line_config_graphite(const SkString & tag,const SkTArray<SkString> & vias,const SkString & options)631 SkCommandLineConfigGraphite* parse_command_line_config_graphite(const SkString& tag,
632 const SkTArray<SkString>& vias,
633 const SkString& options) {
634 using ContextType = skiatest::graphite::ContextFactory::ContextType;
635
636 ContextType contextType = ContextType::kMetal;
637 SkColorType colorType = kRGBA_8888_SkColorType;
638 SkAlphaType alphaType = kPremul_SkAlphaType;
639 bool testPrecompile = false;
640
641 bool parseSucceeded = false;
642 ExtendedOptions extendedOptions(options, &parseSucceeded);
643 if (!parseSucceeded) {
644 return nullptr;
645 }
646
647 bool validOptions = extendedOptions.get_option_graphite_api("api", &contextType) &&
648 extendedOptions.get_option_gpu_color("color", &colorType, &alphaType) &&
649 extendedOptions.get_option_bool("testPrecompile", &testPrecompile);
650 if (!validOptions) {
651 return nullptr;
652 }
653
654 return new SkCommandLineConfigGraphite(tag,
655 vias,
656 contextType,
657 colorType,
658 alphaType,
659 testPrecompile);
660 }
661
662 #endif
663
SkCommandLineConfigSvg(const SkString & tag,const SkTArray<SkString> & viaParts,int pageIndex)664 SkCommandLineConfigSvg::SkCommandLineConfigSvg(const SkString& tag,
665 const SkTArray<SkString>& viaParts,
666 int pageIndex)
667 : SkCommandLineConfig(tag, SkString("svg"), viaParts), fPageIndex(pageIndex) {}
668
parse_command_line_config_svg(const SkString & tag,const SkTArray<SkString> & vias,const SkString & options)669 SkCommandLineConfigSvg* parse_command_line_config_svg(const SkString& tag,
670 const SkTArray<SkString>& vias,
671 const SkString& options) {
672 // Defaults for SVG backend.
673 int pageIndex = 0;
674
675 bool parseSucceeded = false;
676 ExtendedOptions extendedOptions(options, &parseSucceeded);
677 if (!parseSucceeded) {
678 return nullptr;
679 }
680
681 bool validOptions = extendedOptions.get_option_int("page", &pageIndex);
682
683 if (!validOptions) {
684 return nullptr;
685 }
686
687 return new SkCommandLineConfigSvg(tag, vias, pageIndex);
688 }
689
ParseConfigs(const CommandLineFlags::StringArray & configs,SkCommandLineConfigArray * outResult)690 void ParseConfigs(const CommandLineFlags::StringArray& configs,
691 SkCommandLineConfigArray* outResult) {
692 outResult->reset();
693 for (int i = 0; i < configs.count(); ++i) {
694 SkString extendedBackend;
695 SkString extendedOptions;
696 SkString simpleBackend;
697 SkTArray<SkString> vias;
698
699 SkString tag(configs[i]);
700 SkTArray<SkString> parts;
701 SkStrSplit(tag.c_str(), "[", kStrict_SkStrSplitMode, &parts);
702 if (parts.count() == 2) {
703 SkTArray<SkString> parts2;
704 SkStrSplit(parts[1].c_str(), "]", kStrict_SkStrSplitMode, &parts2);
705 if (parts2.count() == 2 && parts2[1].isEmpty()) {
706 SkStrSplit(parts[0].c_str(), "-", kStrict_SkStrSplitMode, &vias);
707 if (vias.count()) {
708 extendedBackend = vias[vias.count() - 1];
709 vias.pop_back();
710 } else {
711 extendedBackend = parts[0];
712 }
713 extendedOptions = parts2[0];
714 simpleBackend.printf("%s[%s]", extendedBackend.c_str(), extendedOptions.c_str());
715 }
716 }
717
718 if (extendedBackend.isEmpty()) {
719 simpleBackend = tag;
720 SkStrSplit(tag.c_str(), "-", kStrict_SkStrSplitMode, &vias);
721 if (vias.count()) {
722 simpleBackend = vias[vias.count() - 1];
723 vias.pop_back();
724 }
725 for (auto& predefinedConfig : gPredefinedConfigs) {
726 if (simpleBackend.equals(predefinedConfig.predefinedConfig)) {
727 extendedBackend = predefinedConfig.backend;
728 extendedOptions = predefinedConfig.options;
729 break;
730 }
731 }
732 }
733 SkCommandLineConfig* parsedConfig = nullptr;
734 if (extendedBackend.equals("gpu")) {
735 parsedConfig = parse_command_line_config_gpu(tag, vias, extendedOptions);
736 }
737 #ifdef SK_GRAPHITE_ENABLED
738 if (extendedBackend.equals("graphite")) {
739 parsedConfig = parse_command_line_config_graphite(tag, vias, extendedOptions);
740 }
741 #endif
742 if (extendedBackend.equals("svg")) {
743 parsedConfig = parse_command_line_config_svg(tag, vias, extendedOptions);
744 }
745 if (!parsedConfig) {
746 parsedConfig = new SkCommandLineConfig(tag, simpleBackend, vias);
747 }
748 outResult->emplace_back(parsedConfig);
749 }
750 }
751