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