• 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 "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