blob: 408f114e25fd99ba9da9344a6c6ee1535c4f0eba [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;
John Kessenich4d65ee32016-03-12 18:17:47 -0700452const char* entryPointName = nullptr;
John Kessenich68d78fd2015-07-12 19:28:10 -0600453
454//
455// Create the default name for saving a binary if -o is not provided.
456//
457const char* GetBinaryName(EShLanguage stage)
458{
459 const char* name;
460 if (binaryFileName == nullptr) {
461 switch (stage) {
462 case EShLangVertex: name = "vert.spv"; break;
463 case EShLangTessControl: name = "tesc.spv"; break;
464 case EShLangTessEvaluation: name = "tese.spv"; break;
465 case EShLangGeometry: name = "geom.spv"; break;
466 case EShLangFragment: name = "frag.spv"; break;
467 case EShLangCompute: name = "comp.spv"; break;
468 default: name = "unknown"; break;
469 }
470 } else
471 name = binaryFileName;
472
473 return name;
474}
John Kessenich2b07c7e2013-07-31 18:44:13 +0000475
John Kessenich05a70632013-09-17 19:26:08 +0000476//
477// *.conf => this is a config file that can set limits/resources
478//
479bool SetConfigFile(const std::string& name)
480{
481 if (name.size() < 5)
482 return false;
483
John Kessenich4c706852013-10-11 16:28:43 +0000484 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000485 ConfigFile = name;
486 return true;
487 }
488
489 return false;
490}
491
John Kessenich68d78fd2015-07-12 19:28:10 -0600492//
493// Give error and exit with failure code.
494//
495void Error(const char* message)
496{
497 printf("%s: Error %s (use -h for usage)\n", ExecutableName, message);
498 exit(EFailUsage);
499}
500
501//
502// Do all command-line argument parsing. This includes building up the work-items
503// to be processed later, and saving all the command-line options.
504//
505// Does not return (it exits) if command-line is fatally flawed.
506//
507void ProcessArguments(int argc, char* argv[])
John Kessenich2b07c7e2013-07-31 18:44:13 +0000508{
John Kessenich38f3b892013-09-06 19:52:57 +0000509 ExecutableName = argv[0];
510 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 +0000511 Work = new glslang::TWorkItem*[NumWorkItems];
John Kessenich68d78fd2015-07-12 19:28:10 -0600512 for (int w = 0; w < NumWorkItems; ++w)
513 Work[w] = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000514
John Kessenich2b07c7e2013-07-31 18:44:13 +0000515 argc--;
516 argv++;
517 for (; argc >= 1; argc--, argv++) {
518 if (argv[0][0] == '-') {
John Kessenich2aa7f3a2015-05-15 16:02:07 +0000519 switch (argv[0][1]) {
520 case 'H':
521 Options |= EOptionHumanReadableSpv;
522 // fall through to -V
John Kessenich0df0cde2015-03-03 17:09:43 +0000523 case 'V':
524 Options |= EOptionSpv;
John Kessenich68d78fd2015-07-12 19:28:10 -0600525 Options |= EOptionVulkanRules;
526 Options |= EOptionLinkProgram;
527 break;
528 case 'G':
529 Options |= EOptionSpv;
John Kessenichd78e3512014-08-25 20:07:55 +0000530 Options |= EOptionLinkProgram;
John Kessenich92f90382014-07-28 04:21:04 +0000531 break;
John Kessenichc555ddd2015-06-17 02:38:44 +0000532 case 'E':
533 Options |= EOptionOutputPreprocessed;
534 break;
John Kessenich05a70632013-09-17 19:26:08 +0000535 case 'c':
536 Options |= EOptionDumpConfig;
537 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000538 case 'd':
John Kessenich26ad2682014-08-13 20:17:19 +0000539 Options |= EOptionDefaultDesktop;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000540 break;
John Kessenich4d65ee32016-03-12 18:17:47 -0700541 case 'e':
542 // HLSL todo: entry point handle needs much more sophistication.
543 // This is okay for one compilation unit with one entry point.
544 entryPointName = argv[1];
545 if (argc > 0) {
546 argc--;
547 argv++;
548 } else
549 Error("no <entry-point> provided for -e");
550 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600551 case 'h':
552 usage();
553 break;
John Kessenich05a70632013-09-17 19:26:08 +0000554 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000555 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000556 break;
557 case 'l':
John Kessenichd78e3512014-08-25 20:07:55 +0000558 Options |= EOptionLinkProgram;
John Kessenich94a81fb2013-08-31 02:41:30 +0000559 break;
560 case 'm':
561 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000562 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600563 case 'o':
564 binaryFileName = argv[1];
565 if (argc > 0) {
566 argc--;
567 argv++;
568 } else
569 Error("no <file> provided for -o");
570 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000571 case 'q':
572 Options |= EOptionDumpReflection;
573 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000574 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000575 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000576 break;
577 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000578 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000579 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000580 case 't':
581 #ifdef _WIN32
John Kessenichb0a7eb52013-11-07 17:44:20 +0000582 Options |= EOptionMultiThreaded;
John Kessenich38f3b892013-09-06 19:52:57 +0000583 #endif
584 break;
John Kessenich319de232013-12-04 04:43:40 +0000585 case 'v':
586 Options |= EOptionDumpVersions;
587 break;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000588 case 'w':
589 Options |= EOptionSuppressWarnings;
590 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000591 default:
John Kessenich68d78fd2015-07-12 19:28:10 -0600592 usage();
593 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000594 }
John Kessenich38f3b892013-09-06 19:52:57 +0000595 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000596 std::string name(argv[0]);
597 if (! SetConfigFile(name)) {
598 Work[argc] = new glslang::TWorkItem(name);
599 Worklist.add(Work[argc]);
600 }
John Kessenich38f3b892013-09-06 19:52:57 +0000601 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000602 }
603
John Kessenich68d78fd2015-07-12 19:28:10 -0600604 // Make sure that -E is not specified alongside linking (which includes SPV generation)
605 if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
606 Error("can't use -E when linking is selected");
John Kessenichc555ddd2015-06-17 02:38:44 +0000607
John Kessenich68d78fd2015-07-12 19:28:10 -0600608 // -o makes no sense if there is no target binary
609 if (binaryFileName && (Options & EOptionSpv) == 0)
610 Error("no binary generation requested (e.g., -V)");
John Kessenich2b07c7e2013-07-31 18:44:13 +0000611}
612
John Kessenich68d78fd2015-07-12 19:28:10 -0600613//
614// Translate the meaningful subset of command-line options to parser-behavior options.
615//
John Kessenichb0a7eb52013-11-07 17:44:20 +0000616void SetMessageOptions(EShMessages& messages)
617{
618 if (Options & EOptionRelaxedErrors)
619 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
620 if (Options & EOptionIntermediate)
621 messages = (EShMessages)(messages | EShMsgAST);
622 if (Options & EOptionSuppressWarnings)
623 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
John Kessenich68d78fd2015-07-12 19:28:10 -0600624 if (Options & EOptionSpv)
625 messages = (EShMessages)(messages | EShMsgSpvRules);
626 if (Options & EOptionVulkanRules)
627 messages = (EShMessages)(messages | EShMsgVulkanRules);
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400628 if (Options & EOptionOutputPreprocessed)
629 messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
John Kessenichb0a7eb52013-11-07 17:44:20 +0000630}
631
John Kessenich68d78fd2015-07-12 19:28:10 -0600632//
John Kessenich69f4b512013-09-04 21:19:27 +0000633// Thread entry point, for non-linking asynchronous mode.
John Kessenichc999ba22013-11-07 23:33:24 +0000634//
635// Return 0 for failure, 1 for success.
636//
Pyry Haulos5f6892e2015-12-01 12:59:53 -0800637unsigned int CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000638{
John Kessenich38f3b892013-09-06 19:52:57 +0000639 glslang::TWorkItem* workItem;
640 while (Worklist.remove(workItem)) {
641 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000642 if (compiler == 0)
John Kessenichc999ba22013-11-07 23:33:24 +0000643 return 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000644
John Kessenichb0a7eb52013-11-07 17:44:20 +0000645 CompileFile(workItem->name.c_str(), compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000646
John Kessenich94a81fb2013-08-31 02:41:30 +0000647 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000648 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000649
650 ShDestruct(compiler);
651 }
652
653 return 0;
654}
655
John Kessenich6626cad2015-06-19 05:14:19 +0000656// Outputs the given string, but only if it is non-null and non-empty.
657// This prevents erroneous newlines from appearing.
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400658void PutsIfNonEmpty(const char* str)
John Kessenich6626cad2015-06-19 05:14:19 +0000659{
660 if (str && str[0]) {
661 puts(str);
662 }
663}
664
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400665// Outputs the given string to stderr, but only if it is non-null and non-empty.
666// This prevents erroneous newlines from appearing.
667void StderrIfNonEmpty(const char* str)
668{
669 if (str && str[0]) {
670 fprintf(stderr, "%s\n", str);
671 }
672}
673
John Kessenichc57b2a92016-01-16 15:30:03 -0700674// Simple bundling of what makes a compilation unit for ease in passing around,
675// and separation of handling file IO versus API (programmatic) compilation.
676struct ShaderCompUnit {
677 EShLanguage stage;
678 std::string fileName;
679 char** text; // memory owned/managed externally
680};
681
John Kessenich69f4b512013-09-04 21:19:27 +0000682//
John Kessenichc57b2a92016-01-16 15:30:03 -0700683// For linking mode: Will independently parse each compilation unit, but then put them
684// in the same program and link them together, making at most one linked module per
685// pipeline stage.
John Kessenich69f4b512013-09-04 21:19:27 +0000686//
687// Uses the new C++ interface instead of the old handle-based interface.
688//
John Kessenichc57b2a92016-01-16 15:30:03 -0700689
690void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
John Kessenich69f4b512013-09-04 21:19:27 +0000691{
692 // keep track of what to free
693 std::list<glslang::TShader*> shaders;
John Kessenichc57b2a92016-01-16 15:30:03 -0700694
John Kessenich69f4b512013-09-04 21:19:27 +0000695 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000696 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000697
John Kessenich69f4b512013-09-04 21:19:27 +0000698 //
699 // Per-shader processing...
700 //
701
John Kessenich5b0f13a2013-11-01 03:08:40 +0000702 glslang::TProgram& program = *new glslang::TProgram;
rdb32084e82016-02-23 22:17:38 +0100703 for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
704 const auto &compUnit = *it;
John Kessenichc57b2a92016-01-16 15:30:03 -0700705 glslang::TShader* shader = new glslang::TShader(compUnit.stage);
706 shader->setStrings(compUnit.text, 1);
John Kessenich4d65ee32016-03-12 18:17:47 -0700707 if (entryPointName) // HLSL todo: this needs to be tracked per compUnits
708 shader->setEntryPoint(entryPointName);
John Kessenich69f4b512013-09-04 21:19:27 +0000709 shaders.push_back(shader);
John Kessenichb3297152015-07-11 18:01:03 -0600710
John Kessenichc555ddd2015-06-17 02:38:44 +0000711 const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;
John Kessenich69f4b512013-09-04 21:19:27 +0000712
John Kessenichc555ddd2015-06-17 02:38:44 +0000713 if (Options & EOptionOutputPreprocessed) {
714 std::string str;
Dejan Mircevski7be4b822015-06-17 11:40:33 -0400715 if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
716 messages, &str, glslang::TShader::ForbidInclude())) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400717 PutsIfNonEmpty(str.c_str());
718 } else {
719 CompileFailed = true;
720 }
721 StderrIfNonEmpty(shader->getInfoLog());
722 StderrIfNonEmpty(shader->getInfoDebugLog());
John Kessenichc555ddd2015-06-17 02:38:44 +0000723 continue;
724 }
725 if (! shader->parse(&Resources, defaultVersion, false, messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000726 CompileFailed = true;
John Kessenichc555ddd2015-06-17 02:38:44 +0000727
John Kessenich69f4b512013-09-04 21:19:27 +0000728 program.addShader(shader);
729
John Kessenichc57b2a92016-01-16 15:30:03 -0700730 if (! (Options & EOptionSuppressInfolog) &&
731 ! (Options & EOptionMemoryLeakMode)) {
732 PutsIfNonEmpty(compUnit.fileName.c_str());
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400733 PutsIfNonEmpty(shader->getInfoLog());
734 PutsIfNonEmpty(shader->getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000735 }
John Kessenich69f4b512013-09-04 21:19:27 +0000736 }
737
738 //
739 // Program-level processing...
740 //
741
John Kessenich4d65ee32016-03-12 18:17:47 -0700742 // Link
John Kessenich68d78fd2015-07-12 19:28:10 -0600743 if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000744 LinkFailed = true;
745
John Kessenich4d65ee32016-03-12 18:17:47 -0700746 // Report
John Kessenichc57b2a92016-01-16 15:30:03 -0700747 if (! (Options & EOptionSuppressInfolog) &&
748 ! (Options & EOptionMemoryLeakMode)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400749 PutsIfNonEmpty(program.getInfoLog());
750 PutsIfNonEmpty(program.getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000751 }
752
John Kessenich4d65ee32016-03-12 18:17:47 -0700753 // Reflect
John Kessenich11f9fc72013-11-07 01:06:34 +0000754 if (Options & EOptionDumpReflection) {
755 program.buildReflection();
756 program.dumpReflection();
757 }
758
John Kessenich4d65ee32016-03-12 18:17:47 -0700759 // Dump SPIR-V
John Kessenich0df0cde2015-03-03 17:09:43 +0000760 if (Options & EOptionSpv) {
John Kessenich92f90382014-07-28 04:21:04 +0000761 if (CompileFailed || LinkFailed)
John Kessenich68d78fd2015-07-12 19:28:10 -0600762 printf("SPIR-V is not generated for failed compile or link\n");
John Kessenich92f90382014-07-28 04:21:04 +0000763 else {
764 for (int stage = 0; stage < EShLangCount; ++stage) {
John Kessenicha7a68a92014-08-24 18:21:00 +0000765 if (program.getIntermediate((EShLanguage)stage)) {
John Kessenich0df0cde2015-03-03 17:09:43 +0000766 std::vector<unsigned int> spirv;
767 glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
John Kessenichc57b2a92016-01-16 15:30:03 -0700768
769 // Dump the spv to a file or stdout, etc., but only if not doing
770 // memory/perf testing, as it's not internal to programmatic use.
771 if (! (Options & EOptionMemoryLeakMode)) {
772 glslang::OutputSpv(spirv, GetBinaryName((EShLanguage)stage));
773 if (Options & EOptionHumanReadableSpv) {
John Kessenichc57b2a92016-01-16 15:30:03 -0700774 spv::Disassemble(std::cout, spirv);
775 }
John Kessenichacba7722015-03-04 03:48:38 +0000776 }
John Kessenicha7a68a92014-08-24 18:21:00 +0000777 }
John Kessenich92f90382014-07-28 04:21:04 +0000778 }
779 }
780 }
781
John Kessenich5b0f13a2013-11-01 03:08:40 +0000782 // Free everything up, program has to go before the shaders
783 // because it might have merged stuff from the shaders, and
784 // the stuff from the shaders has to have its destructors called
785 // before the pools holding the memory in the shaders is freed.
786 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000787 while (shaders.size() > 0) {
788 delete shaders.back();
789 shaders.pop_back();
790 }
John Kessenich69f4b512013-09-04 21:19:27 +0000791}
792
John Kessenichc57b2a92016-01-16 15:30:03 -0700793//
794// Do file IO part of compile and link, handing off the pure
795// API/programmatic mode to CompileAndLinkShaderUnits(), which can
796// be put in a loop for testing memory footprint and performance.
797//
798// This is just for linking mode: meaning all the shaders will be put into the
799// the same program linked together.
800//
801// This means there are a limited number of work items (not multi-threading mode)
802// and that the point is testing at the linking level. Hence, to enable
803// performance and memory testing, the actual compile/link can be put in
804// a loop, independent of processing the work items and file IO.
805//
806void CompileAndLinkShaderFiles()
807{
808 std::vector<ShaderCompUnit> compUnits;
809
810 // Transfer all the work items from to a simple list of
811 // of compilation units. (We don't care about the thread
812 // work-item distribution properties in this path, which
813 // is okay due to the limited number of shaders, know since
814 // they are all getting linked together.)
815 glslang::TWorkItem* workItem;
816 while (Worklist.remove(workItem)) {
817 ShaderCompUnit compUnit = {
818 FindLanguage(workItem->name),
819 workItem->name,
820 ReadFileData(workItem->name.c_str())
821 };
822
823 if (! compUnit.text) {
824 usage();
825 return;
826 }
827
828 compUnits.push_back(compUnit);
829 }
830
831 // Actual call to programmatic processing of compile and link,
832 // in a loop for testing memory and performance. This part contains
833 // all the perf/memory that a programmatic consumer will care about.
834 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
835 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
836 CompileAndLinkShaderUnits(compUnits);
837
838 if (Options & EOptionMemoryLeakMode)
839 glslang::OS_DumpMemoryCounters();
840 }
841
rdb32084e82016-02-23 22:17:38 +0100842 for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
843 FreeFileData(it->text);
John Kessenichc57b2a92016-01-16 15:30:03 -0700844}
845
John Kessenicha0af4732012-12-12 21:15:54 +0000846int C_DECL main(int argc, char* argv[])
847{
John Kessenich68d78fd2015-07-12 19:28:10 -0600848 ProcessArguments(argc, argv);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000849
John Kessenich05a70632013-09-17 19:26:08 +0000850 if (Options & EOptionDumpConfig) {
851 printf("%s", DefaultConfig);
852 if (Worklist.empty())
853 return ESuccess;
854 }
855
John Kessenich0da9eaa2015-08-01 17:10:02 -0600856 if (Options & EOptionDumpVersions) {
857 printf("Glslang Version: %s %s\n", GLSLANG_REVISION, GLSLANG_DATE);
John Kessenich319de232013-12-04 04:43:40 +0000858 printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
859 printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
John Kessenich68d78fd2015-07-12 19:28:10 -0600860 std::string spirvVersion;
861 glslang::GetSpirvVersion(spirvVersion);
John Kessenich0da9eaa2015-08-01 17:10:02 -0600862 printf("SPIR-V Version %s\n", spirvVersion.c_str());
John Kessenich5e4b1242015-08-06 22:53:06 -0600863 printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
John Kessenich55e7d112015-11-15 21:33:39 -0700864 printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId());
John Kessenich319de232013-12-04 04:43:40 +0000865 if (Worklist.empty())
866 return ESuccess;
867 }
868
John Kessenich05a70632013-09-17 19:26:08 +0000869 if (Worklist.empty()) {
870 usage();
John Kessenich05a70632013-09-17 19:26:08 +0000871 }
872
873 ProcessConfigFile();
874
John Kessenich69f4b512013-09-04 21:19:27 +0000875 //
876 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000877 // 1) linking all arguments together, single-threaded, new C++ interface
878 // 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 +0000879 //
John Kessenichc555ddd2015-06-17 02:38:44 +0000880 if (Options & EOptionLinkProgram ||
881 Options & EOptionOutputPreprocessed) {
John Kessenichc36e1d82013-11-01 17:41:52 +0000882 glslang::InitializeProcess();
John Kessenichc57b2a92016-01-16 15:30:03 -0700883 CompileAndLinkShaderFiles();
John Kessenichc36e1d82013-11-01 17:41:52 +0000884 glslang::FinalizeProcess();
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500885 for (int w = 0; w < NumWorkItems; ++w) {
886 if (Work[w]) {
887 delete Work[w];
888 }
889 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000890 } else {
891 ShInitialize();
892
John Kessenich38f3b892013-09-06 19:52:57 +0000893 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000894
John Kessenich38f3b892013-09-06 19:52:57 +0000895 if (Options & EOptionMultiThreaded) {
896 const int NumThreads = 16;
897 void* threads[NumThreads];
898 for (int t = 0; t < NumThreads; ++t) {
899 threads[t] = glslang::OS_CreateThread(&CompileShaders);
900 if (! threads[t]) {
901 printf("Failed to create thread\n");
902 return EFailThreadCreate;
903 }
John Kessenicha0af4732012-12-12 21:15:54 +0000904 }
John Kessenich38f3b892013-09-06 19:52:57 +0000905 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenichc999ba22013-11-07 23:33:24 +0000906 } else
907 CompileShaders(0);
John Kessenich38f3b892013-09-06 19:52:57 +0000908
909 // Print out all the resulting infologs
910 for (int w = 0; w < NumWorkItems; ++w) {
911 if (Work[w]) {
Kenneth Perryb07e6be2015-12-15 10:52:34 -0600912 if (printShaderNames || Work[w]->results.size() > 0)
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400913 PutsIfNonEmpty(Work[w]->name.c_str());
914 PutsIfNonEmpty(Work[w]->results.c_str());
John Kessenich38f3b892013-09-06 19:52:57 +0000915 delete Work[w];
916 }
917 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000918
919 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000920 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000921
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500922 delete[] Work;
923
John Kessenichc999ba22013-11-07 23:33:24 +0000924 if (CompileFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000925 return EFailCompile;
John Kessenichc999ba22013-11-07 23:33:24 +0000926 if (LinkFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000927 return EFailLink;
928
929 return 0;
930}
931
932//
933// Deduce the language from the filename. Files must end in one of the
934// following extensions:
935//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000936// .vert = vertex
937// .tesc = tessellation control
938// .tese = tessellation evaluation
939// .geom = geometry
940// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000941// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000942//
John Kessenichb603f912013-08-29 00:39:25 +0000943EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000944{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000945 size_t ext = name.rfind('.');
946 if (ext == std::string::npos) {
947 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000948 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000949 }
950
John Kessenich2b07c7e2013-07-31 18:44:13 +0000951 std::string suffix = name.substr(ext + 1, std::string::npos);
952 if (suffix == "vert")
953 return EShLangVertex;
954 else if (suffix == "tesc")
955 return EShLangTessControl;
956 else if (suffix == "tese")
957 return EShLangTessEvaluation;
958 else if (suffix == "geom")
959 return EShLangGeometry;
960 else if (suffix == "frag")
961 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000962 else if (suffix == "comp")
963 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000964
965 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000966 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000967}
968
John Kessenicha0af4732012-12-12 21:15:54 +0000969//
John Kessenich69f4b512013-09-04 21:19:27 +0000970// Read a file's data into a string, and compile it using the old interface ShCompile,
971// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000972//
John Kessenich51cdd902014-02-18 23:37:57 +0000973void CompileFile(const char* fileName, ShHandle compiler)
John Kessenicha0af4732012-12-12 21:15:54 +0000974{
John Kessenichca3457f2015-05-18 01:59:45 +0000975 int ret = 0;
John Kessenich41cf6b52013-06-25 18:10:05 +0000976 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000977 if (! shaderStrings) {
978 usage();
John Kessenichdb4cd542013-06-26 22:42:55 +0000979 }
980
John Kessenich41cf6b52013-06-25 18:10:05 +0000981 int* lengths = new int[NumShaderStrings];
982
983 // move to length-based strings, rather than null-terminated strings
984 for (int s = 0; s < NumShaderStrings; ++s)
John Kessenich35f04bd2014-02-19 02:47:20 +0000985 lengths[s] = (int)strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000986
John Kessenichc999ba22013-11-07 23:33:24 +0000987 if (! shaderStrings) {
988 CompileFailed = true;
989 return;
990 }
John Kessenicha0af4732012-12-12 21:15:54 +0000991
John Kessenich52ac67e2013-05-05 23:46:22 +0000992 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000993 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000994
John Kessenich94a81fb2013-08-31 02:41:30 +0000995 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
996 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich26ad2682014-08-13 20:17:19 +0000997 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichca3457f2015-05-18 01:59:45 +0000998 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +0000999 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
1000 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
1001 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +00001002 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichca3457f2015-05-18 01:59:45 +00001003 //ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +00001004 }
John Kessenicha0af4732012-12-12 21:15:54 +00001005
John Kessenich94a81fb2013-08-31 02:41:30 +00001006 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +00001007 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +00001008 }
John Kessenicha0af4732012-12-12 21:15:54 +00001009
John Kessenich41cf6b52013-06-25 18:10:05 +00001010 delete [] lengths;
1011 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +00001012
John Kessenichc999ba22013-11-07 23:33:24 +00001013 if (ret == 0)
1014 CompileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +00001015}
1016
John Kessenicha0af4732012-12-12 21:15:54 +00001017//
1018// print usage to stdout
1019//
1020void usage()
1021{
John Kessenich319de232013-12-04 04:43:40 +00001022 printf("Usage: glslangValidator [option]... [file]...\n"
1023 "\n"
John Kessenich0df0cde2015-03-03 17:09:43 +00001024 "Where: each 'file' ends in .<stage>, where <stage> is one of\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001025 " .conf to provide an optional config file that replaces the default configuration\n"
1026 " (see -c option below for generating a template)\n"
1027 " .vert for a vertex shader\n"
1028 " .tesc for a tessellation control shader\n"
1029 " .tese for a tessellation evaluation shader\n"
1030 " .geom for a geometry shader\n"
1031 " .frag for a fragment shader\n"
1032 " .comp for a compute shader\n"
John Kessenich319de232013-12-04 04:43:40 +00001033 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +00001034 "Compilation warnings and errors will be printed to stdout.\n"
John Kessenich319de232013-12-04 04:43:40 +00001035 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +00001036 "To get other information, use one of the following options:\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001037 "Each option must be specified separately.\n"
1038 " -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
1039 " default file name is <stage>.spv (-o overrides this)\n"
1040 " (unless -o is specified, which overrides the default file name)\n"
1041 " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
1042 " default file name is <stage>.spv (-o overrides this)\n"
1043 " -H print human readable form of SPIR-V; turns on -V\n"
Andrew Woloszynaae1ad82015-06-24 17:00:46 -04001044 " -E print pre-processed GLSL; cannot be used with -l;\n"
1045 " errors will appear on stderr.\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001046 " -c configuration dump;\n"
1047 " creates the default configuration file (redirect to a .conf file)\n"
1048 " -d default to desktop (#version 110) when there is no shader #version\n"
1049 " (default is ES version 100)\n"
John Kessenich4d65ee32016-03-12 18:17:47 -07001050 " -e specify entry-point name\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001051 " -h print this usage message\n"
1052 " -i intermediate tree (glslang AST) is printed out\n"
1053 " -l link all input files together to form a single module\n"
1054 " -m memory leak mode\n"
1055 " -o <file> save binary into <file>, requires a binary option (e.g., -V)\n"
1056 " -q dump reflection query database\n"
1057 " -r relaxed semantic error-checking mode\n"
1058 " -s silent mode\n"
1059 " -t multi-threaded mode\n"
1060 " -v print version strings\n"
1061 " -w suppress warnings (except as required by #extension : warn)\n"
John Kessenichb0a7eb52013-11-07 17:44:20 +00001062 );
John Kessenich68d78fd2015-07-12 19:28:10 -06001063
1064 exit(EFailUsage);
John Kessenicha0af4732012-12-12 21:15:54 +00001065}
1066
John Kessenich3ce4e592014-10-06 19:57:34 +00001067#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
John Kessenichcfd643e2013-03-08 23:14:42 +00001068
1069#include <errno.h>
1070
1071int fopen_s(
1072 FILE** pFile,
John Kessenich51cdd902014-02-18 23:37:57 +00001073 const char* filename,
1074 const char* mode
John Kessenichcfd643e2013-03-08 23:14:42 +00001075)
1076{
1077 if (!pFile || !filename || !mode) {
1078 return EINVAL;
1079 }
1080
1081 FILE* f = fopen(filename, mode);
1082 if (! f) {
1083 if (errno != 0) {
1084 return errno;
1085 } else {
1086 return ENOENT;
1087 }
1088 }
1089 *pFile = f;
1090
1091 return 0;
1092}
1093
1094#endif
1095
John Kessenicha0af4732012-12-12 21:15:54 +00001096//
1097// Malloc a string of sufficient size and read a string into it.
1098//
John Kessenich51cdd902014-02-18 23:37:57 +00001099char** ReadFileData(const char* fileName)
John Kessenicha0af4732012-12-12 21:15:54 +00001100{
John Kessenichb3297152015-07-11 18:01:03 -06001101 FILE *in = nullptr;
John Kessenich3ce4e592014-10-06 19:57:34 +00001102 int errorCode = fopen_s(&in, fileName, "r");
John Kessenichd6c72a42014-08-18 19:42:35 +00001103
John Kessenicha0af4732012-12-12 21:15:54 +00001104 int count = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001105 const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
1106 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001107
John Kessenich68d78fd2015-07-12 19:28:10 -06001108 if (errorCode || in == nullptr)
1109 Error("unable to open input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001110
1111 while (fgetc(in) != EOF)
1112 count++;
1113
John Kessenichd6c72a42014-08-18 19:42:35 +00001114 fseek(in, 0, SEEK_SET);
John Kessenichca3457f2015-05-18 01:59:45 +00001115
John Kessenichb3297152015-07-11 18:01:03 -06001116 char *fdata = (char*)malloc(count+2); // freed before return of this function
John Kessenich68d78fd2015-07-12 19:28:10 -06001117 if (! fdata)
1118 Error("can't allocate memory");
1119
John Kessenichb3297152015-07-11 18:01:03 -06001120 if ((int)fread(fdata, 1, count, in) != count) {
John Kessenichb3297152015-07-11 18:01:03 -06001121 free(fdata);
John Kessenich68d78fd2015-07-12 19:28:10 -06001122 Error("can't read input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001123 }
John Kessenich68d78fd2015-07-12 19:28:10 -06001124
John Kessenicha0af4732012-12-12 21:15:54 +00001125 fdata[count] = '\0';
1126 fclose(in);
John Kessenichb3297152015-07-11 18:01:03 -06001127
John Kessenichea869fb2013-10-28 18:12:06 +00001128 if (count == 0) {
John Kessenichb3297152015-07-11 18:01:03 -06001129 // recover from empty file
1130 return_data[0] = (char*)malloc(count+2); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001131 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +00001132 NumShaderStrings = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001133 free(fdata);
John Kessenicha0af4732012-12-12 21:15:54 +00001134
John Kessenichb3297152015-07-11 18:01:03 -06001135 return return_data;
1136 } else
1137 NumShaderStrings = 1; // Set to larger than 1 for testing multiple strings
1138
1139 // compute how to split up the file into multiple strings, for testing multiple strings
John Kessenichd6c72a42014-08-18 19:42:35 +00001140 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenichb3297152015-07-11 18:01:03 -06001141 int ptr_len = 0;
1142 int i = 0;
1143 while (count > 0) {
1144 return_data[i] = (char*)malloc(len + 2); // freed in FreeFileData()
1145 memcpy(return_data[i], fdata + ptr_len, len);
1146 return_data[i][len] = '\0';
1147 count -= len;
1148 ptr_len += len;
1149 if (count < len) {
1150 if (count == 0) {
1151 NumShaderStrings = i + 1;
John Kessenicha0af4732012-12-12 21:15:54 +00001152 break;
1153 }
John Kessenichb3297152015-07-11 18:01:03 -06001154 len = count;
John Kessenichd6c72a42014-08-18 19:42:35 +00001155 }
1156 ++i;
1157 }
John Kessenichb3297152015-07-11 18:01:03 -06001158
1159 free(fdata);
1160
John Kessenicha0af4732012-12-12 21:15:54 +00001161 return return_data;
1162}
1163
John Kessenich51cdd902014-02-18 23:37:57 +00001164void FreeFileData(char** data)
John Kessenicha0af4732012-12-12 21:15:54 +00001165{
John Kessenichb3297152015-07-11 18:01:03 -06001166 for(int i = 0; i < NumShaderStrings; i++)
John Kessenicha0af4732012-12-12 21:15:54 +00001167 free(data[i]);
John Kessenichb3297152015-07-11 18:01:03 -06001168
1169 free(data);
John Kessenicha0af4732012-12-12 21:15:54 +00001170}
1171
John Kessenich54d8cda2013-02-11 22:36:01 +00001172void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +00001173{
John Kessenichfae38ee2015-06-10 23:23:12 +00001174 if (num >= 0 )
1175 printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
1176 else
1177 printf("#### %s %s INFO LOG ####\n", msg, name);
John Kessenicha0af4732012-12-12 21:15:54 +00001178}