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