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 "SkCommonFlagsConfig.h" 9 10#include <stdlib.h> 11 12static const char defaultConfigs[] = 13 "565 8888 gpu nonrendering" 14#if SK_ANGLE 15#ifdef SK_BUILD_FOR_WIN 16 " angle" 17#endif 18#endif 19#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 20 " hwui" 21#endif 22 ; 23 24static const char configHelp[] = 25 "Options: 565 8888 debug gpu gpudebug gpudft gpunull " 26 "msaa16 msaa4 nonrendering null nullgpu nvprmsaa16 nvprmsaa4 " 27 "pdf pdf_poppler skp svg xps" 28#if SK_ANGLE 29#ifdef SK_BUILD_FOR_WIN 30 " angle" 31#endif 32 " angle-gl" 33#endif 34#if SK_COMMAND_BUFFER 35 " commandbuffer" 36#endif 37#if SK_MESA 38 " mesa" 39#endif 40#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 41 " hwui" 42#endif 43 " or use extended form 'backend(option=value,...)'.\n"; 44 45static const char configExtendedHelp[] = 46 "Extended form: 'backend(option=value,...)'\n\n" 47 "Possible backends and options:\n" 48#if SK_SUPPORT_GPU 49 "\n" 50 "gpu(api=string,dit=bool,nvpr=bool,samples=int)\tGPU backend\n" 51 "\tapi\ttype: string\tdefault: native.\n" 52 "\t Select graphics API to use with gpu backend.\n" 53 "\t Options:\n" 54 "\t\tnative\t\t\tUse platform default OpenGL or OpenGL ES backend.\n" 55 "\t\tgl \t\t\tUse OpenGL.\n" 56 "\t\tgles \t\t\tUse OpenGL ES.\n" 57 "\t\tdebug \t\t\tUse debug OpenGL.\n" 58 "\t\tnull \t\t\tUse null OpenGL.\n" 59#if SK_ANGLE 60#ifdef SK_BUILD_FOR_WIN 61 "\t\tangle\t\t\tUse ANGLE DirectX.\n" 62#endif 63 "\t\tangle-gl\t\t\tUse ANGLE OpenGL.\n" 64#endif 65#if SK_COMMAND_BUFFER 66 "\t\tcommandbuffer\t\tUse command buffer.\n" 67 "\t\tcommandbuffer3\t\tUse command buffer ES 3.0 (experimental).\n" 68#endif 69#if SK_MESA 70 "\t\tmesa\t\t\tUse MESA.\n" 71#endif 72 "\tdit\ttype: bool\tdefault: false.\n" 73 "\t Use device independent text.\n" 74 "\tnvpr\ttype: bool\tdefault: false.\n" 75 "\t Use NV_path_rendering OpenGL and OpenGL ES extension.\n" 76 "\tsamples\ttype: int\tdefault: 0.\n" 77 "\t Use multisampling with N samples.\n" 78 "\n" 79 "Predefined configs:\n\n" 80 "\tgpu \t= gpu()\n" 81 "\tmsaa4 \t= gpu(samples=4)\n" 82 "\tmsaa16 \t= gpu(samples=16)\n" 83 "\tnvprmsaa4\t= gpu(nvpr=true,samples=4)\n" 84 "\tnvprmsaa16\t= gpu(nvpr=true,samples=16)\n" 85 "\tgpudft \t= gpu(dit=true)\n" 86 "\tgpudebug \t= gpu(api=debug)\n" 87 "\tgpunull \t= gpu(api=null)\n" 88 "\tdebug \t= gpu(api=debug)\n" 89 "\tnullgpu \t= gpu(api=null)\n" 90#if SK_ANGLE 91#ifdef SK_BUILD_FOR_WIN 92 "\tangle \t= gpu(api=angle)\n" 93#endif 94 "\tangle-gl \t= gpu(api=angle-gl)\n" 95#endif 96#if SK_COMMAND_BUFFER 97 "\tcommandbuffer\t= gpu(api=commandbuffer)\n" 98#endif 99#if SK_MESA 100 "\tmesa \t= gpu(api=mesa)\n" 101#endif 102#endif 103 ; 104 105DEFINE_extended_string(config, defaultConfigs, configHelp, configExtendedHelp); 106 107static const struct { 108 const char* predefinedConfig; 109 const char* backend; 110 const char* options; 111} gPredefinedConfigs[] = { 112#if SK_SUPPORT_GPU 113 { "gpu", "gpu", "" }, 114 { "msaa4", "gpu", "samples=4" }, 115 { "msaa16", "gpu", "samples=16" }, 116 { "nvprmsaa4", "gpu", "nvpr=true,samples=4,dit=true" }, 117 { "nvprmsaa16", "gpu", "nvpr=true,samples=16,dit=true" }, 118 { "gpudft", "gpu", "dit=true" }, 119 { "gpudebug", "gpu", "api=debug" }, 120 { "gpunull", "gpu", "api=null" }, 121 { "debug", "gpu", "api=debug" }, 122 { "nullgpu", "gpu", "api=null" } 123#if SK_ANGLE 124#ifdef SK_BUILD_FOR_WIN 125 , { "angle", "gpu", "api=angle" } 126#endif 127 , { "angle-gl", "gpu", "api=angle-gl" } 128#endif 129#if SK_COMMAND_BUFFER 130 , { "commandbuffer", "gpu", "api=commandbuffer" } 131#endif 132#if SK_MESA 133 , { "mesa", "gpu", "api=mesa" } 134#endif 135#else 136 { "", "", "" } 137#endif 138}; 139 140SkCommandLineConfig::SkCommandLineConfig(const SkString& tag, const SkString& backend, 141 const SkTArray<SkString>& viaParts) 142 : fTag(tag) 143 , fBackend(backend) 144 , fViaParts(viaParts) { 145} 146SkCommandLineConfig::~SkCommandLineConfig() { 147} 148 149#if SK_SUPPORT_GPU 150SkCommandLineConfigGpu::SkCommandLineConfigGpu( 151 const SkString& tag, const SkTArray<SkString>& viaParts, 152 ContextType contextType, bool useNVPR, bool useDIText, int samples) 153 : SkCommandLineConfig(tag, SkString("gpu"), viaParts) 154 , fContextType(contextType) 155 , fUseNVPR(useNVPR) 156 , fUseDIText(useDIText) 157 , fSamples(samples) { 158} 159static bool parse_option_int(const SkString& value, int* outInt) { 160 if (value.isEmpty()) { 161 return false; 162 } 163 char* endptr = nullptr; 164 long intValue = strtol(value.c_str(), &endptr, 10); 165 if (*endptr != '\0') { 166 return false; 167 } 168 *outInt = static_cast<int>(intValue); 169 return true; 170} 171static bool parse_option_bool(const SkString& value, bool* outBool) { 172 if (value.equals("true")) { 173 *outBool = true; 174 return true; 175 } 176 if (value.equals("false")) { 177 *outBool = false; 178 return true; 179 } 180 return false; 181} 182static bool parse_option_gpu_api(const SkString& value, 183 SkCommandLineConfigGpu::ContextType* outContextType) { 184 if (value.equals("native")) { 185 *outContextType = GrContextFactory::kNative_GLContextType; 186 return true; 187 } 188 if (value.equals("gl")) { 189 *outContextType = GrContextFactory::kGL_GLContextType; 190 return true; 191 } 192 if (value.equals("gles")) { 193 *outContextType = GrContextFactory::kGLES_GLContextType; 194 return true; 195 } 196 if (value.equals("debug")) { 197 *outContextType = GrContextFactory::kDebug_GLContextType; 198 return true; 199 } 200 if (value.equals("null")) { 201 *outContextType = GrContextFactory::kNull_GLContextType; 202 return true; 203 } 204#if SK_ANGLE 205#ifdef SK_BUILD_FOR_WIN 206 if (value.equals("angle")) { 207 *outContextType = GrContextFactory::kANGLE_GLContextType; 208 return true; 209 } 210#endif 211 if (value.equals("angle-gl")) { 212 *outContextType = GrContextFactory::kANGLE_GL_GLContextType; 213 return true; 214 } 215#endif 216#if SK_COMMAND_BUFFER 217 if (value.equals("commandbuffer")) { 218 *outContextType = GrContextFactory::kCommandBufferES2_GLContextType; 219 return true; 220 } 221 if (value.equals("commandbuffer3")) { 222 *outContextType = GrContextFactory::kCommandBufferES3_GLContextType; 223 return true; 224 } 225#endif 226#if SK_MESA 227 if (value.equals("mesa")) { 228 *outContextType = GrContextFactory::kMESA_GLContextType; 229 return true; 230 } 231#endif 232 return false; 233} 234 235SkCommandLineConfigGpu* parse_command_line_config_gpu(const SkString& tag, 236 const SkTArray<SkString>& vias, 237 const SkString& options) { 238 // Defaults for GPU backend. 239 bool seenAPI = false; 240 SkCommandLineConfigGpu::ContextType contextType = GrContextFactory::kNative_GLContextType; 241 bool seenUseNVPR = false; 242 bool useNVPR = false; 243 bool seenUseDIText =false; 244 bool useDIText = false; 245 bool seenSamples = false; 246 int samples = 0; 247 248 SkTArray<SkString> optionParts; 249 SkStrSplit(options.c_str(), ",", kStrict_SkStrSplitMode, &optionParts); 250 for (int i = 0; i < optionParts.count(); ++i) { 251 SkTArray<SkString> keyValueParts; 252 SkStrSplit(optionParts[i].c_str(), "=", kStrict_SkStrSplitMode, &keyValueParts); 253 if (keyValueParts.count() != 2) { 254 return nullptr; 255 } 256 const SkString& key = keyValueParts[0]; 257 const SkString& value = keyValueParts[1]; 258 bool valueOk = false; 259 if (key.equals("api") && !seenAPI) { 260 valueOk = parse_option_gpu_api(value, &contextType); 261 seenAPI = true; 262 } else if (key.equals("nvpr") && !seenUseNVPR) { 263 valueOk = parse_option_bool(value, &useNVPR); 264 seenUseNVPR = true; 265 } else if (key.equals("dit") && !seenUseDIText) { 266 valueOk = parse_option_bool(value, &useDIText); 267 seenUseDIText = true; 268 } else if (key.equals("samples") && !seenSamples) { 269 valueOk = parse_option_int(value, &samples); 270 seenSamples = true; 271 } 272 if (!valueOk) { 273 return nullptr; 274 } 275 } 276 return new SkCommandLineConfigGpu(tag, vias, contextType, useNVPR, useDIText, samples); 277} 278#endif 279 280void ParseConfigs(const SkCommandLineFlags::StringArray& configs, 281 SkCommandLineConfigArray* outResult) { 282 outResult->reset(); 283 for (int i = 0; i < configs.count(); ++i) { 284 SkString extendedBackend; 285 SkString extendedOptions; 286 SkString simpleBackend; 287 SkTArray<SkString> vias; 288 289 SkString tag(configs[i]); 290 SkTArray<SkString> parts; 291 SkStrSplit(tag.c_str(), "(", kStrict_SkStrSplitMode, &parts); 292 if (parts.count() == 2) { 293 SkTArray<SkString> parts2; 294 SkStrSplit(parts[1].c_str(), ")", kStrict_SkStrSplitMode, &parts2); 295 if (parts2.count() == 2 && parts2[1].isEmpty()) { 296 SkStrSplit(parts[0].c_str(), "-", kStrict_SkStrSplitMode, &vias); 297 if (vias.count()) { 298 extendedBackend = vias[vias.count() - 1]; 299 vias.pop_back(); 300 } else { 301 extendedBackend = parts[0]; 302 } 303 extendedOptions = parts2[0]; 304 simpleBackend.printf("%s(%s)", extendedBackend.c_str(), extendedOptions.c_str()); 305 } 306 } 307 308 if (extendedBackend.isEmpty()) { 309 simpleBackend = tag; 310 SkStrSplit(tag.c_str(), "-", kStrict_SkStrSplitMode, &vias); 311 if (vias.count()) { 312 simpleBackend = vias[vias.count() - 1]; 313 vias.pop_back(); 314 } 315 // Note: no #if SK_ANGLE: this is a special rule in the via-tag grammar. 316 if (vias.count() && simpleBackend.equals("gl") && 317 vias[vias.count() - 1].equals("angle")) { 318 simpleBackend = "angle-gl"; 319 vias.pop_back(); 320 } 321 322 for (auto& predefinedConfig : gPredefinedConfigs) { 323 if (simpleBackend.equals(predefinedConfig.predefinedConfig)) { 324 extendedBackend = predefinedConfig.backend; 325 extendedOptions = predefinedConfig.options; 326 break; 327 } 328 } 329 } 330 SkCommandLineConfig* parsedConfig = nullptr; 331#if SK_SUPPORT_GPU 332 if (extendedBackend.equals("gpu")) { 333 parsedConfig = parse_command_line_config_gpu(tag, vias, extendedOptions); 334 } 335#endif 336 if (!parsedConfig) { 337 parsedConfig = new SkCommandLineConfig(tag, simpleBackend, vias); 338 } 339 outResult->emplace_back(parsedConfig); 340 } 341} 342