blob: a1a2957d43b2342dda77756b59ba1c75b4c2a015 [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
John Kessenich2b07c7e2013-07-31 18:44:13 +000040#include "Worklist.h"
John Kessenicha0af4732012-12-12 21:15:54 +000041#include "./../glslang/Include/ShHandle.h"
John Kessenich0da9eaa2015-08-01 17:10:02 -060042#include "./../glslang/Include/revision.h"
John Kessenicha0af4732012-12-12 21:15:54 +000043#include "./../glslang/Public/ShaderLang.h"
John Kessenich0df0cde2015-03-03 17:09:43 +000044#include "../SPIRV/GlslangToSpv.h"
John Kessenich5e4b1242015-08-06 22:53:06 -060045#include "../SPIRV/GLSL.std.450.h"
John Kessenichacba7722015-03-04 03:48:38 +000046#include "../SPIRV/doc.h"
47#include "../SPIRV/disassemble.h"
John Kessenicha0af4732012-12-12 21:15:54 +000048#include <string.h>
John Kessenichcfd643e2013-03-08 23:14:42 +000049#include <stdlib.h>
John Kessenicha0af4732012-12-12 21:15:54 +000050#include <math.h>
51
baldurk876a0e32015-11-16 18:03:28 +010052#include "../glslang/OSDependent/osinclude.h"
John Kessenicha0af4732012-12-12 21:15:54 +000053
54extern "C" {
55 SH_IMPORT_EXPORT void ShOutputHtml();
56}
57
John Kessenich94a81fb2013-08-31 02:41:30 +000058// Command-line options
59enum TOptions {
John Kessenichacba7722015-03-04 03:48:38 +000060 EOptionNone = 0x0000,
61 EOptionIntermediate = 0x0001,
62 EOptionSuppressInfolog = 0x0002,
63 EOptionMemoryLeakMode = 0x0004,
64 EOptionRelaxedErrors = 0x0008,
65 EOptionGiveWarnings = 0x0010,
66 EOptionLinkProgram = 0x0020,
67 EOptionMultiThreaded = 0x0040,
68 EOptionDumpConfig = 0x0080,
69 EOptionDumpReflection = 0x0100,
70 EOptionSuppressWarnings = 0x0200,
71 EOptionDumpVersions = 0x0400,
72 EOptionSpv = 0x0800,
73 EOptionHumanReadableSpv = 0x1000,
John Kessenich68d78fd2015-07-12 19:28:10 -060074 EOptionVulkanRules = 0x2000,
75 EOptionDefaultDesktop = 0x4000,
76 EOptionOutputPreprocessed = 0x8000,
John Kessenich94a81fb2013-08-31 02:41:30 +000077};
78
John Kessenicha0af4732012-12-12 21:15:54 +000079//
John Kessenich68d78fd2015-07-12 19:28:10 -060080// Return codes from main/exit().
John Kessenicha0af4732012-12-12 21:15:54 +000081//
82enum TFailCode {
83 ESuccess = 0,
84 EFailUsage,
85 EFailCompile,
86 EFailLink,
87 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000088 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000089 EFailLinkerCreate
90};
91
92//
John Kessenich68d78fd2015-07-12 19:28:10 -060093// Forward declarations.
John Kessenicha0af4732012-12-12 21:15:54 +000094//
John Kessenichb603f912013-08-29 00:39:25 +000095EShLanguage FindLanguage(const std::string& name);
John Kessenich51cdd902014-02-18 23:37:57 +000096void CompileFile(const char* fileName, ShHandle);
John Kessenicha0af4732012-12-12 21:15:54 +000097void usage();
John Kessenichea869fb2013-10-28 18:12:06 +000098void FreeFileData(char** data);
99char** ReadFileData(const char* fileName);
John Kessenich54d8cda2013-02-11 22:36:01 +0000100void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +0000101
John Kessenichc999ba22013-11-07 23:33:24 +0000102// Globally track if any compile or link failure.
103bool CompileFailed = false;
104bool LinkFailed = false;
105
John Kessenich05a70632013-09-17 19:26:08 +0000106// Use to test breaking up a single shader file into multiple strings.
John Kessenich68d78fd2015-07-12 19:28:10 -0600107// Set in ReadFileData().
John Kessenichea869fb2013-10-28 18:12:06 +0000108int NumShaderStrings;
John Kessenicha0af4732012-12-12 21:15:54 +0000109
John Kessenich05a70632013-09-17 19:26:08 +0000110TBuiltInResource Resources;
111std::string ConfigFile;
112
John Kessenicha0af4732012-12-12 21:15:54 +0000113//
John Kessenich05a70632013-09-17 19:26:08 +0000114// These are the default resources for TBuiltInResources, used for both
115// - parsing this string for the case where the user didn't supply one
116// - dumping out a template for user construction of a config file
John Kessenicha0af4732012-12-12 21:15:54 +0000117//
John Kessenich284231c2013-10-22 01:50:39 +0000118const char* DefaultConfig =
119 "MaxLights 32\n"
120 "MaxClipPlanes 6\n"
121 "MaxTextureUnits 32\n"
122 "MaxTextureCoords 32\n"
123 "MaxVertexAttribs 64\n"
124 "MaxVertexUniformComponents 4096\n"
125 "MaxVaryingFloats 64\n"
126 "MaxVertexTextureImageUnits 32\n"
John Kessenich623833f2013-12-11 18:57:40 +0000127 "MaxCombinedTextureImageUnits 80\n"
John Kessenich284231c2013-10-22 01:50:39 +0000128 "MaxTextureImageUnits 32\n"
129 "MaxFragmentUniformComponents 4096\n"
130 "MaxDrawBuffers 32\n"
131 "MaxVertexUniformVectors 128\n"
132 "MaxVaryingVectors 8\n"
133 "MaxFragmentUniformVectors 16\n"
134 "MaxVertexOutputVectors 16\n"
135 "MaxFragmentInputVectors 15\n"
136 "MinProgramTexelOffset -8\n"
137 "MaxProgramTexelOffset 7\n"
138 "MaxClipDistances 8\n"
139 "MaxComputeWorkGroupCountX 65535\n"
140 "MaxComputeWorkGroupCountY 65535\n"
141 "MaxComputeWorkGroupCountZ 65535\n"
142 "MaxComputeWorkGroupSizeX 1024\n"
John Kessenichda66bc72014-08-19 20:32:48 +0000143 "MaxComputeWorkGroupSizeY 1024\n"
John Kessenich284231c2013-10-22 01:50:39 +0000144 "MaxComputeWorkGroupSizeZ 64\n"
145 "MaxComputeUniformComponents 1024\n"
146 "MaxComputeTextureImageUnits 16\n"
147 "MaxComputeImageUniforms 8\n"
148 "MaxComputeAtomicCounters 8\n"
149 "MaxComputeAtomicCounterBuffers 1\n"
150 "MaxVaryingComponents 60\n"
151 "MaxVertexOutputComponents 64\n"
152 "MaxGeometryInputComponents 64\n"
153 "MaxGeometryOutputComponents 128\n"
154 "MaxFragmentInputComponents 128\n"
155 "MaxImageUnits 8\n"
156 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
John Kessenichddea6782014-08-10 18:19:36 +0000157 "MaxCombinedShaderOutputResources 8\n"
John Kessenich284231c2013-10-22 01:50:39 +0000158 "MaxImageSamples 0\n"
159 "MaxVertexImageUniforms 0\n"
160 "MaxTessControlImageUniforms 0\n"
161 "MaxTessEvaluationImageUniforms 0\n"
162 "MaxGeometryImageUniforms 0\n"
163 "MaxFragmentImageUniforms 8\n"
164 "MaxCombinedImageUniforms 8\n"
165 "MaxGeometryTextureImageUnits 16\n"
166 "MaxGeometryOutputVertices 256\n"
167 "MaxGeometryTotalOutputComponents 1024\n"
168 "MaxGeometryUniformComponents 1024\n"
169 "MaxGeometryVaryingComponents 64\n"
170 "MaxTessControlInputComponents 128\n"
171 "MaxTessControlOutputComponents 128\n"
172 "MaxTessControlTextureImageUnits 16\n"
173 "MaxTessControlUniformComponents 1024\n"
174 "MaxTessControlTotalOutputComponents 4096\n"
175 "MaxTessEvaluationInputComponents 128\n"
176 "MaxTessEvaluationOutputComponents 128\n"
177 "MaxTessEvaluationTextureImageUnits 16\n"
178 "MaxTessEvaluationUniformComponents 1024\n"
179 "MaxTessPatchComponents 120\n"
180 "MaxPatchVertices 32\n"
181 "MaxTessGenLevel 64\n"
182 "MaxViewports 16\n"
183 "MaxVertexAtomicCounters 0\n"
184 "MaxTessControlAtomicCounters 0\n"
185 "MaxTessEvaluationAtomicCounters 0\n"
186 "MaxGeometryAtomicCounters 0\n"
187 "MaxFragmentAtomicCounters 8\n"
188 "MaxCombinedAtomicCounters 8\n"
189 "MaxAtomicCounterBindings 1\n"
190 "MaxVertexAtomicCounterBuffers 0\n"
191 "MaxTessControlAtomicCounterBuffers 0\n"
192 "MaxTessEvaluationAtomicCounterBuffers 0\n"
193 "MaxGeometryAtomicCounterBuffers 0\n"
194 "MaxFragmentAtomicCounterBuffers 1\n"
195 "MaxCombinedAtomicCounterBuffers 1\n"
196 "MaxAtomicCounterBufferSize 16384\n"
John Kessenichc7776ec2014-01-26 01:37:13 +0000197 "MaxTransformFeedbackBuffers 4\n"
198 "MaxTransformFeedbackInterleavedComponents 64\n"
John Kessenich69968412014-08-13 06:37:59 +0000199 "MaxCullDistances 8\n"
200 "MaxCombinedClipAndCullDistances 8\n"
John Kessenichcd77f8e2014-08-13 16:54:02 +0000201 "MaxSamples 4\n"
John Kessenich284231c2013-10-22 01:50:39 +0000202
203 "nonInductiveForLoops 1\n"
204 "whileLoops 1\n"
205 "doWhileLoops 1\n"
206 "generalUniformIndexing 1\n"
207 "generalAttributeMatrixVectorIndexing 1\n"
208 "generalVaryingIndexing 1\n"
209 "generalSamplerIndexing 1\n"
210 "generalVariableIndexing 1\n"
211 "generalConstantMatrixVectorIndexing 1\n"
212 ;
John Kessenich05a70632013-09-17 19:26:08 +0000213
214//
215// Parse either a .conf file provided by the user or the default string above.
216//
217void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000218{
John Kessenich05a70632013-09-17 19:26:08 +0000219 char** configStrings = 0;
John Kessenich51cdd902014-02-18 23:37:57 +0000220 char* config = 0;
John Kessenich05a70632013-09-17 19:26:08 +0000221 if (ConfigFile.size() > 0) {
John Kessenichea869fb2013-10-28 18:12:06 +0000222 configStrings = ReadFileData(ConfigFile.c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000223 if (configStrings)
224 config = *configStrings;
225 else {
226 printf("Error opening configuration file; will instead use the default configuration\n");
227 usage();
228 }
229 }
230
231 if (config == 0) {
John Kessenich6494baf2014-02-19 00:08:59 +0000232 config = new char[strlen(DefaultConfig) + 1];
John Kessenich05a70632013-09-17 19:26:08 +0000233 strcpy(config, DefaultConfig);
234 }
235
236 const char* delims = " \t\n\r";
237 const char* token = strtok(config, delims);
238 while (token) {
239 const char* valueStr = strtok(0, delims);
240 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
241 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
242 return;
243 }
244 int value = atoi(valueStr);
245
246 if (strcmp(token, "MaxLights") == 0)
247 Resources.maxLights = value;
248 else if (strcmp(token, "MaxClipPlanes") == 0)
249 Resources.maxClipPlanes = value;
250 else if (strcmp(token, "MaxTextureUnits") == 0)
251 Resources.maxTextureUnits = value;
252 else if (strcmp(token, "MaxTextureCoords") == 0)
253 Resources.maxTextureCoords = value;
254 else if (strcmp(token, "MaxVertexAttribs") == 0)
255 Resources.maxVertexAttribs = value;
256 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
257 Resources.maxVertexUniformComponents = value;
258 else if (strcmp(token, "MaxVaryingFloats") == 0)
259 Resources.maxVaryingFloats = value;
260 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
261 Resources.maxVertexTextureImageUnits = value;
262 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
263 Resources.maxCombinedTextureImageUnits = value;
264 else if (strcmp(token, "MaxTextureImageUnits") == 0)
265 Resources.maxTextureImageUnits = value;
266 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
267 Resources.maxFragmentUniformComponents = value;
268 else if (strcmp(token, "MaxDrawBuffers") == 0)
269 Resources.maxDrawBuffers = value;
270 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
271 Resources.maxVertexUniformVectors = value;
272 else if (strcmp(token, "MaxVaryingVectors") == 0)
273 Resources.maxVaryingVectors = value;
274 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
275 Resources.maxFragmentUniformVectors = value;
276 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
277 Resources.maxVertexOutputVectors = value;
278 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
279 Resources.maxFragmentInputVectors = value;
280 else if (strcmp(token, "MinProgramTexelOffset") == 0)
281 Resources.minProgramTexelOffset = value;
282 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
283 Resources.maxProgramTexelOffset = value;
John Kesseniche7c59c12013-10-16 22:28:35 +0000284 else if (strcmp(token, "MaxClipDistances") == 0)
285 Resources.maxClipDistances = value;
John Kessenich284231c2013-10-22 01:50:39 +0000286 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
287 Resources.maxComputeWorkGroupCountX = value;
288 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
289 Resources.maxComputeWorkGroupCountY = value;
290 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
291 Resources.maxComputeWorkGroupCountZ = value;
292 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
293 Resources.maxComputeWorkGroupSizeX = value;
294 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
295 Resources.maxComputeWorkGroupSizeY = value;
296 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
297 Resources.maxComputeWorkGroupSizeZ = value;
298 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
299 Resources.maxComputeUniformComponents = value;
300 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
301 Resources.maxComputeTextureImageUnits = value;
302 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
303 Resources.maxComputeImageUniforms = value;
304 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
305 Resources.maxComputeAtomicCounters = value;
306 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
307 Resources.maxComputeAtomicCounterBuffers = value;
308 else if (strcmp(token, "MaxVaryingComponents") == 0)
309 Resources.maxVaryingComponents = value;
310 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
311 Resources.maxVertexOutputComponents = value;
312 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
313 Resources.maxGeometryInputComponents = value;
314 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
315 Resources.maxGeometryOutputComponents = value;
316 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
317 Resources.maxFragmentInputComponents = value;
318 else if (strcmp(token, "MaxImageUnits") == 0)
319 Resources.maxImageUnits = value;
320 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
321 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
John Kessenichddea6782014-08-10 18:19:36 +0000322 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
323 Resources.maxCombinedShaderOutputResources = value;
John Kessenich284231c2013-10-22 01:50:39 +0000324 else if (strcmp(token, "MaxImageSamples") == 0)
325 Resources.maxImageSamples = value;
326 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
327 Resources.maxVertexImageUniforms = value;
328 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
329 Resources.maxTessControlImageUniforms = value;
330 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
331 Resources.maxTessEvaluationImageUniforms = value;
332 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
333 Resources.maxGeometryImageUniforms = value;
334 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
335 Resources.maxFragmentImageUniforms = value;
336 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
337 Resources.maxCombinedImageUniforms = value;
338 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
339 Resources.maxGeometryTextureImageUnits = value;
340 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
341 Resources.maxGeometryOutputVertices = value;
342 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
343 Resources.maxGeometryTotalOutputComponents = value;
344 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
345 Resources.maxGeometryUniformComponents = value;
346 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
347 Resources.maxGeometryVaryingComponents = value;
348 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
349 Resources.maxTessControlInputComponents = value;
350 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
351 Resources.maxTessControlOutputComponents = value;
352 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
353 Resources.maxTessControlTextureImageUnits = value;
354 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
355 Resources.maxTessControlUniformComponents = value;
356 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
357 Resources.maxTessControlTotalOutputComponents = value;
358 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
359 Resources.maxTessEvaluationInputComponents = value;
360 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
361 Resources.maxTessEvaluationOutputComponents = value;
362 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
363 Resources.maxTessEvaluationTextureImageUnits = value;
364 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
365 Resources.maxTessEvaluationUniformComponents = value;
366 else if (strcmp(token, "MaxTessPatchComponents") == 0)
367 Resources.maxTessPatchComponents = value;
368 else if (strcmp(token, "MaxPatchVertices") == 0)
369 Resources.maxPatchVertices = value;
370 else if (strcmp(token, "MaxTessGenLevel") == 0)
371 Resources.maxTessGenLevel = value;
372 else if (strcmp(token, "MaxViewports") == 0)
373 Resources.maxViewports = value;
374 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
375 Resources.maxVertexAtomicCounters = value;
376 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
377 Resources.maxTessControlAtomicCounters = value;
378 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
379 Resources.maxTessEvaluationAtomicCounters = value;
380 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
381 Resources.maxGeometryAtomicCounters = value;
382 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
383 Resources.maxFragmentAtomicCounters = value;
384 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
385 Resources.maxCombinedAtomicCounters = value;
386 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
387 Resources.maxAtomicCounterBindings = value;
388 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
389 Resources.maxVertexAtomicCounterBuffers = value;
390 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
391 Resources.maxTessControlAtomicCounterBuffers = value;
392 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
393 Resources.maxTessEvaluationAtomicCounterBuffers = value;
394 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
395 Resources.maxGeometryAtomicCounterBuffers = value;
396 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
397 Resources.maxFragmentAtomicCounterBuffers = value;
398 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
399 Resources.maxCombinedAtomicCounterBuffers = value;
400 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
401 Resources.maxAtomicCounterBufferSize = value;
John Kessenichc7776ec2014-01-26 01:37:13 +0000402 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
403 Resources.maxTransformFeedbackBuffers = value;
404 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
405 Resources.maxTransformFeedbackInterleavedComponents = value;
John Kessenich69968412014-08-13 06:37:59 +0000406 else if (strcmp(token, "MaxCullDistances") == 0)
407 Resources.maxCullDistances = value;
408 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
409 Resources.maxCombinedClipAndCullDistances = value;
John Kessenichcd77f8e2014-08-13 16:54:02 +0000410 else if (strcmp(token, "MaxSamples") == 0)
411 Resources.maxSamples = value;
John Kessenich284231c2013-10-22 01:50:39 +0000412
John Kessenicha5830df2013-10-02 05:10:48 +0000413 else if (strcmp(token, "nonInductiveForLoops") == 0)
414 Resources.limits.nonInductiveForLoops = (value != 0);
415 else if (strcmp(token, "whileLoops") == 0)
416 Resources.limits.whileLoops = (value != 0);
417 else if (strcmp(token, "doWhileLoops") == 0)
418 Resources.limits.doWhileLoops = (value != 0);
419 else if (strcmp(token, "generalUniformIndexing") == 0)
420 Resources.limits.generalUniformIndexing = (value != 0);
421 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
422 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
423 else if (strcmp(token, "generalVaryingIndexing") == 0)
424 Resources.limits.generalVaryingIndexing = (value != 0);
425 else if (strcmp(token, "generalSamplerIndexing") == 0)
426 Resources.limits.generalSamplerIndexing = (value != 0);
427 else if (strcmp(token, "generalVariableIndexing") == 0)
428 Resources.limits.generalVariableIndexing = (value != 0);
429 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
430 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000431 else
432 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
433
434 token = strtok(0, delims);
435 }
436 if (configStrings)
437 FreeFileData(configStrings);
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500438 else
439 delete[] config;
John Kessenicha0af4732012-12-12 21:15:54 +0000440}
441
John Kessenich38f3b892013-09-06 19:52:57 +0000442// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000443glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000444
445// array of unique places to leave the shader names and infologs for the asynchronous compiles
John Kessenichfd305422014-06-05 16:30:53 +0000446glslang::TWorkItem** Work = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000447int NumWorkItems = 0;
448
John Kessenich94a81fb2013-08-31 02:41:30 +0000449int Options = 0;
John Kessenich68d78fd2015-07-12 19:28:10 -0600450const char* ExecutableName = nullptr;
451const char* binaryFileName = nullptr;
452
453//
454// Create the default name for saving a binary if -o is not provided.
455//
456const char* GetBinaryName(EShLanguage stage)
457{
458 const char* name;
459 if (binaryFileName == nullptr) {
460 switch (stage) {
461 case EShLangVertex: name = "vert.spv"; break;
462 case EShLangTessControl: name = "tesc.spv"; break;
463 case EShLangTessEvaluation: name = "tese.spv"; break;
464 case EShLangGeometry: name = "geom.spv"; break;
465 case EShLangFragment: name = "frag.spv"; break;
466 case EShLangCompute: name = "comp.spv"; break;
467 default: name = "unknown"; break;
468 }
469 } else
470 name = binaryFileName;
471
472 return name;
473}
John Kessenich2b07c7e2013-07-31 18:44:13 +0000474
John Kessenich05a70632013-09-17 19:26:08 +0000475//
476// *.conf => this is a config file that can set limits/resources
477//
478bool SetConfigFile(const std::string& name)
479{
480 if (name.size() < 5)
481 return false;
482
John Kessenich4c706852013-10-11 16:28:43 +0000483 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000484 ConfigFile = name;
485 return true;
486 }
487
488 return false;
489}
490
John Kessenich68d78fd2015-07-12 19:28:10 -0600491//
492// Give error and exit with failure code.
493//
494void Error(const char* message)
495{
496 printf("%s: Error %s (use -h for usage)\n", ExecutableName, message);
497 exit(EFailUsage);
498}
499
500//
501// Do all command-line argument parsing. This includes building up the work-items
502// to be processed later, and saving all the command-line options.
503//
504// Does not return (it exits) if command-line is fatally flawed.
505//
506void ProcessArguments(int argc, char* argv[])
John Kessenich2b07c7e2013-07-31 18:44:13 +0000507{
John Kessenich38f3b892013-09-06 19:52:57 +0000508 ExecutableName = argv[0];
509 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 +0000510 Work = new glslang::TWorkItem*[NumWorkItems];
John Kessenich68d78fd2015-07-12 19:28:10 -0600511 for (int w = 0; w < NumWorkItems; ++w)
512 Work[w] = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000513
John Kessenich2b07c7e2013-07-31 18:44:13 +0000514 argc--;
515 argv++;
516 for (; argc >= 1; argc--, argv++) {
517 if (argv[0][0] == '-') {
John Kessenich2aa7f3a2015-05-15 16:02:07 +0000518 switch (argv[0][1]) {
519 case 'H':
520 Options |= EOptionHumanReadableSpv;
521 // fall through to -V
John Kessenich0df0cde2015-03-03 17:09:43 +0000522 case 'V':
523 Options |= EOptionSpv;
John Kessenich68d78fd2015-07-12 19:28:10 -0600524 Options |= EOptionVulkanRules;
525 Options |= EOptionLinkProgram;
526 break;
527 case 'G':
528 Options |= EOptionSpv;
John Kessenichd78e3512014-08-25 20:07:55 +0000529 Options |= EOptionLinkProgram;
John Kessenich92f90382014-07-28 04:21:04 +0000530 break;
John Kessenichc555ddd2015-06-17 02:38:44 +0000531 case 'E':
532 Options |= EOptionOutputPreprocessed;
533 break;
John Kessenich05a70632013-09-17 19:26:08 +0000534 case 'c':
535 Options |= EOptionDumpConfig;
536 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000537 case 'd':
John Kessenich26ad2682014-08-13 20:17:19 +0000538 Options |= EOptionDefaultDesktop;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000539 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600540 case 'h':
541 usage();
542 break;
John Kessenich05a70632013-09-17 19:26:08 +0000543 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000544 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000545 break;
546 case 'l':
John Kessenichd78e3512014-08-25 20:07:55 +0000547 Options |= EOptionLinkProgram;
John Kessenich94a81fb2013-08-31 02:41:30 +0000548 break;
549 case 'm':
550 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000551 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600552 case 'o':
553 binaryFileName = argv[1];
554 if (argc > 0) {
555 argc--;
556 argv++;
557 } else
558 Error("no <file> provided for -o");
559 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000560 case 'q':
561 Options |= EOptionDumpReflection;
562 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000563 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000564 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000565 break;
566 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000567 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000568 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000569 case 't':
570 #ifdef _WIN32
John Kessenichb0a7eb52013-11-07 17:44:20 +0000571 Options |= EOptionMultiThreaded;
John Kessenich38f3b892013-09-06 19:52:57 +0000572 #endif
573 break;
John Kessenich319de232013-12-04 04:43:40 +0000574 case 'v':
575 Options |= EOptionDumpVersions;
576 break;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000577 case 'w':
578 Options |= EOptionSuppressWarnings;
579 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000580 default:
John Kessenich68d78fd2015-07-12 19:28:10 -0600581 usage();
582 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000583 }
John Kessenich38f3b892013-09-06 19:52:57 +0000584 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000585 std::string name(argv[0]);
586 if (! SetConfigFile(name)) {
587 Work[argc] = new glslang::TWorkItem(name);
588 Worklist.add(Work[argc]);
589 }
John Kessenich38f3b892013-09-06 19:52:57 +0000590 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000591 }
592
John Kessenich68d78fd2015-07-12 19:28:10 -0600593 // Make sure that -E is not specified alongside linking (which includes SPV generation)
594 if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
595 Error("can't use -E when linking is selected");
John Kessenichc555ddd2015-06-17 02:38:44 +0000596
John Kessenich68d78fd2015-07-12 19:28:10 -0600597 // -o makes no sense if there is no target binary
598 if (binaryFileName && (Options & EOptionSpv) == 0)
599 Error("no binary generation requested (e.g., -V)");
John Kessenich2b07c7e2013-07-31 18:44:13 +0000600}
601
John Kessenich68d78fd2015-07-12 19:28:10 -0600602//
603// Translate the meaningful subset of command-line options to parser-behavior options.
604//
John Kessenichb0a7eb52013-11-07 17:44:20 +0000605void SetMessageOptions(EShMessages& messages)
606{
607 if (Options & EOptionRelaxedErrors)
608 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
609 if (Options & EOptionIntermediate)
610 messages = (EShMessages)(messages | EShMsgAST);
611 if (Options & EOptionSuppressWarnings)
612 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
John Kessenich68d78fd2015-07-12 19:28:10 -0600613 if (Options & EOptionSpv)
614 messages = (EShMessages)(messages | EShMsgSpvRules);
615 if (Options & EOptionVulkanRules)
616 messages = (EShMessages)(messages | EShMsgVulkanRules);
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400617 if (Options & EOptionOutputPreprocessed)
618 messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
John Kessenichb0a7eb52013-11-07 17:44:20 +0000619}
620
John Kessenich68d78fd2015-07-12 19:28:10 -0600621//
John Kessenich69f4b512013-09-04 21:19:27 +0000622// Thread entry point, for non-linking asynchronous mode.
John Kessenichc999ba22013-11-07 23:33:24 +0000623//
624// Return 0 for failure, 1 for success.
625//
Pyry Haulos5f6892e2015-12-01 12:59:53 -0800626unsigned int CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000627{
John Kessenich38f3b892013-09-06 19:52:57 +0000628 glslang::TWorkItem* workItem;
629 while (Worklist.remove(workItem)) {
630 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000631 if (compiler == 0)
John Kessenichc999ba22013-11-07 23:33:24 +0000632 return 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000633
John Kessenichb0a7eb52013-11-07 17:44:20 +0000634 CompileFile(workItem->name.c_str(), compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000635
John Kessenich94a81fb2013-08-31 02:41:30 +0000636 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000637 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000638
639 ShDestruct(compiler);
640 }
641
642 return 0;
643}
644
John Kessenich6626cad2015-06-19 05:14:19 +0000645// Outputs the given string, but only if it is non-null and non-empty.
646// This prevents erroneous newlines from appearing.
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400647void PutsIfNonEmpty(const char* str)
John Kessenich6626cad2015-06-19 05:14:19 +0000648{
649 if (str && str[0]) {
650 puts(str);
651 }
652}
653
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400654// Outputs the given string to stderr, but only if it is non-null and non-empty.
655// This prevents erroneous newlines from appearing.
656void StderrIfNonEmpty(const char* str)
657{
658 if (str && str[0]) {
659 fprintf(stderr, "%s\n", str);
660 }
661}
662
John Kessenichc57b2a92016-01-16 15:30:03 -0700663// Simple bundling of what makes a compilation unit for ease in passing around,
664// and separation of handling file IO versus API (programmatic) compilation.
665struct ShaderCompUnit {
666 EShLanguage stage;
667 std::string fileName;
668 char** text; // memory owned/managed externally
669};
670
John Kessenich69f4b512013-09-04 21:19:27 +0000671//
John Kessenichc57b2a92016-01-16 15:30:03 -0700672// For linking mode: Will independently parse each compilation unit, but then put them
673// in the same program and link them together, making at most one linked module per
674// pipeline stage.
John Kessenich69f4b512013-09-04 21:19:27 +0000675//
676// Uses the new C++ interface instead of the old handle-based interface.
677//
John Kessenichc57b2a92016-01-16 15:30:03 -0700678
679void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
John Kessenich69f4b512013-09-04 21:19:27 +0000680{
681 // keep track of what to free
682 std::list<glslang::TShader*> shaders;
John Kessenichc57b2a92016-01-16 15:30:03 -0700683
John Kessenich69f4b512013-09-04 21:19:27 +0000684 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000685 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000686
John Kessenich69f4b512013-09-04 21:19:27 +0000687 //
688 // Per-shader processing...
689 //
690
John Kessenich5b0f13a2013-11-01 03:08:40 +0000691 glslang::TProgram& program = *new glslang::TProgram;
rdb32084e82016-02-23 22:17:38 +0100692 for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
693 const auto &compUnit = *it;
John Kessenichc57b2a92016-01-16 15:30:03 -0700694 glslang::TShader* shader = new glslang::TShader(compUnit.stage);
695 shader->setStrings(compUnit.text, 1);
John Kessenich69f4b512013-09-04 21:19:27 +0000696 shaders.push_back(shader);
John Kessenichb3297152015-07-11 18:01:03 -0600697
John Kessenichc555ddd2015-06-17 02:38:44 +0000698 const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;
John Kessenich69f4b512013-09-04 21:19:27 +0000699
John Kessenichc555ddd2015-06-17 02:38:44 +0000700 if (Options & EOptionOutputPreprocessed) {
701 std::string str;
Dejan Mircevski7be4b822015-06-17 11:40:33 -0400702 if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
703 messages, &str, glslang::TShader::ForbidInclude())) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400704 PutsIfNonEmpty(str.c_str());
705 } else {
706 CompileFailed = true;
707 }
708 StderrIfNonEmpty(shader->getInfoLog());
709 StderrIfNonEmpty(shader->getInfoDebugLog());
John Kessenichc555ddd2015-06-17 02:38:44 +0000710 continue;
711 }
712 if (! shader->parse(&Resources, defaultVersion, false, messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000713 CompileFailed = true;
John Kessenichc555ddd2015-06-17 02:38:44 +0000714
John Kessenich69f4b512013-09-04 21:19:27 +0000715 program.addShader(shader);
716
John Kessenichc57b2a92016-01-16 15:30:03 -0700717 if (! (Options & EOptionSuppressInfolog) &&
718 ! (Options & EOptionMemoryLeakMode)) {
719 PutsIfNonEmpty(compUnit.fileName.c_str());
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400720 PutsIfNonEmpty(shader->getInfoLog());
721 PutsIfNonEmpty(shader->getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000722 }
John Kessenich69f4b512013-09-04 21:19:27 +0000723 }
724
725 //
726 // Program-level processing...
727 //
728
John Kessenich68d78fd2015-07-12 19:28:10 -0600729 if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000730 LinkFailed = true;
731
John Kessenichc57b2a92016-01-16 15:30:03 -0700732 if (! (Options & EOptionSuppressInfolog) &&
733 ! (Options & EOptionMemoryLeakMode)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400734 PutsIfNonEmpty(program.getInfoLog());
735 PutsIfNonEmpty(program.getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000736 }
737
John Kessenich11f9fc72013-11-07 01:06:34 +0000738 if (Options & EOptionDumpReflection) {
739 program.buildReflection();
740 program.dumpReflection();
741 }
742
John Kessenich0df0cde2015-03-03 17:09:43 +0000743 if (Options & EOptionSpv) {
John Kessenich92f90382014-07-28 04:21:04 +0000744 if (CompileFailed || LinkFailed)
John Kessenich68d78fd2015-07-12 19:28:10 -0600745 printf("SPIR-V is not generated for failed compile or link\n");
John Kessenich92f90382014-07-28 04:21:04 +0000746 else {
747 for (int stage = 0; stage < EShLangCount; ++stage) {
John Kessenicha7a68a92014-08-24 18:21:00 +0000748 if (program.getIntermediate((EShLanguage)stage)) {
John Kessenich0df0cde2015-03-03 17:09:43 +0000749 std::vector<unsigned int> spirv;
750 glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
John Kessenichc57b2a92016-01-16 15:30:03 -0700751
752 // Dump the spv to a file or stdout, etc., but only if not doing
753 // memory/perf testing, as it's not internal to programmatic use.
754 if (! (Options & EOptionMemoryLeakMode)) {
755 glslang::OutputSpv(spirv, GetBinaryName((EShLanguage)stage));
756 if (Options & EOptionHumanReadableSpv) {
757 spv::Parameterize();
758 spv::Disassemble(std::cout, spirv);
759 }
John Kessenichacba7722015-03-04 03:48:38 +0000760 }
John Kessenicha7a68a92014-08-24 18:21:00 +0000761 }
John Kessenich92f90382014-07-28 04:21:04 +0000762 }
763 }
764 }
765
John Kessenich5b0f13a2013-11-01 03:08:40 +0000766 // Free everything up, program has to go before the shaders
767 // because it might have merged stuff from the shaders, and
768 // the stuff from the shaders has to have its destructors called
769 // before the pools holding the memory in the shaders is freed.
770 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000771 while (shaders.size() > 0) {
772 delete shaders.back();
773 shaders.pop_back();
774 }
John Kessenich69f4b512013-09-04 21:19:27 +0000775}
776
John Kessenichc57b2a92016-01-16 15:30:03 -0700777//
778// Do file IO part of compile and link, handing off the pure
779// API/programmatic mode to CompileAndLinkShaderUnits(), which can
780// be put in a loop for testing memory footprint and performance.
781//
782// This is just for linking mode: meaning all the shaders will be put into the
783// the same program linked together.
784//
785// This means there are a limited number of work items (not multi-threading mode)
786// and that the point is testing at the linking level. Hence, to enable
787// performance and memory testing, the actual compile/link can be put in
788// a loop, independent of processing the work items and file IO.
789//
790void CompileAndLinkShaderFiles()
791{
792 std::vector<ShaderCompUnit> compUnits;
793
794 // Transfer all the work items from to a simple list of
795 // of compilation units. (We don't care about the thread
796 // work-item distribution properties in this path, which
797 // is okay due to the limited number of shaders, know since
798 // they are all getting linked together.)
799 glslang::TWorkItem* workItem;
800 while (Worklist.remove(workItem)) {
801 ShaderCompUnit compUnit = {
802 FindLanguage(workItem->name),
803 workItem->name,
804 ReadFileData(workItem->name.c_str())
805 };
806
807 if (! compUnit.text) {
808 usage();
809 return;
810 }
811
812 compUnits.push_back(compUnit);
813 }
814
815 // Actual call to programmatic processing of compile and link,
816 // in a loop for testing memory and performance. This part contains
817 // all the perf/memory that a programmatic consumer will care about.
818 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
819 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
820 CompileAndLinkShaderUnits(compUnits);
821
822 if (Options & EOptionMemoryLeakMode)
823 glslang::OS_DumpMemoryCounters();
824 }
825
rdb32084e82016-02-23 22:17:38 +0100826 for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
827 FreeFileData(it->text);
John Kessenichc57b2a92016-01-16 15:30:03 -0700828}
829
John Kessenicha0af4732012-12-12 21:15:54 +0000830int C_DECL main(int argc, char* argv[])
831{
John Kessenich68d78fd2015-07-12 19:28:10 -0600832 ProcessArguments(argc, argv);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000833
John Kessenich05a70632013-09-17 19:26:08 +0000834 if (Options & EOptionDumpConfig) {
835 printf("%s", DefaultConfig);
836 if (Worklist.empty())
837 return ESuccess;
838 }
839
John Kessenich0da9eaa2015-08-01 17:10:02 -0600840 if (Options & EOptionDumpVersions) {
841 printf("Glslang Version: %s %s\n", GLSLANG_REVISION, GLSLANG_DATE);
John Kessenich319de232013-12-04 04:43:40 +0000842 printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
843 printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
John Kessenich68d78fd2015-07-12 19:28:10 -0600844 std::string spirvVersion;
845 glslang::GetSpirvVersion(spirvVersion);
John Kessenich0da9eaa2015-08-01 17:10:02 -0600846 printf("SPIR-V Version %s\n", spirvVersion.c_str());
John Kessenich5e4b1242015-08-06 22:53:06 -0600847 printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
John Kessenich55e7d112015-11-15 21:33:39 -0700848 printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId());
John Kessenich319de232013-12-04 04:43:40 +0000849 if (Worklist.empty())
850 return ESuccess;
851 }
852
John Kessenich05a70632013-09-17 19:26:08 +0000853 if (Worklist.empty()) {
854 usage();
John Kessenich05a70632013-09-17 19:26:08 +0000855 }
856
857 ProcessConfigFile();
858
John Kessenich69f4b512013-09-04 21:19:27 +0000859 //
860 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000861 // 1) linking all arguments together, single-threaded, new C++ interface
862 // 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 +0000863 //
John Kessenichc555ddd2015-06-17 02:38:44 +0000864 if (Options & EOptionLinkProgram ||
865 Options & EOptionOutputPreprocessed) {
John Kessenichc36e1d82013-11-01 17:41:52 +0000866 glslang::InitializeProcess();
John Kessenichc57b2a92016-01-16 15:30:03 -0700867 CompileAndLinkShaderFiles();
John Kessenichc36e1d82013-11-01 17:41:52 +0000868 glslang::FinalizeProcess();
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500869 for (int w = 0; w < NumWorkItems; ++w) {
870 if (Work[w]) {
871 delete Work[w];
872 }
873 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000874 } else {
875 ShInitialize();
876
John Kessenich38f3b892013-09-06 19:52:57 +0000877 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000878
John Kessenich38f3b892013-09-06 19:52:57 +0000879 if (Options & EOptionMultiThreaded) {
880 const int NumThreads = 16;
881 void* threads[NumThreads];
882 for (int t = 0; t < NumThreads; ++t) {
883 threads[t] = glslang::OS_CreateThread(&CompileShaders);
884 if (! threads[t]) {
885 printf("Failed to create thread\n");
886 return EFailThreadCreate;
887 }
John Kessenicha0af4732012-12-12 21:15:54 +0000888 }
John Kessenich38f3b892013-09-06 19:52:57 +0000889 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenichc999ba22013-11-07 23:33:24 +0000890 } else
891 CompileShaders(0);
John Kessenich38f3b892013-09-06 19:52:57 +0000892
893 // Print out all the resulting infologs
894 for (int w = 0; w < NumWorkItems; ++w) {
895 if (Work[w]) {
Kenneth Perryb07e6be2015-12-15 10:52:34 -0600896 if (printShaderNames || Work[w]->results.size() > 0)
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400897 PutsIfNonEmpty(Work[w]->name.c_str());
898 PutsIfNonEmpty(Work[w]->results.c_str());
John Kessenich38f3b892013-09-06 19:52:57 +0000899 delete Work[w];
900 }
901 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000902
903 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000904 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000905
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500906 delete[] Work;
907
John Kessenichc999ba22013-11-07 23:33:24 +0000908 if (CompileFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000909 return EFailCompile;
John Kessenichc999ba22013-11-07 23:33:24 +0000910 if (LinkFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000911 return EFailLink;
912
913 return 0;
914}
915
916//
917// Deduce the language from the filename. Files must end in one of the
918// following extensions:
919//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000920// .vert = vertex
921// .tesc = tessellation control
922// .tese = tessellation evaluation
923// .geom = geometry
924// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000925// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000926//
John Kessenichb603f912013-08-29 00:39:25 +0000927EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000928{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000929 size_t ext = name.rfind('.');
930 if (ext == std::string::npos) {
931 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000932 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000933 }
934
John Kessenich2b07c7e2013-07-31 18:44:13 +0000935 std::string suffix = name.substr(ext + 1, std::string::npos);
936 if (suffix == "vert")
937 return EShLangVertex;
938 else if (suffix == "tesc")
939 return EShLangTessControl;
940 else if (suffix == "tese")
941 return EShLangTessEvaluation;
942 else if (suffix == "geom")
943 return EShLangGeometry;
944 else if (suffix == "frag")
945 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000946 else if (suffix == "comp")
947 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000948
949 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000950 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000951}
952
John Kessenicha0af4732012-12-12 21:15:54 +0000953//
John Kessenich69f4b512013-09-04 21:19:27 +0000954// Read a file's data into a string, and compile it using the old interface ShCompile,
955// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000956//
John Kessenich51cdd902014-02-18 23:37:57 +0000957void CompileFile(const char* fileName, ShHandle compiler)
John Kessenicha0af4732012-12-12 21:15:54 +0000958{
John Kessenichca3457f2015-05-18 01:59:45 +0000959 int ret = 0;
John Kessenich41cf6b52013-06-25 18:10:05 +0000960 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000961 if (! shaderStrings) {
962 usage();
John Kessenichdb4cd542013-06-26 22:42:55 +0000963 }
964
John Kessenich41cf6b52013-06-25 18:10:05 +0000965 int* lengths = new int[NumShaderStrings];
966
967 // move to length-based strings, rather than null-terminated strings
968 for (int s = 0; s < NumShaderStrings; ++s)
John Kessenich35f04bd2014-02-19 02:47:20 +0000969 lengths[s] = (int)strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000970
John Kessenichc999ba22013-11-07 23:33:24 +0000971 if (! shaderStrings) {
972 CompileFailed = true;
973 return;
974 }
John Kessenicha0af4732012-12-12 21:15:54 +0000975
John Kessenich52ac67e2013-05-05 23:46:22 +0000976 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000977 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000978
John Kessenich94a81fb2013-08-31 02:41:30 +0000979 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
980 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich26ad2682014-08-13 20:17:19 +0000981 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichca3457f2015-05-18 01:59:45 +0000982 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +0000983 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
984 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
985 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +0000986 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichca3457f2015-05-18 01:59:45 +0000987 //ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000988 }
John Kessenicha0af4732012-12-12 21:15:54 +0000989
John Kessenich94a81fb2013-08-31 02:41:30 +0000990 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000991 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000992 }
John Kessenicha0af4732012-12-12 21:15:54 +0000993
John Kessenich41cf6b52013-06-25 18:10:05 +0000994 delete [] lengths;
995 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000996
John Kessenichc999ba22013-11-07 23:33:24 +0000997 if (ret == 0)
998 CompileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +0000999}
1000
John Kessenicha0af4732012-12-12 21:15:54 +00001001//
1002// print usage to stdout
1003//
1004void usage()
1005{
John Kessenich319de232013-12-04 04:43:40 +00001006 printf("Usage: glslangValidator [option]... [file]...\n"
1007 "\n"
John Kessenich0df0cde2015-03-03 17:09:43 +00001008 "Where: each 'file' ends in .<stage>, where <stage> is one of\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001009 " .conf to provide an optional config file that replaces the default configuration\n"
1010 " (see -c option below for generating a template)\n"
1011 " .vert for a vertex shader\n"
1012 " .tesc for a tessellation control shader\n"
1013 " .tese for a tessellation evaluation shader\n"
1014 " .geom for a geometry shader\n"
1015 " .frag for a fragment shader\n"
1016 " .comp for a compute shader\n"
John Kessenich319de232013-12-04 04:43:40 +00001017 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +00001018 "Compilation warnings and errors will be printed to stdout.\n"
John Kessenich319de232013-12-04 04:43:40 +00001019 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +00001020 "To get other information, use one of the following options:\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001021 "Each option must be specified separately.\n"
1022 " -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
1023 " default file name is <stage>.spv (-o overrides this)\n"
1024 " (unless -o is specified, which overrides the default file name)\n"
1025 " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
1026 " default file name is <stage>.spv (-o overrides this)\n"
1027 " -H print human readable form of SPIR-V; turns on -V\n"
Andrew Woloszynaae1ad82015-06-24 17:00:46 -04001028 " -E print pre-processed GLSL; cannot be used with -l;\n"
1029 " errors will appear on stderr.\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001030 " -c configuration dump;\n"
1031 " creates the default configuration file (redirect to a .conf file)\n"
1032 " -d default to desktop (#version 110) when there is no shader #version\n"
1033 " (default is ES version 100)\n"
1034 " -h print this usage message\n"
1035 " -i intermediate tree (glslang AST) is printed out\n"
1036 " -l link all input files together to form a single module\n"
1037 " -m memory leak mode\n"
1038 " -o <file> save binary into <file>, requires a binary option (e.g., -V)\n"
1039 " -q dump reflection query database\n"
1040 " -r relaxed semantic error-checking mode\n"
1041 " -s silent mode\n"
1042 " -t multi-threaded mode\n"
1043 " -v print version strings\n"
1044 " -w suppress warnings (except as required by #extension : warn)\n"
John Kessenichb0a7eb52013-11-07 17:44:20 +00001045 );
John Kessenich68d78fd2015-07-12 19:28:10 -06001046
1047 exit(EFailUsage);
John Kessenicha0af4732012-12-12 21:15:54 +00001048}
1049
John Kessenich3ce4e592014-10-06 19:57:34 +00001050#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
John Kessenichcfd643e2013-03-08 23:14:42 +00001051
1052#include <errno.h>
1053
1054int fopen_s(
1055 FILE** pFile,
John Kessenich51cdd902014-02-18 23:37:57 +00001056 const char* filename,
1057 const char* mode
John Kessenichcfd643e2013-03-08 23:14:42 +00001058)
1059{
1060 if (!pFile || !filename || !mode) {
1061 return EINVAL;
1062 }
1063
1064 FILE* f = fopen(filename, mode);
1065 if (! f) {
1066 if (errno != 0) {
1067 return errno;
1068 } else {
1069 return ENOENT;
1070 }
1071 }
1072 *pFile = f;
1073
1074 return 0;
1075}
1076
1077#endif
1078
John Kessenicha0af4732012-12-12 21:15:54 +00001079//
1080// Malloc a string of sufficient size and read a string into it.
1081//
John Kessenich51cdd902014-02-18 23:37:57 +00001082char** ReadFileData(const char* fileName)
John Kessenicha0af4732012-12-12 21:15:54 +00001083{
John Kessenichb3297152015-07-11 18:01:03 -06001084 FILE *in = nullptr;
John Kessenich3ce4e592014-10-06 19:57:34 +00001085 int errorCode = fopen_s(&in, fileName, "r");
John Kessenichd6c72a42014-08-18 19:42:35 +00001086
John Kessenicha0af4732012-12-12 21:15:54 +00001087 int count = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001088 const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
1089 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001090
John Kessenich68d78fd2015-07-12 19:28:10 -06001091 if (errorCode || in == nullptr)
1092 Error("unable to open input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001093
1094 while (fgetc(in) != EOF)
1095 count++;
1096
John Kessenichd6c72a42014-08-18 19:42:35 +00001097 fseek(in, 0, SEEK_SET);
John Kessenichca3457f2015-05-18 01:59:45 +00001098
John Kessenichb3297152015-07-11 18:01:03 -06001099 char *fdata = (char*)malloc(count+2); // freed before return of this function
John Kessenich68d78fd2015-07-12 19:28:10 -06001100 if (! fdata)
1101 Error("can't allocate memory");
1102
John Kessenichb3297152015-07-11 18:01:03 -06001103 if ((int)fread(fdata, 1, count, in) != count) {
John Kessenichb3297152015-07-11 18:01:03 -06001104 free(fdata);
John Kessenich68d78fd2015-07-12 19:28:10 -06001105 Error("can't read input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001106 }
John Kessenich68d78fd2015-07-12 19:28:10 -06001107
John Kessenicha0af4732012-12-12 21:15:54 +00001108 fdata[count] = '\0';
1109 fclose(in);
John Kessenichb3297152015-07-11 18:01:03 -06001110
John Kessenichea869fb2013-10-28 18:12:06 +00001111 if (count == 0) {
John Kessenichb3297152015-07-11 18:01:03 -06001112 // recover from empty file
1113 return_data[0] = (char*)malloc(count+2); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001114 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +00001115 NumShaderStrings = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001116 free(fdata);
John Kessenicha0af4732012-12-12 21:15:54 +00001117
John Kessenichb3297152015-07-11 18:01:03 -06001118 return return_data;
1119 } else
1120 NumShaderStrings = 1; // Set to larger than 1 for testing multiple strings
1121
1122 // compute how to split up the file into multiple strings, for testing multiple strings
John Kessenichd6c72a42014-08-18 19:42:35 +00001123 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenichb3297152015-07-11 18:01:03 -06001124 int ptr_len = 0;
1125 int i = 0;
1126 while (count > 0) {
1127 return_data[i] = (char*)malloc(len + 2); // freed in FreeFileData()
1128 memcpy(return_data[i], fdata + ptr_len, len);
1129 return_data[i][len] = '\0';
1130 count -= len;
1131 ptr_len += len;
1132 if (count < len) {
1133 if (count == 0) {
1134 NumShaderStrings = i + 1;
John Kessenicha0af4732012-12-12 21:15:54 +00001135 break;
1136 }
John Kessenichb3297152015-07-11 18:01:03 -06001137 len = count;
John Kessenichd6c72a42014-08-18 19:42:35 +00001138 }
1139 ++i;
1140 }
John Kessenichb3297152015-07-11 18:01:03 -06001141
1142 free(fdata);
1143
John Kessenicha0af4732012-12-12 21:15:54 +00001144 return return_data;
1145}
1146
John Kessenich51cdd902014-02-18 23:37:57 +00001147void FreeFileData(char** data)
John Kessenicha0af4732012-12-12 21:15:54 +00001148{
John Kessenichb3297152015-07-11 18:01:03 -06001149 for(int i = 0; i < NumShaderStrings; i++)
John Kessenicha0af4732012-12-12 21:15:54 +00001150 free(data[i]);
John Kessenichb3297152015-07-11 18:01:03 -06001151
1152 free(data);
John Kessenicha0af4732012-12-12 21:15:54 +00001153}
1154
John Kessenich54d8cda2013-02-11 22:36:01 +00001155void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +00001156{
John Kessenichfae38ee2015-06-10 23:23:12 +00001157 if (num >= 0 )
1158 printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
1159 else
1160 printf("#### %s %s INFO LOG ####\n", msg, name);
John Kessenicha0af4732012-12-12 21:15:54 +00001161}