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