923ded3052eba5290969fd6dcb8bfed2a4c7aa10
[platform/upstream/glslang.git] / StandAlone / StandAlone.cpp
1 //
2 // Copyright (C) 2002-2005  3Dlabs Inc. Ltd.
3 // Copyright (C) 2013-2016 LunarG, Inc.
4 // Copyright (C) 2016-2020 Google, Inc.
5 //
6 // All rights reserved.
7 //
8 // Redistribution and use in source and binary forms, with or without
9 // modification, are permitted provided that the following conditions
10 // are met:
11 //
12 //    Redistributions of source code must retain the above copyright
13 //    notice, this list of conditions and the following disclaimer.
14 //
15 //    Redistributions in binary form must reproduce the above
16 //    copyright notice, this list of conditions and the following
17 //    disclaimer in the documentation and/or other materials provided
18 //    with the distribution.
19 //
20 //    Neither the name of 3Dlabs Inc. Ltd. nor the names of its
21 //    contributors may be used to endorse or promote products derived
22 //    from this software without specific prior written permission.
23 //
24 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
27 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
28 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
29 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
30 // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
31 // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
32 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 // ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 // POSSIBILITY OF SUCH DAMAGE.
36 //
37
38 // this only applies to the standalone wrapper, not the front end in general
39 #ifndef _CRT_SECURE_NO_WARNINGS
40 #define _CRT_SECURE_NO_WARNINGS
41 #endif
42
43 #include "ResourceLimits.h"
44 #include "Worklist.h"
45 #include "DirStackFileIncluder.h"
46 #include "./../glslang/Include/ShHandle.h"
47 #include "./../glslang/Public/ShaderLang.h"
48 #include "../SPIRV/GlslangToSpv.h"
49 #include "../SPIRV/GLSL.std.450.h"
50 #include "../SPIRV/doc.h"
51 #include "../SPIRV/disassemble.h"
52
53 #include <cstring>
54 #include <cstdlib>
55 #include <cctype>
56 #include <cmath>
57 #include <array>
58 #include <map>
59 #include <memory>
60 #include <thread>
61
62 #include "../glslang/OSDependent/osinclude.h"
63
64 // Build-time generated includes
65 #include "glslang/build_info.h"
66
67 extern "C" {
68     GLSLANG_EXPORT void ShOutputHtml();
69 }
70
71 // Command-line options
72 enum TOptions {
73     EOptionNone                 = 0,
74     EOptionIntermediate         = (1 <<  0),
75     EOptionSuppressInfolog      = (1 <<  1),
76     EOptionMemoryLeakMode       = (1 <<  2),
77     EOptionRelaxedErrors        = (1 <<  3),
78     EOptionGiveWarnings         = (1 <<  4),
79     EOptionLinkProgram          = (1 <<  5),
80     EOptionMultiThreaded        = (1 <<  6),
81     EOptionDumpConfig           = (1 <<  7),
82     EOptionDumpReflection       = (1 <<  8),
83     EOptionSuppressWarnings     = (1 <<  9),
84     EOptionDumpVersions         = (1 << 10),
85     EOptionSpv                  = (1 << 11),
86     EOptionHumanReadableSpv     = (1 << 12),
87     EOptionVulkanRules          = (1 << 13),
88     EOptionDefaultDesktop       = (1 << 14),
89     EOptionOutputPreprocessed   = (1 << 15),
90     EOptionOutputHexadecimal    = (1 << 16),
91     EOptionReadHlsl             = (1 << 17),
92     EOptionCascadingErrors      = (1 << 18),
93     EOptionAutoMapBindings      = (1 << 19),
94     EOptionFlattenUniformArrays = (1 << 20),
95     EOptionNoStorageFormat      = (1 << 21),
96     EOptionKeepUncalled         = (1 << 22),
97     EOptionHlslOffsets          = (1 << 23),
98     EOptionHlslIoMapping        = (1 << 24),
99     EOptionAutoMapLocations     = (1 << 25),
100     EOptionDebug                = (1 << 26),
101     EOptionStdin                = (1 << 27),
102     EOptionOptimizeDisable      = (1 << 28),
103     EOptionOptimizeSize         = (1 << 29),
104     EOptionInvertY              = (1 << 30),
105     EOptionDumpBareVersion      = (1 << 31),
106 };
107 bool targetHlslFunctionality1 = false;
108 bool SpvToolsDisassembler = false;
109 bool SpvToolsValidate = false;
110 bool NaNClamp = false;
111 bool stripDebugInfo = false;
112 bool beQuiet = false;
113 bool VulkanRulesRelaxed = false;
114
115 //
116 // Return codes from main/exit().
117 //
118 enum TFailCode {
119     ESuccess = 0,
120     EFailUsage,
121     EFailCompile,
122     EFailLink,
123     EFailCompilerCreate,
124     EFailThreadCreate,
125     EFailLinkerCreate
126 };
127
128 //
129 // Forward declarations.
130 //
131 EShLanguage FindLanguage(const std::string& name, bool parseSuffix=true);
132 void CompileFile(const char* fileName, ShHandle);
133 void usage();
134 char* ReadFileData(const char* fileName);
135 void FreeFileData(char* data);
136 void InfoLogMsg(const char* msg, const char* name, const int num);
137
138 // Globally track if any compile or link failure.
139 bool CompileFailed = false;
140 bool LinkFailed = false;
141
142 // array of unique places to leave the shader names and infologs for the asynchronous compiles
143 std::vector<std::unique_ptr<glslang::TWorkItem>> WorkItems;
144
145 TBuiltInResource Resources;
146 std::string ConfigFile;
147
148 //
149 // Parse either a .conf file provided by the user or the default from glslang::DefaultTBuiltInResource
150 //
151 void ProcessConfigFile()
152 {
153     if (ConfigFile.size() == 0)
154         Resources = glslang::DefaultTBuiltInResource;
155 #ifndef GLSLANG_WEB
156     else {
157         char* configString = ReadFileData(ConfigFile.c_str());
158         glslang::DecodeResourceLimits(&Resources,  configString);
159         FreeFileData(configString);
160     }
161 #endif
162 }
163
164 int ReflectOptions = EShReflectionDefault;
165 int Options = 0;
166 const char* ExecutableName = nullptr;
167 const char* binaryFileName = nullptr;
168 const char* entryPointName = nullptr;
169 const char* sourceEntryPointName = nullptr;
170 const char* shaderStageName = nullptr;
171 const char* variableName = nullptr;
172 bool HlslEnable16BitTypes = false;
173 bool HlslDX9compatible = false;
174 bool DumpBuiltinSymbols = false;
175 std::vector<std::string> IncludeDirectoryList;
176
177 // Source environment
178 // (source 'Client' is currently the same as target 'Client')
179 int ClientInputSemanticsVersion = 100;
180
181 // Target environment
182 glslang::EShClient Client = glslang::EShClientNone;  // will stay EShClientNone if only validating
183 glslang::EShTargetClientVersion ClientVersion;       // not valid until Client is set
184 glslang::EShTargetLanguage TargetLanguage = glslang::EShTargetNone;
185 glslang::EShTargetLanguageVersion TargetVersion;     // not valid until TargetLanguage is set
186
187 std::vector<std::string> Processes;                     // what should be recorded by OpModuleProcessed, or equivalent
188
189 // Per descriptor-set binding base data
190 typedef std::map<unsigned int, unsigned int> TPerSetBaseBinding;
191
192 std::vector<std::pair<std::string, int>> uniformLocationOverrides;
193 int uniformBase = 0;
194
195 std::array<std::array<unsigned int, EShLangCount>, glslang::EResCount> baseBinding;
196 std::array<std::array<TPerSetBaseBinding, EShLangCount>, glslang::EResCount> baseBindingForSet;
197 std::array<std::vector<std::string>, EShLangCount> baseResourceSetBinding;
198
199 std::vector<std::pair<std::string, glslang::TBlockStorageClass>> blockStorageOverrides;
200
201 bool setGlobalUniformBlock = false;
202 std::string globalUniformName;
203 unsigned int globalUniformBinding;
204 unsigned int globalUniformSet;
205
206 bool setGlobalBufferBlock = false;
207 std::string atomicCounterBlockName;
208 unsigned int atomicCounterBlockSet;
209
210 // Add things like "#define ..." to a preamble to use in the beginning of the shader.
211 class TPreamble {
212 public:
213     TPreamble() { }
214
215     bool isSet() const { return text.size() > 0; }
216     const char* get() const { return text.c_str(); }
217
218     // #define...
219     void addDef(std::string def)
220     {
221         text.append("#define ");
222         fixLine(def);
223
224         Processes.push_back("define-macro ");
225         Processes.back().append(def);
226
227         // The first "=" needs to turn into a space
228         const size_t equal = def.find_first_of("=");
229         if (equal != def.npos)
230             def[equal] = ' ';
231
232         text.append(def);
233         text.append("\n");
234     }
235
236     // #undef...
237     void addUndef(std::string undef)
238     {
239         text.append("#undef ");
240         fixLine(undef);
241
242         Processes.push_back("undef-macro ");
243         Processes.back().append(undef);
244
245         text.append(undef);
246         text.append("\n");
247     }
248
249 protected:
250     void fixLine(std::string& line)
251     {
252         // Can't go past a newline in the line
253         const size_t end = line.find_first_of("\n");
254         if (end != line.npos)
255             line = line.substr(0, end);
256     }
257
258     std::string text;  // contents of preamble
259 };
260
261 // Track the user's #define and #undef from the command line.
262 TPreamble UserPreamble;
263
264 //
265 // Create the default name for saving a binary if -o is not provided.
266 //
267 const char* GetBinaryName(EShLanguage stage)
268 {
269     const char* name;
270     if (binaryFileName == nullptr) {
271         switch (stage) {
272         case EShLangVertex:          name = "vert.spv";    break;
273         case EShLangTessControl:     name = "tesc.spv";    break;
274         case EShLangTessEvaluation:  name = "tese.spv";    break;
275         case EShLangGeometry:        name = "geom.spv";    break;
276         case EShLangFragment:        name = "frag.spv";    break;
277         case EShLangCompute:         name = "comp.spv";    break;
278         case EShLangRayGen:          name = "rgen.spv";    break;
279         case EShLangIntersect:       name = "rint.spv";    break;
280         case EShLangAnyHit:          name = "rahit.spv";   break;
281         case EShLangClosestHit:      name = "rchit.spv";   break;
282         case EShLangMiss:            name = "rmiss.spv";   break;
283         case EShLangCallable:        name = "rcall.spv";   break;
284         case EShLangMeshNV:          name = "mesh.spv";    break;
285         case EShLangTaskNV:          name = "task.spv";    break;
286         default:                     name = "unknown";     break;
287         }
288     } else
289         name = binaryFileName;
290
291     return name;
292 }
293
294 //
295 // *.conf => this is a config file that can set limits/resources
296 //
297 bool SetConfigFile(const std::string& name)
298 {
299     if (name.size() < 5)
300         return false;
301
302     if (name.compare(name.size() - 5, 5, ".conf") == 0) {
303         ConfigFile = name;
304         return true;
305     }
306
307     return false;
308 }
309
310 //
311 // Give error and exit with failure code.
312 //
313 void Error(const char* message, const char* detail = nullptr)
314 {
315     fprintf(stderr, "%s: Error: ", ExecutableName);
316     if (detail != nullptr)
317         fprintf(stderr, "%s: ", detail);
318     fprintf(stderr, "%s (use -h for usage)\n", message);
319     exit(EFailUsage);
320 }
321
322 //
323 // Process an optional binding base of one the forms:
324 //   --argname [stage] base            // base for stage (if given) or all stages (if not)
325 //   --argname [stage] [base set]...   // set/base pairs: set the base for given binding set.
326
327 // Where stage is one of the forms accepted by FindLanguage, and base is an integer
328 //
329 void ProcessBindingBase(int& argc, char**& argv, glslang::TResourceType res)
330 {
331     if (argc < 2)
332         usage();
333
334     EShLanguage lang = EShLangCount;
335     int singleBase = 0;
336     TPerSetBaseBinding perSetBase;
337     int arg = 1;
338
339     // Parse stage, if given
340     if (!isdigit(argv[arg][0])) {
341         if (argc < 3) // this form needs one more argument
342             usage();
343
344         lang = FindLanguage(argv[arg++], false);
345     }
346
347     if ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) {
348         // Parse a per-set binding base
349         while ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) {
350             const int baseNum = atoi(argv[arg++]);
351             const int setNum = atoi(argv[arg++]);
352             perSetBase[setNum] = baseNum;
353         }
354     } else {
355         // Parse single binding base
356         singleBase = atoi(argv[arg++]);
357     }
358
359     argc -= (arg-1);
360     argv += (arg-1);
361
362     // Set one or all languages
363     const int langMin = (lang < EShLangCount) ? lang+0 : 0;
364     const int langMax = (lang < EShLangCount) ? lang+1 : EShLangCount;
365
366     for (int lang = langMin; lang < langMax; ++lang) {
367         if (!perSetBase.empty())
368             baseBindingForSet[res][lang].insert(perSetBase.begin(), perSetBase.end());
369         else
370             baseBinding[res][lang] = singleBase;
371     }
372 }
373
374 void ProcessResourceSetBindingBase(int& argc, char**& argv, std::array<std::vector<std::string>, EShLangCount>& base)
375 {
376     if (argc < 2)
377         usage();
378
379     if (!isdigit(argv[1][0])) {
380         if (argc < 3) // this form needs one more argument
381             usage();
382
383         // Parse form: --argname stage [regname set base...], or:
384         //             --argname stage set
385         const EShLanguage lang = FindLanguage(argv[1], false);
386
387         argc--;
388         argv++;
389
390         while (argc > 1 && argv[1] != nullptr && argv[1][0] != '-') {
391             base[lang].push_back(argv[1]);
392
393             argc--;
394             argv++;
395         }
396
397         // Must have one arg, or a multiple of three (for [regname set binding] triples)
398         if (base[lang].size() != 1 && (base[lang].size() % 3) != 0)
399             usage();
400
401     } else {
402         // Parse form: --argname set
403         for (int lang=0; lang<EShLangCount; ++lang)
404             base[lang].push_back(argv[1]);
405
406         argc--;
407         argv++;
408     }
409 }
410
411 //
412 // Process an optional binding base of one the forms:
413 //   --argname name {uniform|buffer|push_constant}
414 void ProcessBlockStorage(int& argc, char**& argv, std::vector<std::pair<std::string, glslang::TBlockStorageClass>>& storage)
415 {
416     if (argc < 3)
417         usage();
418
419     glslang::TBlockStorageClass blockStorage = glslang::EbsNone;
420
421     std::string strBacking(argv[2]);
422     if (strBacking == "uniform")
423         blockStorage = glslang::EbsUniform;
424     else if (strBacking == "buffer")
425         blockStorage = glslang::EbsStorageBuffer;
426     else if (strBacking == "push_constant")
427         blockStorage = glslang::EbsPushConstant;
428     else {
429         printf("%s: invalid block storage\n", strBacking.c_str());
430         usage();
431     }
432
433     storage.push_back(std::make_pair(std::string(argv[1]), blockStorage));
434
435     argc -= 2;
436     argv += 2;
437 }
438
439 inline bool isNonDigit(char c) {
440     // a non-digit character valid in a glsl identifier
441     return (c == '_') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
442 }
443
444 // whether string isa  valid identifier to be used in glsl
445 bool isValidIdentifier(const char* str) {
446     std::string idn(str);
447
448     if (idn.length() == 0) {
449         return false;
450     }
451
452     if (idn.length() >= 3 && idn.substr(0, 3) == "gl_") {
453         // identifiers startin with "gl_" are reserved
454         return false;
455     }
456
457     if (!isNonDigit(idn[0])) {
458         return false;
459     }
460
461     for (unsigned int i = 1; i < idn.length(); ++i) {
462         if (!(isdigit(idn[i]) || isNonDigit(idn[i]))) {
463             return false;
464         }
465     }
466
467     return true;
468 }
469
470 // Process settings for either the global buffer block or global unfirom block
471 // of the form:
472 //      --argname name set binding
473 void ProcessGlobalBlockSettings(int& argc, char**& argv, std::string* name, unsigned int* set, unsigned int* binding)
474 {
475     if (argc < 4)
476         usage();
477
478     unsigned int curArg = 1;
479
480     assert(name || set || binding);
481
482     if (name) {
483         if (!isValidIdentifier(argv[curArg])) {
484             printf("%s: invalid identifier\n", argv[curArg]);
485             usage();
486         }
487         *name = argv[curArg];
488
489         curArg++;
490     }
491
492     if (set) {
493         errno = 0;
494         int setVal = ::strtol(argv[curArg], NULL, 10);
495         if (errno || setVal < 0) {
496             printf("%s: invalid set\n", argv[curArg]);
497             usage();
498         }
499         *set = setVal;
500
501         curArg++;
502     }
503
504     if (binding) {
505         errno = 0;
506         int bindingVal = ::strtol(argv[curArg], NULL, 10);
507         if (errno || bindingVal < 0) {
508             printf("%s: invalid binding\n", argv[curArg]);
509             usage();
510         }
511         *binding = bindingVal;
512
513         curArg++;
514     }
515
516     argc -= (curArg - 1);
517     argv += (curArg - 1);
518 }
519
520 //
521 // Do all command-line argument parsing.  This includes building up the work-items
522 // to be processed later, and saving all the command-line options.
523 //
524 // Does not return (it exits) if command-line is fatally flawed.
525 //
526 void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItems, int argc, char* argv[])
527 {
528     for (int res = 0; res < glslang::EResCount; ++res)
529         baseBinding[res].fill(0);
530
531     ExecutableName = argv[0];
532     workItems.reserve(argc);
533
534     const auto bumpArg = [&]() {
535         if (argc > 0) {
536             argc--;
537             argv++;
538         }
539     };
540
541     // read a string directly attached to a single-letter option
542     const auto getStringOperand = [&](const char* desc) {
543         if (argv[0][2] == 0) {
544             printf("%s must immediately follow option (no spaces)\n", desc);
545             exit(EFailUsage);
546         }
547         return argv[0] + 2;
548     };
549
550     // read a number attached to a single-letter option
551     const auto getAttachedNumber = [&](const char* desc) {
552         int num = atoi(argv[0] + 2);
553         if (num == 0) {
554             printf("%s: expected attached non-0 number\n", desc);
555             exit(EFailUsage);
556         }
557         return num;
558     };
559
560     // minimum needed (without overriding something else) to target Vulkan SPIR-V
561     const auto setVulkanSpv = []() {
562         if (Client == glslang::EShClientNone)
563             ClientVersion = glslang::EShTargetVulkan_1_0;
564         Client = glslang::EShClientVulkan;
565         Options |= EOptionSpv;
566         Options |= EOptionVulkanRules;
567         Options |= EOptionLinkProgram;
568     };
569
570     // minimum needed (without overriding something else) to target OpenGL SPIR-V
571     const auto setOpenGlSpv = []() {
572         if (Client == glslang::EShClientNone)
573             ClientVersion = glslang::EShTargetOpenGL_450;
574         Client = glslang::EShClientOpenGL;
575         Options |= EOptionSpv;
576         Options |= EOptionLinkProgram;
577         // undo a -H default to Vulkan
578         Options &= ~EOptionVulkanRules;
579     };
580
581     const auto getUniformOverride = [getStringOperand]() {
582         const char *arg = getStringOperand("-u<name>:<location>");
583         const char *split = strchr(arg, ':');
584         if (split == NULL) {
585             printf("%s: missing location\n", arg);
586             exit(EFailUsage);
587         }
588         errno = 0;
589         int location = ::strtol(split + 1, NULL, 10);
590         if (errno) {
591             printf("%s: invalid location\n", arg);
592             exit(EFailUsage);
593         }
594         return std::make_pair(std::string(arg, split - arg), location);
595     };
596
597     for (bumpArg(); argc >= 1; bumpArg()) {
598         if (argv[0][0] == '-') {
599             switch (argv[0][1]) {
600             case '-':
601                 {
602                     std::string lowerword(argv[0]+2);
603                     std::transform(lowerword.begin(), lowerword.end(), lowerword.begin(), ::tolower);
604
605                     // handle --word style options
606                     if (lowerword == "auto-map-bindings" ||  // synonyms
607                         lowerword == "auto-map-binding"  ||
608                         lowerword == "amb") {
609                         Options |= EOptionAutoMapBindings;
610                     } else if (lowerword == "auto-map-locations" || // synonyms
611                                lowerword == "aml") {
612                         Options |= EOptionAutoMapLocations;
613                     } else if (lowerword == "uniform-base") {
614                         if (argc <= 1)
615                             Error("no <base> provided", lowerword.c_str());
616                         uniformBase = ::strtol(argv[1], NULL, 10);
617                         bumpArg();
618                         break;
619                     } else if (lowerword == "client") {
620                         if (argc > 1) {
621                             if (strcmp(argv[1], "vulkan100") == 0)
622                                 setVulkanSpv();
623                             else if (strcmp(argv[1], "opengl100") == 0)
624                                 setOpenGlSpv();
625                             else
626                                 Error("expects vulkan100 or opengl100", lowerword.c_str());
627                         } else
628                             Error("expects vulkan100 or opengl100", lowerword.c_str());
629                         bumpArg();
630                     } else if (lowerword == "define-macro" ||
631                                lowerword == "d") {
632                         if (argc > 1)
633                             UserPreamble.addDef(argv[1]);
634                         else
635                             Error("expects <name[=def]>", argv[0]);
636                         bumpArg();
637                     } else if (lowerword == "dump-builtin-symbols") {
638                         DumpBuiltinSymbols = true;
639                     } else if (lowerword == "entry-point") {
640                         entryPointName = argv[1];
641                         if (argc <= 1)
642                             Error("no <name> provided", lowerword.c_str());
643                         bumpArg();
644                     } else if (lowerword == "flatten-uniform-arrays" || // synonyms
645                                lowerword == "flatten-uniform-array"  ||
646                                lowerword == "fua") {
647                         Options |= EOptionFlattenUniformArrays;
648                     } else if (lowerword == "hlsl-offsets") {
649                         Options |= EOptionHlslOffsets;
650                     } else if (lowerword == "hlsl-iomap" ||
651                                lowerword == "hlsl-iomapper" ||
652                                lowerword == "hlsl-iomapping") {
653                         Options |= EOptionHlslIoMapping;
654                     } else if (lowerword == "hlsl-enable-16bit-types") {
655                         HlslEnable16BitTypes = true;
656                     } else if (lowerword == "hlsl-dx9-compatible") {
657                         HlslDX9compatible = true;
658                     } else if (lowerword == "invert-y" ||  // synonyms
659                                lowerword == "iy") {
660                         Options |= EOptionInvertY;
661                     } else if (lowerword == "keep-uncalled" || // synonyms
662                                lowerword == "ku") {
663                         Options |= EOptionKeepUncalled;
664                     } else if (lowerword == "nan-clamp") {
665                         NaNClamp = true;
666                     } else if (lowerword == "no-storage-format" || // synonyms
667                                lowerword == "nsf") {
668                         Options |= EOptionNoStorageFormat;
669                     } else if (lowerword == "relaxed-errors") {
670                         Options |= EOptionRelaxedErrors;
671                     } else if (lowerword == "reflect-strict-array-suffix") {
672                         ReflectOptions |= EShReflectionStrictArraySuffix;
673                     } else if (lowerword == "reflect-basic-array-suffix") {
674                         ReflectOptions |= EShReflectionBasicArraySuffix;
675                     } else if (lowerword == "reflect-intermediate-io") {
676                         ReflectOptions |= EShReflectionIntermediateIO;
677                     } else if (lowerword == "reflect-separate-buffers") {
678                         ReflectOptions |= EShReflectionSeparateBuffers;
679                     } else if (lowerword == "reflect-all-block-variables") {
680                         ReflectOptions |= EShReflectionAllBlockVariables;
681                     } else if (lowerword == "reflect-unwrap-io-blocks") {
682                         ReflectOptions |= EShReflectionUnwrapIOBlocks;
683                     } else if (lowerword == "reflect-all-io-variables") {
684                         ReflectOptions |= EShReflectionAllIOVariables;
685                     } else if (lowerword == "reflect-shared-std140-ubo") {
686                         ReflectOptions |= EShReflectionSharedStd140UBO;
687                     } else if (lowerword == "reflect-shared-std140-ssbo") {
688                         ReflectOptions |= EShReflectionSharedStd140SSBO;
689                     } else if (lowerword == "resource-set-bindings" ||  // synonyms
690                                lowerword == "resource-set-binding"  ||
691                                lowerword == "rsb") {
692                         ProcessResourceSetBindingBase(argc, argv, baseResourceSetBinding);
693                     } else if (lowerword == "set-block-storage" ||
694                                lowerword == "sbs") {
695                         ProcessBlockStorage(argc, argv, blockStorageOverrides);
696                     } else if (lowerword == "set-atomic-counter-block" ||
697                                lowerword == "sacb") {
698                         ProcessGlobalBlockSettings(argc, argv, &atomicCounterBlockName, &atomicCounterBlockSet, nullptr);
699                         setGlobalBufferBlock = true;
700                     } else if (lowerword == "set-default-uniform-block" ||
701                                lowerword == "sdub") {
702                         ProcessGlobalBlockSettings(argc, argv, &globalUniformName, &globalUniformSet, &globalUniformBinding);
703                         setGlobalUniformBlock = true;
704                     } else if (lowerword == "shift-image-bindings" ||  // synonyms
705                                lowerword == "shift-image-binding"  ||
706                                lowerword == "sib") {
707                         ProcessBindingBase(argc, argv, glslang::EResImage);
708                     } else if (lowerword == "shift-sampler-bindings" || // synonyms
709                                lowerword == "shift-sampler-binding"  ||
710                                lowerword == "ssb") {
711                         ProcessBindingBase(argc, argv, glslang::EResSampler);
712                     } else if (lowerword == "shift-uav-bindings" ||  // synonyms
713                                lowerword == "shift-uav-binding"  ||
714                                lowerword == "suavb") {
715                         ProcessBindingBase(argc, argv, glslang::EResUav);
716                     } else if (lowerword == "shift-texture-bindings" ||  // synonyms
717                                lowerword == "shift-texture-binding"  ||
718                                lowerword == "stb") {
719                         ProcessBindingBase(argc, argv, glslang::EResTexture);
720                     } else if (lowerword == "shift-ubo-bindings" ||  // synonyms
721                                lowerword == "shift-ubo-binding"  ||
722                                lowerword == "shift-cbuffer-bindings" ||
723                                lowerword == "shift-cbuffer-binding"  ||
724                                lowerword == "sub" ||
725                                lowerword == "scb") {
726                         ProcessBindingBase(argc, argv, glslang::EResUbo);
727                     } else if (lowerword == "shift-ssbo-bindings" ||  // synonyms
728                                lowerword == "shift-ssbo-binding"  ||
729                                lowerword == "sbb") {
730                         ProcessBindingBase(argc, argv, glslang::EResSsbo);
731                     } else if (lowerword == "source-entrypoint" || // synonyms
732                                lowerword == "sep") {
733                         if (argc <= 1)
734                             Error("no <entry-point> provided", lowerword.c_str());
735                         sourceEntryPointName = argv[1];
736                         bumpArg();
737                         break;
738                     } else if (lowerword == "spirv-dis") {
739                         SpvToolsDisassembler = true;
740                     } else if (lowerword == "spirv-val") {
741                         SpvToolsValidate = true;
742                     } else if (lowerword == "stdin") {
743                         Options |= EOptionStdin;
744                         shaderStageName = argv[1];
745                     } else if (lowerword == "suppress-warnings") {
746                         Options |= EOptionSuppressWarnings;
747                     } else if (lowerword == "target-env") {
748                         if (argc > 1) {
749                             if (strcmp(argv[1], "vulkan1.0") == 0) {
750                                 setVulkanSpv();
751                                 ClientVersion = glslang::EShTargetVulkan_1_0;
752                             } else if (strcmp(argv[1], "vulkan1.1") == 0) {
753                                 setVulkanSpv();
754                                 ClientVersion = glslang::EShTargetVulkan_1_1;
755                             } else if (strcmp(argv[1], "vulkan1.2") == 0) {
756                                 setVulkanSpv();
757                                 ClientVersion = glslang::EShTargetVulkan_1_2;
758                             } else if (strcmp(argv[1], "opengl") == 0) {
759                                 setOpenGlSpv();
760                                 ClientVersion = glslang::EShTargetOpenGL_450;
761                             } else if (strcmp(argv[1], "spirv1.0") == 0) {
762                                 TargetLanguage = glslang::EShTargetSpv;
763                                 TargetVersion = glslang::EShTargetSpv_1_0;
764                             } else if (strcmp(argv[1], "spirv1.1") == 0) {
765                                 TargetLanguage = glslang::EShTargetSpv;
766                                 TargetVersion = glslang::EShTargetSpv_1_1;
767                             } else if (strcmp(argv[1], "spirv1.2") == 0) {
768                                 TargetLanguage = glslang::EShTargetSpv;
769                                 TargetVersion = glslang::EShTargetSpv_1_2;
770                             } else if (strcmp(argv[1], "spirv1.3") == 0) {
771                                 TargetLanguage = glslang::EShTargetSpv;
772                                 TargetVersion = glslang::EShTargetSpv_1_3;
773                             } else if (strcmp(argv[1], "spirv1.4") == 0) {
774                                 TargetLanguage = glslang::EShTargetSpv;
775                                 TargetVersion = glslang::EShTargetSpv_1_4;
776                             } else if (strcmp(argv[1], "spirv1.5") == 0) {
777                                 TargetLanguage = glslang::EShTargetSpv;
778                                 TargetVersion = glslang::EShTargetSpv_1_5;
779                             } else
780                                 Error("--target-env expected one of: vulkan1.0, vulkan1.1, vulkan1.2, opengl,\n"
781                                       "spirv1.0, spirv1.1, spirv1.2, spirv1.3, spirv1.4, or spirv1.5");
782                         }
783                         bumpArg();
784                     } else if (lowerword == "undef-macro" ||
785                                lowerword == "u") {
786                         if (argc > 1)
787                             UserPreamble.addUndef(argv[1]);
788                         else
789                             Error("expects <name>", argv[0]);
790                         bumpArg();
791                     } else if (lowerword == "variable-name" || // synonyms
792                                lowerword == "vn") {
793                         Options |= EOptionOutputHexadecimal;
794                         if (argc <= 1)
795                             Error("no <C-variable-name> provided", lowerword.c_str());
796                         variableName = argv[1];
797                         bumpArg();
798                         break;
799                     } else if (lowerword == "quiet") {
800                         beQuiet = true;
801                     } else if (lowerword == "version") {
802                         Options |= EOptionDumpVersions;
803                     } else if (lowerword == "help") {
804                         usage();
805                         break;
806                     } else {
807                         Error("unrecognized command-line option", argv[0]);
808                     }
809                 }
810                 break;
811             case 'C':
812                 Options |= EOptionCascadingErrors;
813                 break;
814             case 'D':
815                 if (argv[0][2] == 0)
816                     Options |= EOptionReadHlsl;
817                 else
818                     UserPreamble.addDef(getStringOperand("-D<name[=def]>"));
819                 break;
820             case 'u':
821                 uniformLocationOverrides.push_back(getUniformOverride());
822                 break;
823             case 'E':
824                 Options |= EOptionOutputPreprocessed;
825                 break;
826             case 'G':
827                 // OpenGL client
828                 setOpenGlSpv();
829                 if (argv[0][2] != 0)
830                     ClientInputSemanticsVersion = getAttachedNumber("-G<num> client input semantics");
831                 if (ClientInputSemanticsVersion != 100)
832                     Error("unknown client version for -G, should be 100");
833                 break;
834             case 'H':
835                 Options |= EOptionHumanReadableSpv;
836                 if ((Options & EOptionSpv) == 0) {
837                     // default to Vulkan
838                     setVulkanSpv();
839                 }
840                 break;
841             case 'I':
842                 IncludeDirectoryList.push_back(getStringOperand("-I<dir> include path"));
843                 break;
844             case 'O':
845                 if (argv[0][2] == 'd')
846                     Options |= EOptionOptimizeDisable;
847                 else if (argv[0][2] == 's')
848 #if ENABLE_OPT
849                     Options |= EOptionOptimizeSize;
850 #else
851                     Error("-Os not available; optimizer not linked");
852 #endif
853                 else
854                     Error("unknown -O option");
855                 break;
856             case 'R':
857                 VulkanRulesRelaxed = true;
858                 break;
859             case 'S':
860                 if (argc <= 1)
861                     Error("no <stage> specified for -S");
862                 shaderStageName = argv[1];
863                 bumpArg();
864                 break;
865             case 'U':
866                 UserPreamble.addUndef(getStringOperand("-U<name>"));
867                 break;
868             case 'V':
869                 setVulkanSpv();
870                 if (argv[0][2] != 0)
871                     ClientInputSemanticsVersion = getAttachedNumber("-V<num> client input semantics");
872                 if (ClientInputSemanticsVersion != 100)
873                     Error("unknown client version for -V, should be 100");
874                 break;
875             case 'c':
876                 Options |= EOptionDumpConfig;
877                 break;
878             case 'd':
879                 if (strncmp(&argv[0][1], "dumpversion", strlen(&argv[0][1]) + 1) == 0 ||
880                     strncmp(&argv[0][1], "dumpfullversion", strlen(&argv[0][1]) + 1) == 0)
881                     Options |= EOptionDumpBareVersion;
882                 else
883                     Options |= EOptionDefaultDesktop;
884                 break;
885             case 'e':
886                 entryPointName = argv[1];
887                 if (argc <= 1)
888                     Error("no <name> provided for -e");
889                 bumpArg();
890                 break;
891             case 'f':
892                 if (strcmp(&argv[0][2], "hlsl_functionality1") == 0)
893                     targetHlslFunctionality1 = true;
894                 else
895                     Error("-f: expected hlsl_functionality1");
896                 break;
897             case 'g':
898                 // Override previous -g or -g0 argument
899                 stripDebugInfo = false;
900                 Options &= ~EOptionDebug;
901                 if (argv[0][2] == '0')
902                     stripDebugInfo = true;
903                 else
904                     Options |= EOptionDebug;
905                 break;
906             case 'h':
907                 usage();
908                 break;
909             case 'i':
910                 Options |= EOptionIntermediate;
911                 break;
912             case 'l':
913                 Options |= EOptionLinkProgram;
914                 break;
915             case 'm':
916                 Options |= EOptionMemoryLeakMode;
917                 break;
918             case 'o':
919                 if (argc <= 1)
920                     Error("no <file> provided for -o");
921                 binaryFileName = argv[1];
922                 bumpArg();
923                 break;
924             case 'q':
925                 Options |= EOptionDumpReflection;
926                 break;
927             case 'r':
928                 Options |= EOptionRelaxedErrors;
929                 break;
930             case 's':
931                 Options |= EOptionSuppressInfolog;
932                 break;
933             case 't':
934                 Options |= EOptionMultiThreaded;
935                 break;
936             case 'v':
937                 Options |= EOptionDumpVersions;
938                 break;
939             case 'w':
940                 Options |= EOptionSuppressWarnings;
941                 break;
942             case 'x':
943                 Options |= EOptionOutputHexadecimal;
944                 break;
945             default:
946                 Error("unrecognized command-line option", argv[0]);
947                 break;
948             }
949         } else {
950             std::string name(argv[0]);
951             if (! SetConfigFile(name)) {
952                 workItems.push_back(std::unique_ptr<glslang::TWorkItem>(new glslang::TWorkItem(name)));
953             }
954         }
955     }
956
957     // Make sure that -S is always specified if --stdin is specified
958     if ((Options & EOptionStdin) && shaderStageName == nullptr)
959         Error("must provide -S when --stdin is given");
960
961     // Make sure that -E is not specified alongside linking (which includes SPV generation)
962     // Or things that require linking
963     if (Options & EOptionOutputPreprocessed) {
964         if (Options & EOptionLinkProgram)
965             Error("can't use -E when linking is selected");
966         if (Options & EOptionDumpReflection)
967             Error("reflection requires linking, which can't be used when -E when is selected");
968     }
969
970     // reflection requires linking
971     if ((Options & EOptionDumpReflection) && !(Options & EOptionLinkProgram))
972         Error("reflection requires -l for linking");
973
974     // -o or -x makes no sense if there is no target binary
975     if (binaryFileName && (Options & EOptionSpv) == 0)
976         Error("no binary generation requested (e.g., -V)");
977
978     if ((Options & EOptionFlattenUniformArrays) != 0 &&
979         (Options & EOptionReadHlsl) == 0)
980         Error("uniform array flattening only valid when compiling HLSL source.");
981
982     if ((Options & EOptionReadHlsl) && (Client == glslang::EShClientOpenGL)) {
983         Error("Using HLSL input under OpenGL semantics is not currently supported.");
984     }
985
986     // rationalize client and target language
987     if (TargetLanguage == glslang::EShTargetNone) {
988         switch (ClientVersion) {
989         case glslang::EShTargetVulkan_1_0:
990             TargetLanguage = glslang::EShTargetSpv;
991             TargetVersion = glslang::EShTargetSpv_1_0;
992             break;
993         case glslang::EShTargetVulkan_1_1:
994             TargetLanguage = glslang::EShTargetSpv;
995             TargetVersion = glslang::EShTargetSpv_1_3;
996             break;
997         case glslang::EShTargetVulkan_1_2:
998             TargetLanguage = glslang::EShTargetSpv;
999             TargetVersion = glslang::EShTargetSpv_1_5;
1000             break;
1001         case glslang::EShTargetOpenGL_450:
1002             TargetLanguage = glslang::EShTargetSpv;
1003             TargetVersion = glslang::EShTargetSpv_1_0;
1004             break;
1005         default:
1006             break;
1007         }
1008     }
1009     if (TargetLanguage != glslang::EShTargetNone && Client == glslang::EShClientNone)
1010         Error("To generate SPIR-V, also specify client semantics. See -G and -V.");
1011 }
1012
1013 //
1014 // Translate the meaningful subset of command-line options to parser-behavior options.
1015 //
1016 void SetMessageOptions(EShMessages& messages)
1017 {
1018     if (Options & EOptionRelaxedErrors)
1019         messages = (EShMessages)(messages | EShMsgRelaxedErrors);
1020     if (Options & EOptionIntermediate)
1021         messages = (EShMessages)(messages | EShMsgAST);
1022     if (Options & EOptionSuppressWarnings)
1023         messages = (EShMessages)(messages | EShMsgSuppressWarnings);
1024     if (Options & EOptionSpv)
1025         messages = (EShMessages)(messages | EShMsgSpvRules);
1026     if (Options & EOptionVulkanRules)
1027         messages = (EShMessages)(messages | EShMsgVulkanRules);
1028     if (Options & EOptionOutputPreprocessed)
1029         messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
1030     if (Options & EOptionReadHlsl)
1031         messages = (EShMessages)(messages | EShMsgReadHlsl);
1032     if (Options & EOptionCascadingErrors)
1033         messages = (EShMessages)(messages | EShMsgCascadingErrors);
1034     if (Options & EOptionKeepUncalled)
1035         messages = (EShMessages)(messages | EShMsgKeepUncalled);
1036     if (Options & EOptionHlslOffsets)
1037         messages = (EShMessages)(messages | EShMsgHlslOffsets);
1038     if (Options & EOptionDebug)
1039         messages = (EShMessages)(messages | EShMsgDebugInfo);
1040     if (HlslEnable16BitTypes)
1041         messages = (EShMessages)(messages | EShMsgHlslEnable16BitTypes);
1042     if ((Options & EOptionOptimizeDisable) || !ENABLE_OPT)
1043         messages = (EShMessages)(messages | EShMsgHlslLegalization);
1044     if (HlslDX9compatible)
1045         messages = (EShMessages)(messages | EShMsgHlslDX9Compatible);
1046     if (DumpBuiltinSymbols)
1047         messages = (EShMessages)(messages | EShMsgBuiltinSymbolTable);
1048 }
1049
1050 //
1051 // Thread entry point, for non-linking asynchronous mode.
1052 //
1053 void CompileShaders(glslang::TWorklist& worklist)
1054 {
1055     if (Options & EOptionDebug)
1056         Error("cannot generate debug information unless linking to generate code");
1057
1058     glslang::TWorkItem* workItem;
1059     if (Options & EOptionStdin) {
1060         if (worklist.remove(workItem)) {
1061             ShHandle compiler = ShConstructCompiler(FindLanguage("stdin"), Options);
1062             if (compiler == nullptr)
1063                 return;
1064
1065             CompileFile("stdin", compiler);
1066
1067             if (! (Options & EOptionSuppressInfolog))
1068                 workItem->results = ShGetInfoLog(compiler);
1069
1070             ShDestruct(compiler);
1071         }
1072     } else {
1073         while (worklist.remove(workItem)) {
1074             ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
1075             if (compiler == 0)
1076                 return;
1077
1078             CompileFile(workItem->name.c_str(), compiler);
1079
1080             if (! (Options & EOptionSuppressInfolog))
1081                 workItem->results = ShGetInfoLog(compiler);
1082
1083             ShDestruct(compiler);
1084         }
1085     }
1086 }
1087
1088 // Outputs the given string, but only if it is non-null and non-empty.
1089 // This prevents erroneous newlines from appearing.
1090 void PutsIfNonEmpty(const char* str)
1091 {
1092     if (str && str[0]) {
1093         puts(str);
1094     }
1095 }
1096
1097 // Outputs the given string to stderr, but only if it is non-null and non-empty.
1098 // This prevents erroneous newlines from appearing.
1099 void StderrIfNonEmpty(const char* str)
1100 {
1101     if (str && str[0])
1102         fprintf(stderr, "%s\n", str);
1103 }
1104
1105 // Simple bundling of what makes a compilation unit for ease in passing around,
1106 // and separation of handling file IO versus API (programmatic) compilation.
1107 struct ShaderCompUnit {
1108     EShLanguage stage;
1109     static const int maxCount = 1;
1110     int count;                          // live number of strings/names
1111     const char* text[maxCount];         // memory owned/managed externally
1112     std::string fileName[maxCount];     // hold's the memory, but...
1113     const char* fileNameList[maxCount]; // downstream interface wants pointers
1114
1115     ShaderCompUnit(EShLanguage stage) : stage(stage), count(0) { }
1116
1117     ShaderCompUnit(const ShaderCompUnit& rhs)
1118     {
1119         stage = rhs.stage;
1120         count = rhs.count;
1121         for (int i = 0; i < count; ++i) {
1122             fileName[i] = rhs.fileName[i];
1123             text[i] = rhs.text[i];
1124             fileNameList[i] = rhs.fileName[i].c_str();
1125         }
1126     }
1127
1128     void addString(std::string& ifileName, const char* itext)
1129     {
1130         assert(count < maxCount);
1131         fileName[count] = ifileName;
1132         text[count] = itext;
1133         fileNameList[count] = fileName[count].c_str();
1134         ++count;
1135     }
1136 };
1137
1138 //
1139 // For linking mode: Will independently parse each compilation unit, but then put them
1140 // in the same program and link them together, making at most one linked module per
1141 // pipeline stage.
1142 //
1143 // Uses the new C++ interface instead of the old handle-based interface.
1144 //
1145
1146 void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
1147 {
1148     // keep track of what to free
1149     std::list<glslang::TShader*> shaders;
1150
1151     EShMessages messages = EShMsgDefault;
1152     SetMessageOptions(messages);
1153
1154     //
1155     // Per-shader processing...
1156     //
1157
1158     glslang::TProgram& program = *new glslang::TProgram;
1159     for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
1160         const auto &compUnit = *it;
1161         glslang::TShader* shader = new glslang::TShader(compUnit.stage);
1162         shader->setStringsWithLengthsAndNames(compUnit.text, NULL, compUnit.fileNameList, compUnit.count);
1163         if (entryPointName)
1164             shader->setEntryPoint(entryPointName);
1165         if (sourceEntryPointName) {
1166             if (entryPointName == nullptr)
1167                 printf("Warning: Changing source entry point name without setting an entry-point name.\n"
1168                        "Use '-e <name>'.\n");
1169             shader->setSourceEntryPoint(sourceEntryPointName);
1170         }
1171         if (UserPreamble.isSet())
1172             shader->setPreamble(UserPreamble.get());
1173         shader->addProcesses(Processes);
1174
1175 #ifndef GLSLANG_WEB
1176         // Set IO mapper binding shift values
1177         for (int r = 0; r < glslang::EResCount; ++r) {
1178             const glslang::TResourceType res = glslang::TResourceType(r);
1179
1180             // Set base bindings
1181             shader->setShiftBinding(res, baseBinding[res][compUnit.stage]);
1182
1183             // Set bindings for particular resource sets
1184             // TODO: use a range based for loop here, when available in all environments.
1185             for (auto i = baseBindingForSet[res][compUnit.stage].begin();
1186                  i != baseBindingForSet[res][compUnit.stage].end(); ++i)
1187                 shader->setShiftBindingForSet(res, i->second, i->first);
1188         }
1189         shader->setNoStorageFormat((Options & EOptionNoStorageFormat) != 0);
1190         shader->setResourceSetBinding(baseResourceSetBinding[compUnit.stage]);
1191
1192         if (Options & EOptionAutoMapBindings)
1193             shader->setAutoMapBindings(true);
1194
1195         if (Options & EOptionAutoMapLocations)
1196             shader->setAutoMapLocations(true);
1197
1198         for (auto& uniOverride : uniformLocationOverrides) {
1199             shader->addUniformLocationOverride(uniOverride.first.c_str(),
1200                                                uniOverride.second);
1201         }
1202
1203         shader->setUniformLocationBase(uniformBase);
1204 #endif
1205
1206         if (VulkanRulesRelaxed) {
1207             for (auto& storageOverride : blockStorageOverrides) {
1208                 shader->addBlockStorageOverride(storageOverride.first.c_str(),
1209                     storageOverride.second);
1210             }
1211
1212             if (setGlobalBufferBlock) {
1213                 shader->setAtomicCounterBlockName(atomicCounterBlockName.c_str());
1214                 shader->setAtomicCounterBlockSet(atomicCounterBlockSet);
1215             }
1216
1217             if (setGlobalUniformBlock) {
1218                 shader->setGlobalUniformBlockName(globalUniformName.c_str());
1219                 shader->setGlobalUniformSet(globalUniformSet);
1220                 shader->setGlobalUniformBinding(globalUniformBinding);
1221             }
1222         }
1223
1224         shader->setNanMinMaxClamp(NaNClamp);
1225
1226 #ifdef ENABLE_HLSL
1227         shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0);
1228         if (Options & EOptionHlslIoMapping)
1229             shader->setHlslIoMapping(true);
1230 #endif
1231
1232         if (Options & EOptionInvertY)
1233             shader->setInvertY(true);
1234
1235         // Set up the environment, some subsettings take precedence over earlier
1236         // ways of setting things.
1237         if (Options & EOptionSpv) {
1238             shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl
1239                                                             : glslang::EShSourceGlsl,
1240                                 compUnit.stage, Client, ClientInputSemanticsVersion);
1241             shader->setEnvClient(Client, ClientVersion);
1242             shader->setEnvTarget(TargetLanguage, TargetVersion);
1243 #ifdef ENABLE_HLSL
1244             if (targetHlslFunctionality1)
1245                 shader->setEnvTargetHlslFunctionality1();
1246 #endif
1247             if (VulkanRulesRelaxed)
1248                 shader->setEnvInputVulkanRulesRelaxed();
1249         }
1250
1251         shaders.push_back(shader);
1252
1253         const int defaultVersion = Options & EOptionDefaultDesktop ? 110 : 100;
1254
1255         DirStackFileIncluder includer;
1256         std::for_each(IncludeDirectoryList.rbegin(), IncludeDirectoryList.rend(), [&includer](const std::string& dir) {
1257             includer.pushExternalLocalDirectory(dir); });
1258 #ifndef GLSLANG_WEB
1259         if (Options & EOptionOutputPreprocessed) {
1260             std::string str;
1261             if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false, messages, &str, includer)) {
1262                 PutsIfNonEmpty(str.c_str());
1263             } else {
1264                 CompileFailed = true;
1265             }
1266             StderrIfNonEmpty(shader->getInfoLog());
1267             StderrIfNonEmpty(shader->getInfoDebugLog());
1268             continue;
1269         }
1270 #endif
1271
1272         if (! shader->parse(&Resources, defaultVersion, false, messages, includer))
1273             CompileFailed = true;
1274
1275         program.addShader(shader);
1276
1277         if (! (Options & EOptionSuppressInfolog) &&
1278             ! (Options & EOptionMemoryLeakMode)) {
1279             if (!beQuiet)
1280                 PutsIfNonEmpty(compUnit.fileName[0].c_str());
1281             PutsIfNonEmpty(shader->getInfoLog());
1282             PutsIfNonEmpty(shader->getInfoDebugLog());
1283         }
1284     }
1285
1286     //
1287     // Program-level processing...
1288     //
1289
1290     // Link
1291     if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
1292         LinkFailed = true;
1293
1294 #ifndef GLSLANG_WEB
1295     // Map IO
1296     if (Options & EOptionSpv) {
1297         if (!program.mapIO())
1298             LinkFailed = true;
1299     }
1300 #endif
1301
1302     // Report
1303     if (! (Options & EOptionSuppressInfolog) &&
1304         ! (Options & EOptionMemoryLeakMode)) {
1305         PutsIfNonEmpty(program.getInfoLog());
1306         PutsIfNonEmpty(program.getInfoDebugLog());
1307     }
1308
1309 #ifndef GLSLANG_WEB
1310     // Reflect
1311     if (Options & EOptionDumpReflection) {
1312         program.buildReflection(ReflectOptions);
1313         program.dumpReflection();
1314     }
1315 #endif
1316
1317     // Dump SPIR-V
1318     if (Options & EOptionSpv) {
1319         if (CompileFailed || LinkFailed)
1320             printf("SPIR-V is not generated for failed compile or link\n");
1321         else {
1322             for (int stage = 0; stage < EShLangCount; ++stage) {
1323                 if (program.getIntermediate((EShLanguage)stage)) {
1324                     std::vector<unsigned int> spirv;
1325                     spv::SpvBuildLogger logger;
1326                     glslang::SpvOptions spvOptions;
1327                     if (Options & EOptionDebug)
1328                         spvOptions.generateDebugInfo = true;
1329                     else if (stripDebugInfo)
1330                         spvOptions.stripDebugInfo = true;
1331                     spvOptions.disableOptimizer = (Options & EOptionOptimizeDisable) != 0;
1332                     spvOptions.optimizeSize = (Options & EOptionOptimizeSize) != 0;
1333                     spvOptions.disassemble = SpvToolsDisassembler;
1334                     spvOptions.validate = SpvToolsValidate;
1335                     glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions);
1336
1337                     // Dump the spv to a file or stdout, etc., but only if not doing
1338                     // memory/perf testing, as it's not internal to programmatic use.
1339                     if (! (Options & EOptionMemoryLeakMode)) {
1340                         printf("%s", logger.getAllMessages().c_str());
1341                         if (Options & EOptionOutputHexadecimal) {
1342                             glslang::OutputSpvHex(spirv, GetBinaryName((EShLanguage)stage), variableName);
1343                         } else {
1344                             glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage));
1345                         }
1346 #ifndef GLSLANG_WEB
1347                         if (!SpvToolsDisassembler && (Options & EOptionHumanReadableSpv))
1348                             spv::Disassemble(std::cout, spirv);
1349 #endif
1350                     }
1351                 }
1352             }
1353         }
1354     }
1355
1356     // Free everything up, program has to go before the shaders
1357     // because it might have merged stuff from the shaders, and
1358     // the stuff from the shaders has to have its destructors called
1359     // before the pools holding the memory in the shaders is freed.
1360     delete &program;
1361     while (shaders.size() > 0) {
1362         delete shaders.back();
1363         shaders.pop_back();
1364     }
1365 }
1366
1367 //
1368 // Do file IO part of compile and link, handing off the pure
1369 // API/programmatic mode to CompileAndLinkShaderUnits(), which can
1370 // be put in a loop for testing memory footprint and performance.
1371 //
1372 // This is just for linking mode: meaning all the shaders will be put into the
1373 // the same program linked together.
1374 //
1375 // This means there are a limited number of work items (not multi-threading mode)
1376 // and that the point is testing at the linking level. Hence, to enable
1377 // performance and memory testing, the actual compile/link can be put in
1378 // a loop, independent of processing the work items and file IO.
1379 //
1380 void CompileAndLinkShaderFiles(glslang::TWorklist& Worklist)
1381 {
1382     std::vector<ShaderCompUnit> compUnits;
1383
1384     // If this is using stdin, we can't really detect multiple different file
1385     // units by input type. We need to assume that we're just being given one
1386     // file of a certain type.
1387     if ((Options & EOptionStdin) != 0) {
1388         ShaderCompUnit compUnit(FindLanguage("stdin"));
1389         std::istreambuf_iterator<char> begin(std::cin), end;
1390         std::string tempString(begin, end);
1391         char* fileText = strdup(tempString.c_str());
1392         std::string fileName = "stdin";
1393         compUnit.addString(fileName, fileText);
1394         compUnits.push_back(compUnit);
1395     } else {
1396         // Transfer all the work items from to a simple list of
1397         // of compilation units.  (We don't care about the thread
1398         // work-item distribution properties in this path, which
1399         // is okay due to the limited number of shaders, know since
1400         // they are all getting linked together.)
1401         glslang::TWorkItem* workItem;
1402         while (Worklist.remove(workItem)) {
1403             ShaderCompUnit compUnit(FindLanguage(workItem->name));
1404             char* fileText = ReadFileData(workItem->name.c_str());
1405             if (fileText == nullptr)
1406                 usage();
1407             compUnit.addString(workItem->name, fileText);
1408             compUnits.push_back(compUnit);
1409         }
1410     }
1411
1412     // Actual call to programmatic processing of compile and link,
1413     // in a loop for testing memory and performance.  This part contains
1414     // all the perf/memory that a programmatic consumer will care about.
1415     for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
1416         for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
1417            CompileAndLinkShaderUnits(compUnits);
1418
1419         if (Options & EOptionMemoryLeakMode)
1420             glslang::OS_DumpMemoryCounters();
1421     }
1422
1423     // free memory from ReadFileData, which got stored in a const char*
1424     // as the first string above
1425     for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
1426         FreeFileData(const_cast<char*>(it->text[0]));
1427 }
1428
1429 int singleMain()
1430 {
1431     glslang::TWorklist workList;
1432     std::for_each(WorkItems.begin(), WorkItems.end(), [&workList](std::unique_ptr<glslang::TWorkItem>& item) {
1433         assert(item);
1434         workList.add(item.get());
1435     });
1436
1437 #ifndef GLSLANG_WEB
1438     if (Options & EOptionDumpConfig) {
1439         printf("%s", glslang::GetDefaultTBuiltInResourceString().c_str());
1440         if (workList.empty())
1441             return ESuccess;
1442     }
1443 #endif
1444
1445     if (Options & EOptionDumpBareVersion) {
1446         printf("%d:%d.%d.%d%s\n", glslang::GetSpirvGeneratorVersion(), GLSLANG_VERSION_MAJOR, GLSLANG_VERSION_MINOR,
1447                 GLSLANG_VERSION_PATCH, GLSLANG_VERSION_FLAVOR);
1448         if (workList.empty())
1449             return ESuccess;
1450     } else if (Options & EOptionDumpVersions) {
1451         printf("Glslang Version: %d:%d.%d.%d%s\n", glslang::GetSpirvGeneratorVersion(), GLSLANG_VERSION_MAJOR,
1452                 GLSLANG_VERSION_MINOR, GLSLANG_VERSION_PATCH, GLSLANG_VERSION_FLAVOR);
1453         printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
1454         printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
1455         std::string spirvVersion;
1456         glslang::GetSpirvVersion(spirvVersion);
1457         printf("SPIR-V Version %s\n", spirvVersion.c_str());
1458         printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
1459         printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId());
1460         printf("SPIR-V Generator Version %d\n", glslang::GetSpirvGeneratorVersion());
1461         printf("GL_KHR_vulkan_glsl version %d\n", 100);
1462         printf("ARB_GL_gl_spirv version %d\n", 100);
1463         if (workList.empty())
1464             return ESuccess;
1465     }
1466
1467     if (workList.empty() && ((Options & EOptionStdin) == 0)) {
1468         usage();
1469     }
1470
1471     if (Options & EOptionStdin) {
1472         WorkItems.push_back(std::unique_ptr<glslang::TWorkItem>{new glslang::TWorkItem("stdin")});
1473         workList.add(WorkItems.back().get());
1474     }
1475
1476     ProcessConfigFile();
1477
1478     if ((Options & EOptionReadHlsl) && !((Options & EOptionOutputPreprocessed) || (Options & EOptionSpv)))
1479         Error("HLSL requires SPIR-V code generation (or preprocessing only)");
1480
1481     //
1482     // Two modes:
1483     // 1) linking all arguments together, single-threaded, new C++ interface
1484     // 2) independent arguments, can be tackled by multiple asynchronous threads, for testing thread safety, using the old handle interface
1485     //
1486     if (Options & (EOptionLinkProgram | EOptionOutputPreprocessed)) {
1487         glslang::InitializeProcess();
1488         glslang::InitializeProcess();  // also test reference counting of users
1489         glslang::InitializeProcess();  // also test reference counting of users
1490         glslang::FinalizeProcess();    // also test reference counting of users
1491         glslang::FinalizeProcess();    // also test reference counting of users
1492         CompileAndLinkShaderFiles(workList);
1493         glslang::FinalizeProcess();
1494     } else {
1495         ShInitialize();
1496         ShInitialize();  // also test reference counting of users
1497         ShFinalize();    // also test reference counting of users
1498
1499         bool printShaderNames = workList.size() > 1;
1500
1501         if (Options & EOptionMultiThreaded) {
1502             std::array<std::thread, 16> threads;
1503             for (unsigned int t = 0; t < threads.size(); ++t) {
1504                 threads[t] = std::thread(CompileShaders, std::ref(workList));
1505                 if (threads[t].get_id() == std::thread::id()) {
1506                     fprintf(stderr, "Failed to create thread\n");
1507                     return EFailThreadCreate;
1508                 }
1509             }
1510
1511             std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
1512         } else
1513             CompileShaders(workList);
1514
1515         // Print out all the resulting infologs
1516         for (size_t w = 0; w < WorkItems.size(); ++w) {
1517             if (WorkItems[w]) {
1518                 if (printShaderNames || WorkItems[w]->results.size() > 0)
1519                     PutsIfNonEmpty(WorkItems[w]->name.c_str());
1520                 PutsIfNonEmpty(WorkItems[w]->results.c_str());
1521             }
1522         }
1523
1524         ShFinalize();
1525     }
1526
1527     if (CompileFailed)
1528         return EFailCompile;
1529     if (LinkFailed)
1530         return EFailLink;
1531
1532     return 0;
1533 }
1534
1535 int C_DECL main(int argc, char* argv[])
1536 {
1537     ProcessArguments(WorkItems, argc, argv);
1538
1539     int ret = 0;
1540
1541     // Loop over the entire init/finalize cycle to watch memory changes
1542     const int iterations = 1;
1543     if (iterations > 1)
1544         glslang::OS_DumpMemoryCounters();
1545     for (int i = 0; i < iterations; ++i) {
1546         ret = singleMain();
1547         if (iterations > 1)
1548             glslang::OS_DumpMemoryCounters();
1549     }
1550
1551     return ret;
1552 }
1553
1554 //
1555 //   Deduce the language from the filename.  Files must end in one of the
1556 //   following extensions:
1557 //
1558 //   .vert = vertex
1559 //   .tesc = tessellation control
1560 //   .tese = tessellation evaluation
1561 //   .geom = geometry
1562 //   .frag = fragment
1563 //   .comp = compute
1564 //   .rgen = ray generation
1565 //   .rint = ray intersection
1566 //   .rahit = ray any hit
1567 //   .rchit = ray closest hit
1568 //   .rmiss = ray miss
1569 //   .rcall = ray callable
1570 //   .mesh  = mesh
1571 //   .task  = task
1572 //   Additionally, the file names may end in .<stage>.glsl and .<stage>.hlsl
1573 //   where <stage> is one of the stages listed above.
1574 //
1575 EShLanguage FindLanguage(const std::string& name, bool parseStageName)
1576 {
1577     std::string stageName;
1578     if (shaderStageName)
1579         stageName = shaderStageName;
1580     else if (parseStageName) {
1581         // Note: "first" extension means "first from the end", i.e.
1582         // if the file is named foo.vert.glsl, then "glsl" is first,
1583         // "vert" is second.
1584         size_t firstExtStart = name.find_last_of(".");
1585         bool hasFirstExt = firstExtStart != std::string::npos;
1586         size_t secondExtStart = hasFirstExt ? name.find_last_of(".", firstExtStart - 1) : std::string::npos;
1587         bool hasSecondExt = secondExtStart != std::string::npos;
1588         std::string firstExt = name.substr(firstExtStart + 1, std::string::npos);
1589         bool usesUnifiedExt = hasFirstExt && (firstExt == "glsl" || firstExt == "hlsl");
1590         if (usesUnifiedExt && firstExt == "hlsl")
1591             Options |= EOptionReadHlsl;
1592         if (hasFirstExt && !usesUnifiedExt)
1593             stageName = firstExt;
1594         else if (usesUnifiedExt && hasSecondExt)
1595             stageName = name.substr(secondExtStart + 1, firstExtStart - secondExtStart - 1);
1596         else {
1597             usage();
1598             return EShLangVertex;
1599         }
1600     } else
1601         stageName = name;
1602
1603     if (stageName == "vert")
1604         return EShLangVertex;
1605     else if (stageName == "tesc")
1606         return EShLangTessControl;
1607     else if (stageName == "tese")
1608         return EShLangTessEvaluation;
1609     else if (stageName == "geom")
1610         return EShLangGeometry;
1611     else if (stageName == "frag")
1612         return EShLangFragment;
1613     else if (stageName == "comp")
1614         return EShLangCompute;
1615     else if (stageName == "rgen")
1616         return EShLangRayGen;
1617     else if (stageName == "rint")
1618         return EShLangIntersect;
1619     else if (stageName == "rahit")
1620         return EShLangAnyHit;
1621     else if (stageName == "rchit")
1622         return EShLangClosestHit;
1623     else if (stageName == "rmiss")
1624         return EShLangMiss;
1625     else if (stageName == "rcall")
1626         return EShLangCallable;
1627     else if (stageName == "mesh")
1628         return EShLangMeshNV;
1629     else if (stageName == "task")
1630         return EShLangTaskNV;
1631
1632     usage();
1633     return EShLangVertex;
1634 }
1635
1636 //
1637 // Read a file's data into a string, and compile it using the old interface ShCompile,
1638 // for non-linkable results.
1639 //
1640 void CompileFile(const char* fileName, ShHandle compiler)
1641 {
1642     int ret = 0;
1643     char* shaderString;
1644     if ((Options & EOptionStdin) != 0) {
1645         std::istreambuf_iterator<char> begin(std::cin), end;
1646         std::string tempString(begin, end);
1647         shaderString = strdup(tempString.c_str());
1648     } else {
1649         shaderString = ReadFileData(fileName);
1650     }
1651
1652     // move to length-based strings, rather than null-terminated strings
1653     int* lengths = new int[1];
1654     lengths[0] = (int)strlen(shaderString);
1655
1656     EShMessages messages = EShMsgDefault;
1657     SetMessageOptions(messages);
1658
1659     if (UserPreamble.isSet())
1660         Error("-D and -U options require -l (linking)\n");
1661
1662     for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
1663         for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
1664             // ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
1665             ret = ShCompile(compiler, &shaderString, 1, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
1666             // const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
1667             //                         "or should be l", "ine 1", "string 5\n", "float glo", "bal",
1668             //                         ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
1669             // const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
1670             // ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
1671         }
1672
1673         if (Options & EOptionMemoryLeakMode)
1674             glslang::OS_DumpMemoryCounters();
1675     }
1676
1677     delete [] lengths;
1678     FreeFileData(shaderString);
1679
1680     if (ret == 0)
1681         CompileFailed = true;
1682 }
1683
1684 //
1685 //   print usage to stdout
1686 //
1687 void usage()
1688 {
1689     printf("Usage: glslangValidator [option]... [file]...\n"
1690            "\n"
1691            "'file' can end in .<stage> for auto-stage classification, where <stage> is:\n"
1692            "    .conf   to provide a config file that replaces the default configuration\n"
1693            "            (see -c option below for generating a template)\n"
1694            "    .vert   for a vertex shader\n"
1695            "    .tesc   for a tessellation control shader\n"
1696            "    .tese   for a tessellation evaluation shader\n"
1697            "    .geom   for a geometry shader\n"
1698            "    .frag   for a fragment shader\n"
1699            "    .comp   for a compute shader\n"
1700            "    .mesh   for a mesh shader\n"
1701            "    .task   for a task shader\n"
1702            "    .rgen    for a ray generation shader\n"
1703            "    .rint    for a ray intersection shader\n"
1704            "    .rahit   for a ray any hit shader\n"
1705            "    .rchit   for a ray closest hit shader\n"
1706            "    .rmiss   for a ray miss shader\n"
1707            "    .rcall   for a ray callable shader\n"
1708            "    .glsl   for .vert.glsl, .tesc.glsl, ..., .comp.glsl compound suffixes\n"
1709            "    .hlsl   for .vert.hlsl, .tesc.hlsl, ..., .comp.hlsl compound suffixes\n"
1710            "\n"
1711            "Options:\n"
1712            "  -C          cascading errors; risk crash from accumulation of error recoveries\n"
1713            "  -D          input is HLSL (this is the default when any suffix is .hlsl)\n"
1714            "  -D<name[=def]> | --define-macro <name[=def]> | --D <name[=def]>\n"
1715            "              define a pre-processor macro\n"
1716            "  -E          print pre-processed GLSL; cannot be used with -l;\n"
1717            "              errors will appear on stderr\n"
1718            "  -G[ver]     create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
1719            "              default file name is <stage>.spv (-o overrides this);\n"
1720            "              'ver', when present, is the version of the input semantics,\n"
1721            "              which will appear in #define GL_SPIRV ver;\n"
1722            "              '--client opengl100' is the same as -G100;\n"
1723            "              a '--target-env' for OpenGL will also imply '-G';\n"
1724            "              currently only supports GLSL\n"
1725            "  -H          print human readable form of SPIR-V; turns on -V\n"
1726            "  -I<dir>     add dir to the include search path; includer's directory\n"
1727            "              is searched first, followed by left-to-right order of -I\n"
1728            "  -Od         disables optimization; may cause illegal SPIR-V for HLSL\n"
1729            "  -Os         optimizes SPIR-V to minimize size\n"
1730            "  -R          use relaxed verification rules for generating Vulkan SPIR-V,\n"
1731            "              allowing the use of default uniforms, atomic_uints, and\n"
1732            "              gl_VertexID and gl_InstanceID keywords.\n"
1733            "  -S <stage>  uses specified stage rather than parsing the file extension\n"
1734            "              choices for <stage> are vert, tesc, tese, geom, frag, or comp\n"
1735            "  -U<name> | --undef-macro <name> | --U <name>\n"
1736            "              undefine a pre-processor macro\n"
1737            "  -V[ver]     create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
1738            "              default file name is <stage>.spv (-o overrides this)\n"
1739            "              'ver', when present, is the version of the input semantics,\n"
1740            "              which will appear in #define VULKAN ver\n"
1741            "              '--client vulkan100' is the same as -V100\n"
1742            "              a '--target-env' for Vulkan will also imply '-V'\n"
1743            "  -c          configuration dump;\n"
1744            "              creates the default configuration file (redirect to a .conf file)\n"
1745            "  -d          default to desktop (#version 110) when there is no shader #version\n"
1746            "              (default is ES version 100)\n"
1747            "  -e <name> | --entry-point <name>\n"
1748            "              specify <name> as the entry-point function name\n"
1749            "  -f{hlsl_functionality1}\n"
1750            "              'hlsl_functionality1' enables use of the\n"
1751            "              SPV_GOOGLE_hlsl_functionality1 extension\n"
1752            "  -g          generate debug information\n"
1753            "  -g0         strip debug information\n"
1754            "  -h          print this usage message\n"
1755            "  -i          intermediate tree (glslang AST) is printed out\n"
1756            "  -l          link all input files together to form a single module\n"
1757            "  -m          memory leak mode\n"
1758            "  -o <file>   save binary to <file>, requires a binary option (e.g., -V)\n"
1759            "  -q          dump reflection query database; requires -l for linking\n"
1760            "  -r | --relaxed-errors"
1761            "              relaxed GLSL semantic error-checking mode\n"
1762            "  -s          silence syntax and semantic error reporting\n"
1763            "  -t          multi-threaded mode\n"
1764            "  -v | --version\n"
1765            "              print version strings\n"
1766            "  -w | --suppress-warnings\n"
1767            "              suppress GLSL warnings, except as required by \"#extension : warn\"\n"
1768            "  -x          save binary output as text-based 32-bit hexadecimal numbers\n"
1769            "  -u<name>:<loc> specify a uniform location override for --aml\n"
1770            "  --uniform-base <base> set a base to use for generated uniform locations\n"
1771            "  --auto-map-bindings | --amb       automatically bind uniform variables\n"
1772            "                                    without explicit bindings\n"
1773            "  --auto-map-locations | --aml      automatically locate input/output lacking\n"
1774            "                                    'location' (fragile, not cross stage)\n"
1775            "  --client {vulkan<ver>|opengl<ver>} see -V and -G\n"
1776            "  --dump-builtin-symbols            prints builtin symbol table prior each compile\n"
1777            "  -dumpfullversion | -dumpversion   print bare major.minor.patchlevel\n"
1778            "  --flatten-uniform-arrays | --fua  flatten uniform texture/sampler arrays to\n"
1779            "                                    scalars\n"
1780            "  --hlsl-offsets                    allow block offsets to follow HLSL rules\n"
1781            "                                    works independently of source language\n"
1782            "  --hlsl-iomap                      perform IO mapping in HLSL register space\n"
1783            "  --hlsl-enable-16bit-types         allow 16-bit types in SPIR-V for HLSL\n"
1784            "  --hlsl-dx9-compatible             interprets sampler declarations as a\n"
1785            "                                    texture/sampler combo like DirectX9 would,\n"
1786            "                                    and recognizes DirectX9-specific semantics\n"
1787            "  --invert-y | --iy                 invert position.Y output in vertex shader\n"
1788            "  --keep-uncalled | --ku            don't eliminate uncalled functions\n"
1789            "  --nan-clamp                       favor non-NaN operand in min, max, and clamp\n"
1790            "  --no-storage-format | --nsf       use Unknown image format\n"
1791            "  --quiet                           do not print anything to stdout, unless\n"
1792            "                                    requested by another option\n"
1793            "  --reflect-strict-array-suffix     use strict array suffix rules when\n"
1794            "                                    reflecting\n"
1795            "  --reflect-basic-array-suffix      arrays of basic types will have trailing [0]\n"
1796            "  --reflect-intermediate-io         reflection includes inputs/outputs of linked\n"
1797            "                                    shaders rather than just vertex/fragment\n"
1798            "  --reflect-separate-buffers        reflect buffer variables and blocks\n"
1799            "                                    separately to uniforms\n"
1800            "  --reflect-all-block-variables     reflect all variables in blocks, whether\n"
1801            "                                    inactive or active\n"
1802            "  --reflect-unwrap-io-blocks        unwrap input/output blocks the same as\n"
1803            "                                    uniform blocks\n"
1804            "  --resource-set-binding [stage] name set binding\n"
1805            "                                    set descriptor set and binding for\n"
1806            "                                    individual resources\n"
1807            "  --resource-set-binding [stage] set\n"
1808            "                                    set descriptor set for all resources\n"
1809            "  --rsb                             synonym for --resource-set-binding\n"
1810            "  --set-block-backing name {uniform|buffer|push_constant}\n"
1811            "                                    changes the backing type of a uniform, buffer,\n"
1812            "                                    or push_constant block declared in\n"
1813            "                                    in the program, when using -R option.\n"
1814            "                                    This can be used to change the backing\n"
1815            "                                    for existing blocks as well as implicit ones\n"
1816            "                                    such as 'gl_DefaultUniformBlock'.\n"
1817            "  --sbs                             synonym for set-block-storage\n"
1818            "  --set-atomic-counter-block name set\n"
1819            "                                    set name, and descriptor set for\n"
1820            "                                    atomic counter blocks, with -R opt\n"
1821            "  --sacb                            synonym for set-atomic-counter-block\n"
1822            "  --set-default-uniform-block name set binding\n"
1823            "                                    set name, descriptor set, and binding for\n"
1824            "                                    global default-uniform-block, with -R opt\n"
1825            "  --sdub                            synonym for set-default-uniform-block\n"
1826            "  --shift-image-binding [stage] num\n"
1827            "                                    base binding number for images (uav)\n"
1828            "  --shift-image-binding [stage] [num set]...\n"
1829            "                                    per-descriptor-set shift values\n"
1830            "  --sib                             synonym for --shift-image-binding\n"
1831            "  --shift-sampler-binding [stage] num\n"
1832            "                                    base binding number for samplers\n"
1833            "  --shift-sampler-binding [stage] [num set]...\n"
1834            "                                    per-descriptor-set shift values\n"
1835            "  --ssb                             synonym for --shift-sampler-binding\n"
1836            "  --shift-ssbo-binding [stage] num  base binding number for SSBOs\n"
1837            "  --shift-ssbo-binding [stage] [num set]...\n"
1838            "                                    per-descriptor-set shift values\n"
1839            "  --sbb                             synonym for --shift-ssbo-binding\n"
1840            "  --shift-texture-binding [stage] num\n"
1841            "                                    base binding number for textures\n"
1842            "  --shift-texture-binding [stage] [num set]...\n"
1843            "                                    per-descriptor-set shift values\n"
1844            "  --stb                             synonym for --shift-texture-binding\n"
1845            "  --shift-uav-binding [stage] num   base binding number for UAVs\n"
1846            "  --shift-uav-binding [stage] [num set]...\n"
1847            "                                    per-descriptor-set shift values\n"
1848            "  --suavb                           synonym for --shift-uav-binding\n"
1849            "  --shift-UBO-binding [stage] num   base binding number for UBOs\n"
1850            "  --shift-UBO-binding [stage] [num set]...\n"
1851            "                                    per-descriptor-set shift values\n"
1852            "  --sub                             synonym for --shift-UBO-binding\n"
1853            "  --shift-cbuffer-binding | --scb   synonyms for --shift-UBO-binding\n"
1854            "  --spirv-dis                       output standard-form disassembly; works only\n"
1855            "                                    when a SPIR-V generation option is also used\n"
1856            "  --spirv-val                       execute the SPIRV-Tools validator\n"
1857            "  --source-entrypoint <name>        the given shader source function is\n"
1858            "                                    renamed to be the <name> given in -e\n"
1859            "  --sep                             synonym for --source-entrypoint\n"
1860            "  --stdin                           read from stdin instead of from a file;\n"
1861            "                                    requires providing the shader stage using -S\n"
1862            "  --target-env {vulkan1.0 | vulkan1.1 | vulkan1.2 | opengl | \n"
1863            "                spirv1.0 | spirv1.1 | spirv1.2 | spirv1.3 | spirv1.4 | spirv1.5}\n"
1864            "                                    Set the execution environment that the\n"
1865            "                                    generated code will be executed in.\n"
1866            "                                    Defaults to:\n"
1867            "                                     * vulkan1.0 under --client vulkan<ver>\n"
1868            "                                     * opengl    under --client opengl<ver>\n"
1869            "                                     * spirv1.0  under --target-env vulkan1.0\n"
1870            "                                     * spirv1.3  under --target-env vulkan1.1\n"
1871            "                                     * spirv1.5  under --target-env vulkan1.2\n"
1872            "                                    Multiple --target-env can be specified.\n"
1873            "  --variable-name <name>\n"
1874            "  --vn <name>                       creates a C header file that contains a\n"
1875            "                                    uint32_t array named <name>\n"
1876            "                                    initialized with the shader binary code\n"
1877            );
1878
1879     exit(EFailUsage);
1880 }
1881
1882 #if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
1883
1884 #include <errno.h>
1885
1886 int fopen_s(
1887    FILE** pFile,
1888    const char* filename,
1889    const char* mode
1890 )
1891 {
1892    if (!pFile || !filename || !mode) {
1893       return EINVAL;
1894    }
1895
1896    FILE* f = fopen(filename, mode);
1897    if (! f) {
1898       if (errno != 0) {
1899          return errno;
1900       } else {
1901          return ENOENT;
1902       }
1903    }
1904    *pFile = f;
1905
1906    return 0;
1907 }
1908
1909 #endif
1910
1911 //
1912 //   Malloc a string of sufficient size and read a string into it.
1913 //
1914 char* ReadFileData(const char* fileName)
1915 {
1916     FILE *in = nullptr;
1917     int errorCode = fopen_s(&in, fileName, "r");
1918     if (errorCode || in == nullptr)
1919         Error("unable to open input file");
1920
1921     int count = 0;
1922     while (fgetc(in) != EOF)
1923         count++;
1924
1925     fseek(in, 0, SEEK_SET);
1926
1927     char* return_data = (char*)malloc(count + 1);  // freed in FreeFileData()
1928     if ((int)fread(return_data, 1, count, in) != count) {
1929         free(return_data);
1930         Error("can't read input file");
1931     }
1932
1933     return_data[count] = '\0';
1934     fclose(in);
1935
1936     return return_data;
1937 }
1938
1939 void FreeFileData(char* data)
1940 {
1941     free(data);
1942 }
1943
1944 void InfoLogMsg(const char* msg, const char* name, const int num)
1945 {
1946     if (num >= 0 )
1947         printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
1948     else
1949         printf("#### %s %s INFO LOG ####\n", msg, name);
1950 }