blob: 8a497a2bb366e4de30df8182705396eb19e08c09 [file] [log] [blame]
John Kessenicha0af4732012-12-12 21:15:54 +00001//
2//Copyright (C) 2002-2005 3Dlabs Inc. Ltd.
John Kessenichbd0747d2013-02-17 06:01:50 +00003//Copyright (C) 2013 LunarG, Inc.
4//
John Kessenicha0af4732012-12-12 21:15:54 +00005//All rights reserved.
6//
7//Redistribution and use in source and binary forms, with or without
8//modification, are permitted provided that the following conditions
9//are met:
10//
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//
23//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.
35//
John Kessenich05a70632013-09-17 19:26:08 +000036
37// this only applies to the standalone wrapper, not the front end in general
38#define _CRT_SECURE_NO_WARNINGS
39
Lei Zhang8a9b1ee2016-05-19 13:31:43 -040040#include "ResourceLimits.h"
John Kessenich2b07c7e2013-07-31 18:44:13 +000041#include "Worklist.h"
John Kessenicha0af4732012-12-12 21:15:54 +000042#include "./../glslang/Include/ShHandle.h"
John Kessenich0da9eaa2015-08-01 17:10:02 -060043#include "./../glslang/Include/revision.h"
John Kessenicha0af4732012-12-12 21:15:54 +000044#include "./../glslang/Public/ShaderLang.h"
John Kessenich0df0cde2015-03-03 17:09:43 +000045#include "../SPIRV/GlslangToSpv.h"
John Kessenich5e4b1242015-08-06 22:53:06 -060046#include "../SPIRV/GLSL.std.450.h"
John Kessenichacba7722015-03-04 03:48:38 +000047#include "../SPIRV/doc.h"
48#include "../SPIRV/disassemble.h"
John Kessenicha0af4732012-12-12 21:15:54 +000049#include <string.h>
John Kessenichcfd643e2013-03-08 23:14:42 +000050#include <stdlib.h>
John Kessenicha0af4732012-12-12 21:15:54 +000051#include <math.h>
52
baldurk876a0e32015-11-16 18:03:28 +010053#include "../glslang/OSDependent/osinclude.h"
John Kessenicha0af4732012-12-12 21:15:54 +000054
55extern "C" {
56 SH_IMPORT_EXPORT void ShOutputHtml();
57}
58
John Kessenich94a81fb2013-08-31 02:41:30 +000059// Command-line options
60enum TOptions {
John Kessenichacba7722015-03-04 03:48:38 +000061 EOptionNone = 0x0000,
62 EOptionIntermediate = 0x0001,
63 EOptionSuppressInfolog = 0x0002,
64 EOptionMemoryLeakMode = 0x0004,
65 EOptionRelaxedErrors = 0x0008,
66 EOptionGiveWarnings = 0x0010,
67 EOptionLinkProgram = 0x0020,
68 EOptionMultiThreaded = 0x0040,
69 EOptionDumpConfig = 0x0080,
70 EOptionDumpReflection = 0x0100,
71 EOptionSuppressWarnings = 0x0200,
72 EOptionDumpVersions = 0x0400,
73 EOptionSpv = 0x0800,
74 EOptionHumanReadableSpv = 0x1000,
John Kessenich68d78fd2015-07-12 19:28:10 -060075 EOptionVulkanRules = 0x2000,
76 EOptionDefaultDesktop = 0x4000,
77 EOptionOutputPreprocessed = 0x8000,
John Kessenich66e2faf2016-03-12 18:34:36 -070078 EOptionReadHlsl = 0x10000,
John Kessenich94a81fb2013-08-31 02:41:30 +000079};
80
John Kessenicha0af4732012-12-12 21:15:54 +000081//
John Kessenich68d78fd2015-07-12 19:28:10 -060082// Return codes from main/exit().
John Kessenicha0af4732012-12-12 21:15:54 +000083//
84enum TFailCode {
85 ESuccess = 0,
86 EFailUsage,
87 EFailCompile,
88 EFailLink,
89 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000090 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000091 EFailLinkerCreate
92};
93
94//
John Kessenich68d78fd2015-07-12 19:28:10 -060095// Forward declarations.
John Kessenicha0af4732012-12-12 21:15:54 +000096//
John Kessenichb603f912013-08-29 00:39:25 +000097EShLanguage FindLanguage(const std::string& name);
John Kessenich51cdd902014-02-18 23:37:57 +000098void CompileFile(const char* fileName, ShHandle);
John Kessenicha0af4732012-12-12 21:15:54 +000099void usage();
John Kessenichea869fb2013-10-28 18:12:06 +0000100void FreeFileData(char** data);
101char** ReadFileData(const char* fileName);
John Kessenich54d8cda2013-02-11 22:36:01 +0000102void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +0000103
John Kessenichc999ba22013-11-07 23:33:24 +0000104// Globally track if any compile or link failure.
105bool CompileFailed = false;
106bool LinkFailed = false;
107
John Kessenich05a70632013-09-17 19:26:08 +0000108// Use to test breaking up a single shader file into multiple strings.
John Kessenich68d78fd2015-07-12 19:28:10 -0600109// Set in ReadFileData().
John Kessenichea869fb2013-10-28 18:12:06 +0000110int NumShaderStrings;
John Kessenicha0af4732012-12-12 21:15:54 +0000111
John Kessenich05a70632013-09-17 19:26:08 +0000112TBuiltInResource Resources;
113std::string ConfigFile;
114
John Kessenicha0af4732012-12-12 21:15:54 +0000115//
John Kessenichf0bcb0a2016-04-02 13:09:14 -0600116// Parse either a .conf file provided by the user or the default from glslang::DefaultTBuiltInResource
John Kessenich05a70632013-09-17 19:26:08 +0000117//
118void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000119{
John Kessenich05a70632013-09-17 19:26:08 +0000120 char** configStrings = 0;
John Kessenich51cdd902014-02-18 23:37:57 +0000121 char* config = 0;
John Kessenich05a70632013-09-17 19:26:08 +0000122 if (ConfigFile.size() > 0) {
John Kessenichea869fb2013-10-28 18:12:06 +0000123 configStrings = ReadFileData(ConfigFile.c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000124 if (configStrings)
125 config = *configStrings;
126 else {
127 printf("Error opening configuration file; will instead use the default configuration\n");
128 usage();
129 }
130 }
131
132 if (config == 0) {
Lei Zhang414eb602016-03-04 16:22:34 -0500133 Resources = glslang::DefaultTBuiltInResource;
134 return;
John Kessenich05a70632013-09-17 19:26:08 +0000135 }
136
137 const char* delims = " \t\n\r";
138 const char* token = strtok(config, delims);
139 while (token) {
140 const char* valueStr = strtok(0, delims);
141 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
142 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
143 return;
144 }
145 int value = atoi(valueStr);
146
147 if (strcmp(token, "MaxLights") == 0)
148 Resources.maxLights = value;
149 else if (strcmp(token, "MaxClipPlanes") == 0)
150 Resources.maxClipPlanes = value;
151 else if (strcmp(token, "MaxTextureUnits") == 0)
152 Resources.maxTextureUnits = value;
153 else if (strcmp(token, "MaxTextureCoords") == 0)
154 Resources.maxTextureCoords = value;
155 else if (strcmp(token, "MaxVertexAttribs") == 0)
156 Resources.maxVertexAttribs = value;
157 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
158 Resources.maxVertexUniformComponents = value;
159 else if (strcmp(token, "MaxVaryingFloats") == 0)
160 Resources.maxVaryingFloats = value;
161 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
162 Resources.maxVertexTextureImageUnits = value;
163 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
164 Resources.maxCombinedTextureImageUnits = value;
165 else if (strcmp(token, "MaxTextureImageUnits") == 0)
166 Resources.maxTextureImageUnits = value;
167 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
168 Resources.maxFragmentUniformComponents = value;
169 else if (strcmp(token, "MaxDrawBuffers") == 0)
170 Resources.maxDrawBuffers = value;
171 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
172 Resources.maxVertexUniformVectors = value;
173 else if (strcmp(token, "MaxVaryingVectors") == 0)
174 Resources.maxVaryingVectors = value;
175 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
176 Resources.maxFragmentUniformVectors = value;
177 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
178 Resources.maxVertexOutputVectors = value;
179 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
180 Resources.maxFragmentInputVectors = value;
181 else if (strcmp(token, "MinProgramTexelOffset") == 0)
182 Resources.minProgramTexelOffset = value;
183 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
184 Resources.maxProgramTexelOffset = value;
John Kesseniche7c59c12013-10-16 22:28:35 +0000185 else if (strcmp(token, "MaxClipDistances") == 0)
186 Resources.maxClipDistances = value;
John Kessenich284231c2013-10-22 01:50:39 +0000187 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
188 Resources.maxComputeWorkGroupCountX = value;
189 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
190 Resources.maxComputeWorkGroupCountY = value;
191 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
192 Resources.maxComputeWorkGroupCountZ = value;
193 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
194 Resources.maxComputeWorkGroupSizeX = value;
195 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
196 Resources.maxComputeWorkGroupSizeY = value;
197 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
198 Resources.maxComputeWorkGroupSizeZ = value;
199 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
200 Resources.maxComputeUniformComponents = value;
201 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
202 Resources.maxComputeTextureImageUnits = value;
203 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
204 Resources.maxComputeImageUniforms = value;
205 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
206 Resources.maxComputeAtomicCounters = value;
207 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
208 Resources.maxComputeAtomicCounterBuffers = value;
209 else if (strcmp(token, "MaxVaryingComponents") == 0)
210 Resources.maxVaryingComponents = value;
211 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
212 Resources.maxVertexOutputComponents = value;
213 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
214 Resources.maxGeometryInputComponents = value;
215 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
216 Resources.maxGeometryOutputComponents = value;
217 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
218 Resources.maxFragmentInputComponents = value;
219 else if (strcmp(token, "MaxImageUnits") == 0)
220 Resources.maxImageUnits = value;
221 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
222 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
John Kessenichddea6782014-08-10 18:19:36 +0000223 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
224 Resources.maxCombinedShaderOutputResources = value;
John Kessenich284231c2013-10-22 01:50:39 +0000225 else if (strcmp(token, "MaxImageSamples") == 0)
226 Resources.maxImageSamples = value;
227 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
228 Resources.maxVertexImageUniforms = value;
229 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
230 Resources.maxTessControlImageUniforms = value;
231 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
232 Resources.maxTessEvaluationImageUniforms = value;
233 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
234 Resources.maxGeometryImageUniforms = value;
235 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
236 Resources.maxFragmentImageUniforms = value;
237 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
238 Resources.maxCombinedImageUniforms = value;
239 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
240 Resources.maxGeometryTextureImageUnits = value;
241 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
242 Resources.maxGeometryOutputVertices = value;
243 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
244 Resources.maxGeometryTotalOutputComponents = value;
245 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
246 Resources.maxGeometryUniformComponents = value;
247 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
248 Resources.maxGeometryVaryingComponents = value;
249 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
250 Resources.maxTessControlInputComponents = value;
251 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
252 Resources.maxTessControlOutputComponents = value;
253 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
254 Resources.maxTessControlTextureImageUnits = value;
255 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
256 Resources.maxTessControlUniformComponents = value;
257 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
258 Resources.maxTessControlTotalOutputComponents = value;
259 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
260 Resources.maxTessEvaluationInputComponents = value;
261 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
262 Resources.maxTessEvaluationOutputComponents = value;
263 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
264 Resources.maxTessEvaluationTextureImageUnits = value;
265 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
266 Resources.maxTessEvaluationUniformComponents = value;
267 else if (strcmp(token, "MaxTessPatchComponents") == 0)
268 Resources.maxTessPatchComponents = value;
269 else if (strcmp(token, "MaxPatchVertices") == 0)
270 Resources.maxPatchVertices = value;
271 else if (strcmp(token, "MaxTessGenLevel") == 0)
272 Resources.maxTessGenLevel = value;
273 else if (strcmp(token, "MaxViewports") == 0)
274 Resources.maxViewports = value;
275 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
276 Resources.maxVertexAtomicCounters = value;
277 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
278 Resources.maxTessControlAtomicCounters = value;
279 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
280 Resources.maxTessEvaluationAtomicCounters = value;
281 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
282 Resources.maxGeometryAtomicCounters = value;
283 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
284 Resources.maxFragmentAtomicCounters = value;
285 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
286 Resources.maxCombinedAtomicCounters = value;
287 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
288 Resources.maxAtomicCounterBindings = value;
289 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
290 Resources.maxVertexAtomicCounterBuffers = value;
291 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
292 Resources.maxTessControlAtomicCounterBuffers = value;
293 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
294 Resources.maxTessEvaluationAtomicCounterBuffers = value;
295 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
296 Resources.maxGeometryAtomicCounterBuffers = value;
297 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
298 Resources.maxFragmentAtomicCounterBuffers = value;
299 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
300 Resources.maxCombinedAtomicCounterBuffers = value;
301 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
302 Resources.maxAtomicCounterBufferSize = value;
John Kessenichc7776ec2014-01-26 01:37:13 +0000303 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
304 Resources.maxTransformFeedbackBuffers = value;
305 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
306 Resources.maxTransformFeedbackInterleavedComponents = value;
John Kessenich69968412014-08-13 06:37:59 +0000307 else if (strcmp(token, "MaxCullDistances") == 0)
308 Resources.maxCullDistances = value;
309 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
310 Resources.maxCombinedClipAndCullDistances = value;
John Kessenichcd77f8e2014-08-13 16:54:02 +0000311 else if (strcmp(token, "MaxSamples") == 0)
312 Resources.maxSamples = value;
John Kessenich284231c2013-10-22 01:50:39 +0000313
John Kessenicha5830df2013-10-02 05:10:48 +0000314 else if (strcmp(token, "nonInductiveForLoops") == 0)
315 Resources.limits.nonInductiveForLoops = (value != 0);
316 else if (strcmp(token, "whileLoops") == 0)
317 Resources.limits.whileLoops = (value != 0);
318 else if (strcmp(token, "doWhileLoops") == 0)
319 Resources.limits.doWhileLoops = (value != 0);
320 else if (strcmp(token, "generalUniformIndexing") == 0)
321 Resources.limits.generalUniformIndexing = (value != 0);
322 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
323 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
324 else if (strcmp(token, "generalVaryingIndexing") == 0)
325 Resources.limits.generalVaryingIndexing = (value != 0);
326 else if (strcmp(token, "generalSamplerIndexing") == 0)
327 Resources.limits.generalSamplerIndexing = (value != 0);
328 else if (strcmp(token, "generalVariableIndexing") == 0)
329 Resources.limits.generalVariableIndexing = (value != 0);
330 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
331 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000332 else
333 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
334
335 token = strtok(0, delims);
336 }
337 if (configStrings)
338 FreeFileData(configStrings);
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500339 else
340 delete[] config;
John Kessenicha0af4732012-12-12 21:15:54 +0000341}
342
John Kessenich38f3b892013-09-06 19:52:57 +0000343// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000344glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000345
346// array of unique places to leave the shader names and infologs for the asynchronous compiles
John Kessenichfd305422014-06-05 16:30:53 +0000347glslang::TWorkItem** Work = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000348int NumWorkItems = 0;
349
John Kessenich94a81fb2013-08-31 02:41:30 +0000350int Options = 0;
John Kessenich68d78fd2015-07-12 19:28:10 -0600351const char* ExecutableName = nullptr;
352const char* binaryFileName = nullptr;
John Kessenich4d65ee32016-03-12 18:17:47 -0700353const char* entryPointName = nullptr;
John Kessenich68d78fd2015-07-12 19:28:10 -0600354
355//
356// Create the default name for saving a binary if -o is not provided.
357//
358const char* GetBinaryName(EShLanguage stage)
359{
360 const char* name;
361 if (binaryFileName == nullptr) {
362 switch (stage) {
363 case EShLangVertex: name = "vert.spv"; break;
364 case EShLangTessControl: name = "tesc.spv"; break;
365 case EShLangTessEvaluation: name = "tese.spv"; break;
366 case EShLangGeometry: name = "geom.spv"; break;
367 case EShLangFragment: name = "frag.spv"; break;
368 case EShLangCompute: name = "comp.spv"; break;
369 default: name = "unknown"; break;
370 }
371 } else
372 name = binaryFileName;
373
374 return name;
375}
John Kessenich2b07c7e2013-07-31 18:44:13 +0000376
John Kessenich05a70632013-09-17 19:26:08 +0000377//
378// *.conf => this is a config file that can set limits/resources
379//
380bool SetConfigFile(const std::string& name)
381{
382 if (name.size() < 5)
383 return false;
384
John Kessenich4c706852013-10-11 16:28:43 +0000385 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000386 ConfigFile = name;
387 return true;
388 }
389
390 return false;
391}
392
John Kessenich68d78fd2015-07-12 19:28:10 -0600393//
394// Give error and exit with failure code.
395//
396void Error(const char* message)
397{
398 printf("%s: Error %s (use -h for usage)\n", ExecutableName, message);
399 exit(EFailUsage);
400}
401
402//
403// Do all command-line argument parsing. This includes building up the work-items
404// to be processed later, and saving all the command-line options.
405//
406// Does not return (it exits) if command-line is fatally flawed.
407//
408void ProcessArguments(int argc, char* argv[])
John Kessenich2b07c7e2013-07-31 18:44:13 +0000409{
John Kessenich38f3b892013-09-06 19:52:57 +0000410 ExecutableName = argv[0];
411 NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
John Kessenichfd305422014-06-05 16:30:53 +0000412 Work = new glslang::TWorkItem*[NumWorkItems];
John Kessenich68d78fd2015-07-12 19:28:10 -0600413 for (int w = 0; w < NumWorkItems; ++w)
414 Work[w] = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000415
John Kessenich2b07c7e2013-07-31 18:44:13 +0000416 argc--;
417 argv++;
418 for (; argc >= 1; argc--, argv++) {
419 if (argv[0][0] == '-') {
John Kessenich2aa7f3a2015-05-15 16:02:07 +0000420 switch (argv[0][1]) {
421 case 'H':
422 Options |= EOptionHumanReadableSpv;
423 // fall through to -V
John Kessenich0df0cde2015-03-03 17:09:43 +0000424 case 'V':
425 Options |= EOptionSpv;
John Kessenich68d78fd2015-07-12 19:28:10 -0600426 Options |= EOptionVulkanRules;
427 Options |= EOptionLinkProgram;
428 break;
429 case 'G':
430 Options |= EOptionSpv;
John Kessenichd78e3512014-08-25 20:07:55 +0000431 Options |= EOptionLinkProgram;
John Kessenich92f90382014-07-28 04:21:04 +0000432 break;
John Kessenichc555ddd2015-06-17 02:38:44 +0000433 case 'E':
434 Options |= EOptionOutputPreprocessed;
435 break;
John Kessenich05a70632013-09-17 19:26:08 +0000436 case 'c':
437 Options |= EOptionDumpConfig;
438 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000439 case 'd':
John Kessenich26ad2682014-08-13 20:17:19 +0000440 Options |= EOptionDefaultDesktop;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000441 break;
John Kessenich66e2faf2016-03-12 18:34:36 -0700442 case 'D':
443 Options |= EOptionReadHlsl;
444 break;
John Kessenich4d65ee32016-03-12 18:17:47 -0700445 case 'e':
446 // HLSL todo: entry point handle needs much more sophistication.
447 // This is okay for one compilation unit with one entry point.
448 entryPointName = argv[1];
449 if (argc > 0) {
450 argc--;
451 argv++;
452 } else
453 Error("no <entry-point> provided for -e");
454 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600455 case 'h':
456 usage();
457 break;
John Kessenich05a70632013-09-17 19:26:08 +0000458 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000459 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000460 break;
461 case 'l':
John Kessenichd78e3512014-08-25 20:07:55 +0000462 Options |= EOptionLinkProgram;
John Kessenich94a81fb2013-08-31 02:41:30 +0000463 break;
464 case 'm':
465 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000466 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600467 case 'o':
468 binaryFileName = argv[1];
469 if (argc > 0) {
470 argc--;
471 argv++;
472 } else
473 Error("no <file> provided for -o");
474 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000475 case 'q':
476 Options |= EOptionDumpReflection;
477 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000478 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000479 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000480 break;
481 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000482 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000483 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000484 case 't':
485 #ifdef _WIN32
John Kessenichb0a7eb52013-11-07 17:44:20 +0000486 Options |= EOptionMultiThreaded;
John Kessenich38f3b892013-09-06 19:52:57 +0000487 #endif
488 break;
John Kessenich319de232013-12-04 04:43:40 +0000489 case 'v':
490 Options |= EOptionDumpVersions;
491 break;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000492 case 'w':
493 Options |= EOptionSuppressWarnings;
494 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000495 default:
John Kessenich68d78fd2015-07-12 19:28:10 -0600496 usage();
497 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000498 }
John Kessenich38f3b892013-09-06 19:52:57 +0000499 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000500 std::string name(argv[0]);
501 if (! SetConfigFile(name)) {
502 Work[argc] = new glslang::TWorkItem(name);
503 Worklist.add(Work[argc]);
504 }
John Kessenich38f3b892013-09-06 19:52:57 +0000505 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000506 }
507
John Kessenich68d78fd2015-07-12 19:28:10 -0600508 // Make sure that -E is not specified alongside linking (which includes SPV generation)
509 if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
510 Error("can't use -E when linking is selected");
John Kessenichc555ddd2015-06-17 02:38:44 +0000511
John Kessenich68d78fd2015-07-12 19:28:10 -0600512 // -o makes no sense if there is no target binary
513 if (binaryFileName && (Options & EOptionSpv) == 0)
514 Error("no binary generation requested (e.g., -V)");
John Kessenich2b07c7e2013-07-31 18:44:13 +0000515}
516
John Kessenich68d78fd2015-07-12 19:28:10 -0600517//
518// Translate the meaningful subset of command-line options to parser-behavior options.
519//
John Kessenichb0a7eb52013-11-07 17:44:20 +0000520void SetMessageOptions(EShMessages& messages)
521{
522 if (Options & EOptionRelaxedErrors)
523 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
524 if (Options & EOptionIntermediate)
525 messages = (EShMessages)(messages | EShMsgAST);
526 if (Options & EOptionSuppressWarnings)
527 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
John Kessenich68d78fd2015-07-12 19:28:10 -0600528 if (Options & EOptionSpv)
529 messages = (EShMessages)(messages | EShMsgSpvRules);
530 if (Options & EOptionVulkanRules)
531 messages = (EShMessages)(messages | EShMsgVulkanRules);
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400532 if (Options & EOptionOutputPreprocessed)
533 messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
John Kessenich66e2faf2016-03-12 18:34:36 -0700534 if (Options & EOptionReadHlsl)
535 messages = (EShMessages)(messages | EShMsgReadHlsl);
John Kessenichb0a7eb52013-11-07 17:44:20 +0000536}
537
John Kessenich68d78fd2015-07-12 19:28:10 -0600538//
John Kessenich69f4b512013-09-04 21:19:27 +0000539// Thread entry point, for non-linking asynchronous mode.
John Kessenichc999ba22013-11-07 23:33:24 +0000540//
541// Return 0 for failure, 1 for success.
542//
Pyry Haulos5f6892e2015-12-01 12:59:53 -0800543unsigned int CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000544{
John Kessenich38f3b892013-09-06 19:52:57 +0000545 glslang::TWorkItem* workItem;
546 while (Worklist.remove(workItem)) {
547 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000548 if (compiler == 0)
John Kessenichc999ba22013-11-07 23:33:24 +0000549 return 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000550
John Kessenichb0a7eb52013-11-07 17:44:20 +0000551 CompileFile(workItem->name.c_str(), compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000552
John Kessenich94a81fb2013-08-31 02:41:30 +0000553 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000554 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000555
556 ShDestruct(compiler);
557 }
558
559 return 0;
560}
561
John Kessenich6626cad2015-06-19 05:14:19 +0000562// Outputs the given string, but only if it is non-null and non-empty.
563// This prevents erroneous newlines from appearing.
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400564void PutsIfNonEmpty(const char* str)
John Kessenich6626cad2015-06-19 05:14:19 +0000565{
566 if (str && str[0]) {
567 puts(str);
568 }
569}
570
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400571// Outputs the given string to stderr, but only if it is non-null and non-empty.
572// This prevents erroneous newlines from appearing.
573void StderrIfNonEmpty(const char* str)
574{
575 if (str && str[0]) {
576 fprintf(stderr, "%s\n", str);
577 }
578}
579
John Kessenichc57b2a92016-01-16 15:30:03 -0700580// Simple bundling of what makes a compilation unit for ease in passing around,
581// and separation of handling file IO versus API (programmatic) compilation.
582struct ShaderCompUnit {
583 EShLanguage stage;
584 std::string fileName;
585 char** text; // memory owned/managed externally
586};
587
John Kessenich69f4b512013-09-04 21:19:27 +0000588//
John Kessenichc57b2a92016-01-16 15:30:03 -0700589// For linking mode: Will independently parse each compilation unit, but then put them
590// in the same program and link them together, making at most one linked module per
591// pipeline stage.
John Kessenich69f4b512013-09-04 21:19:27 +0000592//
593// Uses the new C++ interface instead of the old handle-based interface.
594//
John Kessenichc57b2a92016-01-16 15:30:03 -0700595
596void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
John Kessenich69f4b512013-09-04 21:19:27 +0000597{
598 // keep track of what to free
599 std::list<glslang::TShader*> shaders;
John Kessenichc57b2a92016-01-16 15:30:03 -0700600
John Kessenich69f4b512013-09-04 21:19:27 +0000601 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000602 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000603
John Kessenich69f4b512013-09-04 21:19:27 +0000604 //
605 // Per-shader processing...
606 //
607
John Kessenich5b0f13a2013-11-01 03:08:40 +0000608 glslang::TProgram& program = *new glslang::TProgram;
rdb32084e82016-02-23 22:17:38 +0100609 for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
610 const auto &compUnit = *it;
John Kessenichc57b2a92016-01-16 15:30:03 -0700611 glslang::TShader* shader = new glslang::TShader(compUnit.stage);
612 shader->setStrings(compUnit.text, 1);
John Kessenich4d65ee32016-03-12 18:17:47 -0700613 if (entryPointName) // HLSL todo: this needs to be tracked per compUnits
614 shader->setEntryPoint(entryPointName);
John Kessenich69f4b512013-09-04 21:19:27 +0000615 shaders.push_back(shader);
John Kessenichb3297152015-07-11 18:01:03 -0600616
John Kessenichc555ddd2015-06-17 02:38:44 +0000617 const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;
John Kessenich69f4b512013-09-04 21:19:27 +0000618
John Kessenichc555ddd2015-06-17 02:38:44 +0000619 if (Options & EOptionOutputPreprocessed) {
620 std::string str;
Andrew Woloszyna132af52016-03-07 13:23:09 -0500621 glslang::TShader::ForbidInclude includer;
Dejan Mircevski7be4b822015-06-17 11:40:33 -0400622 if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
Andrew Woloszyna132af52016-03-07 13:23:09 -0500623 messages, &str, includer)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400624 PutsIfNonEmpty(str.c_str());
625 } else {
626 CompileFailed = true;
627 }
628 StderrIfNonEmpty(shader->getInfoLog());
629 StderrIfNonEmpty(shader->getInfoDebugLog());
John Kessenichc555ddd2015-06-17 02:38:44 +0000630 continue;
631 }
632 if (! shader->parse(&Resources, defaultVersion, false, messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000633 CompileFailed = true;
John Kessenichc555ddd2015-06-17 02:38:44 +0000634
John Kessenich69f4b512013-09-04 21:19:27 +0000635 program.addShader(shader);
636
John Kessenichc57b2a92016-01-16 15:30:03 -0700637 if (! (Options & EOptionSuppressInfolog) &&
638 ! (Options & EOptionMemoryLeakMode)) {
639 PutsIfNonEmpty(compUnit.fileName.c_str());
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400640 PutsIfNonEmpty(shader->getInfoLog());
641 PutsIfNonEmpty(shader->getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000642 }
John Kessenich69f4b512013-09-04 21:19:27 +0000643 }
644
645 //
646 // Program-level processing...
647 //
648
John Kessenich4d65ee32016-03-12 18:17:47 -0700649 // Link
John Kessenich68d78fd2015-07-12 19:28:10 -0600650 if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000651 LinkFailed = true;
652
John Kessenich4d65ee32016-03-12 18:17:47 -0700653 // Report
John Kessenichc57b2a92016-01-16 15:30:03 -0700654 if (! (Options & EOptionSuppressInfolog) &&
655 ! (Options & EOptionMemoryLeakMode)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400656 PutsIfNonEmpty(program.getInfoLog());
657 PutsIfNonEmpty(program.getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000658 }
659
John Kessenich4d65ee32016-03-12 18:17:47 -0700660 // Reflect
John Kessenich11f9fc72013-11-07 01:06:34 +0000661 if (Options & EOptionDumpReflection) {
662 program.buildReflection();
663 program.dumpReflection();
664 }
665
John Kessenich4d65ee32016-03-12 18:17:47 -0700666 // Dump SPIR-V
John Kessenich0df0cde2015-03-03 17:09:43 +0000667 if (Options & EOptionSpv) {
John Kessenich92f90382014-07-28 04:21:04 +0000668 if (CompileFailed || LinkFailed)
John Kessenich68d78fd2015-07-12 19:28:10 -0600669 printf("SPIR-V is not generated for failed compile or link\n");
John Kessenich92f90382014-07-28 04:21:04 +0000670 else {
671 for (int stage = 0; stage < EShLangCount; ++stage) {
John Kessenicha7a68a92014-08-24 18:21:00 +0000672 if (program.getIntermediate((EShLanguage)stage)) {
John Kessenich0df0cde2015-03-03 17:09:43 +0000673 std::vector<unsigned int> spirv;
Lei Zhang09caf122016-05-02 18:11:54 -0400674 std::string warningsErrors;
Lei Zhang17535f72016-05-04 15:55:59 -0400675 spv::SpvBuildLogger logger;
676 glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv, &logger);
John Kessenichc57b2a92016-01-16 15:30:03 -0700677
678 // Dump the spv to a file or stdout, etc., but only if not doing
679 // memory/perf testing, as it's not internal to programmatic use.
680 if (! (Options & EOptionMemoryLeakMode)) {
Lei Zhang17535f72016-05-04 15:55:59 -0400681 printf("%s", logger.getAllMessages().c_str());
John Kessenichc57b2a92016-01-16 15:30:03 -0700682 glslang::OutputSpv(spirv, GetBinaryName((EShLanguage)stage));
683 if (Options & EOptionHumanReadableSpv) {
John Kessenichc57b2a92016-01-16 15:30:03 -0700684 spv::Disassemble(std::cout, spirv);
685 }
John Kessenichacba7722015-03-04 03:48:38 +0000686 }
John Kessenicha7a68a92014-08-24 18:21:00 +0000687 }
John Kessenich92f90382014-07-28 04:21:04 +0000688 }
689 }
690 }
691
John Kessenich5b0f13a2013-11-01 03:08:40 +0000692 // Free everything up, program has to go before the shaders
693 // because it might have merged stuff from the shaders, and
694 // the stuff from the shaders has to have its destructors called
695 // before the pools holding the memory in the shaders is freed.
696 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000697 while (shaders.size() > 0) {
698 delete shaders.back();
699 shaders.pop_back();
700 }
John Kessenich69f4b512013-09-04 21:19:27 +0000701}
702
John Kessenichc57b2a92016-01-16 15:30:03 -0700703//
704// Do file IO part of compile and link, handing off the pure
705// API/programmatic mode to CompileAndLinkShaderUnits(), which can
706// be put in a loop for testing memory footprint and performance.
707//
708// This is just for linking mode: meaning all the shaders will be put into the
709// the same program linked together.
710//
711// This means there are a limited number of work items (not multi-threading mode)
712// and that the point is testing at the linking level. Hence, to enable
713// performance and memory testing, the actual compile/link can be put in
714// a loop, independent of processing the work items and file IO.
715//
716void CompileAndLinkShaderFiles()
717{
718 std::vector<ShaderCompUnit> compUnits;
719
720 // Transfer all the work items from to a simple list of
721 // of compilation units. (We don't care about the thread
722 // work-item distribution properties in this path, which
723 // is okay due to the limited number of shaders, know since
724 // they are all getting linked together.)
725 glslang::TWorkItem* workItem;
726 while (Worklist.remove(workItem)) {
727 ShaderCompUnit compUnit = {
728 FindLanguage(workItem->name),
729 workItem->name,
730 ReadFileData(workItem->name.c_str())
731 };
732
733 if (! compUnit.text) {
734 usage();
735 return;
736 }
737
738 compUnits.push_back(compUnit);
739 }
740
741 // Actual call to programmatic processing of compile and link,
742 // in a loop for testing memory and performance. This part contains
743 // all the perf/memory that a programmatic consumer will care about.
744 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
745 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
746 CompileAndLinkShaderUnits(compUnits);
747
748 if (Options & EOptionMemoryLeakMode)
749 glslang::OS_DumpMemoryCounters();
750 }
751
rdb32084e82016-02-23 22:17:38 +0100752 for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
753 FreeFileData(it->text);
John Kessenichc57b2a92016-01-16 15:30:03 -0700754}
755
John Kessenicha0af4732012-12-12 21:15:54 +0000756int C_DECL main(int argc, char* argv[])
757{
John Kessenich68d78fd2015-07-12 19:28:10 -0600758 ProcessArguments(argc, argv);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000759
John Kessenich05a70632013-09-17 19:26:08 +0000760 if (Options & EOptionDumpConfig) {
Lei Zhang414eb602016-03-04 16:22:34 -0500761 printf("%s", glslang::GetDefaultTBuiltInResourceString().c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000762 if (Worklist.empty())
763 return ESuccess;
764 }
765
John Kessenich0da9eaa2015-08-01 17:10:02 -0600766 if (Options & EOptionDumpVersions) {
767 printf("Glslang Version: %s %s\n", GLSLANG_REVISION, GLSLANG_DATE);
John Kessenich319de232013-12-04 04:43:40 +0000768 printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
769 printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
John Kessenich68d78fd2015-07-12 19:28:10 -0600770 std::string spirvVersion;
771 glslang::GetSpirvVersion(spirvVersion);
John Kessenich0da9eaa2015-08-01 17:10:02 -0600772 printf("SPIR-V Version %s\n", spirvVersion.c_str());
John Kessenich5e4b1242015-08-06 22:53:06 -0600773 printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
John Kessenich55e7d112015-11-15 21:33:39 -0700774 printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId());
John Kessenich319de232013-12-04 04:43:40 +0000775 if (Worklist.empty())
776 return ESuccess;
777 }
778
John Kessenich05a70632013-09-17 19:26:08 +0000779 if (Worklist.empty()) {
780 usage();
John Kessenich05a70632013-09-17 19:26:08 +0000781 }
782
783 ProcessConfigFile();
784
John Kessenich69f4b512013-09-04 21:19:27 +0000785 //
786 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000787 // 1) linking all arguments together, single-threaded, new C++ interface
788 // 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 +0000789 //
John Kessenichc555ddd2015-06-17 02:38:44 +0000790 if (Options & EOptionLinkProgram ||
791 Options & EOptionOutputPreprocessed) {
John Kessenichc36e1d82013-11-01 17:41:52 +0000792 glslang::InitializeProcess();
John Kessenichc57b2a92016-01-16 15:30:03 -0700793 CompileAndLinkShaderFiles();
John Kessenichc36e1d82013-11-01 17:41:52 +0000794 glslang::FinalizeProcess();
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500795 for (int w = 0; w < NumWorkItems; ++w) {
796 if (Work[w]) {
797 delete Work[w];
798 }
799 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000800 } else {
801 ShInitialize();
802
John Kessenich38f3b892013-09-06 19:52:57 +0000803 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000804
John Kessenich38f3b892013-09-06 19:52:57 +0000805 if (Options & EOptionMultiThreaded) {
806 const int NumThreads = 16;
807 void* threads[NumThreads];
808 for (int t = 0; t < NumThreads; ++t) {
809 threads[t] = glslang::OS_CreateThread(&CompileShaders);
810 if (! threads[t]) {
811 printf("Failed to create thread\n");
812 return EFailThreadCreate;
813 }
John Kessenicha0af4732012-12-12 21:15:54 +0000814 }
John Kessenich38f3b892013-09-06 19:52:57 +0000815 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenichc999ba22013-11-07 23:33:24 +0000816 } else
817 CompileShaders(0);
John Kessenich38f3b892013-09-06 19:52:57 +0000818
819 // Print out all the resulting infologs
820 for (int w = 0; w < NumWorkItems; ++w) {
821 if (Work[w]) {
Kenneth Perryb07e6be2015-12-15 10:52:34 -0600822 if (printShaderNames || Work[w]->results.size() > 0)
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400823 PutsIfNonEmpty(Work[w]->name.c_str());
824 PutsIfNonEmpty(Work[w]->results.c_str());
John Kessenich38f3b892013-09-06 19:52:57 +0000825 delete Work[w];
826 }
827 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000828
829 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000830 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000831
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500832 delete[] Work;
833
John Kessenichc999ba22013-11-07 23:33:24 +0000834 if (CompileFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000835 return EFailCompile;
John Kessenichc999ba22013-11-07 23:33:24 +0000836 if (LinkFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000837 return EFailLink;
838
839 return 0;
840}
841
842//
843// Deduce the language from the filename. Files must end in one of the
844// following extensions:
845//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000846// .vert = vertex
847// .tesc = tessellation control
848// .tese = tessellation evaluation
849// .geom = geometry
850// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000851// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000852//
John Kessenichb603f912013-08-29 00:39:25 +0000853EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000854{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000855 size_t ext = name.rfind('.');
856 if (ext == std::string::npos) {
857 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000858 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000859 }
860
John Kessenich2b07c7e2013-07-31 18:44:13 +0000861 std::string suffix = name.substr(ext + 1, std::string::npos);
862 if (suffix == "vert")
863 return EShLangVertex;
864 else if (suffix == "tesc")
865 return EShLangTessControl;
866 else if (suffix == "tese")
867 return EShLangTessEvaluation;
868 else if (suffix == "geom")
869 return EShLangGeometry;
870 else if (suffix == "frag")
871 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000872 else if (suffix == "comp")
873 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000874
875 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000876 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000877}
878
John Kessenicha0af4732012-12-12 21:15:54 +0000879//
John Kessenich69f4b512013-09-04 21:19:27 +0000880// Read a file's data into a string, and compile it using the old interface ShCompile,
881// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000882//
John Kessenich51cdd902014-02-18 23:37:57 +0000883void CompileFile(const char* fileName, ShHandle compiler)
John Kessenicha0af4732012-12-12 21:15:54 +0000884{
John Kessenichca3457f2015-05-18 01:59:45 +0000885 int ret = 0;
John Kessenich41cf6b52013-06-25 18:10:05 +0000886 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000887 if (! shaderStrings) {
888 usage();
John Kessenichdb4cd542013-06-26 22:42:55 +0000889 }
890
John Kessenich41cf6b52013-06-25 18:10:05 +0000891 int* lengths = new int[NumShaderStrings];
892
893 // move to length-based strings, rather than null-terminated strings
894 for (int s = 0; s < NumShaderStrings; ++s)
John Kessenich35f04bd2014-02-19 02:47:20 +0000895 lengths[s] = (int)strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000896
John Kessenichc999ba22013-11-07 23:33:24 +0000897 if (! shaderStrings) {
898 CompileFailed = true;
899 return;
900 }
John Kessenicha0af4732012-12-12 21:15:54 +0000901
John Kessenich52ac67e2013-05-05 23:46:22 +0000902 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000903 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000904
John Kessenich94a81fb2013-08-31 02:41:30 +0000905 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
906 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich26ad2682014-08-13 20:17:19 +0000907 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichca3457f2015-05-18 01:59:45 +0000908 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +0000909 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
910 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
911 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +0000912 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichca3457f2015-05-18 01:59:45 +0000913 //ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000914 }
John Kessenicha0af4732012-12-12 21:15:54 +0000915
John Kessenich94a81fb2013-08-31 02:41:30 +0000916 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000917 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000918 }
John Kessenicha0af4732012-12-12 21:15:54 +0000919
John Kessenich41cf6b52013-06-25 18:10:05 +0000920 delete [] lengths;
921 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000922
John Kessenichc999ba22013-11-07 23:33:24 +0000923 if (ret == 0)
924 CompileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +0000925}
926
John Kessenicha0af4732012-12-12 21:15:54 +0000927//
928// print usage to stdout
929//
930void usage()
931{
John Kessenich319de232013-12-04 04:43:40 +0000932 printf("Usage: glslangValidator [option]... [file]...\n"
933 "\n"
John Kessenich0df0cde2015-03-03 17:09:43 +0000934 "Where: each 'file' ends in .<stage>, where <stage> is one of\n"
John Kessenich68d78fd2015-07-12 19:28:10 -0600935 " .conf to provide an optional config file that replaces the default configuration\n"
936 " (see -c option below for generating a template)\n"
937 " .vert for a vertex shader\n"
938 " .tesc for a tessellation control shader\n"
939 " .tese for a tessellation evaluation shader\n"
940 " .geom for a geometry shader\n"
941 " .frag for a fragment shader\n"
942 " .comp for a compute shader\n"
John Kessenich319de232013-12-04 04:43:40 +0000943 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000944 "Compilation warnings and errors will be printed to stdout.\n"
John Kessenich319de232013-12-04 04:43:40 +0000945 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000946 "To get other information, use one of the following options:\n"
John Kessenich68d78fd2015-07-12 19:28:10 -0600947 "Each option must be specified separately.\n"
948 " -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
949 " default file name is <stage>.spv (-o overrides this)\n"
950 " (unless -o is specified, which overrides the default file name)\n"
951 " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
952 " default file name is <stage>.spv (-o overrides this)\n"
953 " -H print human readable form of SPIR-V; turns on -V\n"
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400954 " -E print pre-processed GLSL; cannot be used with -l;\n"
955 " errors will appear on stderr.\n"
John Kessenich68d78fd2015-07-12 19:28:10 -0600956 " -c configuration dump;\n"
957 " creates the default configuration file (redirect to a .conf file)\n"
958 " -d default to desktop (#version 110) when there is no shader #version\n"
959 " (default is ES version 100)\n"
John Kessenich66e2faf2016-03-12 18:34:36 -0700960 " -D input is HLSL\n"
John Kessenich4d65ee32016-03-12 18:17:47 -0700961 " -e specify entry-point name\n"
John Kessenich68d78fd2015-07-12 19:28:10 -0600962 " -h print this usage message\n"
963 " -i intermediate tree (glslang AST) is printed out\n"
964 " -l link all input files together to form a single module\n"
965 " -m memory leak mode\n"
966 " -o <file> save binary into <file>, requires a binary option (e.g., -V)\n"
967 " -q dump reflection query database\n"
968 " -r relaxed semantic error-checking mode\n"
969 " -s silent mode\n"
970 " -t multi-threaded mode\n"
971 " -v print version strings\n"
972 " -w suppress warnings (except as required by #extension : warn)\n"
John Kessenichb0a7eb52013-11-07 17:44:20 +0000973 );
John Kessenich68d78fd2015-07-12 19:28:10 -0600974
975 exit(EFailUsage);
John Kessenicha0af4732012-12-12 21:15:54 +0000976}
977
John Kessenich3ce4e592014-10-06 19:57:34 +0000978#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
John Kessenichcfd643e2013-03-08 23:14:42 +0000979
980#include <errno.h>
981
982int fopen_s(
983 FILE** pFile,
John Kessenich51cdd902014-02-18 23:37:57 +0000984 const char* filename,
985 const char* mode
John Kessenichcfd643e2013-03-08 23:14:42 +0000986)
987{
988 if (!pFile || !filename || !mode) {
989 return EINVAL;
990 }
991
992 FILE* f = fopen(filename, mode);
993 if (! f) {
994 if (errno != 0) {
995 return errno;
996 } else {
997 return ENOENT;
998 }
999 }
1000 *pFile = f;
1001
1002 return 0;
1003}
1004
1005#endif
1006
John Kessenicha0af4732012-12-12 21:15:54 +00001007//
1008// Malloc a string of sufficient size and read a string into it.
1009//
John Kessenich51cdd902014-02-18 23:37:57 +00001010char** ReadFileData(const char* fileName)
John Kessenicha0af4732012-12-12 21:15:54 +00001011{
John Kessenichb3297152015-07-11 18:01:03 -06001012 FILE *in = nullptr;
John Kessenich3ce4e592014-10-06 19:57:34 +00001013 int errorCode = fopen_s(&in, fileName, "r");
John Kessenichd6c72a42014-08-18 19:42:35 +00001014
John Kessenicha0af4732012-12-12 21:15:54 +00001015 int count = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001016 const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
1017 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001018
John Kessenich68d78fd2015-07-12 19:28:10 -06001019 if (errorCode || in == nullptr)
1020 Error("unable to open input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001021
1022 while (fgetc(in) != EOF)
1023 count++;
1024
John Kessenichd6c72a42014-08-18 19:42:35 +00001025 fseek(in, 0, SEEK_SET);
John Kessenichca3457f2015-05-18 01:59:45 +00001026
John Kessenichb3297152015-07-11 18:01:03 -06001027 char *fdata = (char*)malloc(count+2); // freed before return of this function
John Kessenich68d78fd2015-07-12 19:28:10 -06001028 if (! fdata)
1029 Error("can't allocate memory");
1030
John Kessenichb3297152015-07-11 18:01:03 -06001031 if ((int)fread(fdata, 1, count, in) != count) {
John Kessenichb3297152015-07-11 18:01:03 -06001032 free(fdata);
John Kessenich68d78fd2015-07-12 19:28:10 -06001033 Error("can't read input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001034 }
John Kessenich68d78fd2015-07-12 19:28:10 -06001035
John Kessenicha0af4732012-12-12 21:15:54 +00001036 fdata[count] = '\0';
1037 fclose(in);
John Kessenichb3297152015-07-11 18:01:03 -06001038
John Kessenichea869fb2013-10-28 18:12:06 +00001039 if (count == 0) {
John Kessenichb3297152015-07-11 18:01:03 -06001040 // recover from empty file
1041 return_data[0] = (char*)malloc(count+2); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001042 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +00001043 NumShaderStrings = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001044 free(fdata);
John Kessenicha0af4732012-12-12 21:15:54 +00001045
John Kessenichb3297152015-07-11 18:01:03 -06001046 return return_data;
1047 } else
1048 NumShaderStrings = 1; // Set to larger than 1 for testing multiple strings
1049
1050 // compute how to split up the file into multiple strings, for testing multiple strings
John Kessenichd6c72a42014-08-18 19:42:35 +00001051 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenichb3297152015-07-11 18:01:03 -06001052 int ptr_len = 0;
1053 int i = 0;
1054 while (count > 0) {
1055 return_data[i] = (char*)malloc(len + 2); // freed in FreeFileData()
1056 memcpy(return_data[i], fdata + ptr_len, len);
1057 return_data[i][len] = '\0';
1058 count -= len;
1059 ptr_len += len;
1060 if (count < len) {
1061 if (count == 0) {
1062 NumShaderStrings = i + 1;
John Kessenicha0af4732012-12-12 21:15:54 +00001063 break;
1064 }
John Kessenichb3297152015-07-11 18:01:03 -06001065 len = count;
John Kessenichd6c72a42014-08-18 19:42:35 +00001066 }
1067 ++i;
1068 }
John Kessenichb3297152015-07-11 18:01:03 -06001069
1070 free(fdata);
1071
John Kessenicha0af4732012-12-12 21:15:54 +00001072 return return_data;
1073}
1074
John Kessenich51cdd902014-02-18 23:37:57 +00001075void FreeFileData(char** data)
John Kessenicha0af4732012-12-12 21:15:54 +00001076{
John Kessenichb3297152015-07-11 18:01:03 -06001077 for(int i = 0; i < NumShaderStrings; i++)
John Kessenicha0af4732012-12-12 21:15:54 +00001078 free(data[i]);
John Kessenichb3297152015-07-11 18:01:03 -06001079
1080 free(data);
John Kessenicha0af4732012-12-12 21:15:54 +00001081}
1082
John Kessenich54d8cda2013-02-11 22:36:01 +00001083void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +00001084{
John Kessenichfae38ee2015-06-10 23:23:12 +00001085 if (num >= 0 )
1086 printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
1087 else
1088 printf("#### %s %s INFO LOG ####\n", msg, name);
John Kessenicha0af4732012-12-12 21:15:54 +00001089}