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