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 "include/core/SkImageInfo.h"
9 #include "include/private/SkTHash.h"
10 #include "src/core/SkColorSpacePriv.h"
11 #include "tools/flags/CommonFlagsConfig.h"
12 
13 #include <stdlib.h>
14 
15 using sk_gpu_test::GrContextFactory;
16 
17 #if defined(SK_BUILD_FOR_ANDROID) || defined(SK_BUILD_FOR_IOS)
18 #define DEFAULT_GPU_CONFIG "gles"
19 #else
20 #define DEFAULT_GPU_CONFIG "gl"
21 #endif
22 
23 static const char defaultConfigs[] = "8888 " DEFAULT_GPU_CONFIG
24                                      " nonrendering "
25 #if SK_ANGLE && defined(SK_BUILD_FOR_WIN)
26                                      " angle_d3d11_es2"
27 #endif
28         ;
29 
30 #undef DEFAULT_GPU_CONFIG
31 
32 // clang-format off
33 static const struct {
34     const char* predefinedConfig;
35     const char* backend;
36     const char* options;
37 } gPredefinedConfigs[] = {
38     { "gl",                    "gpu", "api=gl" },
39     { "gles",                  "gpu", "api=gles" },
40     { "glesfakev2",            "gpu", "api=glesfakev2" },
41     { "glmsaa4",               "gpu", "api=gl,samples=4" },
42     { "glmsaa8" ,              "gpu", "api=gl,samples=8" },
43     { "glesmsaa4",             "gpu", "api=gles,samples=4" },
44     { "glbetex",               "gpu", "api=gl,surf=betex" },
45     { "glesbetex",             "gpu", "api=gles,surf=betex" },
46     { "glbert",                "gpu", "api=gl,surf=bert" },
47     { "glesbert",              "gpu", "api=gles,surf=bert" },
48     { "gl4444",                "gpu", "api=gl,color=4444" },
49     { "gles4444",              "gpu", "api=gles,color=4444" },
50     { "gl565",                 "gpu", "api=gl,color=565" },
51     { "gl888x",                "gpu", "api=gl,color=888x" },
52     { "gles888x",              "gpu", "api=gles,color=888x" },
53     { "gl1010102",             "gpu", "api=gl,color=1010102" },
54     { "gles1010102",           "gpu", "api=gles,color=1010102" },
55     { "glsrgb",                "gpu", "api=gl,color=srgb" },
56     { "glp3",                  "gpu", "api=gl,color=p3" },
57     { "glesrgb",               "gpu", "api=gl,color=esrgb" },
58     { "glnarrow",              "gpu", "api=gl,color=narrow" },
59     { "glenarrow",             "gpu", "api=gl,color=enarrow" },
60     { "glf16",                 "gpu", "api=gl,color=f16" },
61     { "glf16norm",             "gpu", "api=gl,color=f16norm" },
62     { "glessrgb",              "gpu", "api=gles,color=srgb" },
63     { "glesesrgb",             "gpu", "api=gles,color=esrgb" },
64     { "glesnarrow",            "gpu", "api=gles,color=narrow" },
65     { "glesenarrow",           "gpu", "api=gles,color=enarrow" },
66     { "glesf16",               "gpu", "api=gles,color=f16" },
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     { "angle_d3d11_es2",       "gpu", "api=angle_d3d11_es2" },
78     { "angle_d3d11_es3",       "gpu", "api=angle_d3d11_es3" },
79     { "angle_d3d9_es2",        "gpu", "api=angle_d3d9_es2" },
80     { "angle_d3d11_es2_msaa4", "gpu", "api=angle_d3d11_es2,samples=4" },
81     { "angle_d3d11_es2_msaa8", "gpu", "api=angle_d3d11_es2,samples=8" },
82     { "angle_d3d11_es3_msaa4", "gpu", "api=angle_d3d11_es3,samples=4" },
83     { "angle_d3d11_es3_msaa8", "gpu", "api=angle_d3d11_es3,samples=8" },
84     { "angle_gl_es2",          "gpu", "api=angle_gl_es2" },
85     { "angle_gl_es3",          "gpu", "api=angle_gl_es3" },
86     { "angle_gl_es2_msaa8",    "gpu", "api=angle_gl_es2,samples=8" },
87     { "angle_gl_es3_msaa8",    "gpu", "api=angle_gl_es3,samples=8" },
88     { "commandbuffer",         "gpu", "api=commandbuffer" },
89     { "mock",                  "gpu", "api=mock" },
90 #ifdef SK_DAWN
91     { "dawn",                  "gpu", "api=dawn" },
92 #endif
93 #ifdef SK_VULKAN
94     { "vk",                    "gpu", "api=vulkan" },
95     { "vknostencils",          "gpu", "api=vulkan,stencils=false" },
96     { "vk1010102",             "gpu", "api=vulkan,color=1010102" },
97     { "vksrgb",                "gpu", "api=vulkan,color=srgb" },
98     { "vkesrgb",               "gpu", "api=vulkan,color=esrgb" },
99     { "vknarrow",              "gpu", "api=vulkan,color=narrow" },
100     { "vkenarrow",             "gpu", "api=vulkan,color=enarrow" },
101     { "vkf16",                 "gpu", "api=vulkan,color=f16" },
102     { "vkmsaa4",               "gpu", "api=vulkan,samples=4" },
103     { "vkmsaa8",               "gpu", "api=vulkan,samples=8" },
104     { "vkbetex",               "gpu", "api=vulkan,surf=betex" },
105     { "vkbert",                "gpu", "api=vulkan,surf=bert" },
106     { "vktestpersistentcache", "gpu", "api=vulkan,testPersistentCache=1" },
107     { "vkddl",                 "gpu", "api=vulkan,useDDLSink=true" },
108     { "vkooprddl",             "gpu", "api=vulkan,OOPRish=true" },
109 #endif
110 #ifdef SK_METAL
111     { "mtl",                   "gpu", "api=metal" },
112     { "mtl1010102",            "gpu", "api=metal,color=1010102" },
113     { "mtlmsaa4",              "gpu", "api=metal,samples=4" },
114     { "mtlmsaa8",              "gpu", "api=metal,samples=8" },
115     { "mtlddl",                "gpu", "api=metal,useDDLSink=true" },
116     { "mtlooprddl",            "gpu", "api=metal,OOPRish=true" },
117 #endif
118 #ifdef SK_DIRECT3D
119     { "d3d",                   "gpu", "api=direct3d" },
120     { "d3dmsaa4",              "gpu", "api=direct3d,samples=4" },
121     { "d3dmsaa8",              "gpu", "api=direct3d,samples=8" },
122 #endif
123 };
124 // clang-format on
125 
126 static const char configHelp[] =
127         "Options: 565 8888 srgb f16 nonrendering null pdf pdfa skp pipe svg xps";
128 
config_help_fn()129 static const char* config_help_fn() {
130     static SkString helpString;
131     helpString.set(configHelp);
132     for (const auto& config : gPredefinedConfigs) {
133         helpString.appendf(" %s", config.predefinedConfig);
134     }
135     helpString.append(" or use extended form 'backend[option=value,...]'.\n");
136     return helpString.c_str();
137 }
138 
139 static const char configExtendedHelp[] =
140         "Extended form: 'backend(option=value,...)'\n\n"
141         "Possible backends and options:\n"
142         "\n"
143         "gpu[api=string,color=string,dit=bool,samples=int]\n"
144         "\tapi\ttype: string\trequired\n"
145         "\t    Select graphics API to use with gpu backend.\n"
146         "\t    Options:\n"
147         "\t\tgl    \t\t\tUse OpenGL.\n"
148         "\t\tgles  \t\t\tUse OpenGL ES.\n"
149         "\t\tglesfakev2  \t\t\tUse OpenGL ES with version faked as 2.0.\n"
150         "\t\tnullgl \t\t\tUse null OpenGL.\n"
151         "\t\tangle_d3d9_es2\t\tUse OpenGL ES2 on the ANGLE Direct3D9 backend.\n"
152         "\t\tangle_d3d11_es2\t\tUse OpenGL ES2 on the ANGLE Direct3D11 backend.\n"
153         "\t\tangle_d3d11_es3\t\tUse OpenGL ES3 on the ANGLE Direct3D11 backend.\n"
154         "\t\tangle_gl_es2\t\tUse OpenGL ES2 on the ANGLE OpenGL backend.\n"
155         "\t\tangle_gl_es3\t\tUse OpenGL ES3 on the ANGLE OpenGL backend.\n"
156         "\t\tcommandbuffer\t\tUse command buffer.\n"
157         "\t\tmock\t\t\tUse mock context.\n"
158 #ifdef SK_VULKAN
159         "\t\tvulkan\t\t\tUse Vulkan.\n"
160 #endif
161 #ifdef SK_METAL
162         "\t\tmetal\t\t\tUse Metal.\n"
163 #endif
164         "\tcolor\ttype: string\tdefault: 8888.\n"
165         "\t    Select framebuffer color format.\n"
166         "\t    Options:\n"
167         "\t\t8888\t\t\tLinear 8888.\n"
168         "\t\t888x\t\t\tLinear 888x.\n"
169         "\t\t4444\t\t\tLinear 4444.\n"
170         "\t\t565\t\t\tLinear 565.\n"
171         "\t\t1010102\t\t\tLinear 1010102.\n"
172         "\t\tsrgb\t\t\tsRGB 8888.\n"
173         "\t\tesrgb\t\t\tsRGB 16-bit floating point.\n"
174         "\t\tnarrow\t\t\tNarrow gamut 8888.\n"
175         "\t\tenarrow\t\t\tNarrow gamut 16-bit floating point.\n"
176         "\t\tf16\t\t\tLinearly blended 16-bit floating point.\n"
177         "\tdit\ttype: bool\tdefault: false.\n"
178         "\t    Use device independent text.\n"
179         "\tsamples\ttype: int\tdefault: 0.\n"
180         "\t    Use multisampling with N samples.\n"
181         "\tstencils\ttype: bool\tdefault: true.\n"
182         "\t    Allow the use of stencil buffers.\n"
183         "\ttestThreading\ttype: bool\tdefault: false.\n"
184         "\t    Run with and without worker threads, check that results match.\n"
185         "\ttestPersistentCache\ttype: int\tdefault: 0.\n"
186         "\t    1: Run using a pre-warmed binary GrContextOptions::fPersistentCache.\n"
187         "\t    2: Run using a pre-warmed GLSL GrContextOptions::fPersistentCache.\n"
188         "\tsurf\ttype: string\tdefault: default.\n"
189         "\t    Controls the type of backing store for SkSurfaces.\n"
190         "\t    Options:\n"
191         "\t\tdefault\t\t\tA renderable texture created in Skia's resource cache.\n"
192         "\t\tbetex\t\t\tA wrapped backend texture.\n"
193         "\t\tbert\t\t\tA wrapped backend render target\n"
194         "\n"
195         "Predefined configs:\n\n"
196         // Help text for pre-defined configs is auto-generated from gPredefinedConfigs
197         ;
198 
config_extended_help_fn()199 static const char* config_extended_help_fn() {
200     static SkString helpString;
201     helpString.set(configExtendedHelp);
202     for (const auto& config : gPredefinedConfigs) {
203         helpString.appendf("\t%-10s\t= gpu(%s)\n", config.predefinedConfig, config.options);
204     }
205     return helpString.c_str();
206 }
207 
208 DEFINE_extended_string(config, defaultConfigs, config_help_fn(), config_extended_help_fn());
209 
SkCommandLineConfig(const SkString & tag,const SkString & backend,const SkTArray<SkString> & viaParts)210 SkCommandLineConfig::SkCommandLineConfig(const SkString&           tag,
211                                          const SkString&           backend,
212                                          const SkTArray<SkString>& viaParts)
213         : fTag(tag), fBackend(backend), fViaParts(viaParts) {}
~SkCommandLineConfig()214 SkCommandLineConfig::~SkCommandLineConfig() {}
215 
parse_option_int(const SkString & value,int * outInt)216 static bool parse_option_int(const SkString& value, int* outInt) {
217     if (value.isEmpty()) {
218         return false;
219     }
220     char* endptr   = nullptr;
221     long  intValue = strtol(value.c_str(), &endptr, 10);
222     if (*endptr != '\0') {
223         return false;
224     }
225     *outInt = static_cast<int>(intValue);
226     return true;
227 }
parse_option_bool(const SkString & value,bool * outBool)228 static bool parse_option_bool(const SkString& value, bool* outBool) {
229     if (value.equals("true")) {
230         *outBool = true;
231         return true;
232     }
233     if (value.equals("false")) {
234         *outBool = false;
235         return true;
236     }
237     return false;
238 }
parse_option_gpu_api(const SkString & value,SkCommandLineConfigGpu::ContextType * outContextType,bool * outFakeGLESVersion2)239 static bool parse_option_gpu_api(const SkString&                      value,
240                                  SkCommandLineConfigGpu::ContextType* outContextType,
241                                  bool*                                outFakeGLESVersion2) {
242     *outFakeGLESVersion2 = false;
243     if (value.equals("gl")) {
244         *outContextType = GrContextFactory::kGL_ContextType;
245         return true;
246     }
247     if (value.equals("gles")) {
248         *outContextType = GrContextFactory::kGLES_ContextType;
249         return true;
250     }
251     if (value.equals("glesfakev2")) {
252         *outContextType = GrContextFactory::kGLES_ContextType;
253         *outFakeGLESVersion2 = true;
254         return true;
255     }
256     if (value.equals("angle_d3d9_es2")) {
257         *outContextType = GrContextFactory::kANGLE_D3D9_ES2_ContextType;
258         return true;
259     }
260     if (value.equals("angle_d3d11_es2")) {
261         *outContextType = GrContextFactory::kANGLE_D3D11_ES2_ContextType;
262         return true;
263     }
264     if (value.equals("angle_d3d11_es3")) {
265         *outContextType = GrContextFactory::kANGLE_D3D11_ES3_ContextType;
266         return true;
267     }
268     if (value.equals("angle_gl_es2")) {
269         *outContextType = GrContextFactory::kANGLE_GL_ES2_ContextType;
270         return true;
271     }
272     if (value.equals("angle_gl_es3")) {
273         *outContextType = GrContextFactory::kANGLE_GL_ES3_ContextType;
274         return true;
275     }
276     if (value.equals("commandbuffer")) {
277         *outContextType = GrContextFactory::kCommandBuffer_ContextType;
278         return true;
279     }
280     if (value.equals("mock")) {
281         *outContextType = GrContextFactory::kMock_ContextType;
282         return true;
283     }
284 #ifdef SK_VULKAN
285     if (value.equals("vulkan")) {
286         *outContextType = GrContextFactory::kVulkan_ContextType;
287         return true;
288     }
289 #endif
290 #ifdef SK_METAL
291     if (value.equals("metal")) {
292         *outContextType = GrContextFactory::kMetal_ContextType;
293         return true;
294     }
295 #endif
296 #ifdef SK_DIRECT3D
297     if (value.equals("direct3d")) {
298         *outContextType = GrContextFactory::kDirect3D_ContextType;
299         return true;
300     }
301 #endif
302 #ifdef SK_DAWN
303     if (value.equals("dawn")) {
304         *outContextType = GrContextFactory::kDawn_ContextType;
305         return true;
306     }
307 #endif
308     return false;
309 }
310 
parse_option_gpu_color(const SkString & value,SkColorType * outColorType,SkAlphaType * alphaType,sk_sp<SkColorSpace> * outColorSpace)311 static bool parse_option_gpu_color(const SkString&      value,
312                                    SkColorType*         outColorType,
313                                    SkAlphaType*         alphaType,
314                                    sk_sp<SkColorSpace>* outColorSpace) {
315     // We always use premul unless the color type is 565.
316     *alphaType = kPremul_SkAlphaType;
317 
318     if (value.equals("8888")) {
319         *outColorType  = kRGBA_8888_SkColorType;
320         *outColorSpace = nullptr;
321     } else if (value.equals("888x")) {
322         *outColorType  = kRGB_888x_SkColorType;
323         *outColorSpace = nullptr;
324     } else if (value.equals("8888s")) {
325         *outColorType  = kRGBA_8888_SkColorType;
326         *outColorSpace = SkColorSpace::MakeSRGB();
327     } else if (value.equals("bgra8")) {
328         *outColorType  = kBGRA_8888_SkColorType;
329         *outColorSpace = nullptr;
330     } else if (value.equals("bgra8s")) {
331         *outColorType  = kBGRA_8888_SkColorType;
332         *outColorSpace = SkColorSpace::MakeSRGB();
333     } else if (value.equals("4444")) {
334         *outColorType  = kARGB_4444_SkColorType;
335         *outColorSpace = nullptr;
336     } else if (value.equals("565")) {
337         *outColorType  = kRGB_565_SkColorType;
338         *alphaType     = kOpaque_SkAlphaType;
339         *outColorSpace = nullptr;
340     } else if (value.equals("1010102")) {
341         *outColorType  = kRGBA_1010102_SkColorType;
342         *outColorSpace = nullptr;
343     } else if (value.equals("srgb")) {
344         *outColorType  = kRGBA_8888_SkColorType;
345         *outColorSpace = SkColorSpace::MakeSRGB();
346     } else if (value.equals("p3")) {
347         *outColorType  = kRGBA_8888_SkColorType;
348         *outColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3);
349     } else if (value.equals("esrgb")) {
350         *outColorType  = kRGBA_F16_SkColorType;
351         *outColorSpace = SkColorSpace::MakeSRGB();
352     } else if (value.equals("narrow") || value.equals("enarrow")) {
353         *outColorType  = value.equals("narrow") ? kRGBA_8888_SkColorType : kRGBA_F16_SkColorType;
354         *outColorSpace = SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gNarrow_toXYZD50);
355     } else if (value.equals("f16")) {
356         *outColorType  = kRGBA_F16_SkColorType;
357         *outColorSpace = SkColorSpace::MakeSRGBLinear();
358     } else if (value.equals("f16norm")) {
359         *outColorType  = kRGBA_F16Norm_SkColorType;
360         *outColorSpace = SkColorSpace::MakeSRGB();
361     } else {
362         return false;
363     }
364     return true;
365 }
366 
parse_option_gpu_surf_type(const SkString & value,SkCommandLineConfigGpu::SurfType * surfType)367 static bool parse_option_gpu_surf_type(const SkString&                   value,
368                                        SkCommandLineConfigGpu::SurfType* surfType) {
369     if (value.equals("default")) {
370         *surfType = SkCommandLineConfigGpu::SurfType::kDefault;
371         return true;
372     }
373     if (value.equals("betex")) {
374         *surfType = SkCommandLineConfigGpu::SurfType::kBackendTexture;
375         return true;
376     }
377     if (value.equals("bert")) {
378         *surfType = SkCommandLineConfigGpu::SurfType::kBackendRenderTarget;
379         return true;
380     }
381     return false;
382 }
383 
384 // Extended options take form --config item[key1=value1,key2=value2,...]
385 // Example: --config gpu[api=gl,color=8888]
386 class ExtendedOptions {
387 public:
ExtendedOptions(const SkString & optionsString,bool * outParseSucceeded)388     ExtendedOptions(const SkString& optionsString, bool* outParseSucceeded) {
389         SkTArray<SkString> optionParts;
390         SkStrSplit(optionsString.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
391         for (int i = 0; i < optionParts.count(); ++i) {
392             SkTArray<SkString> keyValueParts;
393             SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts);
394             if (keyValueParts.count() != 2) {
395                 *outParseSucceeded = false;
396                 return;
397             }
398             const SkString& key   = keyValueParts[0];
399             const SkString& value = keyValueParts[1];
400             if (fOptionsMap.find(key) == nullptr) {
401                 fOptionsMap.set(key, value);
402             } else {
403                 // Duplicate values are not allowed.
404                 *outParseSucceeded = false;
405                 return;
406             }
407         }
408         *outParseSucceeded = true;
409     }
410 
get_option_gpu_color(const char * optionKey,SkColorType * outColorType,SkAlphaType * alphaType,sk_sp<SkColorSpace> * outColorSpace,bool optional=true) const411     bool get_option_gpu_color(const char*          optionKey,
412                               SkColorType*         outColorType,
413                               SkAlphaType*         alphaType,
414                               sk_sp<SkColorSpace>* outColorSpace,
415                               bool                 optional = true) const {
416         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
417         if (optionValue == nullptr) {
418             return optional;
419         }
420         return parse_option_gpu_color(*optionValue, outColorType, alphaType, outColorSpace);
421     }
422 
get_option_gpu_api(const char * optionKey,SkCommandLineConfigGpu::ContextType * outContextType,bool * outFakeGLESVersion2,bool optional=true) const423     bool get_option_gpu_api(const char*                          optionKey,
424                             SkCommandLineConfigGpu::ContextType* outContextType,
425                             bool*                                outFakeGLESVersion2,
426                             bool                                 optional = true) const {
427         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
428         if (optionValue == nullptr) {
429             return optional;
430         }
431         return parse_option_gpu_api(*optionValue, outContextType, outFakeGLESVersion2);
432     }
433 
get_option_gpu_surf_type(const char * optionKey,SkCommandLineConfigGpu::SurfType * outSurfType,bool optional=true) const434     bool get_option_gpu_surf_type(const char*                       optionKey,
435                                   SkCommandLineConfigGpu::SurfType* outSurfType,
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_surf_type(*optionValue, outSurfType);
442     }
443 
get_option_int(const char * optionKey,int * outInt,bool optional=true) const444     bool get_option_int(const char* optionKey, int* outInt, bool optional = true) const {
445         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
446         if (optionValue == nullptr) {
447             return optional;
448         }
449         return parse_option_int(*optionValue, outInt);
450     }
451 
get_option_bool(const char * optionKey,bool * outBool,bool optional=true) const452     bool get_option_bool(const char* optionKey, bool* outBool, bool optional = true) const {
453         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
454         if (optionValue == nullptr) {
455             return optional;
456         }
457         return parse_option_bool(*optionValue, outBool);
458     }
459 
460 private:
461     SkTHashMap<SkString, SkString> fOptionsMap;
462 };
463 
SkCommandLineConfigGpu(const SkString & tag,const SkTArray<SkString> & viaParts,ContextType contextType,bool fakeGLESVersion2,bool useDIText,int samples,SkColorType colorType,SkAlphaType alphaType,sk_sp<SkColorSpace> colorSpace,bool useStencilBuffers,bool testThreading,int testPersistentCache,bool testPrecompile,bool useDDLSink,bool OOPRish,SurfType surfType)464 SkCommandLineConfigGpu::SkCommandLineConfigGpu(const SkString&           tag,
465                                                const SkTArray<SkString>& viaParts,
466                                                ContextType               contextType,
467                                                bool                      fakeGLESVersion2,
468                                                bool                      useDIText,
469                                                int                       samples,
470                                                SkColorType               colorType,
471                                                SkAlphaType               alphaType,
472                                                sk_sp<SkColorSpace>       colorSpace,
473                                                bool                      useStencilBuffers,
474                                                bool                      testThreading,
475                                                int                       testPersistentCache,
476                                                bool                      testPrecompile,
477                                                bool                      useDDLSink,
478                                                bool                      OOPRish,
479                                                SurfType                  surfType)
480         : SkCommandLineConfig(tag, SkString("gpu"), viaParts)
481         , fContextType(contextType)
482         , fContextOverrides(ContextOverrides::kNone)
483         , fUseDIText(useDIText)
484         , fSamples(samples)
485         , fColorType(colorType)
486         , fAlphaType(alphaType)
487         , fColorSpace(std::move(colorSpace))
488         , fTestThreading(testThreading)
489         , fTestPersistentCache(testPersistentCache)
490         , fTestPrecompile(testPrecompile)
491         , fUseDDLSink(useDDLSink)
492         , fOOPRish(OOPRish)
493         , fSurfType(surfType) {
494     if (!useStencilBuffers) {
495         fContextOverrides |= ContextOverrides::kAvoidStencilBuffers;
496     }
497     if (fakeGLESVersion2) {
498         fContextOverrides |= ContextOverrides::kFakeGLESVersionAs2;
499     }
500 }
501 
parse_command_line_config_gpu(const SkString & tag,const SkTArray<SkString> & vias,const SkString & options)502 SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString&           tag,
503                                                       const SkTArray<SkString>& vias,
504                                                       const SkString&           options) {
505     // Defaults for GPU backend.
506     SkCommandLineConfigGpu::ContextType contextType         = GrContextFactory::kGL_ContextType;
507     bool                                useDIText           = false;
508     int                                 samples             = 1;
509     SkColorType                         colorType           = kRGBA_8888_SkColorType;
510     SkAlphaType                         alphaType           = kPremul_SkAlphaType;
511     sk_sp<SkColorSpace>                 colorSpace          = nullptr;
512     bool                                useStencils         = true;
513     bool                                testThreading       = false;
514     int                                 testPersistentCache = 0;
515     bool                                testPrecompile      = false;
516     bool                                useDDLs             = false;
517     bool                                ooprish             = false;
518     bool                                fakeGLESVersion2    = false;
519     SkCommandLineConfigGpu::SurfType    surfType = SkCommandLineConfigGpu::SurfType::kDefault;
520 
521     bool            parseSucceeded = false;
522     ExtendedOptions extendedOptions(options, &parseSucceeded);
523     if (!parseSucceeded) {
524         return nullptr;
525     }
526 
527     bool validOptions =
528             extendedOptions.get_option_gpu_api("api", &contextType, &fakeGLESVersion2, false) &&
529             extendedOptions.get_option_bool("dit", &useDIText) &&
530             extendedOptions.get_option_int("samples", &samples) &&
531             extendedOptions.get_option_gpu_color("color", &colorType, &alphaType, &colorSpace) &&
532             extendedOptions.get_option_bool("stencils", &useStencils) &&
533             extendedOptions.get_option_bool("testThreading", &testThreading) &&
534             extendedOptions.get_option_int("testPersistentCache", &testPersistentCache) &&
535             extendedOptions.get_option_bool("testPrecompile", &testPrecompile) &&
536             extendedOptions.get_option_bool("useDDLSink", &useDDLs) &&
537             extendedOptions.get_option_bool("OOPRish", &ooprish) &&
538             extendedOptions.get_option_gpu_surf_type("surf", &surfType);
539 
540     // testing threading and the persistent cache are mutually exclusive.
541     if (!validOptions || (testThreading && (testPersistentCache != 0))) {
542         return nullptr;
543     }
544 
545     return new SkCommandLineConfigGpu(tag,
546                                       vias,
547                                       contextType,
548                                       fakeGLESVersion2,
549                                       useDIText,
550                                       samples,
551                                       colorType,
552                                       alphaType,
553                                       colorSpace,
554                                       useStencils,
555                                       testThreading,
556                                       testPersistentCache,
557                                       testPrecompile,
558                                       useDDLs,
559                                       ooprish,
560                                       surfType);
561 }
562 
SkCommandLineConfigSvg(const SkString & tag,const SkTArray<SkString> & viaParts,int pageIndex)563 SkCommandLineConfigSvg::SkCommandLineConfigSvg(const SkString&           tag,
564                                                const SkTArray<SkString>& viaParts,
565                                                int                       pageIndex)
566         : SkCommandLineConfig(tag, SkString("svg"), viaParts), fPageIndex(pageIndex) {}
567 
parse_command_line_config_svg(const SkString & tag,const SkTArray<SkString> & vias,const SkString & options)568 SkCommandLineConfigSvg* parse_command_line_config_svg(const SkString&           tag,
569                                                       const SkTArray<SkString>& vias,
570                                                       const SkString&           options) {
571     // Defaults for SVG backend.
572     int pageIndex = 0;
573 
574     bool            parseSucceeded = false;
575     ExtendedOptions extendedOptions(options, &parseSucceeded);
576     if (!parseSucceeded) {
577         return nullptr;
578     }
579 
580     bool validOptions = extendedOptions.get_option_int("page", &pageIndex);
581 
582     if (!validOptions) {
583         return nullptr;
584     }
585 
586     return new SkCommandLineConfigSvg(tag, vias, pageIndex);
587 }
588 
ParseConfigs(const CommandLineFlags::StringArray & configs,SkCommandLineConfigArray * outResult)589 void ParseConfigs(const CommandLineFlags::StringArray& configs,
590                   SkCommandLineConfigArray*            outResult) {
591     outResult->reset();
592     for (int i = 0; i < configs.count(); ++i) {
593         SkString           extendedBackend;
594         SkString           extendedOptions;
595         SkString           simpleBackend;
596         SkTArray<SkString> vias;
597 
598         SkString           tag(configs[i]);
599         SkTArray<SkString> parts;
600         SkStrSplit(tag.c_str(), "[", kStrict_SkStrSplitMode, &parts);
601         if (parts.count() == 2) {
602             SkTArray<SkString> parts2;
603             SkStrSplit(parts[1].c_str(), "]", kStrict_SkStrSplitMode, &parts2);
604             if (parts2.count() == 2 && parts2[1].isEmpty()) {
605                 SkStrSplit(parts[0].c_str(), "-", kStrict_SkStrSplitMode, &vias);
606                 if (vias.count()) {
607                     extendedBackend = vias[vias.count() - 1];
608                     vias.pop_back();
609                 } else {
610                     extendedBackend = parts[0];
611                 }
612                 extendedOptions = parts2[0];
613                 simpleBackend.printf("%s[%s]", extendedBackend.c_str(), extendedOptions.c_str());
614             }
615         }
616 
617         if (extendedBackend.isEmpty()) {
618             simpleBackend = tag;
619             SkStrSplit(tag.c_str(), "-", kStrict_SkStrSplitMode, &vias);
620             if (vias.count()) {
621                 simpleBackend = vias[vias.count() - 1];
622                 vias.pop_back();
623             }
624             for (auto& predefinedConfig : gPredefinedConfigs) {
625                 if (simpleBackend.equals(predefinedConfig.predefinedConfig)) {
626                     extendedBackend = predefinedConfig.backend;
627                     extendedOptions = predefinedConfig.options;
628                     break;
629                 }
630             }
631         }
632         SkCommandLineConfig* parsedConfig = nullptr;
633         if (extendedBackend.equals("gpu")) {
634             parsedConfig = parse_command_line_config_gpu(tag, vias, extendedOptions);
635         }
636         if (extendedBackend.equals("svg")) {
637             parsedConfig = parse_command_line_config_svg(tag, vias, extendedOptions);
638         }
639         if (!parsedConfig) {
640             parsedConfig = new SkCommandLineConfig(tag, simpleBackend, vias);
641         }
642         outResult->emplace_back(parsedConfig);
643     }
644 }
645