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