• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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