blob: fc5913e909401a6820ad06abb172421a936690b2 [file] [log] [blame]
John Kessenicha0af4732012-12-12 21:15:54 +00001//
John Kessenich927608b2017-01-06 12:34:14 -07002// Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
3// Copyright (C) 2013-2016 LunarG, Inc.
John Kessenichbd0747d2013-02-17 06:01:50 +00004//
John Kessenich927608b2017-01-06 12:34:14 -07005// All rights reserved.
John Kessenicha0af4732012-12-12 21:15:54 +00006//
John Kessenich927608b2017-01-06 12:34:14 -07007// Redistribution and use in source and binary forms, with or without
8// modification, are permitted provided that the following conditions
9// are met:
John Kessenicha0af4732012-12-12 21:15:54 +000010//
11// Redistributions of source code must retain the above copyright
12// notice, this list of conditions and the following disclaimer.
13//
14// Redistributions in binary form must reproduce the above
15// copyright notice, this list of conditions and the following
16// disclaimer in the documentation and/or other materials provided
17// with the distribution.
18//
19// Neither the name of 3Dlabs Inc. Ltd. nor the names of its
20// contributors may be used to endorse or promote products derived
21// from this software without specific prior written permission.
22//
John Kessenich927608b2017-01-06 12:34:14 -070023// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27// COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
29// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
31// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
33// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
34// POSSIBILITY OF SUCH DAMAGE.
John Kessenicha0af4732012-12-12 21:15:54 +000035//
John Kessenich05a70632013-09-17 19:26:08 +000036
37// this only applies to the standalone wrapper, not the front end in general
Aras Pranckevicius8e204b22017-05-10 16:52:50 +030038#ifndef _CRT_SECURE_NO_WARNINGS
John Kessenich05a70632013-09-17 19:26:08 +000039#define _CRT_SECURE_NO_WARNINGS
Aras Pranckevicius8e204b22017-05-10 16:52:50 +030040#endif
John Kessenich05a70632013-09-17 19:26:08 +000041
Lei Zhang8a9b1ee2016-05-19 13:31:43 -040042#include "ResourceLimits.h"
John Kessenich2b07c7e2013-07-31 18:44:13 +000043#include "Worklist.h"
John Kessenich3494b4d2017-05-22 15:00:42 -060044#include "DirStackFileIncluder.h"
John Kessenicha0af4732012-12-12 21:15:54 +000045#include "./../glslang/Include/ShHandle.h"
John Kessenich0da9eaa2015-08-01 17:10:02 -060046#include "./../glslang/Include/revision.h"
John Kessenicha0af4732012-12-12 21:15:54 +000047#include "./../glslang/Public/ShaderLang.h"
John Kessenich0df0cde2015-03-03 17:09:43 +000048#include "../SPIRV/GlslangToSpv.h"
John Kessenich5e4b1242015-08-06 22:53:06 -060049#include "../SPIRV/GLSL.std.450.h"
John Kessenichacba7722015-03-04 03:48:38 +000050#include "../SPIRV/doc.h"
51#include "../SPIRV/disassemble.h"
John Kessenich3494b4d2017-05-22 15:00:42 -060052
John Kessenich66ec80e2016-08-05 14:04:23 -060053#include <cstring>
54#include <cstdlib>
steve-lunarg7f7c2ed2016-09-07 15:20:19 -060055#include <cctype>
John Kessenich66ec80e2016-08-05 14:04:23 -060056#include <cmath>
steve-lunarg7f7c2ed2016-09-07 15:20:19 -060057#include <array>
LoopDawg08a14422017-10-17 19:27:14 -060058#include <map>
Juan Lopeza558b262017-04-02 23:04:00 +020059#include <memory>
60#include <thread>
John Kessenicha0af4732012-12-12 21:15:54 +000061
baldurk876a0e32015-11-16 18:03:28 +010062#include "../glslang/OSDependent/osinclude.h"
John Kessenicha0af4732012-12-12 21:15:54 +000063
64extern "C" {
65 SH_IMPORT_EXPORT void ShOutputHtml();
66}
67
John Kessenich94a81fb2013-08-31 02:41:30 +000068// Command-line options
69enum TOptions {
John Kessenich906cc212016-12-09 19:22:20 -070070 EOptionNone = 0,
71 EOptionIntermediate = (1 << 0),
72 EOptionSuppressInfolog = (1 << 1),
73 EOptionMemoryLeakMode = (1 << 2),
74 EOptionRelaxedErrors = (1 << 3),
75 EOptionGiveWarnings = (1 << 4),
76 EOptionLinkProgram = (1 << 5),
77 EOptionMultiThreaded = (1 << 6),
78 EOptionDumpConfig = (1 << 7),
79 EOptionDumpReflection = (1 << 8),
80 EOptionSuppressWarnings = (1 << 9),
81 EOptionDumpVersions = (1 << 10),
82 EOptionSpv = (1 << 11),
83 EOptionHumanReadableSpv = (1 << 12),
84 EOptionVulkanRules = (1 << 13),
85 EOptionDefaultDesktop = (1 << 14),
86 EOptionOutputPreprocessed = (1 << 15),
87 EOptionOutputHexadecimal = (1 << 16),
88 EOptionReadHlsl = (1 << 17),
89 EOptionCascadingErrors = (1 << 18),
90 EOptionAutoMapBindings = (1 << 19),
steve-lunarge0b9deb2016-09-16 13:26:37 -060091 EOptionFlattenUniformArrays = (1 << 20),
John Kessenich906cc212016-12-09 19:22:20 -070092 EOptionNoStorageFormat = (1 << 21),
John Kessenich20f01e72016-12-12 11:41:43 -070093 EOptionKeepUncalled = (1 << 22),
John Kessenich4f1403e2017-04-05 17:38:20 -060094 EOptionHlslOffsets = (1 << 23),
steve-lunargbe283552017-04-18 12:18:01 -060095 EOptionHlslIoMapping = (1 << 24),
John Kessenich71facdf2017-05-17 18:28:19 -060096 EOptionAutoMapLocations = (1 << 25),
John Kessenich121853f2017-05-31 17:11:16 -060097 EOptionDebug = (1 << 26),
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +020098 EOptionStdin = (1 << 27),
GregFcd1f1692017-09-21 18:40:22 -060099 EOptionOptimizeDisable = (1 << 28),
100 EOptionOptimizeSize = (1 << 29),
LoopDawgb22c0692017-12-06 16:52:03 -0700101 EOptionInvertY = (1 << 30),
John Kessenichc6c80a62018-03-05 22:23:17 -0700102 EOptionDumpBareVersion = (1 << 31),
John Kessenich94a81fb2013-08-31 02:41:30 +0000103};
104
John Kessenicha0af4732012-12-12 21:15:54 +0000105//
John Kessenich68d78fd2015-07-12 19:28:10 -0600106// Return codes from main/exit().
John Kessenicha0af4732012-12-12 21:15:54 +0000107//
108enum TFailCode {
109 ESuccess = 0,
110 EFailUsage,
111 EFailCompile,
112 EFailLink,
113 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +0000114 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +0000115 EFailLinkerCreate
116};
117
118//
John Kessenich68d78fd2015-07-12 19:28:10 -0600119// Forward declarations.
John Kessenicha0af4732012-12-12 21:15:54 +0000120//
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600121EShLanguage FindLanguage(const std::string& name, bool parseSuffix=true);
John Kessenich51cdd902014-02-18 23:37:57 +0000122void CompileFile(const char* fileName, ShHandle);
John Kessenicha0af4732012-12-12 21:15:54 +0000123void usage();
John Kessenich04acb1b2017-06-14 17:36:50 -0600124char* ReadFileData(const char* fileName);
125void FreeFileData(char* data);
John Kessenich54d8cda2013-02-11 22:36:01 +0000126void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +0000127
John Kessenichc999ba22013-11-07 23:33:24 +0000128// Globally track if any compile or link failure.
129bool CompileFailed = false;
130bool LinkFailed = false;
131
John Kessenich94f28eb2017-11-13 01:32:06 -0700132// array of unique places to leave the shader names and infologs for the asynchronous compiles
133std::vector<std::unique_ptr<glslang::TWorkItem>> WorkItems;
134
John Kessenich05a70632013-09-17 19:26:08 +0000135TBuiltInResource Resources;
136std::string ConfigFile;
137
John Kessenicha0af4732012-12-12 21:15:54 +0000138//
John Kessenichf0bcb0a2016-04-02 13:09:14 -0600139// Parse either a .conf file provided by the user or the default from glslang::DefaultTBuiltInResource
John Kessenich05a70632013-09-17 19:26:08 +0000140//
141void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000142{
John Kessenich04acb1b2017-06-14 17:36:50 -0600143 if (ConfigFile.size() == 0)
Lei Zhang414eb602016-03-04 16:22:34 -0500144 Resources = glslang::DefaultTBuiltInResource;
John Kessenich04acb1b2017-06-14 17:36:50 -0600145 else {
146 char* configString = ReadFileData(ConfigFile.c_str());
147 glslang::DecodeResourceLimits(&Resources, configString);
148 FreeFileData(configString);
John Kessenich05a70632013-09-17 19:26:08 +0000149 }
John Kessenicha0af4732012-12-12 21:15:54 +0000150}
151
John Kessenich94a81fb2013-08-31 02:41:30 +0000152int Options = 0;
John Kessenich68d78fd2015-07-12 19:28:10 -0600153const char* ExecutableName = nullptr;
154const char* binaryFileName = nullptr;
John Kessenich4d65ee32016-03-12 18:17:47 -0700155const char* entryPointName = nullptr;
steve-lunargf1e0c872016-10-31 15:13:43 -0600156const char* sourceEntryPointName = nullptr;
Dan Bakerc6ede892016-08-11 14:06:06 -0400157const char* shaderStageName = nullptr;
Flavioaea3c892017-02-06 11:46:35 -0800158const char* variableName = nullptr;
Rex Xucb61eec2018-03-07 13:10:01 +0800159bool HlslEnable16BitTypes = false;
John Kessenich971a0a82017-06-07 15:06:58 -0600160std::vector<std::string> IncludeDirectoryList;
John Kessenich6353d552017-06-23 11:11:09 -0600161int ClientInputSemanticsVersion = 100; // maps to, say, #define VULKAN 100
162int VulkanClientVersion = 100; // would map to, say, Vulkan 1.0
163int OpenGLClientVersion = 450; // doesn't influence anything yet, but maps to OpenGL 4.50
John Kessenich2b5ea9f2018-01-31 18:35:56 -0700164unsigned int TargetVersion = 0x00010000; // maps to, say, SPIR-V 1.0
John Kessenich2a271162017-07-20 20:00:36 -0600165std::vector<std::string> Processes; // what should be recorded by OpModuleProcessed, or equivalent
John Kessenich68d78fd2015-07-12 19:28:10 -0600166
LoopDawg08a14422017-10-17 19:27:14 -0600167// Per descriptor-set binding base data
168typedef std::map<unsigned int, unsigned int> TPerSetBaseBinding;
169
170std::array<std::array<unsigned int, EShLangCount>, glslang::EResCount> baseBinding;
171std::array<std::array<TPerSetBaseBinding, EShLangCount>, glslang::EResCount> baseBindingForSet;
Hyangran Park36dc8292017-05-02 16:27:29 +0900172std::array<std::vector<std::string>, EShLangCount> baseResourceSetBinding;
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600173
John Kessenicha9313662017-06-15 10:40:49 -0600174// Add things like "#define ..." to a preamble to use in the beginning of the shader.
175class TPreamble {
176public:
177 TPreamble() { }
178
179 bool isSet() const { return text.size() > 0; }
180 const char* get() const { return text.c_str(); }
181
182 // #define...
183 void addDef(std::string def)
184 {
185 text.append("#define ");
186 fixLine(def);
187
John Kessenich2a271162017-07-20 20:00:36 -0600188 Processes.push_back("D");
189 Processes.back().append(def);
190
John Kessenicha9313662017-06-15 10:40:49 -0600191 // The first "=" needs to turn into a space
LoopDawgb97b25e2017-07-12 09:04:39 -0600192 const size_t equal = def.find_first_of("=");
John Kessenicha9313662017-06-15 10:40:49 -0600193 if (equal != def.npos)
194 def[equal] = ' ';
195
196 text.append(def);
197 text.append("\n");
198 }
199
200 // #undef...
201 void addUndef(std::string undef)
202 {
203 text.append("#undef ");
204 fixLine(undef);
John Kessenich2a271162017-07-20 20:00:36 -0600205
206 Processes.push_back("U");
207 Processes.back().append(undef);
208
John Kessenicha9313662017-06-15 10:40:49 -0600209 text.append(undef);
210 text.append("\n");
211 }
212
213protected:
214 void fixLine(std::string& line)
215 {
216 // Can't go past a newline in the line
LoopDawgb97b25e2017-07-12 09:04:39 -0600217 const size_t end = line.find_first_of("\n");
John Kessenicha9313662017-06-15 10:40:49 -0600218 if (end != line.npos)
219 line = line.substr(0, end);
220 }
221
222 std::string text; // contents of preamble
223};
224
225TPreamble UserPreamble;
226
John Kessenich68d78fd2015-07-12 19:28:10 -0600227//
228// Create the default name for saving a binary if -o is not provided.
229//
230const char* GetBinaryName(EShLanguage stage)
231{
232 const char* name;
233 if (binaryFileName == nullptr) {
234 switch (stage) {
235 case EShLangVertex: name = "vert.spv"; break;
236 case EShLangTessControl: name = "tesc.spv"; break;
237 case EShLangTessEvaluation: name = "tese.spv"; break;
238 case EShLangGeometry: name = "geom.spv"; break;
239 case EShLangFragment: name = "frag.spv"; break;
240 case EShLangCompute: name = "comp.spv"; break;
241 default: name = "unknown"; break;
242 }
243 } else
244 name = binaryFileName;
245
246 return name;
247}
John Kessenich2b07c7e2013-07-31 18:44:13 +0000248
John Kessenich05a70632013-09-17 19:26:08 +0000249//
250// *.conf => this is a config file that can set limits/resources
251//
252bool SetConfigFile(const std::string& name)
253{
254 if (name.size() < 5)
255 return false;
256
John Kessenich4c706852013-10-11 16:28:43 +0000257 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000258 ConfigFile = name;
259 return true;
260 }
261
262 return false;
263}
264
John Kessenich68d78fd2015-07-12 19:28:10 -0600265//
266// Give error and exit with failure code.
267//
268void Error(const char* message)
269{
John Kessenichaf527992017-11-02 22:48:15 -0600270 fprintf(stderr, "%s: Error %s (use -h for usage)\n", ExecutableName, message);
John Kessenich68d78fd2015-07-12 19:28:10 -0600271 exit(EFailUsage);
272}
273
274//
LoopDawg08a14422017-10-17 19:27:14 -0600275// Process an optional binding base of one the forms:
276// --argname [stage] base // base for stage (if given) or all stages (if not)
LoopDawge5709552017-10-21 10:46:39 -0600277// --argname [stage] [base set]... // set/base pairs: set the base for given binding set.
LoopDawg08a14422017-10-17 19:27:14 -0600278
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600279// Where stage is one of the forms accepted by FindLanguage, and base is an integer
280//
LoopDawg08a14422017-10-17 19:27:14 -0600281void ProcessBindingBase(int& argc, char**& argv, glslang::TResourceType res)
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600282{
283 if (argc < 2)
284 usage();
285
LoopDawg08a14422017-10-17 19:27:14 -0600286 EShLanguage lang = EShLangCount;
287 int singleBase = 0;
288 TPerSetBaseBinding perSetBase;
289 int arg = 1;
290
291 // Parse stage, if given
292 if (!isdigit(argv[arg][0])) {
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600293 if (argc < 3) // this form needs one more argument
294 usage();
John Kessenichecba76f2017-01-06 00:34:48 -0700295
LoopDawg08a14422017-10-17 19:27:14 -0600296 lang = FindLanguage(argv[arg++], false);
297 }
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600298
LoopDawg08a14422017-10-17 19:27:14 -0600299 if ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) {
300 // Parse a per-set binding base
301 while ((argc - arg) > 2 && isdigit(argv[arg+0][0]) && isdigit(argv[arg+1][0])) {
LoopDawg08a14422017-10-17 19:27:14 -0600302 const int baseNum = atoi(argv[arg++]);
LoopDawge5709552017-10-21 10:46:39 -0600303 const int setNum = atoi(argv[arg++]);
LoopDawg08a14422017-10-17 19:27:14 -0600304 perSetBase[setNum] = baseNum;
305 }
306 } else {
307 // Parse single binding base
308 singleBase = atoi(argv[arg++]);
309 }
310
311 argc -= (arg-1);
312 argv += (arg-1);
313
314 // Set one or all languages
315 const int langMin = (lang < EShLangCount) ? lang+0 : 0;
316 const int langMax = (lang < EShLangCount) ? lang+1 : EShLangCount;
317
318 for (int lang = langMin; lang < langMax; ++lang) {
319 if (!perSetBase.empty())
320 baseBindingForSet[res][lang] = perSetBase;
321 else
322 baseBinding[res][lang] = singleBase;
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600323 }
324}
325
Hyangran Park36dc8292017-05-02 16:27:29 +0900326void ProcessResourceSetBindingBase(int& argc, char**& argv, std::array<std::vector<std::string>, EShLangCount>& base)
327{
328 if (argc < 2)
329 usage();
330
331 if (!isdigit(argv[1][0])) {
LoopDawg52017192017-07-14 15:15:47 -0600332 if (argc < 3) // this form needs one more argument
Hyangran Park36dc8292017-05-02 16:27:29 +0900333 usage();
334
LoopDawg52017192017-07-14 15:15:47 -0600335 // Parse form: --argname stage [regname set base...], or:
336 // --argname stage set
Hyangran Park36dc8292017-05-02 16:27:29 +0900337 const EShLanguage lang = FindLanguage(argv[1], false);
338
LoopDawg52017192017-07-14 15:15:47 -0600339 argc--;
340 argv++;
341
342 while (argc > 1 && argv[1] != nullptr && argv[1][0] != '-') {
343 base[lang].push_back(argv[1]);
344
345 argc--;
346 argv++;
Hyangran Park36dc8292017-05-02 16:27:29 +0900347 }
LoopDawg52017192017-07-14 15:15:47 -0600348
349 // Must have one arg, or a multiple of three (for [regname set binding] triples)
350 if (base[lang].size() != 1 && (base[lang].size() % 3) != 0)
351 usage();
352
Hyangran Park36dc8292017-05-02 16:27:29 +0900353 } else {
LoopDawg52017192017-07-14 15:15:47 -0600354 // Parse form: --argname set
Hyangran Park36dc8292017-05-02 16:27:29 +0900355 for (int lang=0; lang<EShLangCount; ++lang)
356 base[lang].push_back(argv[1]);
357
358 argc--;
359 argv++;
360 }
361}
362
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600363//
John Kessenich68d78fd2015-07-12 19:28:10 -0600364// Do all command-line argument parsing. This includes building up the work-items
365// to be processed later, and saving all the command-line options.
366//
367// Does not return (it exits) if command-line is fatally flawed.
368//
Juan Lopeza558b262017-04-02 23:04:00 +0200369void ProcessArguments(std::vector<std::unique_ptr<glslang::TWorkItem>>& workItems, int argc, char* argv[])
John Kessenich2b07c7e2013-07-31 18:44:13 +0000370{
LoopDawg08a14422017-10-17 19:27:14 -0600371 for (int res = 0; res < glslang::EResCount; ++res)
372 baseBinding[res].fill(0);
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600373
John Kessenich38f3b892013-09-06 19:52:57 +0000374 ExecutableName = argv[0];
Juan Lopeza558b262017-04-02 23:04:00 +0200375 workItems.reserve(argc);
John Kessenich38f3b892013-09-06 19:52:57 +0000376
John Kessenichc178f0a2017-06-23 10:58:31 -0600377 const auto bumpArg = [&]() {
378 if (argc > 0) {
379 argc--;
380 argv++;
381 }
382 };
383
384 // read a string directly attached to a single-letter option
John Kessenich6263fb12017-06-14 15:52:44 -0600385 const auto getStringOperand = [&](const char* desc) {
386 if (argv[0][2] == 0) {
387 printf("%s must immediately follow option (no spaces)\n", desc);
388 exit(EFailUsage);
389 }
390 return argv[0] + 2;
391 };
392
John Kessenich6353d552017-06-23 11:11:09 -0600393 // read a number attached to a single-letter option
394 const auto getAttachedNumber = [&](const char* desc) {
395 int num = atoi(argv[0] + 2);
396 if (num == 0) {
397 printf("%s: expected attached non-0 number\n", desc);
398 exit(EFailUsage);
399 }
400 return num;
401 };
402
403 // minimum needed (without overriding something else) to target Vulkan SPIR-V
404 const auto setVulkanSpv = []() {
405 Options |= EOptionSpv;
406 Options |= EOptionVulkanRules;
407 Options |= EOptionLinkProgram;
408 };
409
410 // minimum needed (without overriding something else) to target OpenGL SPIR-V
411 const auto setOpenGlSpv = []() {
412 Options |= EOptionSpv;
413 Options |= EOptionLinkProgram;
414 // undo a -H default to Vulkan
415 Options &= ~EOptionVulkanRules;
416 };
417
John Kessenichc178f0a2017-06-23 10:58:31 -0600418 for (bumpArg(); argc >= 1; bumpArg()) {
John Kessenich2b07c7e2013-07-31 18:44:13 +0000419 if (argv[0][0] == '-') {
John Kessenich2aa7f3a2015-05-15 16:02:07 +0000420 switch (argv[0][1]) {
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600421 case '-':
422 {
423 std::string lowerword(argv[0]+2);
424 std::transform(lowerword.begin(), lowerword.end(), lowerword.begin(), ::tolower);
425
426 // handle --word style options
John Kessenich6263fb12017-06-14 15:52:44 -0600427 if (lowerword == "auto-map-bindings" || // synonyms
John Kessenich6353d552017-06-23 11:11:09 -0600428 lowerword == "auto-map-binding" ||
429 lowerword == "amb") {
John Kessenich6263fb12017-06-14 15:52:44 -0600430 Options |= EOptionAutoMapBindings;
431 } else if (lowerword == "auto-map-locations" || // synonyms
432 lowerword == "aml") {
433 Options |= EOptionAutoMapLocations;
John Kessenich6353d552017-06-23 11:11:09 -0600434 } else if (lowerword == "client") {
435 if (argc > 1) {
436 if (strcmp(argv[1], "vulkan100") == 0)
437 setVulkanSpv();
438 else if (strcmp(argv[1], "opengl100") == 0)
439 setOpenGlSpv();
440 else
441 Error("--client expects vulkan100 or opengl100");
442 }
443 bumpArg();
John Kessenich6263fb12017-06-14 15:52:44 -0600444 } else if (lowerword == "flatten-uniform-arrays" || // synonyms
445 lowerword == "flatten-uniform-array" ||
446 lowerword == "fua") {
447 Options |= EOptionFlattenUniformArrays;
448 } else if (lowerword == "hlsl-offsets") {
449 Options |= EOptionHlslOffsets;
450 } else if (lowerword == "hlsl-iomap" ||
451 lowerword == "hlsl-iomapper" ||
452 lowerword == "hlsl-iomapping") {
453 Options |= EOptionHlslIoMapping;
Rex Xucb61eec2018-03-07 13:10:01 +0800454 } else if (lowerword == "hlsl-enable-16bit-types") {
455 HlslEnable16BitTypes = true;
John Kessenichc6c80a62018-03-05 22:23:17 -0700456 } else if (lowerword == "invert-y" || // synonyms
457 lowerword == "iy") {
458 Options |= EOptionInvertY;
John Kessenich6263fb12017-06-14 15:52:44 -0600459 } else if (lowerword == "keep-uncalled" || // synonyms
460 lowerword == "ku") {
461 Options |= EOptionKeepUncalled;
462 } else if (lowerword == "no-storage-format" || // synonyms
463 lowerword == "nsf") {
464 Options |= EOptionNoStorageFormat;
John Kessenich2a271162017-07-20 20:00:36 -0600465 } else if (lowerword == "relaxed-errors") {
466 Options |= EOptionRelaxedErrors;
John Kessenich6263fb12017-06-14 15:52:44 -0600467 } else if (lowerword == "resource-set-bindings" || // synonyms
468 lowerword == "resource-set-binding" ||
469 lowerword == "rsb") {
470 ProcessResourceSetBindingBase(argc, argv, baseResourceSetBinding);
steve-lunarg9088be42016-11-01 10:31:42 -0600471 } else if (lowerword == "shift-image-bindings" || // synonyms
472 lowerword == "shift-image-binding" ||
473 lowerword == "sib") {
LoopDawg08a14422017-10-17 19:27:14 -0600474 ProcessBindingBase(argc, argv, glslang::EResImage);
John Kessenich6263fb12017-06-14 15:52:44 -0600475 } else if (lowerword == "shift-sampler-bindings" || // synonyms
476 lowerword == "shift-sampler-binding" ||
477 lowerword == "ssb") {
LoopDawg08a14422017-10-17 19:27:14 -0600478 ProcessBindingBase(argc, argv, glslang::EResSampler);
John Kessenich6263fb12017-06-14 15:52:44 -0600479 } else if (lowerword == "shift-uav-bindings" || // synonyms
480 lowerword == "shift-uav-binding" ||
481 lowerword == "suavb") {
LoopDawg08a14422017-10-17 19:27:14 -0600482 ProcessBindingBase(argc, argv, glslang::EResUav);
John Kessenich6263fb12017-06-14 15:52:44 -0600483 } else if (lowerword == "shift-texture-bindings" || // synonyms
484 lowerword == "shift-texture-binding" ||
485 lowerword == "stb") {
LoopDawg08a14422017-10-17 19:27:14 -0600486 ProcessBindingBase(argc, argv, glslang::EResTexture);
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600487 } else if (lowerword == "shift-ubo-bindings" || // synonyms
488 lowerword == "shift-ubo-binding" ||
steve-lunargbe283552017-04-18 12:18:01 -0600489 lowerword == "shift-cbuffer-bindings" ||
490 lowerword == "shift-cbuffer-binding" ||
491 lowerword == "sub" ||
492 lowerword == "scb") {
LoopDawg08a14422017-10-17 19:27:14 -0600493 ProcessBindingBase(argc, argv, glslang::EResUbo);
steve-lunarg932bb5c2017-02-21 17:19:08 -0700494 } else if (lowerword == "shift-ssbo-bindings" || // synonyms
495 lowerword == "shift-ssbo-binding" ||
496 lowerword == "sbb") {
LoopDawg08a14422017-10-17 19:27:14 -0600497 ProcessBindingBase(argc, argv, glslang::EResSsbo);
John Kessenich6263fb12017-06-14 15:52:44 -0600498 } else if (lowerword == "source-entrypoint" || // synonyms
499 lowerword == "sep") {
John Kessenichc178f0a2017-06-23 10:58:31 -0600500 if (argc <= 1)
John Kessenich6263fb12017-06-14 15:52:44 -0600501 Error("no <entry-point> provided for --source-entrypoint");
John Kessenichc178f0a2017-06-23 10:58:31 -0600502 sourceEntryPointName = argv[1];
503 bumpArg();
John Kessenich6263fb12017-06-14 15:52:44 -0600504 break;
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +0200505 } else if (lowerword == "stdin") {
506 Options |= EOptionStdin;
507 shaderStageName = argv[1];
John Kessenich2a271162017-07-20 20:00:36 -0600508 } else if (lowerword == "suppress-warnings") {
509 Options |= EOptionSuppressWarnings;
John Kessenich6353d552017-06-23 11:11:09 -0600510 } else if (lowerword == "target-env") {
511 if (argc > 1) {
512 if (strcmp(argv[1], "vulkan1.0") == 0) {
513 setVulkanSpv();
514 VulkanClientVersion = 100;
515 } else if (strcmp(argv[1], "opengl") == 0) {
516 setOpenGlSpv();
517 OpenGLClientVersion = 450;
518 } else
Rex Xucb61eec2018-03-07 13:10:01 +0800519 Error("--target-env expected vulkan1.0, opengl, or hlsl-16bit-types");
John Kessenich6353d552017-06-23 11:11:09 -0600520 }
521 bumpArg();
Flavio15017db2017-02-15 14:29:33 -0800522 } else if (lowerword == "variable-name" || // synonyms
523 lowerword == "vn") {
524 Options |= EOptionOutputHexadecimal;
John Kessenichc178f0a2017-06-23 10:58:31 -0600525 if (argc <= 1)
Flavio15017db2017-02-15 14:29:33 -0800526 Error("no <C-variable-name> provided for --variable-name");
John Kessenichc178f0a2017-06-23 10:58:31 -0600527 variableName = argv[1];
528 bumpArg();
Flavio15017db2017-02-15 14:29:33 -0800529 break;
John Kessenichc6c80a62018-03-05 22:23:17 -0700530 } else if (lowerword == "version") {
531 Options |= EOptionDumpVersions;
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600532 } else {
533 usage();
534 }
535 }
536 break;
John Kessenich6263fb12017-06-14 15:52:44 -0600537 case 'C':
538 Options |= EOptionCascadingErrors;
539 break;
540 case 'D':
John Kessenicha9313662017-06-15 10:40:49 -0600541 if (argv[0][2] == 0)
542 Options |= EOptionReadHlsl;
543 else
544 UserPreamble.addDef(getStringOperand("-D<macro> macro name"));
John Kessenich6263fb12017-06-14 15:52:44 -0600545 break;
546 case 'E':
547 Options |= EOptionOutputPreprocessed;
548 break;
549 case 'G':
John Kessenich6353d552017-06-23 11:11:09 -0600550 // OpenGL Client
551 setOpenGlSpv();
552 if (argv[0][2] != 0)
553 ClientInputSemanticsVersion = getAttachedNumber("-G<num> client input semantics");
John Kessenich6263fb12017-06-14 15:52:44 -0600554 break;
John Kessenich2aa7f3a2015-05-15 16:02:07 +0000555 case 'H':
556 Options |= EOptionHumanReadableSpv;
John Kessenich91e4aa52016-07-07 17:46:42 -0600557 if ((Options & EOptionSpv) == 0) {
558 // default to Vulkan
John Kessenich6353d552017-06-23 11:11:09 -0600559 setVulkanSpv();
John Kessenich91e4aa52016-07-07 17:46:42 -0600560 }
561 break;
John Kessenich971a0a82017-06-07 15:06:58 -0600562 case 'I':
John Kessenicha9313662017-06-15 10:40:49 -0600563 IncludeDirectoryList.push_back(getStringOperand("-I<dir> include path"));
John Kessenich68d78fd2015-07-12 19:28:10 -0600564 break;
GregFcd1f1692017-09-21 18:40:22 -0600565 case 'O':
566 if (argv[0][2] == 'd')
567 Options |= EOptionOptimizeDisable;
568 else if (argv[0][2] == 's')
569#ifdef ENABLE_OPT
570 Options |= EOptionOptimizeSize;
571#else
572 Error("-Os not available; optimizer not linked");
573#endif
574 else
575 Error("unknown -O option");
576 break;
Dan Baker5afdd782016-08-11 17:53:57 -0400577 case 'S':
John Kessenichc178f0a2017-06-23 10:58:31 -0600578 if (argc <= 1)
Dan Baker5afdd782016-08-11 17:53:57 -0400579 Error("no <stage> specified for -S");
John Kessenichc178f0a2017-06-23 10:58:31 -0600580 shaderStageName = argv[1];
581 bumpArg();
dankbaker45d49bc2016-08-08 21:43:07 -0400582 break;
John Kessenicha9313662017-06-15 10:40:49 -0600583 case 'U':
584 UserPreamble.addUndef(getStringOperand("-U<macro>: macro name"));
585 break;
John Kessenich6263fb12017-06-14 15:52:44 -0600586 case 'V':
John Kessenich6353d552017-06-23 11:11:09 -0600587 setVulkanSpv();
588 if (argv[0][2] != 0)
David Neto506d2c22018-02-27 21:55:23 -0500589 ClientInputSemanticsVersion = getAttachedNumber("-V<num> client input semantics");
John Kessenichc555ddd2015-06-17 02:38:44 +0000590 break;
John Kessenich05a70632013-09-17 19:26:08 +0000591 case 'c':
592 Options |= EOptionDumpConfig;
593 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000594 case 'd':
John Kessenichc6c80a62018-03-05 22:23:17 -0700595 if (strncmp(&argv[0][1], "dumpversion", strlen(&argv[0][1]) + 1) == 0 ||
596 strncmp(&argv[0][1], "dumpfullversion", strlen(&argv[0][1]) + 1) == 0)
597 Options |= EOptionDumpBareVersion;
598 else
599 Options |= EOptionDefaultDesktop;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000600 break;
John Kessenich4d65ee32016-03-12 18:17:47 -0700601 case 'e':
602 // HLSL todo: entry point handle needs much more sophistication.
603 // This is okay for one compilation unit with one entry point.
604 entryPointName = argv[1];
John Kessenichc178f0a2017-06-23 10:58:31 -0600605 if (argc <= 1)
John Kessenicha25530c2017-09-11 20:13:49 -0600606 Error("no <name> provided for -e");
John Kessenichc178f0a2017-06-23 10:58:31 -0600607 bumpArg();
John Kessenich4d65ee32016-03-12 18:17:47 -0700608 break;
John Kessenich121853f2017-05-31 17:11:16 -0600609 case 'g':
610 Options |= EOptionDebug;
611 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600612 case 'h':
613 usage();
614 break;
John Kessenich05a70632013-09-17 19:26:08 +0000615 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000616 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000617 break;
618 case 'l':
John Kessenichd78e3512014-08-25 20:07:55 +0000619 Options |= EOptionLinkProgram;
John Kessenich94a81fb2013-08-31 02:41:30 +0000620 break;
621 case 'm':
622 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000623 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600624 case 'o':
John Kessenichc178f0a2017-06-23 10:58:31 -0600625 if (argc <= 1)
John Kessenich68d78fd2015-07-12 19:28:10 -0600626 Error("no <file> provided for -o");
John Kessenichc178f0a2017-06-23 10:58:31 -0600627 binaryFileName = argv[1];
628 bumpArg();
John Kessenich68d78fd2015-07-12 19:28:10 -0600629 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000630 case 'q':
631 Options |= EOptionDumpReflection;
632 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000633 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000634 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000635 break;
636 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000637 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000638 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000639 case 't':
Juan Lopeza558b262017-04-02 23:04:00 +0200640 Options |= EOptionMultiThreaded;
John Kessenich38f3b892013-09-06 19:52:57 +0000641 break;
John Kessenich319de232013-12-04 04:43:40 +0000642 case 'v':
643 Options |= EOptionDumpVersions;
644 break;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000645 case 'w':
646 Options |= EOptionSuppressWarnings;
647 break;
Johannes van Waverenecb0f3b2016-05-27 12:55:53 -0500648 case 'x':
649 Options |= EOptionOutputHexadecimal;
Johannes van Waverenecb0f3b2016-05-27 12:55:53 -0500650 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000651 default:
John Kessenich68d78fd2015-07-12 19:28:10 -0600652 usage();
653 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000654 }
John Kessenich38f3b892013-09-06 19:52:57 +0000655 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000656 std::string name(argv[0]);
657 if (! SetConfigFile(name)) {
Juan Lopeza558b262017-04-02 23:04:00 +0200658 workItems.push_back(std::unique_ptr<glslang::TWorkItem>(new glslang::TWorkItem(name)));
John Kessenich05a70632013-09-17 19:26:08 +0000659 }
John Kessenich38f3b892013-09-06 19:52:57 +0000660 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000661 }
662
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +0200663 // Make sure that -S is always specified if --stdin is specified
664 if ((Options & EOptionStdin) && shaderStageName == nullptr)
665 Error("must provide -S when --stdin is given");
666
John Kessenich68d78fd2015-07-12 19:28:10 -0600667 // Make sure that -E is not specified alongside linking (which includes SPV generation)
668 if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
669 Error("can't use -E when linking is selected");
John Kessenichc555ddd2015-06-17 02:38:44 +0000670
Johannes van Waverenecb0f3b2016-05-27 12:55:53 -0500671 // -o or -x makes no sense if there is no target binary
John Kessenich68d78fd2015-07-12 19:28:10 -0600672 if (binaryFileName && (Options & EOptionSpv) == 0)
673 Error("no binary generation requested (e.g., -V)");
steve-lunarge0b9deb2016-09-16 13:26:37 -0600674
675 if ((Options & EOptionFlattenUniformArrays) != 0 &&
676 (Options & EOptionReadHlsl) == 0)
677 Error("uniform array flattening only valid when compiling HLSL source.");
John Kessenich2b07c7e2013-07-31 18:44:13 +0000678}
679
John Kessenich68d78fd2015-07-12 19:28:10 -0600680//
681// Translate the meaningful subset of command-line options to parser-behavior options.
682//
John Kessenichb0a7eb52013-11-07 17:44:20 +0000683void SetMessageOptions(EShMessages& messages)
684{
685 if (Options & EOptionRelaxedErrors)
686 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
687 if (Options & EOptionIntermediate)
688 messages = (EShMessages)(messages | EShMsgAST);
689 if (Options & EOptionSuppressWarnings)
690 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
John Kessenich68d78fd2015-07-12 19:28:10 -0600691 if (Options & EOptionSpv)
692 messages = (EShMessages)(messages | EShMsgSpvRules);
693 if (Options & EOptionVulkanRules)
694 messages = (EShMessages)(messages | EShMsgVulkanRules);
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400695 if (Options & EOptionOutputPreprocessed)
696 messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
John Kessenich66e2faf2016-03-12 18:34:36 -0700697 if (Options & EOptionReadHlsl)
698 messages = (EShMessages)(messages | EShMsgReadHlsl);
John Kessenicha86836e2016-07-09 14:50:57 -0600699 if (Options & EOptionCascadingErrors)
700 messages = (EShMessages)(messages | EShMsgCascadingErrors);
John Kessenich906cc212016-12-09 19:22:20 -0700701 if (Options & EOptionKeepUncalled)
702 messages = (EShMessages)(messages | EShMsgKeepUncalled);
John Kessenich4f1403e2017-04-05 17:38:20 -0600703 if (Options & EOptionHlslOffsets)
704 messages = (EShMessages)(messages | EShMsgHlslOffsets);
John Kessenich121853f2017-05-31 17:11:16 -0600705 if (Options & EOptionDebug)
706 messages = (EShMessages)(messages | EShMsgDebugInfo);
Rex Xucb61eec2018-03-07 13:10:01 +0800707 if (HlslEnable16BitTypes)
708 messages = (EShMessages)(messages | EShMsgHlslEnable16BitTypes);
John Kessenichb0a7eb52013-11-07 17:44:20 +0000709}
710
John Kessenich68d78fd2015-07-12 19:28:10 -0600711//
John Kessenich69f4b512013-09-04 21:19:27 +0000712// Thread entry point, for non-linking asynchronous mode.
John Kessenichc999ba22013-11-07 23:33:24 +0000713//
Juan Lopeza558b262017-04-02 23:04:00 +0200714void CompileShaders(glslang::TWorklist& worklist)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000715{
John Kessenich38f3b892013-09-06 19:52:57 +0000716 glslang::TWorkItem* workItem;
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +0200717 if (Options & EOptionStdin) {
718 worklist.remove(workItem);
719 ShHandle compiler = ShConstructCompiler(FindLanguage("stdin"), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000720 if (compiler == 0)
Juan Lopeza558b262017-04-02 23:04:00 +0200721 return;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000722
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +0200723 CompileFile("stdin", compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000724
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +0200725 if (! (Options & EOptionSuppressInfolog))
726 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000727
728 ShDestruct(compiler);
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +0200729 } else {
730 while (worklist.remove(workItem)) {
731 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
732 if (compiler == 0)
733 return;
734
735 CompileFile(workItem->name.c_str(), compiler);
736
737 if (! (Options & EOptionSuppressInfolog))
738 workItem->results = ShGetInfoLog(compiler);
739
740 ShDestruct(compiler);
741 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000742 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000743}
744
John Kessenich6626cad2015-06-19 05:14:19 +0000745// Outputs the given string, but only if it is non-null and non-empty.
746// This prevents erroneous newlines from appearing.
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400747void PutsIfNonEmpty(const char* str)
John Kessenich6626cad2015-06-19 05:14:19 +0000748{
749 if (str && str[0]) {
750 puts(str);
751 }
752}
753
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400754// Outputs the given string to stderr, but only if it is non-null and non-empty.
755// This prevents erroneous newlines from appearing.
756void StderrIfNonEmpty(const char* str)
757{
John Kessenich04acb1b2017-06-14 17:36:50 -0600758 if (str && str[0])
759 fprintf(stderr, "%s\n", str);
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400760}
761
John Kessenichc57b2a92016-01-16 15:30:03 -0700762// Simple bundling of what makes a compilation unit for ease in passing around,
763// and separation of handling file IO versus API (programmatic) compilation.
764struct ShaderCompUnit {
765 EShLanguage stage;
John Kessenich04acb1b2017-06-14 17:36:50 -0600766 static const int maxCount = 1;
767 int count; // live number of strings/names
John Kessenicha9313662017-06-15 10:40:49 -0600768 const char* text[maxCount]; // memory owned/managed externally
John Kessenich04acb1b2017-06-14 17:36:50 -0600769 std::string fileName[maxCount]; // hold's the memory, but...
770 const char* fileNameList[maxCount]; // downstream interface wants pointers
dankbakerafe6e9c2016-08-21 12:29:08 -0400771
John Kessenich04acb1b2017-06-14 17:36:50 -0600772 ShaderCompUnit(EShLanguage stage) : stage(stage), count(0) { }
dankbakerafe6e9c2016-08-21 12:29:08 -0400773
John Kessenich04acb1b2017-06-14 17:36:50 -0600774 ShaderCompUnit(const ShaderCompUnit& rhs)
dankbakerafe6e9c2016-08-21 12:29:08 -0400775 {
776 stage = rhs.stage;
John Kessenich04acb1b2017-06-14 17:36:50 -0600777 count = rhs.count;
778 for (int i = 0; i < count; ++i) {
779 fileName[i] = rhs.fileName[i];
780 text[i] = rhs.text[i];
781 fileNameList[i] = rhs.fileName[i].c_str();
782 }
dankbakerafe6e9c2016-08-21 12:29:08 -0400783 }
784
John Kessenicha9313662017-06-15 10:40:49 -0600785 void addString(std::string& ifileName, const char* itext)
John Kessenich04acb1b2017-06-14 17:36:50 -0600786 {
787 assert(count < maxCount);
788 fileName[count] = ifileName;
789 text[count] = itext;
790 fileNameList[count] = fileName[count].c_str();
791 ++count;
792 }
John Kessenichc57b2a92016-01-16 15:30:03 -0700793};
794
John Kessenich69f4b512013-09-04 21:19:27 +0000795//
John Kessenichc57b2a92016-01-16 15:30:03 -0700796// For linking mode: Will independently parse each compilation unit, but then put them
797// in the same program and link them together, making at most one linked module per
798// pipeline stage.
John Kessenich69f4b512013-09-04 21:19:27 +0000799//
800// Uses the new C++ interface instead of the old handle-based interface.
801//
John Kessenichc57b2a92016-01-16 15:30:03 -0700802
803void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
John Kessenich69f4b512013-09-04 21:19:27 +0000804{
805 // keep track of what to free
806 std::list<glslang::TShader*> shaders;
John Kessenichc57b2a92016-01-16 15:30:03 -0700807
John Kessenich69f4b512013-09-04 21:19:27 +0000808 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000809 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000810
John Kessenich69f4b512013-09-04 21:19:27 +0000811 //
812 // Per-shader processing...
813 //
814
John Kessenich5b0f13a2013-11-01 03:08:40 +0000815 glslang::TProgram& program = *new glslang::TProgram;
rdb32084e82016-02-23 22:17:38 +0100816 for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
817 const auto &compUnit = *it;
John Kessenichc57b2a92016-01-16 15:30:03 -0700818 glslang::TShader* shader = new glslang::TShader(compUnit.stage);
John Kessenich04acb1b2017-06-14 17:36:50 -0600819 shader->setStringsWithLengthsAndNames(compUnit.text, NULL, compUnit.fileNameList, compUnit.count);
John Kessenich4d65ee32016-03-12 18:17:47 -0700820 if (entryPointName) // HLSL todo: this needs to be tracked per compUnits
821 shader->setEntryPoint(entryPointName);
John Kessenich3693e632017-09-29 17:51:52 -0600822 if (sourceEntryPointName) {
823 if (entryPointName == nullptr)
824 printf("Warning: Changing source entry point name without setting an entry-point name.\n"
825 "Use '-e <name>'.\n");
steve-lunargf1e0c872016-10-31 15:13:43 -0600826 shader->setSourceEntryPoint(sourceEntryPointName);
John Kessenich3693e632017-09-29 17:51:52 -0600827 }
John Kessenicha9313662017-06-15 10:40:49 -0600828 if (UserPreamble.isSet())
829 shader->setPreamble(UserPreamble.get());
John Kessenich2a271162017-07-20 20:00:36 -0600830 shader->addProcesses(Processes);
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600831
LoopDawg08a14422017-10-17 19:27:14 -0600832 // Set IO mapper binding shift values
833 for (int r = 0; r < glslang::EResCount; ++r) {
834 const glslang::TResourceType res = glslang::TResourceType(r);
835
836 // Set base bindings
837 shader->setShiftBinding(res, baseBinding[res][compUnit.stage]);
838
839 // Set bindings for particular resource sets
840 // TODO: use a range based for loop here, when available in all environments.
841 for (auto i = baseBindingForSet[res][compUnit.stage].begin();
842 i != baseBindingForSet[res][compUnit.stage].end(); ++i)
LoopDawge5709552017-10-21 10:46:39 -0600843 shader->setShiftBindingForSet(res, i->second, i->first);
LoopDawg08a14422017-10-17 19:27:14 -0600844 }
845
steve-lunarge0b9deb2016-09-16 13:26:37 -0600846 shader->setFlattenUniformArrays((Options & EOptionFlattenUniformArrays) != 0);
steve-lunargcce8d482016-10-14 18:36:42 -0600847 shader->setNoStorageFormat((Options & EOptionNoStorageFormat) != 0);
Hyangran Park36dc8292017-05-02 16:27:29 +0900848 shader->setResourceSetBinding(baseResourceSetBinding[compUnit.stage]);
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600849
steve-lunargbe283552017-04-18 12:18:01 -0600850 if (Options & EOptionHlslIoMapping)
851 shader->setHlslIoMapping(true);
852
steve-lunarg7f7c2ed2016-09-07 15:20:19 -0600853 if (Options & EOptionAutoMapBindings)
854 shader->setAutoMapBindings(true);
John Kessenichecba76f2017-01-06 00:34:48 -0700855
John Kessenich71facdf2017-05-17 18:28:19 -0600856 if (Options & EOptionAutoMapLocations)
857 shader->setAutoMapLocations(true);
858
LoopDawgb22c0692017-12-06 16:52:03 -0700859 if (Options & EOptionInvertY)
860 shader->setInvertY(true);
861
John Kessenich4be4aeb2017-06-23 10:50:22 -0600862 // Set up the environment, some subsettings take precedence over earlier
863 // ways of setting things.
864 if (Options & EOptionSpv) {
865 if (Options & EOptionVulkanRules) {
866 shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl
867 : glslang::EShSourceGlsl,
John Kessenich6353d552017-06-23 11:11:09 -0600868 compUnit.stage, glslang::EShClientVulkan, ClientInputSemanticsVersion);
869 shader->setEnvClient(glslang::EShClientVulkan, VulkanClientVersion);
John Kessenich22f02d02018-01-31 17:53:24 -0700870 shader->setEnvTarget(glslang::EShTargetSpv, TargetVersion);
John Kessenich4be4aeb2017-06-23 10:50:22 -0600871 } else {
872 shader->setEnvInput((Options & EOptionReadHlsl) ? glslang::EShSourceHlsl
873 : glslang::EShSourceGlsl,
John Kessenich6353d552017-06-23 11:11:09 -0600874 compUnit.stage, glslang::EShClientOpenGL, ClientInputSemanticsVersion);
875 shader->setEnvClient(glslang::EShClientOpenGL, OpenGLClientVersion);
876 shader->setEnvTarget(glslang::EshTargetSpv, TargetVersion);
John Kessenich4be4aeb2017-06-23 10:50:22 -0600877 }
878 }
879
John Kessenich69f4b512013-09-04 21:19:27 +0000880 shaders.push_back(shader);
John Kessenichb3297152015-07-11 18:01:03 -0600881
John Kessenich4be4aeb2017-06-23 10:50:22 -0600882 const int defaultVersion = Options & EOptionDefaultDesktop ? 110 : 100;
John Kessenich69f4b512013-09-04 21:19:27 +0000883
John Kessenich3494b4d2017-05-22 15:00:42 -0600884 DirStackFileIncluder includer;
John Kessenich971a0a82017-06-07 15:06:58 -0600885 std::for_each(IncludeDirectoryList.rbegin(), IncludeDirectoryList.rend(), [&includer](const std::string& dir) {
886 includer.pushExternalLocalDirectory(dir); });
John Kessenichc555ddd2015-06-17 02:38:44 +0000887 if (Options & EOptionOutputPreprocessed) {
888 std::string str;
Dejan Mircevski7be4b822015-06-17 11:40:33 -0400889 if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
Andrew Woloszyna132af52016-03-07 13:23:09 -0500890 messages, &str, includer)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400891 PutsIfNonEmpty(str.c_str());
892 } else {
893 CompileFailed = true;
894 }
895 StderrIfNonEmpty(shader->getInfoLog());
896 StderrIfNonEmpty(shader->getInfoDebugLog());
John Kessenichc555ddd2015-06-17 02:38:44 +0000897 continue;
898 }
John Kessenich3494b4d2017-05-22 15:00:42 -0600899 if (! shader->parse(&Resources, defaultVersion, false, messages, includer))
John Kessenichc999ba22013-11-07 23:33:24 +0000900 CompileFailed = true;
John Kessenichc555ddd2015-06-17 02:38:44 +0000901
John Kessenich69f4b512013-09-04 21:19:27 +0000902 program.addShader(shader);
903
John Kessenichc57b2a92016-01-16 15:30:03 -0700904 if (! (Options & EOptionSuppressInfolog) &&
905 ! (Options & EOptionMemoryLeakMode)) {
John Kessenich04acb1b2017-06-14 17:36:50 -0600906 PutsIfNonEmpty(compUnit.fileName[0].c_str());
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400907 PutsIfNonEmpty(shader->getInfoLog());
908 PutsIfNonEmpty(shader->getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000909 }
John Kessenich69f4b512013-09-04 21:19:27 +0000910 }
911
912 //
913 // Program-level processing...
914 //
915
John Kessenich4d65ee32016-03-12 18:17:47 -0700916 // Link
John Kessenich68d78fd2015-07-12 19:28:10 -0600917 if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000918 LinkFailed = true;
919
steve-lunarg9ae34742016-10-05 13:40:13 -0600920 // Map IO
921 if (Options & EOptionSpv) {
922 if (!program.mapIO())
923 LinkFailed = true;
924 }
John Kessenichecba76f2017-01-06 00:34:48 -0700925
John Kessenich4d65ee32016-03-12 18:17:47 -0700926 // Report
John Kessenichc57b2a92016-01-16 15:30:03 -0700927 if (! (Options & EOptionSuppressInfolog) &&
928 ! (Options & EOptionMemoryLeakMode)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400929 PutsIfNonEmpty(program.getInfoLog());
930 PutsIfNonEmpty(program.getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000931 }
932
John Kessenich4d65ee32016-03-12 18:17:47 -0700933 // Reflect
John Kessenich11f9fc72013-11-07 01:06:34 +0000934 if (Options & EOptionDumpReflection) {
935 program.buildReflection();
936 program.dumpReflection();
937 }
938
John Kessenich4d65ee32016-03-12 18:17:47 -0700939 // Dump SPIR-V
John Kessenich0df0cde2015-03-03 17:09:43 +0000940 if (Options & EOptionSpv) {
John Kessenich92f90382014-07-28 04:21:04 +0000941 if (CompileFailed || LinkFailed)
John Kessenich68d78fd2015-07-12 19:28:10 -0600942 printf("SPIR-V is not generated for failed compile or link\n");
John Kessenich92f90382014-07-28 04:21:04 +0000943 else {
944 for (int stage = 0; stage < EShLangCount; ++stage) {
John Kessenicha7a68a92014-08-24 18:21:00 +0000945 if (program.getIntermediate((EShLanguage)stage)) {
John Kessenich0df0cde2015-03-03 17:09:43 +0000946 std::vector<unsigned int> spirv;
Lei Zhang09caf122016-05-02 18:11:54 -0400947 std::string warningsErrors;
Lei Zhang17535f72016-05-04 15:55:59 -0400948 spv::SpvBuildLogger logger;
John Kessenich121853f2017-05-31 17:11:16 -0600949 glslang::SpvOptions spvOptions;
950 if (Options & EOptionDebug)
951 spvOptions.generateDebugInfo = true;
GregF52fe3d52017-09-28 10:08:32 -0600952 spvOptions.disableOptimizer = (Options & EOptionOptimizeDisable) != 0;
953 spvOptions.optimizeSize = (Options & EOptionOptimizeSize) != 0;
John Kessenich121853f2017-05-31 17:11:16 -0600954 glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger, &spvOptions);
John Kessenichc57b2a92016-01-16 15:30:03 -0700955
956 // Dump the spv to a file or stdout, etc., but only if not doing
957 // memory/perf testing, as it's not internal to programmatic use.
958 if (! (Options & EOptionMemoryLeakMode)) {
Johannes van Waverenecb0f3b2016-05-27 12:55:53 -0500959 printf("%s", logger.getAllMessages().c_str());
960 if (Options & EOptionOutputHexadecimal) {
John Kessenich8f674e82017-02-18 09:45:40 -0700961 glslang::OutputSpvHex(spirv, GetBinaryName((EShLanguage)stage), variableName);
Johannes van Waverenecb0f3b2016-05-27 12:55:53 -0500962 } else {
963 glslang::OutputSpvBin(spirv, GetBinaryName((EShLanguage)stage));
964 }
John Kessenichc57b2a92016-01-16 15:30:03 -0700965 if (Options & EOptionHumanReadableSpv) {
John Kessenichc57b2a92016-01-16 15:30:03 -0700966 spv::Disassemble(std::cout, spirv);
967 }
John Kessenichacba7722015-03-04 03:48:38 +0000968 }
John Kessenicha7a68a92014-08-24 18:21:00 +0000969 }
John Kessenich92f90382014-07-28 04:21:04 +0000970 }
971 }
972 }
973
John Kessenich5b0f13a2013-11-01 03:08:40 +0000974 // Free everything up, program has to go before the shaders
975 // because it might have merged stuff from the shaders, and
976 // the stuff from the shaders has to have its destructors called
977 // before the pools holding the memory in the shaders is freed.
978 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000979 while (shaders.size() > 0) {
980 delete shaders.back();
981 shaders.pop_back();
982 }
John Kessenich69f4b512013-09-04 21:19:27 +0000983}
984
John Kessenichc57b2a92016-01-16 15:30:03 -0700985//
986// Do file IO part of compile and link, handing off the pure
987// API/programmatic mode to CompileAndLinkShaderUnits(), which can
988// be put in a loop for testing memory footprint and performance.
989//
990// This is just for linking mode: meaning all the shaders will be put into the
991// the same program linked together.
992//
993// This means there are a limited number of work items (not multi-threading mode)
994// and that the point is testing at the linking level. Hence, to enable
995// performance and memory testing, the actual compile/link can be put in
996// a loop, independent of processing the work items and file IO.
997//
Juan Lopeza558b262017-04-02 23:04:00 +0200998void CompileAndLinkShaderFiles(glslang::TWorklist& Worklist)
John Kessenichc57b2a92016-01-16 15:30:03 -0700999{
1000 std::vector<ShaderCompUnit> compUnits;
1001
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +02001002 // If this is using stdin, we can't really detect multiple different file
1003 // units by input type. We need to assume that we're just being given one
1004 // file of a certain type.
1005 if ((Options & EOptionStdin) != 0) {
1006 ShaderCompUnit compUnit(FindLanguage("stdin"));
1007 std::istreambuf_iterator<char> begin(std::cin), end;
1008 std::string tempString(begin, end);
1009 char* fileText = strdup(tempString.c_str());
1010 std::string fileName = "stdin";
1011 compUnit.addString(fileName, fileText);
John Kessenichc57b2a92016-01-16 15:30:03 -07001012 compUnits.push_back(compUnit);
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +02001013 } else {
1014 // Transfer all the work items from to a simple list of
1015 // of compilation units. (We don't care about the thread
1016 // work-item distribution properties in this path, which
1017 // is okay due to the limited number of shaders, know since
1018 // they are all getting linked together.)
1019 glslang::TWorkItem* workItem;
1020 while (Worklist.remove(workItem)) {
1021 ShaderCompUnit compUnit(FindLanguage(workItem->name));
1022 char* fileText = ReadFileData(workItem->name.c_str());
1023 if (fileText == nullptr)
1024 usage();
1025 compUnit.addString(workItem->name, fileText);
1026 compUnits.push_back(compUnit);
1027 }
John Kessenichc57b2a92016-01-16 15:30:03 -07001028 }
1029
1030 // Actual call to programmatic processing of compile and link,
1031 // in a loop for testing memory and performance. This part contains
1032 // all the perf/memory that a programmatic consumer will care about.
1033 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
1034 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
1035 CompileAndLinkShaderUnits(compUnits);
1036
1037 if (Options & EOptionMemoryLeakMode)
1038 glslang::OS_DumpMemoryCounters();
1039 }
1040
John Kessenicha9313662017-06-15 10:40:49 -06001041 // free memory from ReadFileData, which got stored in a const char*
1042 // as the first string above
rdb32084e82016-02-23 22:17:38 +01001043 for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
John Kessenicha9313662017-06-15 10:40:49 -06001044 FreeFileData(const_cast<char*>(it->text[0]));
John Kessenichc57b2a92016-01-16 15:30:03 -07001045}
1046
John Kessenich94f28eb2017-11-13 01:32:06 -07001047int singleMain()
John Kessenicha0af4732012-12-12 21:15:54 +00001048{
Juan Lopeza558b262017-04-02 23:04:00 +02001049 glslang::TWorklist workList;
John Kessenich94f28eb2017-11-13 01:32:06 -07001050 std::for_each(WorkItems.begin(), WorkItems.end(), [&workList](std::unique_ptr<glslang::TWorkItem>& item) {
Juan Lopeza558b262017-04-02 23:04:00 +02001051 assert(item);
1052 workList.add(item.get());
1053 });
John Kessenich2b07c7e2013-07-31 18:44:13 +00001054
John Kessenich05a70632013-09-17 19:26:08 +00001055 if (Options & EOptionDumpConfig) {
Lei Zhang414eb602016-03-04 16:22:34 -05001056 printf("%s", glslang::GetDefaultTBuiltInResourceString().c_str());
Juan Lopeza558b262017-04-02 23:04:00 +02001057 if (workList.empty())
John Kessenich05a70632013-09-17 19:26:08 +00001058 return ESuccess;
1059 }
1060
John Kessenichc6c80a62018-03-05 22:23:17 -07001061 if (Options & EOptionDumpBareVersion) {
1062 printf("%d.%d.%d\n",
1063 glslang::GetSpirvGeneratorVersion(), GLSLANG_MINOR_VERSION, GLSLANG_PATCH_LEVEL);
1064 if (workList.empty())
1065 return ESuccess;
1066 } else if (Options & EOptionDumpVersions) {
1067 printf("Glslang Version: %d.%d.%d\n",
1068 glslang::GetSpirvGeneratorVersion(), GLSLANG_MINOR_VERSION, GLSLANG_PATCH_LEVEL);
John Kessenich319de232013-12-04 04:43:40 +00001069 printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
1070 printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
John Kessenich68d78fd2015-07-12 19:28:10 -06001071 std::string spirvVersion;
1072 glslang::GetSpirvVersion(spirvVersion);
John Kessenich0da9eaa2015-08-01 17:10:02 -06001073 printf("SPIR-V Version %s\n", spirvVersion.c_str());
John Kessenich5e4b1242015-08-06 22:53:06 -06001074 printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
John Kessenich55e7d112015-11-15 21:33:39 -07001075 printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId());
John Kessenicha372a3e2017-11-02 22:32:14 -06001076 printf("SPIR-V Generator Version %d\n", glslang::GetSpirvGeneratorVersion());
John Kessenichb84313d2016-07-20 16:03:29 -06001077 printf("GL_KHR_vulkan_glsl version %d\n", 100);
1078 printf("ARB_GL_gl_spirv version %d\n", 100);
Juan Lopeza558b262017-04-02 23:04:00 +02001079 if (workList.empty())
John Kessenich319de232013-12-04 04:43:40 +00001080 return ESuccess;
1081 }
1082
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +02001083 if (workList.empty() && ((Options & EOptionStdin) == 0)) {
John Kessenich05a70632013-09-17 19:26:08 +00001084 usage();
John Kessenich05a70632013-09-17 19:26:08 +00001085 }
1086
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +02001087 if (Options & EOptionStdin) {
John Kessenich94f28eb2017-11-13 01:32:06 -07001088 WorkItems.push_back(std::unique_ptr<glslang::TWorkItem>{new glslang::TWorkItem("stdin")});
1089 workList.add(WorkItems.back().get());
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +02001090 }
1091
John Kessenich05a70632013-09-17 19:26:08 +00001092 ProcessConfigFile();
1093
John Kessenich69f4b512013-09-04 21:19:27 +00001094 //
1095 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +00001096 // 1) linking all arguments together, single-threaded, new C++ interface
1097 // 2) independent arguments, can be tackled by multiple asynchronous threads, for testing thread safety, using the old handle interface
John Kessenich69f4b512013-09-04 21:19:27 +00001098 //
John Kessenichc555ddd2015-06-17 02:38:44 +00001099 if (Options & EOptionLinkProgram ||
1100 Options & EOptionOutputPreprocessed) {
John Kessenichc36e1d82013-11-01 17:41:52 +00001101 glslang::InitializeProcess();
John Kesseniche2c15b42017-11-16 22:48:41 -07001102 glslang::InitializeProcess(); // also test reference counting of users
1103 glslang::InitializeProcess(); // also test reference counting of users
1104 glslang::FinalizeProcess(); // also test reference counting of users
1105 glslang::FinalizeProcess(); // also test reference counting of users
Juan Lopeza558b262017-04-02 23:04:00 +02001106 CompileAndLinkShaderFiles(workList);
John Kessenichc36e1d82013-11-01 17:41:52 +00001107 glslang::FinalizeProcess();
1108 } else {
1109 ShInitialize();
John Kesseniche2c15b42017-11-16 22:48:41 -07001110 ShInitialize(); // also test reference counting of users
1111 ShFinalize(); // also test reference counting of users
John Kessenichc36e1d82013-11-01 17:41:52 +00001112
Juan Lopeza558b262017-04-02 23:04:00 +02001113 bool printShaderNames = workList.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +00001114
John Kesseniche2c15b42017-11-16 22:48:41 -07001115 if (Options & EOptionMultiThreaded) {
Juan Lopeza558b262017-04-02 23:04:00 +02001116 std::array<std::thread, 16> threads;
John Kesseniche2c15b42017-11-16 22:48:41 -07001117 for (unsigned int t = 0; t < threads.size(); ++t) {
Juan Lopeza558b262017-04-02 23:04:00 +02001118 threads[t] = std::thread(CompileShaders, std::ref(workList));
John Kesseniche2c15b42017-11-16 22:48:41 -07001119 if (threads[t].get_id() == std::thread::id()) {
John Kessenichaf527992017-11-02 22:48:15 -06001120 fprintf(stderr, "Failed to create thread\n");
John Kessenich38f3b892013-09-06 19:52:57 +00001121 return EFailThreadCreate;
1122 }
John Kessenicha0af4732012-12-12 21:15:54 +00001123 }
Juan Lopeza558b262017-04-02 23:04:00 +02001124
1125 std::for_each(threads.begin(), threads.end(), [](std::thread& t) { t.join(); });
John Kessenichc999ba22013-11-07 23:33:24 +00001126 } else
Juan Lopeza558b262017-04-02 23:04:00 +02001127 CompileShaders(workList);
John Kessenich38f3b892013-09-06 19:52:57 +00001128
1129 // Print out all the resulting infologs
John Kessenich94f28eb2017-11-13 01:32:06 -07001130 for (size_t w = 0; w < WorkItems.size(); ++w) {
1131 if (WorkItems[w]) {
1132 if (printShaderNames || WorkItems[w]->results.size() > 0)
1133 PutsIfNonEmpty(WorkItems[w]->name.c_str());
1134 PutsIfNonEmpty(WorkItems[w]->results.c_str());
John Kessenich38f3b892013-09-06 19:52:57 +00001135 }
1136 }
John Kessenichc36e1d82013-11-01 17:41:52 +00001137
1138 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +00001139 }
John Kessenich2b07c7e2013-07-31 18:44:13 +00001140
John Kessenichc999ba22013-11-07 23:33:24 +00001141 if (CompileFailed)
John Kessenicha0af4732012-12-12 21:15:54 +00001142 return EFailCompile;
John Kessenichc999ba22013-11-07 23:33:24 +00001143 if (LinkFailed)
John Kessenicha0af4732012-12-12 21:15:54 +00001144 return EFailLink;
1145
1146 return 0;
1147}
1148
John Kessenich94f28eb2017-11-13 01:32:06 -07001149int C_DECL main(int argc, char* argv[])
1150{
1151 ProcessArguments(WorkItems, argc, argv);
1152
1153 int ret = 0;
1154
1155 // Loop over the entire init/finalize cycle to watch memory changes
1156 const int iterations = 1;
1157 if (iterations > 1)
1158 glslang::OS_DumpMemoryCounters();
1159 for (int i = 0; i < iterations; ++i) {
1160 ret = singleMain();
1161 if (iterations > 1)
1162 glslang::OS_DumpMemoryCounters();
1163 }
1164
1165 return ret;
1166}
1167
John Kessenicha0af4732012-12-12 21:15:54 +00001168//
1169// Deduce the language from the filename. Files must end in one of the
1170// following extensions:
1171//
John Kessenich2b07c7e2013-07-31 18:44:13 +00001172// .vert = vertex
1173// .tesc = tessellation control
1174// .tese = tessellation evaluation
1175// .geom = geometry
1176// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +00001177// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +00001178//
steve-lunarg7f7c2ed2016-09-07 15:20:19 -06001179EShLanguage FindLanguage(const std::string& name, bool parseSuffix)
John Kessenicha0af4732012-12-12 21:15:54 +00001180{
steve-lunarg7f7c2ed2016-09-07 15:20:19 -06001181 size_t ext = 0;
John Kesseniche751bca2017-03-16 11:20:38 -06001182 std::string suffix;
steve-lunarg7f7c2ed2016-09-07 15:20:19 -06001183
Dan Bakerc6ede892016-08-11 14:06:06 -04001184 if (shaderStageName)
1185 suffix = shaderStageName;
John Kesseniche751bca2017-03-16 11:20:38 -06001186 else {
1187 // Search for a suffix on a filename: e.g, "myfile.frag". If given
1188 // the suffix directly, we skip looking for the '.'
1189 if (parseSuffix) {
1190 ext = name.rfind('.');
1191 if (ext == std::string::npos) {
1192 usage();
1193 return EShLangVertex;
1194 }
1195 ++ext;
1196 }
1197 suffix = name.substr(ext, std::string::npos);
1198 }
dankbaker45d49bc2016-08-08 21:43:07 -04001199
John Kessenich2b07c7e2013-07-31 18:44:13 +00001200 if (suffix == "vert")
1201 return EShLangVertex;
1202 else if (suffix == "tesc")
1203 return EShLangTessControl;
1204 else if (suffix == "tese")
1205 return EShLangTessEvaluation;
1206 else if (suffix == "geom")
1207 return EShLangGeometry;
1208 else if (suffix == "frag")
1209 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +00001210 else if (suffix == "comp")
1211 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +00001212
1213 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +00001214 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +00001215}
1216
John Kessenicha0af4732012-12-12 21:15:54 +00001217//
John Kessenichecba76f2017-01-06 00:34:48 -07001218// Read a file's data into a string, and compile it using the old interface ShCompile,
John Kessenich69f4b512013-09-04 21:19:27 +00001219// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +00001220//
John Kessenich51cdd902014-02-18 23:37:57 +00001221void CompileFile(const char* fileName, ShHandle compiler)
John Kessenicha0af4732012-12-12 21:15:54 +00001222{
John Kessenichca3457f2015-05-18 01:59:45 +00001223 int ret = 0;
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +02001224 char* shaderString;
1225 if ((Options & EOptionStdin) != 0) {
1226 std::istreambuf_iterator<char> begin(std::cin), end;
1227 std::string tempString(begin, end);
1228 shaderString = strdup(tempString.c_str());
1229 } else {
1230 shaderString = ReadFileData(fileName);
1231 }
John Kessenich41cf6b52013-06-25 18:10:05 +00001232
1233 // move to length-based strings, rather than null-terminated strings
John Kessenich04acb1b2017-06-14 17:36:50 -06001234 int* lengths = new int[1];
1235 lengths[0] = (int)strlen(shaderString);
John Kessenicha0af4732012-12-12 21:15:54 +00001236
John Kessenich52ac67e2013-05-05 23:46:22 +00001237 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +00001238 SetMessageOptions(messages);
John Kessenichecba76f2017-01-06 00:34:48 -07001239
John Kessenicha9313662017-06-15 10:40:49 -06001240 if (UserPreamble.isSet())
1241 Error("-D and -U options require -l (linking)\n");
1242
John Kessenich94a81fb2013-08-31 02:41:30 +00001243 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
1244 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich927608b2017-01-06 12:34:14 -07001245 // ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenich04acb1b2017-06-14 17:36:50 -06001246 ret = ShCompile(compiler, &shaderString, 1, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenich927608b2017-01-06 12:34:14 -07001247 // const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
John Kessenichecba76f2017-01-06 00:34:48 -07001248 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
John Kessenichea869fb2013-10-28 18:12:06 +00001249 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich927608b2017-01-06 12:34:14 -07001250 // const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
1251 // ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +00001252 }
John Kessenicha0af4732012-12-12 21:15:54 +00001253
John Kessenich94a81fb2013-08-31 02:41:30 +00001254 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +00001255 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +00001256 }
John Kessenicha0af4732012-12-12 21:15:54 +00001257
John Kessenich41cf6b52013-06-25 18:10:05 +00001258 delete [] lengths;
John Kessenich04acb1b2017-06-14 17:36:50 -06001259 FreeFileData(shaderString);
John Kessenicha0af4732012-12-12 21:15:54 +00001260
John Kessenichc999ba22013-11-07 23:33:24 +00001261 if (ret == 0)
1262 CompileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +00001263}
1264
John Kessenicha0af4732012-12-12 21:15:54 +00001265//
1266// print usage to stdout
1267//
1268void usage()
1269{
John Kessenich319de232013-12-04 04:43:40 +00001270 printf("Usage: glslangValidator [option]... [file]...\n"
1271 "\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001272 "'file' can end in .<stage> for auto-stage classification, where <stage> is:\n"
1273 " .conf to provide a config file that replaces the default configuration\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001274 " (see -c option below for generating a template)\n"
1275 " .vert for a vertex shader\n"
1276 " .tesc for a tessellation control shader\n"
1277 " .tese for a tessellation evaluation shader\n"
1278 " .geom for a geometry shader\n"
1279 " .frag for a fragment shader\n"
1280 " .comp for a compute shader\n"
John Kessenich319de232013-12-04 04:43:40 +00001281 "\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001282 "Options:\n"
1283 " -C cascading errors; risk crash from accumulation of error recoveries\n"
1284 " -D input is HLSL\n"
John Kessenicha9313662017-06-15 10:40:49 -06001285 " -D<macro=def>\n"
1286 " -D<macro> define a pre-processor macro\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001287 " -E print pre-processed GLSL; cannot be used with -l;\n"
1288 " errors will appear on stderr.\n"
John Kessenich6353d552017-06-23 11:11:09 -06001289 " -G[ver] create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001290 " default file name is <stage>.spv (-o overrides this)\n"
John Kessenich6353d552017-06-23 11:11:09 -06001291 " 'ver', when present, is the version of the input semantics,\n"
1292 " which will appear in #define GL_SPIRV ver\n"
1293 " '--client opengl100' is the same as -G100\n"
1294 " a '--target-env' for OpenGL will also imply '-G'\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001295 " -H print human readable form of SPIR-V; turns on -V\n"
John Kessenich971a0a82017-06-07 15:06:58 -06001296 " -I<dir> add dir to the include search path; includer's directory\n"
1297 " is searched first, followed by left-to-right order of -I\n"
GregFcd1f1692017-09-21 18:40:22 -06001298 " -Od disables optimization. May cause illegal SPIR-V for HLSL.\n"
1299 " -Os optimizes SPIR-V to minimize size.\n"
John Kesseniche751bca2017-03-16 11:20:38 -06001300 " -S <stage> uses specified stage rather than parsing the file extension\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001301 " choices for <stage> are vert, tesc, tese, geom, frag, or comp\n"
John Kessenich6353d552017-06-23 11:11:09 -06001302 " -U<macro> undefine a pre-processor macro\n"
1303 " -V[ver] create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001304 " default file name is <stage>.spv (-o overrides this)\n"
John Kessenich6353d552017-06-23 11:11:09 -06001305 " 'ver', when present, is the version of the input semantics,\n"
1306 " which will appear in #define VULKAN ver\n"
1307 " '--client vulkan100' is the same as -V100\n"
1308 " a '--target-env' for Vulkan will also imply '-V'\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001309 " -c configuration dump;\n"
1310 " creates the default configuration file (redirect to a .conf file)\n"
1311 " -d default to desktop (#version 110) when there is no shader #version\n"
1312 " (default is ES version 100)\n"
John Kessenicha25530c2017-09-11 20:13:49 -06001313 " -e <name> specify <name> as the entry-point name\n"
John Kessenich121853f2017-05-31 17:11:16 -06001314 " -g generate debug information\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001315 " -h print this usage message\n"
1316 " -i intermediate tree (glslang AST) is printed out\n"
1317 " -l link all input files together to form a single module\n"
1318 " -m memory leak mode\n"
John Kessenicha25530c2017-09-11 20:13:49 -06001319 " -o <file> save binary to <file>, requires a binary option (e.g., -V)\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001320 " -q dump reflection query database\n"
John Kessenich2a271162017-07-20 20:00:36 -06001321 " -r synonym for --relaxed-errors\n"
John Kessenichb63f4a32017-11-16 22:32:20 -07001322 " -s silence syntax and semantic error reporting\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001323 " -t multi-threaded mode\n"
1324 " -v print version strings\n"
John Kessenich2a271162017-07-20 20:00:36 -06001325 " -w synonym for --suppress-warnings\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001326 " -x save binary output as text-based 32-bit hexadecimal numbers\n"
1327 " --auto-map-bindings automatically bind uniform variables\n"
1328 " without explicit bindings.\n"
1329 " --amb synonym for --auto-map-bindings\n"
1330 " --auto-map-locations automatically locate input/output lacking\n"
John Kessenichc178f0a2017-06-23 10:58:31 -06001331 " 'location' (fragile, not cross stage)\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001332 " --aml synonym for --auto-map-locations\n"
John Kessenich6353d552017-06-23 11:11:09 -06001333 " --client {vulkan<ver>|opengl<ver>} see -V and -G\n"
John Kessenichc6c80a62018-03-05 22:23:17 -07001334 " -dumpfullversion print bare major.minor.patchlevel\n"
1335 " -dumpversion same as -dumpfullversion\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001336 " --flatten-uniform-arrays flatten uniform texture/sampler arrays to\n"
1337 " scalars\n"
1338 " --fua synonym for --flatten-uniform-arrays\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001339 " --hlsl-offsets Allow block offsets to follow HLSL rules\n"
1340 " Works independently of source language\n"
1341 " --hlsl-iomap Perform IO mapping in HLSL register space\n"
Rex Xucb61eec2018-03-07 13:10:01 +08001342 " --hlsl-enable-16bit-types Allow use of 16-bit types in SPIR-V for HLSL\n"
John Kessenichc6c80a62018-03-05 22:23:17 -07001343 " --invert-y | --iy invert position.Y output in vertex shader\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001344 " --keep-uncalled don't eliminate uncalled functions\n"
1345 " --ku synonym for --keep-uncalled\n"
1346 " --no-storage-format use Unknown image format\n"
1347 " --nsf synonym for --no-storage-format\n"
John Kessenich2a271162017-07-20 20:00:36 -06001348 " --relaxed-errors relaxed GLSL semantic error-checking mode\n"
LoopDawg52017192017-07-14 15:15:47 -06001349 " --resource-set-binding [stage] name set binding\n"
1350 " Set descriptor set and binding for individual resources\n"
1351 " --resource-set-binding [stage] set\n"
1352 " Set descriptor set for all resources\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001353 " --rsb [stage] type set binding synonym for --resource-set-binding\n"
1354 " --shift-image-binding [stage] num base binding number for images (uav)\n"
LoopDawge5709552017-10-21 10:46:39 -06001355 " --shift-image-binding [stage] [num set]... per-descriptor-set shift values\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001356 " --sib [stage] num synonym for --shift-image-binding\n"
1357 " --shift-sampler-binding [stage] num base binding number for samplers\n"
LoopDawge5709552017-10-21 10:46:39 -06001358 " --shift-sampler-binding [stage] [num set]... per-descriptor-set shift values\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001359 " --ssb [stage] num synonym for --shift-sampler-binding\n"
1360 " --shift-ssbo-binding [stage] num base binding number for SSBOs\n"
LoopDawge5709552017-10-21 10:46:39 -06001361 " --shift-ssbo-binding [stage] [num set]... per-descriptor-set shift values\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001362 " --sbb [stage] num synonym for --shift-ssbo-binding\n"
1363 " --shift-texture-binding [stage] num base binding number for textures\n"
LoopDawge5709552017-10-21 10:46:39 -06001364 " --shift-texture-binding [stage] [num set]... per-descriptor-set shift values\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001365 " --stb [stage] num synonym for --shift-texture-binding\n"
1366 " --shift-uav-binding [stage] num base binding number for UAVs\n"
LoopDawge5709552017-10-21 10:46:39 -06001367 " --shift-uav-binding [stage] [num set]... per-descriptor-set shift values\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001368 " --suavb [stage] num synonym for --shift-uav-binding\n"
1369 " --shift-UBO-binding [stage] num base binding number for UBOs\n"
LoopDawge5709552017-10-21 10:46:39 -06001370 " --shift-UBO-binding [stage] [num set]... per-descriptor-set shift values\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001371 " --shift-cbuffer-binding [stage] num synonym for --shift-UBO-binding\n"
LoopDawge5709552017-10-21 10:46:39 -06001372 " --shift-cbuffer-binding [stage] [num set]... per-descriptor-set shift values\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001373 " --sub [stage] num synonym for --shift-UBO-binding\n"
John Kessenicha25530c2017-09-11 20:13:49 -06001374 " --source-entrypoint <name> the given shader source function is\n"
1375 " renamed to be the <name> given in -e\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001376 " --sep synonym for --source-entrypoint\n"
Sven-Hendrik Haase0dd12852017-09-02 19:34:54 +02001377 " --stdin Read from stdin instead of from a file.\n"
1378 " You'll have to provide the shader stage\n"
1379 " using -S.\n"
John Kessenich2a271162017-07-20 20:00:36 -06001380 " --suppress-warnings suppress GLSL warnings\n"
1381 " (except as required by #extension : warn)\n"
1382 " --target-env {vulkan1.0|opengl} set the execution environment code will\n"
1383 " execute in (as opposed to language\n"
1384 " semantics selected by --client) defaults:\n"
1385 " 'vulkan1.0' under '--client vulkan<ver>'\n"
1386 " 'opengl' under '--client opengl<ver>'\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001387 " --variable-name <name> Creates a C header file that contains a\n"
1388 " uint32_t array named <name>\n"
1389 " initialized with the shader binary code.\n"
John Kessenichc6c80a62018-03-05 22:23:17 -07001390 " --version synonym for -v\n"
John Kessenich6263fb12017-06-14 15:52:44 -06001391 " --vn <name> synonym for --variable-name <name>\n"
John Kessenichb0a7eb52013-11-07 17:44:20 +00001392 );
John Kessenich68d78fd2015-07-12 19:28:10 -06001393
1394 exit(EFailUsage);
John Kessenicha0af4732012-12-12 21:15:54 +00001395}
1396
John Kessenich3ce4e592014-10-06 19:57:34 +00001397#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
John Kessenichcfd643e2013-03-08 23:14:42 +00001398
1399#include <errno.h>
1400
1401int fopen_s(
1402 FILE** pFile,
John Kessenich51cdd902014-02-18 23:37:57 +00001403 const char* filename,
1404 const char* mode
John Kessenichcfd643e2013-03-08 23:14:42 +00001405)
1406{
1407 if (!pFile || !filename || !mode) {
1408 return EINVAL;
1409 }
1410
1411 FILE* f = fopen(filename, mode);
1412 if (! f) {
1413 if (errno != 0) {
1414 return errno;
1415 } else {
1416 return ENOENT;
1417 }
1418 }
1419 *pFile = f;
1420
1421 return 0;
1422}
1423
1424#endif
1425
John Kessenicha0af4732012-12-12 21:15:54 +00001426//
1427// Malloc a string of sufficient size and read a string into it.
1428//
John Kessenich04acb1b2017-06-14 17:36:50 -06001429char* ReadFileData(const char* fileName)
John Kessenicha0af4732012-12-12 21:15:54 +00001430{
John Kessenichb3297152015-07-11 18:01:03 -06001431 FILE *in = nullptr;
John Kessenich3ce4e592014-10-06 19:57:34 +00001432 int errorCode = fopen_s(&in, fileName, "r");
John Kessenich68d78fd2015-07-12 19:28:10 -06001433 if (errorCode || in == nullptr)
1434 Error("unable to open input file");
John Kessenichecba76f2017-01-06 00:34:48 -07001435
John Kessenich04acb1b2017-06-14 17:36:50 -06001436 int count = 0;
John Kessenicha0af4732012-12-12 21:15:54 +00001437 while (fgetc(in) != EOF)
1438 count++;
1439
John Kessenichd6c72a42014-08-18 19:42:35 +00001440 fseek(in, 0, SEEK_SET);
John Kessenichca3457f2015-05-18 01:59:45 +00001441
John Kessenich04acb1b2017-06-14 17:36:50 -06001442 char* return_data = (char*)malloc(count + 1); // freed in FreeFileData()
1443 if ((int)fread(return_data, 1, count, in) != count) {
1444 free(return_data);
John Kessenich68d78fd2015-07-12 19:28:10 -06001445 Error("can't read input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001446 }
John Kessenich68d78fd2015-07-12 19:28:10 -06001447
John Kessenich04acb1b2017-06-14 17:36:50 -06001448 return_data[count] = '\0';
John Kessenicha0af4732012-12-12 21:15:54 +00001449 fclose(in);
John Kessenichb3297152015-07-11 18:01:03 -06001450
John Kessenicha0af4732012-12-12 21:15:54 +00001451 return return_data;
1452}
1453
John Kessenich04acb1b2017-06-14 17:36:50 -06001454void FreeFileData(char* data)
John Kessenicha0af4732012-12-12 21:15:54 +00001455{
John Kessenichb3297152015-07-11 18:01:03 -06001456 free(data);
John Kessenicha0af4732012-12-12 21:15:54 +00001457}
1458
John Kessenich54d8cda2013-02-11 22:36:01 +00001459void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +00001460{
John Kessenichfae38ee2015-06-10 23:23:12 +00001461 if (num >= 0 )
1462 printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
1463 else
1464 printf("#### %s %s INFO LOG ####\n", msg, name);
John Kessenicha0af4732012-12-12 21:15:54 +00001465}