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