• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2015 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "tools/flags/CommonFlagsConfig.h"
9 
10 #include "include/core/SkImageInfo.h"
11 #include "include/core/SkSurfaceProps.h"
12 #include "src/core/SkColorSpacePriv.h"
13 #include "src/core/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,testPrecompileGanesh=true" },
78     { "glestestprecompile",    "gpu", "api=gles,testPrecompileGanesh=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,testPrecompileGanesh=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_mtltestprecompile", "graphite", "api=dawn_mtl,testPrecompileGraphite=true" },
147     { "grdawn_vktestprecompile",  "graphite", "api=dawn_vk, testPrecompileGraphite=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     { "grmtltestprecompile",      "graphite", "api=metal,testPrecompileGraphite=true" },
158     { "grmtltestprecompilef16",   "graphite", "api=metal,testPrecompileGraphite=true,color=f16" },
159 #endif
160 #endif
161 #ifdef SK_VULKAN
162     { "grvk",                     "graphite", "api=vulkan" },
163 #if defined(SK_ENABLE_PRECOMPILE)
164     { "grvktestprecompile",       "graphite", "api=vulkan,testPrecompileGraphite=true" },
165 #endif
166 #endif
167 #endif
168 
169 };
170 // clang-format on
171 
172 static const char configHelp[] =
173         "Options: 565 4444 8888 rgba bgra rgbx 1010102 101010x bgra1010102 bgr101010x f16 f16norm f16f16f16x "
174         "f32 nonrendering null pdf pdfa pdf300 skp svg xps";
175 
config_help_fn()176 static const char* config_help_fn() {
177     static SkString helpString;
178     helpString.set(configHelp);
179     for (const auto& config : gPredefinedConfigs) {
180         helpString.appendf(" %s", config.predefinedConfig);
181     }
182     helpString.append(" or use extended form 'backend[option=value,...]'.\n");
183     return helpString.c_str();
184 }
185 
186 static const char configExtendedHelp[] =
187         "Extended form: 'backend(option=value,...)'\n\n"
188         "Possible backends and options:\n"
189         "\n"
190         "gpu[api=string,color=string,dit=bool,dmsaa=bool,samples=int]\n"
191         "\tapi\ttype: string\trequired\n"
192         "\t    Select graphics API to use with gpu backend.\n"
193         "\t    Options:\n"
194         "\t\tgl    \t\t\tUse OpenGL.\n"
195         "\t\tgles  \t\t\tUse OpenGL ES.\n"
196         "\t\tglesfakev2  \t\t\tUse OpenGL ES with version faked as 2.0.\n"
197         "\t\tnullgl \t\t\tUse null OpenGL.\n"
198         "\t\tangle_d3d9_es2\t\tUse OpenGL ES2 on the ANGLE Direct3D9 backend.\n"
199         "\t\tangle_d3d11_es2\t\tUse OpenGL ES2 on the ANGLE Direct3D11 backend.\n"
200         "\t\tangle_d3d11_es3\t\tUse OpenGL ES3 on the ANGLE Direct3D11 backend.\n"
201         "\t\tangle_gl_es2\t\tUse OpenGL ES2 on the ANGLE OpenGL backend.\n"
202         "\t\tangle_gl_es3\t\tUse OpenGL ES3 on the ANGLE OpenGL backend.\n"
203         "\t\tmock\t\t\tUse mock context.\n"
204 #ifdef SK_VULKAN
205         "\t\tvulkan\t\t\tUse Vulkan.\n"
206 #endif
207 #ifdef SK_METAL
208         "\t\tmetal\t\t\tUse Metal.\n"
209 #endif
210         "\tcolor\ttype: string\tdefault: 8888.\n"
211         "\t    Select framebuffer color format.\n"
212         "\t    Options:\n"
213         "\t\t8888\t\t\tLinear 8888.\n"
214         "\t\t888x\t\t\tLinear 888x.\n"
215         "\t\t4444\t\t\tLinear 4444.\n"
216         "\t\t565\t\t\tLinear 565.\n"
217         "\t\t1010102\t\t\tLinear 1010102.\n"
218         "\t\tf16\t\t\t16-bit floating point.\n"
219         "\tdit\ttype: bool\tdefault: false.\n"
220         "\t    Use device independent text.\n"
221         "\tdmsaa\ttype: bool\tdefault: false.\n"
222         "\t    Use internal MSAA to render to non-MSAA surfaces.\n"
223         "\tsamples\ttype: int\tdefault: 0.\n"
224         "\t    Use multisampling with N samples.\n"
225         "\tstencils\ttype: bool\tdefault: true.\n"
226         "\t    Allow the use of stencil buffers.\n"
227         "\t    Run with and without worker threads, check that results match.\n"
228         "\ttestPersistentCache\ttype: int\tdefault: 0.\n"
229         "\t    1: Run using a pre-warmed binary GrContextOptions::fPersistentCache.\n"
230         "\t    2: Run using a pre-warmed GLSL GrContextOptions::fPersistentCache.\n"
231         "\tsurf\ttype: string\tdefault: default.\n"
232         "\t    Controls the type of backing store for SkSurfaces.\n"
233         "\t    Options:\n"
234         "\t\tdefault\t\t\tA renderable texture created in Skia's resource cache.\n"
235         "\t\tbetex\t\t\tA wrapped backend texture.\n"
236         "\t\tbert\t\t\tA wrapped backend render target\n"
237         "\n"
238         "Predefined configs:\n\n"
239         // Help text for pre-defined configs is auto-generated from gPredefinedConfigs
240         ;
241 
config_extended_help_fn()242 static const char* config_extended_help_fn() {
243     static SkString helpString;
244     helpString.set(configExtendedHelp);
245     for (const auto& config : gPredefinedConfigs) {
246         helpString.appendf("\t%-10s\t= gpu(%s)\n", config.predefinedConfig, config.options);
247     }
248     return helpString.c_str();
249 }
250 
251 DEFINE_extended_string(config, defaultConfigs, config_help_fn(), config_extended_help_fn());
252 
SkCommandLineConfig(const SkString & tag,const SkString & backend,const TArray<SkString> & viaParts)253 SkCommandLineConfig::SkCommandLineConfig(const SkString& tag,
254                                          const SkString& backend,
255                                          const TArray<SkString>& viaParts)
256         : fTag(tag), fBackend(backend) {
257     static const auto* kColorSpaces = new std::unordered_map<std::string_view, SkColorSpace*>{
258         {"narrow", // 'narrow' has a gamut narrower than sRGB, and different transfer function.
259          SkColorSpace::MakeRGB(SkNamedTransferFn::k2Dot2, gNarrow_toXYZD50).release()},
260         {"srgb",
261          SkColorSpace::MakeSRGB().release()},
262         {"srgb2",  // The same as "srgb" but works around ignoring prior images in Gold
263          SkColorSpace::MakeSRGB().release()},
264         {"linear",
265          SkColorSpace::MakeSRGBLinear().release()},
266         {"p3",
267          SkColorSpace::MakeRGB(SkNamedTransferFn::kSRGB, SkNamedGamut::kDisplayP3).release()},
268         {"spin",
269          SkColorSpace::MakeSRGB()->makeColorSpin().release()},
270         {"rec2020",
271          SkColorSpace::MakeRGB(SkNamedTransferFn::kRec2020, SkNamedGamut::kRec2020).release()},
272     };
273 
274     // Strip off any via parts that refer to color spaces (and remember the last one we see)
275     for (const SkString& via : viaParts) {
276         auto it = kColorSpaces->find(via.c_str());
277         if (it == kColorSpaces->end()) {
278             fViaParts.push_back(via);
279         } else {
280             fColorSpace = sk_ref_sp(it->second);
281         }
282     }
283 }
284 
~SkCommandLineConfig()285 SkCommandLineConfig::~SkCommandLineConfig() {}
286 
parse_option_int(const SkString & value,int * outInt)287 static bool parse_option_int(const SkString& value, int* outInt) {
288     if (value.isEmpty()) {
289         return false;
290     }
291     char* endptr   = nullptr;
292     long  intValue = strtol(value.c_str(), &endptr, 10);
293     if (*endptr != '\0') {
294         return false;
295     }
296     *outInt = static_cast<int>(intValue);
297     return true;
298 }
parse_option_bool(const SkString & value,bool * outBool)299 static bool parse_option_bool(const SkString& value, bool* outBool) {
300     if (value.equals("true")) {
301         *outBool = true;
302         return true;
303     }
304     if (value.equals("false")) {
305         *outBool = false;
306         return true;
307     }
308     return false;
309 }
parse_option_gpu_api(const SkString & value,SkCommandLineConfigGpu::ContextType * outContextType,bool * outFakeGLESVersion2)310 static bool parse_option_gpu_api(const SkString&                      value,
311                                  SkCommandLineConfigGpu::ContextType* outContextType,
312                                  bool*                                outFakeGLESVersion2) {
313     *outFakeGLESVersion2 = false;
314     if (value.equals("gl")) {
315         *outContextType = skgpu::ContextType::kGL;
316         return true;
317     }
318     if (value.equals("gles")) {
319         *outContextType = skgpu::ContextType::kGLES;
320         return true;
321     }
322     if (value.equals("glesfakev2")) {
323         *outContextType = skgpu::ContextType::kGLES;
324         *outFakeGLESVersion2 = true;
325         return true;
326     }
327     if (value.equals("angle_d3d9_es2")) {
328         *outContextType = skgpu::ContextType::kANGLE_D3D9_ES2;
329         return true;
330     }
331     if (value.equals("angle_d3d11_es2")) {
332         *outContextType = skgpu::ContextType::kANGLE_D3D11_ES2;
333         return true;
334     }
335     if (value.equals("angle_d3d11_es3")) {
336         *outContextType = skgpu::ContextType::kANGLE_D3D11_ES3;
337         return true;
338     }
339     if (value.equals("angle_gl_es2")) {
340         *outContextType = skgpu::ContextType::kANGLE_GL_ES2;
341         return true;
342     }
343     if (value.equals("angle_gl_es3")) {
344         *outContextType = skgpu::ContextType::kANGLE_GL_ES3;
345         return true;
346     }
347     if (value.equals("angle_mtl_es2")) {
348         *outContextType = skgpu::ContextType::kANGLE_Metal_ES2;
349         return true;
350     }
351     if (value.equals("angle_mtl_es3")) {
352         *outContextType = skgpu::ContextType::kANGLE_Metal_ES3;
353         return true;
354     }
355     if (value.equals("mock")) {
356         *outContextType = skgpu::ContextType::kMock;
357         return true;
358     }
359 #ifdef SK_VULKAN
360     if (value.equals("vulkan")) {
361         *outContextType = skgpu::ContextType::kVulkan;
362         return true;
363     }
364 #endif
365 #ifdef SK_METAL
366     if (value.equals("metal")) {
367         *outContextType = skgpu::ContextType::kMetal;
368         return true;
369     }
370 #endif
371 #ifdef SK_DIRECT3D
372     if (value.equals("direct3d")) {
373         *outContextType = skgpu::ContextType::kDirect3D;
374         return true;
375     }
376 #endif
377     return false;
378 }
379 
parse_option_gpu_color(const SkString & value,SkColorType * outColorType,SkAlphaType * alphaType)380 static bool parse_option_gpu_color(const SkString& value,
381                                    SkColorType*    outColorType,
382                                    SkAlphaType*    alphaType) {
383     // We always use premul unless the color type is 565.
384     *alphaType = kPremul_SkAlphaType;
385 
386     if (value.equals("8888")) {
387         *outColorType  = kRGBA_8888_SkColorType;
388     } else if (value.equals("888x")) {
389         *outColorType  = kRGB_888x_SkColorType;
390     } else if (value.equals("bgra8")) {
391         *outColorType  = kBGRA_8888_SkColorType;
392     } else if (value.equals("4444")) {
393         *outColorType  = kARGB_4444_SkColorType;
394     } else if (value.equals("565")) {
395         *outColorType  = kRGB_565_SkColorType;
396         *alphaType     = kOpaque_SkAlphaType;
397     } else if (value.equals("1010102")) {
398         *outColorType  = kRGBA_1010102_SkColorType;
399     } else if (value.equals("f16")) {
400         *outColorType  = kRGBA_F16_SkColorType;
401     } else if (value.equals("f16norm")) {
402         *outColorType  = kRGBA_F16Norm_SkColorType;
403     } else if (value.equals("srgba")) {
404         *outColorType = kSRGBA_8888_SkColorType;
405     } else if (value.equals("r8")) {
406         *outColorType = kR8_unorm_SkColorType;
407         *alphaType = kOpaque_SkAlphaType;
408     } else {
409         return false;
410     }
411     return true;
412 }
413 
parse_option_gpu_surf_type(const SkString & value,SkCommandLineConfigGpu::SurfType * surfType)414 static bool parse_option_gpu_surf_type(const SkString&                   value,
415                                        SkCommandLineConfigGpu::SurfType* surfType) {
416     if (value.equals("default")) {
417         *surfType = SkCommandLineConfigGpu::SurfType::kDefault;
418         return true;
419     }
420     if (value.equals("betex")) {
421         *surfType = SkCommandLineConfigGpu::SurfType::kBackendTexture;
422         return true;
423     }
424     if (value.equals("bert")) {
425         *surfType = SkCommandLineConfigGpu::SurfType::kBackendRenderTarget;
426         return true;
427     }
428     return false;
429 }
430 
431 // Extended options take form --config item[key1=value1,key2=value2,...]
432 // Example: --config gpu[api=gl,color=8888]
433 class ExtendedOptions {
434 public:
ExtendedOptions(const SkString & optionsString,bool * outParseSucceeded)435     ExtendedOptions(const SkString& optionsString, bool* outParseSucceeded) {
436         TArray<SkString> optionParts;
437         SkStrSplit(optionsString.c_str(), ",", kStrict_SkStrSplitMode, &optionParts);
438         for (int i = 0; i < optionParts.size(); ++i) {
439             TArray<SkString> keyValueParts;
440             SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts);
441             if (keyValueParts.size() != 2) {
442                 *outParseSucceeded = false;
443                 return;
444             }
445             const SkString& key   = keyValueParts[0];
446             const SkString& value = keyValueParts[1];
447             if (fOptionsMap.find(key) == nullptr) {
448                 fOptionsMap.set(key, value);
449             } else {
450                 // Duplicate values are not allowed.
451                 *outParseSucceeded = false;
452                 return;
453             }
454         }
455         *outParseSucceeded = true;
456     }
457 
get_option_gpu_color(const char * optionKey,SkColorType * outColorType,SkAlphaType * alphaType,bool optional=true) const458     bool get_option_gpu_color(const char*  optionKey,
459                               SkColorType* outColorType,
460                               SkAlphaType* alphaType,
461                               bool         optional = true) const {
462         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
463         if (optionValue == nullptr) {
464             return optional;
465         }
466         return parse_option_gpu_color(*optionValue, outColorType, alphaType);
467     }
468 
get_option_gpu_api(const char * optionKey,SkCommandLineConfigGpu::ContextType * outContextType,bool * outFakeGLESVersion2,bool optional=true) const469     bool get_option_gpu_api(const char*                          optionKey,
470                             SkCommandLineConfigGpu::ContextType* outContextType,
471                             bool*                                outFakeGLESVersion2,
472                             bool                                 optional = true) const {
473         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
474         if (optionValue == nullptr) {
475             return optional;
476         }
477         return parse_option_gpu_api(*optionValue, outContextType, outFakeGLESVersion2);
478     }
479 
480 #if defined(SK_GRAPHITE)
get_option_graphite_api(const char * optionKey,SkCommandLineConfigGraphite::ContextType * outContextType) const481     bool get_option_graphite_api(const char*                               optionKey,
482                                  SkCommandLineConfigGraphite::ContextType* outContextType) const {
483         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
484         if (optionValue == nullptr) {
485             return false;
486         }
487 #ifdef SK_DAWN
488         if (optionValue->equals("dawn_d3d11")) {
489             *outContextType = skgpu::ContextType::kDawn_D3D11;
490             return true;
491         }
492         if (optionValue->equals("dawn_d3d12")) {
493             *outContextType = skgpu::ContextType::kDawn_D3D12;
494             return true;
495         }
496         if (optionValue->equals("dawn_mtl")) {
497             *outContextType = skgpu::ContextType::kDawn_Metal;
498             return true;
499         }
500         if (optionValue->equals("dawn_vk")) {
501             *outContextType = skgpu::ContextType::kDawn_Vulkan;
502             return true;
503         }
504         if (optionValue->equals("dawn_gl")) {
505             *outContextType = skgpu::ContextType::kDawn_OpenGL;
506             return true;
507         }
508         if (optionValue->equals("dawn_gles")) {
509             *outContextType = skgpu::ContextType::kDawn_OpenGLES;
510             return true;
511         }
512 #endif
513 #ifdef SK_DIRECT3D
514         if (optionValue->equals("direct3d")) {
515             *outContextType = skgpu::ContextType::kDirect3D;
516             return true;
517         }
518 #endif
519 #ifdef SK_METAL
520         if (optionValue->equals("metal")) {
521             *outContextType = skgpu::ContextType::kMetal;
522             return true;
523         }
524 #endif
525 #ifdef SK_VULKAN
526         if (optionValue->equals("vulkan")) {
527             *outContextType = skgpu::ContextType::kVulkan;
528             return true;
529         }
530 #endif
531 
532         return false;
533     }
534 #endif
535 
get_option_gpu_surf_type(const char * optionKey,SkCommandLineConfigGpu::SurfType * outSurfType,bool optional=true) const536     bool get_option_gpu_surf_type(const char*                       optionKey,
537                                   SkCommandLineConfigGpu::SurfType* outSurfType,
538                                   bool                              optional = true) const {
539         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
540         if (optionValue == nullptr) {
541             return optional;
542         }
543         return parse_option_gpu_surf_type(*optionValue, outSurfType);
544     }
545 
get_option_int(const char * optionKey,int * outInt,bool optional=true) const546     bool get_option_int(const char* optionKey, int* outInt, bool optional = true) const {
547         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
548         if (optionValue == nullptr) {
549             return optional;
550         }
551         return parse_option_int(*optionValue, outInt);
552     }
553 
get_option_bool(const char * optionKey,bool * outBool,bool optional=true) const554     bool get_option_bool(const char* optionKey, bool* outBool, bool optional = true) const {
555         SkString* optionValue = fOptionsMap.find(SkString(optionKey));
556         if (optionValue == nullptr) {
557             return optional;
558         }
559         return parse_option_bool(*optionValue, outBool);
560     }
561 
562 private:
563     THashMap<SkString, SkString> fOptionsMap;
564 };
565 
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 testPrecompileGanesh,bool useDDLSink,bool slug,bool serializeSlug,bool remoteSlug,bool reducedShaders,SurfType surfType)566 SkCommandLineConfigGpu::SkCommandLineConfigGpu(const SkString&         tag,
567                                                const TArray<SkString>& viaParts,
568                                                ContextType             contextType,
569                                                bool                    fakeGLESVersion2,
570                                                uint32_t                surfaceFlags,
571                                                int                     samples,
572                                                SkColorType             colorType,
573                                                SkAlphaType             alphaType,
574                                                bool                    useStencilBuffers,
575                                                int                     testPersistentCache,
576                                                bool                    testPrecompileGanesh,
577                                                bool                    useDDLSink,
578                                                bool                    slug,
579                                                bool                    serializeSlug,
580                                                bool                    remoteSlug,
581                                                bool                    reducedShaders,
582                                                SurfType                surfType)
583         : SkCommandLineConfig(tag, SkString("gpu"), viaParts)
584         , fContextType(contextType)
585         , fContextOverrides(ContextOverrides::kNone)
586         , fSurfaceFlags(surfaceFlags)
587         , fSamples(samples)
588         , fColorType(colorType)
589         , fAlphaType(alphaType)
590         , fTestPersistentCache(testPersistentCache)
591         , fTestPrecompileGanesh(testPrecompileGanesh)
592         , fUseDDLSink(useDDLSink)
593         , fSlug(slug)
594         , fSerializeSlug(serializeSlug)
595         , fRemoteSlug(remoteSlug)
596         , fReducedShaders(reducedShaders)
597         , fSurfType(surfType) {
598     if (!useStencilBuffers) {
599         fContextOverrides |= ContextOverrides::kAvoidStencilBuffers;
600     }
601     if (fakeGLESVersion2) {
602         fContextOverrides |= ContextOverrides::kFakeGLESVersionAs2;
603     }
604     if (reducedShaders) {
605         fContextOverrides |= ContextOverrides::kReducedShaders;
606     }
607 }
608 
parse_command_line_config_gpu(const SkString & tag,const TArray<SkString> & vias,const SkString & options)609 SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString&         tag,
610                                                       const TArray<SkString>& vias,
611                                                       const SkString&         options) {
612     // Defaults for GPU backend.
613     SkCommandLineConfigGpu::ContextType contextType         = skgpu::ContextType::kGL;
614     bool                                useDIText           = false;
615     bool                                useDMSAA            = false;
616     int                                 samples             = 1;
617     SkColorType                         colorType           = kRGBA_8888_SkColorType;
618     SkAlphaType                         alphaType           = kPremul_SkAlphaType;
619     bool                                useStencils         = true;
620     int                                 testPersistentCache = 0;
621     bool                                testPrecompileGanesh= false;
622     bool                                useDDLs             = false;
623     bool                                slug                = false;
624     bool                                serializeSlug       = false;
625     bool                                remoteSlug          = false;
626     bool                                reducedShaders      = false;
627     bool                                fakeGLESVersion2    = false;
628     SkCommandLineConfigGpu::SurfType    surfType = SkCommandLineConfigGpu::SurfType::kDefault;
629 
630     bool            parseSucceeded = false;
631     ExtendedOptions extendedOptions(options, &parseSucceeded);
632     if (!parseSucceeded) {
633         return nullptr;
634     }
635 
636     bool validOptions =
637             extendedOptions.get_option_gpu_api("api", &contextType, &fakeGLESVersion2, false) &&
638             extendedOptions.get_option_bool("dit", &useDIText) &&
639             extendedOptions.get_option_int("samples", &samples) &&
640             extendedOptions.get_option_bool("dmsaa", &useDMSAA) &&
641             extendedOptions.get_option_gpu_color("color", &colorType, &alphaType) &&
642             extendedOptions.get_option_bool("stencils", &useStencils) &&
643             extendedOptions.get_option_int("testPersistentCache", &testPersistentCache) &&
644             extendedOptions.get_option_bool("testPrecompileGanesh", &testPrecompileGanesh) &&
645             extendedOptions.get_option_bool("useDDLSink", &useDDLs) &&
646             extendedOptions.get_option_bool("slug", &slug) &&
647             extendedOptions.get_option_bool("serializeSlug", &serializeSlug) &&
648             extendedOptions.get_option_bool("remoteSlug", &remoteSlug) &&
649             extendedOptions.get_option_bool("reducedShaders", &reducedShaders) &&
650             extendedOptions.get_option_gpu_surf_type("surf", &surfType);
651 
652     if (!validOptions) {
653         return nullptr;
654     }
655 
656     uint32_t surfaceFlags = 0;
657     if (useDIText) {
658         surfaceFlags |= SkSurfaceProps::kUseDeviceIndependentFonts_Flag;
659     }
660     if (useDMSAA) {
661         surfaceFlags |= SkSurfaceProps::kDynamicMSAA_Flag;
662     }
663 
664     return new SkCommandLineConfigGpu(tag,
665                                       vias,
666                                       contextType,
667                                       fakeGLESVersion2,
668                                       surfaceFlags,
669                                       samples,
670                                       colorType,
671                                       alphaType,
672                                       useStencils,
673                                       testPersistentCache,
674                                       testPrecompileGanesh,
675                                       useDDLs,
676                                       slug,
677                                       serializeSlug,
678                                       remoteSlug,
679                                       reducedShaders,
680                                       surfType);
681 }
682 
683 #if defined(SK_GRAPHITE)
684 
parse_command_line_config_graphite(const SkString & tag,const TArray<SkString> & vias,const SkString & options)685 SkCommandLineConfigGraphite* parse_command_line_config_graphite(const SkString& tag,
686                                                                 const TArray<SkString>& vias,
687                                                                 const SkString& options) {
688     using ContextType = skgpu::ContextType;
689 
690     ContextType contextType            = skgpu::ContextType::kMetal;
691     SkColorType colorType              = kRGBA_8888_SkColorType;
692     SkAlphaType alphaType              = kPremul_SkAlphaType;
693     bool        testPrecompileGraphite = false;
694 
695     bool parseSucceeded = false;
696     ExtendedOptions extendedOptions(options, &parseSucceeded);
697     if (!parseSucceeded) {
698         return nullptr;
699     }
700 
701     bool validOptions = extendedOptions.get_option_graphite_api("api", &contextType) &&
702                         extendedOptions.get_option_gpu_color("color", &colorType, &alphaType) &&
703                         extendedOptions.get_option_bool("testPrecompileGraphite",
704                                                         &testPrecompileGraphite);
705     if (!validOptions) {
706         return nullptr;
707     }
708 
709     return new SkCommandLineConfigGraphite(tag,
710                                            vias,
711                                            contextType,
712                                            colorType,
713                                            alphaType,
714                                            testPrecompileGraphite);
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