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