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