blob: 2e0db6d417574bad446be9f8115a964634a37afd [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 Kessenich66e2faf2016-03-12 18:34:36 -070077 EOptionReadHlsl = 0x10000,
John Kessenich94a81fb2013-08-31 02:41:30 +000078};
79
John Kessenicha0af4732012-12-12 21:15:54 +000080//
John Kessenich68d78fd2015-07-12 19:28:10 -060081// Return codes from main/exit().
John Kessenicha0af4732012-12-12 21:15:54 +000082//
83enum TFailCode {
84 ESuccess = 0,
85 EFailUsage,
86 EFailCompile,
87 EFailLink,
88 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000089 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000090 EFailLinkerCreate
91};
92
93//
John Kessenich68d78fd2015-07-12 19:28:10 -060094// Forward declarations.
John Kessenicha0af4732012-12-12 21:15:54 +000095//
John Kessenichb603f912013-08-29 00:39:25 +000096EShLanguage FindLanguage(const std::string& name);
John Kessenich51cdd902014-02-18 23:37:57 +000097void CompileFile(const char* fileName, ShHandle);
John Kessenicha0af4732012-12-12 21:15:54 +000098void usage();
John Kessenichea869fb2013-10-28 18:12:06 +000099void FreeFileData(char** data);
100char** ReadFileData(const char* fileName);
John Kessenich54d8cda2013-02-11 22:36:01 +0000101void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +0000102
John Kessenichc999ba22013-11-07 23:33:24 +0000103// Globally track if any compile or link failure.
104bool CompileFailed = false;
105bool LinkFailed = false;
106
John Kessenich05a70632013-09-17 19:26:08 +0000107// Use to test breaking up a single shader file into multiple strings.
John Kessenich68d78fd2015-07-12 19:28:10 -0600108// Set in ReadFileData().
John Kessenichea869fb2013-10-28 18:12:06 +0000109int NumShaderStrings;
John Kessenicha0af4732012-12-12 21:15:54 +0000110
John Kessenich05a70632013-09-17 19:26:08 +0000111TBuiltInResource Resources;
112std::string ConfigFile;
113
John Kessenicha0af4732012-12-12 21:15:54 +0000114//
John Kessenich05a70632013-09-17 19:26:08 +0000115// These are the default resources for TBuiltInResources, used for both
116// - parsing this string for the case where the user didn't supply one
117// - dumping out a template for user construction of a config file
John Kessenicha0af4732012-12-12 21:15:54 +0000118//
John Kessenich284231c2013-10-22 01:50:39 +0000119const char* DefaultConfig =
120 "MaxLights 32\n"
121 "MaxClipPlanes 6\n"
122 "MaxTextureUnits 32\n"
123 "MaxTextureCoords 32\n"
124 "MaxVertexAttribs 64\n"
125 "MaxVertexUniformComponents 4096\n"
126 "MaxVaryingFloats 64\n"
127 "MaxVertexTextureImageUnits 32\n"
John Kessenich623833f2013-12-11 18:57:40 +0000128 "MaxCombinedTextureImageUnits 80\n"
John Kessenich284231c2013-10-22 01:50:39 +0000129 "MaxTextureImageUnits 32\n"
130 "MaxFragmentUniformComponents 4096\n"
131 "MaxDrawBuffers 32\n"
132 "MaxVertexUniformVectors 128\n"
133 "MaxVaryingVectors 8\n"
134 "MaxFragmentUniformVectors 16\n"
135 "MaxVertexOutputVectors 16\n"
136 "MaxFragmentInputVectors 15\n"
137 "MinProgramTexelOffset -8\n"
138 "MaxProgramTexelOffset 7\n"
139 "MaxClipDistances 8\n"
140 "MaxComputeWorkGroupCountX 65535\n"
141 "MaxComputeWorkGroupCountY 65535\n"
142 "MaxComputeWorkGroupCountZ 65535\n"
143 "MaxComputeWorkGroupSizeX 1024\n"
John Kessenichda66bc72014-08-19 20:32:48 +0000144 "MaxComputeWorkGroupSizeY 1024\n"
John Kessenich284231c2013-10-22 01:50:39 +0000145 "MaxComputeWorkGroupSizeZ 64\n"
146 "MaxComputeUniformComponents 1024\n"
147 "MaxComputeTextureImageUnits 16\n"
148 "MaxComputeImageUniforms 8\n"
149 "MaxComputeAtomicCounters 8\n"
150 "MaxComputeAtomicCounterBuffers 1\n"
151 "MaxVaryingComponents 60\n"
152 "MaxVertexOutputComponents 64\n"
153 "MaxGeometryInputComponents 64\n"
154 "MaxGeometryOutputComponents 128\n"
155 "MaxFragmentInputComponents 128\n"
156 "MaxImageUnits 8\n"
157 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
John Kessenichddea6782014-08-10 18:19:36 +0000158 "MaxCombinedShaderOutputResources 8\n"
John Kessenich284231c2013-10-22 01:50:39 +0000159 "MaxImageSamples 0\n"
160 "MaxVertexImageUniforms 0\n"
161 "MaxTessControlImageUniforms 0\n"
162 "MaxTessEvaluationImageUniforms 0\n"
163 "MaxGeometryImageUniforms 0\n"
164 "MaxFragmentImageUniforms 8\n"
165 "MaxCombinedImageUniforms 8\n"
166 "MaxGeometryTextureImageUnits 16\n"
167 "MaxGeometryOutputVertices 256\n"
168 "MaxGeometryTotalOutputComponents 1024\n"
169 "MaxGeometryUniformComponents 1024\n"
170 "MaxGeometryVaryingComponents 64\n"
171 "MaxTessControlInputComponents 128\n"
172 "MaxTessControlOutputComponents 128\n"
173 "MaxTessControlTextureImageUnits 16\n"
174 "MaxTessControlUniformComponents 1024\n"
175 "MaxTessControlTotalOutputComponents 4096\n"
176 "MaxTessEvaluationInputComponents 128\n"
177 "MaxTessEvaluationOutputComponents 128\n"
178 "MaxTessEvaluationTextureImageUnits 16\n"
179 "MaxTessEvaluationUniformComponents 1024\n"
180 "MaxTessPatchComponents 120\n"
181 "MaxPatchVertices 32\n"
182 "MaxTessGenLevel 64\n"
183 "MaxViewports 16\n"
184 "MaxVertexAtomicCounters 0\n"
185 "MaxTessControlAtomicCounters 0\n"
186 "MaxTessEvaluationAtomicCounters 0\n"
187 "MaxGeometryAtomicCounters 0\n"
188 "MaxFragmentAtomicCounters 8\n"
189 "MaxCombinedAtomicCounters 8\n"
190 "MaxAtomicCounterBindings 1\n"
191 "MaxVertexAtomicCounterBuffers 0\n"
192 "MaxTessControlAtomicCounterBuffers 0\n"
193 "MaxTessEvaluationAtomicCounterBuffers 0\n"
194 "MaxGeometryAtomicCounterBuffers 0\n"
195 "MaxFragmentAtomicCounterBuffers 1\n"
196 "MaxCombinedAtomicCounterBuffers 1\n"
197 "MaxAtomicCounterBufferSize 16384\n"
John Kessenichc7776ec2014-01-26 01:37:13 +0000198 "MaxTransformFeedbackBuffers 4\n"
199 "MaxTransformFeedbackInterleavedComponents 64\n"
John Kessenich69968412014-08-13 06:37:59 +0000200 "MaxCullDistances 8\n"
201 "MaxCombinedClipAndCullDistances 8\n"
John Kessenichcd77f8e2014-08-13 16:54:02 +0000202 "MaxSamples 4\n"
John Kessenich284231c2013-10-22 01:50:39 +0000203
204 "nonInductiveForLoops 1\n"
205 "whileLoops 1\n"
206 "doWhileLoops 1\n"
207 "generalUniformIndexing 1\n"
208 "generalAttributeMatrixVectorIndexing 1\n"
209 "generalVaryingIndexing 1\n"
210 "generalSamplerIndexing 1\n"
211 "generalVariableIndexing 1\n"
212 "generalConstantMatrixVectorIndexing 1\n"
213 ;
John Kessenich05a70632013-09-17 19:26:08 +0000214
215//
216// Parse either a .conf file provided by the user or the default string above.
217//
218void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000219{
John Kessenich05a70632013-09-17 19:26:08 +0000220 char** configStrings = 0;
John Kessenich51cdd902014-02-18 23:37:57 +0000221 char* config = 0;
John Kessenich05a70632013-09-17 19:26:08 +0000222 if (ConfigFile.size() > 0) {
John Kessenichea869fb2013-10-28 18:12:06 +0000223 configStrings = ReadFileData(ConfigFile.c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000224 if (configStrings)
225 config = *configStrings;
226 else {
227 printf("Error opening configuration file; will instead use the default configuration\n");
228 usage();
229 }
230 }
231
232 if (config == 0) {
John Kessenich6494baf2014-02-19 00:08:59 +0000233 config = new char[strlen(DefaultConfig) + 1];
John Kessenich05a70632013-09-17 19:26:08 +0000234 strcpy(config, DefaultConfig);
235 }
236
237 const char* delims = " \t\n\r";
238 const char* token = strtok(config, delims);
239 while (token) {
240 const char* valueStr = strtok(0, delims);
241 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
242 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
243 return;
244 }
245 int value = atoi(valueStr);
246
247 if (strcmp(token, "MaxLights") == 0)
248 Resources.maxLights = value;
249 else if (strcmp(token, "MaxClipPlanes") == 0)
250 Resources.maxClipPlanes = value;
251 else if (strcmp(token, "MaxTextureUnits") == 0)
252 Resources.maxTextureUnits = value;
253 else if (strcmp(token, "MaxTextureCoords") == 0)
254 Resources.maxTextureCoords = value;
255 else if (strcmp(token, "MaxVertexAttribs") == 0)
256 Resources.maxVertexAttribs = value;
257 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
258 Resources.maxVertexUniformComponents = value;
259 else if (strcmp(token, "MaxVaryingFloats") == 0)
260 Resources.maxVaryingFloats = value;
261 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
262 Resources.maxVertexTextureImageUnits = value;
263 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
264 Resources.maxCombinedTextureImageUnits = value;
265 else if (strcmp(token, "MaxTextureImageUnits") == 0)
266 Resources.maxTextureImageUnits = value;
267 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
268 Resources.maxFragmentUniformComponents = value;
269 else if (strcmp(token, "MaxDrawBuffers") == 0)
270 Resources.maxDrawBuffers = value;
271 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
272 Resources.maxVertexUniformVectors = value;
273 else if (strcmp(token, "MaxVaryingVectors") == 0)
274 Resources.maxVaryingVectors = value;
275 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
276 Resources.maxFragmentUniformVectors = value;
277 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
278 Resources.maxVertexOutputVectors = value;
279 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
280 Resources.maxFragmentInputVectors = value;
281 else if (strcmp(token, "MinProgramTexelOffset") == 0)
282 Resources.minProgramTexelOffset = value;
283 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
284 Resources.maxProgramTexelOffset = value;
John Kesseniche7c59c12013-10-16 22:28:35 +0000285 else if (strcmp(token, "MaxClipDistances") == 0)
286 Resources.maxClipDistances = value;
John Kessenich284231c2013-10-22 01:50:39 +0000287 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
288 Resources.maxComputeWorkGroupCountX = value;
289 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
290 Resources.maxComputeWorkGroupCountY = value;
291 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
292 Resources.maxComputeWorkGroupCountZ = value;
293 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
294 Resources.maxComputeWorkGroupSizeX = value;
295 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
296 Resources.maxComputeWorkGroupSizeY = value;
297 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
298 Resources.maxComputeWorkGroupSizeZ = value;
299 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
300 Resources.maxComputeUniformComponents = value;
301 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
302 Resources.maxComputeTextureImageUnits = value;
303 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
304 Resources.maxComputeImageUniforms = value;
305 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
306 Resources.maxComputeAtomicCounters = value;
307 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
308 Resources.maxComputeAtomicCounterBuffers = value;
309 else if (strcmp(token, "MaxVaryingComponents") == 0)
310 Resources.maxVaryingComponents = value;
311 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
312 Resources.maxVertexOutputComponents = value;
313 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
314 Resources.maxGeometryInputComponents = value;
315 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
316 Resources.maxGeometryOutputComponents = value;
317 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
318 Resources.maxFragmentInputComponents = value;
319 else if (strcmp(token, "MaxImageUnits") == 0)
320 Resources.maxImageUnits = value;
321 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
322 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
John Kessenichddea6782014-08-10 18:19:36 +0000323 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
324 Resources.maxCombinedShaderOutputResources = value;
John Kessenich284231c2013-10-22 01:50:39 +0000325 else if (strcmp(token, "MaxImageSamples") == 0)
326 Resources.maxImageSamples = value;
327 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
328 Resources.maxVertexImageUniforms = value;
329 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
330 Resources.maxTessControlImageUniforms = value;
331 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
332 Resources.maxTessEvaluationImageUniforms = value;
333 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
334 Resources.maxGeometryImageUniforms = value;
335 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
336 Resources.maxFragmentImageUniforms = value;
337 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
338 Resources.maxCombinedImageUniforms = value;
339 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
340 Resources.maxGeometryTextureImageUnits = value;
341 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
342 Resources.maxGeometryOutputVertices = value;
343 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
344 Resources.maxGeometryTotalOutputComponents = value;
345 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
346 Resources.maxGeometryUniformComponents = value;
347 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
348 Resources.maxGeometryVaryingComponents = value;
349 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
350 Resources.maxTessControlInputComponents = value;
351 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
352 Resources.maxTessControlOutputComponents = value;
353 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
354 Resources.maxTessControlTextureImageUnits = value;
355 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
356 Resources.maxTessControlUniformComponents = value;
357 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
358 Resources.maxTessControlTotalOutputComponents = value;
359 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
360 Resources.maxTessEvaluationInputComponents = value;
361 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
362 Resources.maxTessEvaluationOutputComponents = value;
363 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
364 Resources.maxTessEvaluationTextureImageUnits = value;
365 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
366 Resources.maxTessEvaluationUniformComponents = value;
367 else if (strcmp(token, "MaxTessPatchComponents") == 0)
368 Resources.maxTessPatchComponents = value;
369 else if (strcmp(token, "MaxPatchVertices") == 0)
370 Resources.maxPatchVertices = value;
371 else if (strcmp(token, "MaxTessGenLevel") == 0)
372 Resources.maxTessGenLevel = value;
373 else if (strcmp(token, "MaxViewports") == 0)
374 Resources.maxViewports = value;
375 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
376 Resources.maxVertexAtomicCounters = value;
377 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
378 Resources.maxTessControlAtomicCounters = value;
379 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
380 Resources.maxTessEvaluationAtomicCounters = value;
381 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
382 Resources.maxGeometryAtomicCounters = value;
383 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
384 Resources.maxFragmentAtomicCounters = value;
385 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
386 Resources.maxCombinedAtomicCounters = value;
387 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
388 Resources.maxAtomicCounterBindings = value;
389 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
390 Resources.maxVertexAtomicCounterBuffers = value;
391 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
392 Resources.maxTessControlAtomicCounterBuffers = value;
393 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
394 Resources.maxTessEvaluationAtomicCounterBuffers = value;
395 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
396 Resources.maxGeometryAtomicCounterBuffers = value;
397 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
398 Resources.maxFragmentAtomicCounterBuffers = value;
399 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
400 Resources.maxCombinedAtomicCounterBuffers = value;
401 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
402 Resources.maxAtomicCounterBufferSize = value;
John Kessenichc7776ec2014-01-26 01:37:13 +0000403 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
404 Resources.maxTransformFeedbackBuffers = value;
405 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
406 Resources.maxTransformFeedbackInterleavedComponents = value;
John Kessenich69968412014-08-13 06:37:59 +0000407 else if (strcmp(token, "MaxCullDistances") == 0)
408 Resources.maxCullDistances = value;
409 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
410 Resources.maxCombinedClipAndCullDistances = value;
John Kessenichcd77f8e2014-08-13 16:54:02 +0000411 else if (strcmp(token, "MaxSamples") == 0)
412 Resources.maxSamples = value;
John Kessenich284231c2013-10-22 01:50:39 +0000413
John Kessenicha5830df2013-10-02 05:10:48 +0000414 else if (strcmp(token, "nonInductiveForLoops") == 0)
415 Resources.limits.nonInductiveForLoops = (value != 0);
416 else if (strcmp(token, "whileLoops") == 0)
417 Resources.limits.whileLoops = (value != 0);
418 else if (strcmp(token, "doWhileLoops") == 0)
419 Resources.limits.doWhileLoops = (value != 0);
420 else if (strcmp(token, "generalUniformIndexing") == 0)
421 Resources.limits.generalUniformIndexing = (value != 0);
422 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
423 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
424 else if (strcmp(token, "generalVaryingIndexing") == 0)
425 Resources.limits.generalVaryingIndexing = (value != 0);
426 else if (strcmp(token, "generalSamplerIndexing") == 0)
427 Resources.limits.generalSamplerIndexing = (value != 0);
428 else if (strcmp(token, "generalVariableIndexing") == 0)
429 Resources.limits.generalVariableIndexing = (value != 0);
430 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
431 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000432 else
433 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
434
435 token = strtok(0, delims);
436 }
437 if (configStrings)
438 FreeFileData(configStrings);
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500439 else
440 delete[] config;
John Kessenicha0af4732012-12-12 21:15:54 +0000441}
442
John Kessenich38f3b892013-09-06 19:52:57 +0000443// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000444glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000445
446// array of unique places to leave the shader names and infologs for the asynchronous compiles
John Kessenichfd305422014-06-05 16:30:53 +0000447glslang::TWorkItem** Work = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000448int NumWorkItems = 0;
449
John Kessenich94a81fb2013-08-31 02:41:30 +0000450int Options = 0;
John Kessenich68d78fd2015-07-12 19:28:10 -0600451const char* ExecutableName = nullptr;
452const char* binaryFileName = nullptr;
John Kessenich4d65ee32016-03-12 18:17:47 -0700453const char* entryPointName = nullptr;
John Kessenich68d78fd2015-07-12 19:28:10 -0600454
455//
456// Create the default name for saving a binary if -o is not provided.
457//
458const char* GetBinaryName(EShLanguage stage)
459{
460 const char* name;
461 if (binaryFileName == nullptr) {
462 switch (stage) {
463 case EShLangVertex: name = "vert.spv"; break;
464 case EShLangTessControl: name = "tesc.spv"; break;
465 case EShLangTessEvaluation: name = "tese.spv"; break;
466 case EShLangGeometry: name = "geom.spv"; break;
467 case EShLangFragment: name = "frag.spv"; break;
468 case EShLangCompute: name = "comp.spv"; break;
469 default: name = "unknown"; break;
470 }
471 } else
472 name = binaryFileName;
473
474 return name;
475}
John Kessenich2b07c7e2013-07-31 18:44:13 +0000476
John Kessenich05a70632013-09-17 19:26:08 +0000477//
478// *.conf => this is a config file that can set limits/resources
479//
480bool SetConfigFile(const std::string& name)
481{
482 if (name.size() < 5)
483 return false;
484
John Kessenich4c706852013-10-11 16:28:43 +0000485 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000486 ConfigFile = name;
487 return true;
488 }
489
490 return false;
491}
492
John Kessenich68d78fd2015-07-12 19:28:10 -0600493//
494// Give error and exit with failure code.
495//
496void Error(const char* message)
497{
498 printf("%s: Error %s (use -h for usage)\n", ExecutableName, message);
499 exit(EFailUsage);
500}
501
502//
503// Do all command-line argument parsing. This includes building up the work-items
504// to be processed later, and saving all the command-line options.
505//
506// Does not return (it exits) if command-line is fatally flawed.
507//
508void ProcessArguments(int argc, char* argv[])
John Kessenich2b07c7e2013-07-31 18:44:13 +0000509{
John Kessenich38f3b892013-09-06 19:52:57 +0000510 ExecutableName = argv[0];
511 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 +0000512 Work = new glslang::TWorkItem*[NumWorkItems];
John Kessenich68d78fd2015-07-12 19:28:10 -0600513 for (int w = 0; w < NumWorkItems; ++w)
514 Work[w] = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000515
John Kessenich2b07c7e2013-07-31 18:44:13 +0000516 argc--;
517 argv++;
518 for (; argc >= 1; argc--, argv++) {
519 if (argv[0][0] == '-') {
John Kessenich2aa7f3a2015-05-15 16:02:07 +0000520 switch (argv[0][1]) {
521 case 'H':
522 Options |= EOptionHumanReadableSpv;
523 // fall through to -V
John Kessenich0df0cde2015-03-03 17:09:43 +0000524 case 'V':
525 Options |= EOptionSpv;
John Kessenich68d78fd2015-07-12 19:28:10 -0600526 Options |= EOptionVulkanRules;
527 Options |= EOptionLinkProgram;
528 break;
529 case 'G':
530 Options |= EOptionSpv;
John Kessenichd78e3512014-08-25 20:07:55 +0000531 Options |= EOptionLinkProgram;
John Kessenich92f90382014-07-28 04:21:04 +0000532 break;
John Kessenichc555ddd2015-06-17 02:38:44 +0000533 case 'E':
534 Options |= EOptionOutputPreprocessed;
535 break;
John Kessenich05a70632013-09-17 19:26:08 +0000536 case 'c':
537 Options |= EOptionDumpConfig;
538 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000539 case 'd':
John Kessenich26ad2682014-08-13 20:17:19 +0000540 Options |= EOptionDefaultDesktop;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000541 break;
John Kessenich66e2faf2016-03-12 18:34:36 -0700542 case 'D':
543 Options |= EOptionReadHlsl;
544 break;
John Kessenich4d65ee32016-03-12 18:17:47 -0700545 case 'e':
546 // HLSL todo: entry point handle needs much more sophistication.
547 // This is okay for one compilation unit with one entry point.
548 entryPointName = argv[1];
549 if (argc > 0) {
550 argc--;
551 argv++;
552 } else
553 Error("no <entry-point> provided for -e");
554 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600555 case 'h':
556 usage();
557 break;
John Kessenich05a70632013-09-17 19:26:08 +0000558 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000559 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000560 break;
561 case 'l':
John Kessenichd78e3512014-08-25 20:07:55 +0000562 Options |= EOptionLinkProgram;
John Kessenich94a81fb2013-08-31 02:41:30 +0000563 break;
564 case 'm':
565 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000566 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600567 case 'o':
568 binaryFileName = argv[1];
569 if (argc > 0) {
570 argc--;
571 argv++;
572 } else
573 Error("no <file> provided for -o");
574 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000575 case 'q':
576 Options |= EOptionDumpReflection;
577 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000578 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000579 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000580 break;
581 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000582 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000583 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000584 case 't':
585 #ifdef _WIN32
John Kessenichb0a7eb52013-11-07 17:44:20 +0000586 Options |= EOptionMultiThreaded;
John Kessenich38f3b892013-09-06 19:52:57 +0000587 #endif
588 break;
John Kessenich319de232013-12-04 04:43:40 +0000589 case 'v':
590 Options |= EOptionDumpVersions;
591 break;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000592 case 'w':
593 Options |= EOptionSuppressWarnings;
594 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000595 default:
John Kessenich68d78fd2015-07-12 19:28:10 -0600596 usage();
597 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000598 }
John Kessenich38f3b892013-09-06 19:52:57 +0000599 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000600 std::string name(argv[0]);
601 if (! SetConfigFile(name)) {
602 Work[argc] = new glslang::TWorkItem(name);
603 Worklist.add(Work[argc]);
604 }
John Kessenich38f3b892013-09-06 19:52:57 +0000605 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000606 }
607
John Kessenich68d78fd2015-07-12 19:28:10 -0600608 // Make sure that -E is not specified alongside linking (which includes SPV generation)
609 if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
610 Error("can't use -E when linking is selected");
John Kessenichc555ddd2015-06-17 02:38:44 +0000611
John Kessenich68d78fd2015-07-12 19:28:10 -0600612 // -o makes no sense if there is no target binary
613 if (binaryFileName && (Options & EOptionSpv) == 0)
614 Error("no binary generation requested (e.g., -V)");
John Kessenich2b07c7e2013-07-31 18:44:13 +0000615}
616
John Kessenich68d78fd2015-07-12 19:28:10 -0600617//
618// Translate the meaningful subset of command-line options to parser-behavior options.
619//
John Kessenichb0a7eb52013-11-07 17:44:20 +0000620void SetMessageOptions(EShMessages& messages)
621{
622 if (Options & EOptionRelaxedErrors)
623 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
624 if (Options & EOptionIntermediate)
625 messages = (EShMessages)(messages | EShMsgAST);
626 if (Options & EOptionSuppressWarnings)
627 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
John Kessenich68d78fd2015-07-12 19:28:10 -0600628 if (Options & EOptionSpv)
629 messages = (EShMessages)(messages | EShMsgSpvRules);
630 if (Options & EOptionVulkanRules)
631 messages = (EShMessages)(messages | EShMsgVulkanRules);
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400632 if (Options & EOptionOutputPreprocessed)
633 messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
John Kessenich66e2faf2016-03-12 18:34:36 -0700634 if (Options & EOptionReadHlsl)
635 messages = (EShMessages)(messages | EShMsgReadHlsl);
John Kessenichb0a7eb52013-11-07 17:44:20 +0000636}
637
John Kessenich68d78fd2015-07-12 19:28:10 -0600638//
John Kessenich69f4b512013-09-04 21:19:27 +0000639// Thread entry point, for non-linking asynchronous mode.
John Kessenichc999ba22013-11-07 23:33:24 +0000640//
641// Return 0 for failure, 1 for success.
642//
Pyry Haulos5f6892e2015-12-01 12:59:53 -0800643unsigned int CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000644{
John Kessenich38f3b892013-09-06 19:52:57 +0000645 glslang::TWorkItem* workItem;
646 while (Worklist.remove(workItem)) {
647 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000648 if (compiler == 0)
John Kessenichc999ba22013-11-07 23:33:24 +0000649 return 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000650
John Kessenichb0a7eb52013-11-07 17:44:20 +0000651 CompileFile(workItem->name.c_str(), compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000652
John Kessenich94a81fb2013-08-31 02:41:30 +0000653 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000654 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000655
656 ShDestruct(compiler);
657 }
658
659 return 0;
660}
661
John Kessenich6626cad2015-06-19 05:14:19 +0000662// Outputs the given string, but only if it is non-null and non-empty.
663// This prevents erroneous newlines from appearing.
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400664void PutsIfNonEmpty(const char* str)
John Kessenich6626cad2015-06-19 05:14:19 +0000665{
666 if (str && str[0]) {
667 puts(str);
668 }
669}
670
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400671// Outputs the given string to stderr, but only if it is non-null and non-empty.
672// This prevents erroneous newlines from appearing.
673void StderrIfNonEmpty(const char* str)
674{
675 if (str && str[0]) {
676 fprintf(stderr, "%s\n", str);
677 }
678}
679
John Kessenichc57b2a92016-01-16 15:30:03 -0700680// Simple bundling of what makes a compilation unit for ease in passing around,
681// and separation of handling file IO versus API (programmatic) compilation.
682struct ShaderCompUnit {
683 EShLanguage stage;
684 std::string fileName;
685 char** text; // memory owned/managed externally
686};
687
John Kessenich69f4b512013-09-04 21:19:27 +0000688//
John Kessenichc57b2a92016-01-16 15:30:03 -0700689// For linking mode: Will independently parse each compilation unit, but then put them
690// in the same program and link them together, making at most one linked module per
691// pipeline stage.
John Kessenich69f4b512013-09-04 21:19:27 +0000692//
693// Uses the new C++ interface instead of the old handle-based interface.
694//
John Kessenichc57b2a92016-01-16 15:30:03 -0700695
696void CompileAndLinkShaderUnits(std::vector<ShaderCompUnit> compUnits)
John Kessenich69f4b512013-09-04 21:19:27 +0000697{
698 // keep track of what to free
699 std::list<glslang::TShader*> shaders;
John Kessenichc57b2a92016-01-16 15:30:03 -0700700
John Kessenich69f4b512013-09-04 21:19:27 +0000701 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000702 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000703
John Kessenich69f4b512013-09-04 21:19:27 +0000704 //
705 // Per-shader processing...
706 //
707
John Kessenich5b0f13a2013-11-01 03:08:40 +0000708 glslang::TProgram& program = *new glslang::TProgram;
rdb32084e82016-02-23 22:17:38 +0100709 for (auto it = compUnits.cbegin(); it != compUnits.cend(); ++it) {
710 const auto &compUnit = *it;
John Kessenichc57b2a92016-01-16 15:30:03 -0700711 glslang::TShader* shader = new glslang::TShader(compUnit.stage);
712 shader->setStrings(compUnit.text, 1);
John Kessenich4d65ee32016-03-12 18:17:47 -0700713 if (entryPointName) // HLSL todo: this needs to be tracked per compUnits
714 shader->setEntryPoint(entryPointName);
John Kessenich69f4b512013-09-04 21:19:27 +0000715 shaders.push_back(shader);
John Kessenichb3297152015-07-11 18:01:03 -0600716
John Kessenichc555ddd2015-06-17 02:38:44 +0000717 const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;
John Kessenich69f4b512013-09-04 21:19:27 +0000718
John Kessenichc555ddd2015-06-17 02:38:44 +0000719 if (Options & EOptionOutputPreprocessed) {
720 std::string str;
Dejan Mircevski7be4b822015-06-17 11:40:33 -0400721 if (shader->preprocess(&Resources, defaultVersion, ENoProfile, false, false,
722 messages, &str, glslang::TShader::ForbidInclude())) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400723 PutsIfNonEmpty(str.c_str());
724 } else {
725 CompileFailed = true;
726 }
727 StderrIfNonEmpty(shader->getInfoLog());
728 StderrIfNonEmpty(shader->getInfoDebugLog());
John Kessenichc555ddd2015-06-17 02:38:44 +0000729 continue;
730 }
731 if (! shader->parse(&Resources, defaultVersion, false, messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000732 CompileFailed = true;
John Kessenichc555ddd2015-06-17 02:38:44 +0000733
John Kessenich69f4b512013-09-04 21:19:27 +0000734 program.addShader(shader);
735
John Kessenichc57b2a92016-01-16 15:30:03 -0700736 if (! (Options & EOptionSuppressInfolog) &&
737 ! (Options & EOptionMemoryLeakMode)) {
738 PutsIfNonEmpty(compUnit.fileName.c_str());
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400739 PutsIfNonEmpty(shader->getInfoLog());
740 PutsIfNonEmpty(shader->getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000741 }
John Kessenich69f4b512013-09-04 21:19:27 +0000742 }
743
744 //
745 // Program-level processing...
746 //
747
John Kessenich4d65ee32016-03-12 18:17:47 -0700748 // Link
John Kessenich68d78fd2015-07-12 19:28:10 -0600749 if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000750 LinkFailed = true;
751
John Kessenich4d65ee32016-03-12 18:17:47 -0700752 // Report
John Kessenichc57b2a92016-01-16 15:30:03 -0700753 if (! (Options & EOptionSuppressInfolog) &&
754 ! (Options & EOptionMemoryLeakMode)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400755 PutsIfNonEmpty(program.getInfoLog());
756 PutsIfNonEmpty(program.getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000757 }
758
John Kessenich4d65ee32016-03-12 18:17:47 -0700759 // Reflect
John Kessenich11f9fc72013-11-07 01:06:34 +0000760 if (Options & EOptionDumpReflection) {
761 program.buildReflection();
762 program.dumpReflection();
763 }
764
John Kessenich4d65ee32016-03-12 18:17:47 -0700765 // Dump SPIR-V
John Kessenich0df0cde2015-03-03 17:09:43 +0000766 if (Options & EOptionSpv) {
John Kessenich92f90382014-07-28 04:21:04 +0000767 if (CompileFailed || LinkFailed)
John Kessenich68d78fd2015-07-12 19:28:10 -0600768 printf("SPIR-V is not generated for failed compile or link\n");
John Kessenich92f90382014-07-28 04:21:04 +0000769 else {
770 for (int stage = 0; stage < EShLangCount; ++stage) {
John Kessenicha7a68a92014-08-24 18:21:00 +0000771 if (program.getIntermediate((EShLanguage)stage)) {
John Kessenich0df0cde2015-03-03 17:09:43 +0000772 std::vector<unsigned int> spirv;
773 glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
John Kessenichc57b2a92016-01-16 15:30:03 -0700774
775 // Dump the spv to a file or stdout, etc., but only if not doing
776 // memory/perf testing, as it's not internal to programmatic use.
777 if (! (Options & EOptionMemoryLeakMode)) {
778 glslang::OutputSpv(spirv, GetBinaryName((EShLanguage)stage));
779 if (Options & EOptionHumanReadableSpv) {
John Kessenichc57b2a92016-01-16 15:30:03 -0700780 spv::Disassemble(std::cout, spirv);
781 }
John Kessenichacba7722015-03-04 03:48:38 +0000782 }
John Kessenicha7a68a92014-08-24 18:21:00 +0000783 }
John Kessenich92f90382014-07-28 04:21:04 +0000784 }
785 }
786 }
787
John Kessenich5b0f13a2013-11-01 03:08:40 +0000788 // Free everything up, program has to go before the shaders
789 // because it might have merged stuff from the shaders, and
790 // the stuff from the shaders has to have its destructors called
791 // before the pools holding the memory in the shaders is freed.
792 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000793 while (shaders.size() > 0) {
794 delete shaders.back();
795 shaders.pop_back();
796 }
John Kessenich69f4b512013-09-04 21:19:27 +0000797}
798
John Kessenichc57b2a92016-01-16 15:30:03 -0700799//
800// Do file IO part of compile and link, handing off the pure
801// API/programmatic mode to CompileAndLinkShaderUnits(), which can
802// be put in a loop for testing memory footprint and performance.
803//
804// This is just for linking mode: meaning all the shaders will be put into the
805// the same program linked together.
806//
807// This means there are a limited number of work items (not multi-threading mode)
808// and that the point is testing at the linking level. Hence, to enable
809// performance and memory testing, the actual compile/link can be put in
810// a loop, independent of processing the work items and file IO.
811//
812void CompileAndLinkShaderFiles()
813{
814 std::vector<ShaderCompUnit> compUnits;
815
816 // Transfer all the work items from to a simple list of
817 // of compilation units. (We don't care about the thread
818 // work-item distribution properties in this path, which
819 // is okay due to the limited number of shaders, know since
820 // they are all getting linked together.)
821 glslang::TWorkItem* workItem;
822 while (Worklist.remove(workItem)) {
823 ShaderCompUnit compUnit = {
824 FindLanguage(workItem->name),
825 workItem->name,
826 ReadFileData(workItem->name.c_str())
827 };
828
829 if (! compUnit.text) {
830 usage();
831 return;
832 }
833
834 compUnits.push_back(compUnit);
835 }
836
837 // Actual call to programmatic processing of compile and link,
838 // in a loop for testing memory and performance. This part contains
839 // all the perf/memory that a programmatic consumer will care about.
840 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
841 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j)
842 CompileAndLinkShaderUnits(compUnits);
843
844 if (Options & EOptionMemoryLeakMode)
845 glslang::OS_DumpMemoryCounters();
846 }
847
rdb32084e82016-02-23 22:17:38 +0100848 for (auto it = compUnits.begin(); it != compUnits.end(); ++it)
849 FreeFileData(it->text);
John Kessenichc57b2a92016-01-16 15:30:03 -0700850}
851
John Kessenicha0af4732012-12-12 21:15:54 +0000852int C_DECL main(int argc, char* argv[])
853{
John Kessenich68d78fd2015-07-12 19:28:10 -0600854 ProcessArguments(argc, argv);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000855
John Kessenich05a70632013-09-17 19:26:08 +0000856 if (Options & EOptionDumpConfig) {
857 printf("%s", DefaultConfig);
858 if (Worklist.empty())
859 return ESuccess;
860 }
861
John Kessenich0da9eaa2015-08-01 17:10:02 -0600862 if (Options & EOptionDumpVersions) {
863 printf("Glslang Version: %s %s\n", GLSLANG_REVISION, GLSLANG_DATE);
John Kessenich319de232013-12-04 04:43:40 +0000864 printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
865 printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
John Kessenich68d78fd2015-07-12 19:28:10 -0600866 std::string spirvVersion;
867 glslang::GetSpirvVersion(spirvVersion);
John Kessenich0da9eaa2015-08-01 17:10:02 -0600868 printf("SPIR-V Version %s\n", spirvVersion.c_str());
John Kessenich5e4b1242015-08-06 22:53:06 -0600869 printf("GLSL.std.450 Version %d, Revision %d\n", GLSLstd450Version, GLSLstd450Revision);
John Kessenich55e7d112015-11-15 21:33:39 -0700870 printf("Khronos Tool ID %d\n", glslang::GetKhronosToolId());
John Kessenich319de232013-12-04 04:43:40 +0000871 if (Worklist.empty())
872 return ESuccess;
873 }
874
John Kessenich05a70632013-09-17 19:26:08 +0000875 if (Worklist.empty()) {
876 usage();
John Kessenich05a70632013-09-17 19:26:08 +0000877 }
878
879 ProcessConfigFile();
880
John Kessenich69f4b512013-09-04 21:19:27 +0000881 //
882 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000883 // 1) linking all arguments together, single-threaded, new C++ interface
884 // 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 +0000885 //
John Kessenichc555ddd2015-06-17 02:38:44 +0000886 if (Options & EOptionLinkProgram ||
887 Options & EOptionOutputPreprocessed) {
John Kessenichc36e1d82013-11-01 17:41:52 +0000888 glslang::InitializeProcess();
John Kessenichc57b2a92016-01-16 15:30:03 -0700889 CompileAndLinkShaderFiles();
John Kessenichc36e1d82013-11-01 17:41:52 +0000890 glslang::FinalizeProcess();
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500891 for (int w = 0; w < NumWorkItems; ++w) {
892 if (Work[w]) {
893 delete Work[w];
894 }
895 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000896 } else {
897 ShInitialize();
898
John Kessenich38f3b892013-09-06 19:52:57 +0000899 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000900
John Kessenich38f3b892013-09-06 19:52:57 +0000901 if (Options & EOptionMultiThreaded) {
902 const int NumThreads = 16;
903 void* threads[NumThreads];
904 for (int t = 0; t < NumThreads; ++t) {
905 threads[t] = glslang::OS_CreateThread(&CompileShaders);
906 if (! threads[t]) {
907 printf("Failed to create thread\n");
908 return EFailThreadCreate;
909 }
John Kessenicha0af4732012-12-12 21:15:54 +0000910 }
John Kessenich38f3b892013-09-06 19:52:57 +0000911 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenichc999ba22013-11-07 23:33:24 +0000912 } else
913 CompileShaders(0);
John Kessenich38f3b892013-09-06 19:52:57 +0000914
915 // Print out all the resulting infologs
916 for (int w = 0; w < NumWorkItems; ++w) {
917 if (Work[w]) {
Kenneth Perryb07e6be2015-12-15 10:52:34 -0600918 if (printShaderNames || Work[w]->results.size() > 0)
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400919 PutsIfNonEmpty(Work[w]->name.c_str());
920 PutsIfNonEmpty(Work[w]->results.c_str());
John Kessenich38f3b892013-09-06 19:52:57 +0000921 delete Work[w];
922 }
923 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000924
925 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000926 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000927
Andrew Woloszynb891c2b2016-01-18 09:26:25 -0500928 delete[] Work;
929
John Kessenichc999ba22013-11-07 23:33:24 +0000930 if (CompileFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000931 return EFailCompile;
John Kessenichc999ba22013-11-07 23:33:24 +0000932 if (LinkFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000933 return EFailLink;
934
935 return 0;
936}
937
938//
939// Deduce the language from the filename. Files must end in one of the
940// following extensions:
941//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000942// .vert = vertex
943// .tesc = tessellation control
944// .tese = tessellation evaluation
945// .geom = geometry
946// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000947// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000948//
John Kessenichb603f912013-08-29 00:39:25 +0000949EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000950{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000951 size_t ext = name.rfind('.');
952 if (ext == std::string::npos) {
953 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000954 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000955 }
956
John Kessenich2b07c7e2013-07-31 18:44:13 +0000957 std::string suffix = name.substr(ext + 1, std::string::npos);
958 if (suffix == "vert")
959 return EShLangVertex;
960 else if (suffix == "tesc")
961 return EShLangTessControl;
962 else if (suffix == "tese")
963 return EShLangTessEvaluation;
964 else if (suffix == "geom")
965 return EShLangGeometry;
966 else if (suffix == "frag")
967 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000968 else if (suffix == "comp")
969 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000970
971 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000972 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000973}
974
John Kessenicha0af4732012-12-12 21:15:54 +0000975//
John Kessenich69f4b512013-09-04 21:19:27 +0000976// Read a file's data into a string, and compile it using the old interface ShCompile,
977// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000978//
John Kessenich51cdd902014-02-18 23:37:57 +0000979void CompileFile(const char* fileName, ShHandle compiler)
John Kessenicha0af4732012-12-12 21:15:54 +0000980{
John Kessenichca3457f2015-05-18 01:59:45 +0000981 int ret = 0;
John Kessenich41cf6b52013-06-25 18:10:05 +0000982 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000983 if (! shaderStrings) {
984 usage();
John Kessenichdb4cd542013-06-26 22:42:55 +0000985 }
986
John Kessenich41cf6b52013-06-25 18:10:05 +0000987 int* lengths = new int[NumShaderStrings];
988
989 // move to length-based strings, rather than null-terminated strings
990 for (int s = 0; s < NumShaderStrings; ++s)
John Kessenich35f04bd2014-02-19 02:47:20 +0000991 lengths[s] = (int)strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000992
John Kessenichc999ba22013-11-07 23:33:24 +0000993 if (! shaderStrings) {
994 CompileFailed = true;
995 return;
996 }
John Kessenicha0af4732012-12-12 21:15:54 +0000997
John Kessenich52ac67e2013-05-05 23:46:22 +0000998 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000999 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +00001000
John Kessenich94a81fb2013-08-31 02:41:30 +00001001 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
1002 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich26ad2682014-08-13 20:17:19 +00001003 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichca3457f2015-05-18 01:59:45 +00001004 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +00001005 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
1006 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
1007 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +00001008 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichca3457f2015-05-18 01:59:45 +00001009 //ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +00001010 }
John Kessenicha0af4732012-12-12 21:15:54 +00001011
John Kessenich94a81fb2013-08-31 02:41:30 +00001012 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +00001013 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +00001014 }
John Kessenicha0af4732012-12-12 21:15:54 +00001015
John Kessenich41cf6b52013-06-25 18:10:05 +00001016 delete [] lengths;
1017 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +00001018
John Kessenichc999ba22013-11-07 23:33:24 +00001019 if (ret == 0)
1020 CompileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +00001021}
1022
John Kessenicha0af4732012-12-12 21:15:54 +00001023//
1024// print usage to stdout
1025//
1026void usage()
1027{
John Kessenich319de232013-12-04 04:43:40 +00001028 printf("Usage: glslangValidator [option]... [file]...\n"
1029 "\n"
John Kessenich0df0cde2015-03-03 17:09:43 +00001030 "Where: each 'file' ends in .<stage>, where <stage> is one of\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001031 " .conf to provide an optional config file that replaces the default configuration\n"
1032 " (see -c option below for generating a template)\n"
1033 " .vert for a vertex shader\n"
1034 " .tesc for a tessellation control shader\n"
1035 " .tese for a tessellation evaluation shader\n"
1036 " .geom for a geometry shader\n"
1037 " .frag for a fragment shader\n"
1038 " .comp for a compute shader\n"
John Kessenich319de232013-12-04 04:43:40 +00001039 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +00001040 "Compilation warnings and errors will be printed to stdout.\n"
John Kessenich319de232013-12-04 04:43:40 +00001041 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +00001042 "To get other information, use one of the following options:\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001043 "Each option must be specified separately.\n"
1044 " -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
1045 " default file name is <stage>.spv (-o overrides this)\n"
1046 " (unless -o is specified, which overrides the default file name)\n"
1047 " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
1048 " default file name is <stage>.spv (-o overrides this)\n"
1049 " -H print human readable form of SPIR-V; turns on -V\n"
Andrew Woloszynaae1ad82015-06-24 17:00:46 -04001050 " -E print pre-processed GLSL; cannot be used with -l;\n"
1051 " errors will appear on stderr.\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001052 " -c configuration dump;\n"
1053 " creates the default configuration file (redirect to a .conf file)\n"
1054 " -d default to desktop (#version 110) when there is no shader #version\n"
1055 " (default is ES version 100)\n"
John Kessenich66e2faf2016-03-12 18:34:36 -07001056 " -D input is HLSL\n"
John Kessenich4d65ee32016-03-12 18:17:47 -07001057 " -e specify entry-point name\n"
John Kessenich68d78fd2015-07-12 19:28:10 -06001058 " -h print this usage message\n"
1059 " -i intermediate tree (glslang AST) is printed out\n"
1060 " -l link all input files together to form a single module\n"
1061 " -m memory leak mode\n"
1062 " -o <file> save binary into <file>, requires a binary option (e.g., -V)\n"
1063 " -q dump reflection query database\n"
1064 " -r relaxed semantic error-checking mode\n"
1065 " -s silent mode\n"
1066 " -t multi-threaded mode\n"
1067 " -v print version strings\n"
1068 " -w suppress warnings (except as required by #extension : warn)\n"
John Kessenichb0a7eb52013-11-07 17:44:20 +00001069 );
John Kessenich68d78fd2015-07-12 19:28:10 -06001070
1071 exit(EFailUsage);
John Kessenicha0af4732012-12-12 21:15:54 +00001072}
1073
John Kessenich3ce4e592014-10-06 19:57:34 +00001074#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
John Kessenichcfd643e2013-03-08 23:14:42 +00001075
1076#include <errno.h>
1077
1078int fopen_s(
1079 FILE** pFile,
John Kessenich51cdd902014-02-18 23:37:57 +00001080 const char* filename,
1081 const char* mode
John Kessenichcfd643e2013-03-08 23:14:42 +00001082)
1083{
1084 if (!pFile || !filename || !mode) {
1085 return EINVAL;
1086 }
1087
1088 FILE* f = fopen(filename, mode);
1089 if (! f) {
1090 if (errno != 0) {
1091 return errno;
1092 } else {
1093 return ENOENT;
1094 }
1095 }
1096 *pFile = f;
1097
1098 return 0;
1099}
1100
1101#endif
1102
John Kessenicha0af4732012-12-12 21:15:54 +00001103//
1104// Malloc a string of sufficient size and read a string into it.
1105//
John Kessenich51cdd902014-02-18 23:37:57 +00001106char** ReadFileData(const char* fileName)
John Kessenicha0af4732012-12-12 21:15:54 +00001107{
John Kessenichb3297152015-07-11 18:01:03 -06001108 FILE *in = nullptr;
John Kessenich3ce4e592014-10-06 19:57:34 +00001109 int errorCode = fopen_s(&in, fileName, "r");
John Kessenichd6c72a42014-08-18 19:42:35 +00001110
John Kessenicha0af4732012-12-12 21:15:54 +00001111 int count = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001112 const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
1113 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001114
John Kessenich68d78fd2015-07-12 19:28:10 -06001115 if (errorCode || in == nullptr)
1116 Error("unable to open input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001117
1118 while (fgetc(in) != EOF)
1119 count++;
1120
John Kessenichd6c72a42014-08-18 19:42:35 +00001121 fseek(in, 0, SEEK_SET);
John Kessenichca3457f2015-05-18 01:59:45 +00001122
John Kessenichb3297152015-07-11 18:01:03 -06001123 char *fdata = (char*)malloc(count+2); // freed before return of this function
John Kessenich68d78fd2015-07-12 19:28:10 -06001124 if (! fdata)
1125 Error("can't allocate memory");
1126
John Kessenichb3297152015-07-11 18:01:03 -06001127 if ((int)fread(fdata, 1, count, in) != count) {
John Kessenichb3297152015-07-11 18:01:03 -06001128 free(fdata);
John Kessenich68d78fd2015-07-12 19:28:10 -06001129 Error("can't read input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001130 }
John Kessenich68d78fd2015-07-12 19:28:10 -06001131
John Kessenicha0af4732012-12-12 21:15:54 +00001132 fdata[count] = '\0';
1133 fclose(in);
John Kessenichb3297152015-07-11 18:01:03 -06001134
John Kessenichea869fb2013-10-28 18:12:06 +00001135 if (count == 0) {
John Kessenichb3297152015-07-11 18:01:03 -06001136 // recover from empty file
1137 return_data[0] = (char*)malloc(count+2); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001138 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +00001139 NumShaderStrings = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001140 free(fdata);
John Kessenicha0af4732012-12-12 21:15:54 +00001141
John Kessenichb3297152015-07-11 18:01:03 -06001142 return return_data;
1143 } else
1144 NumShaderStrings = 1; // Set to larger than 1 for testing multiple strings
1145
1146 // compute how to split up the file into multiple strings, for testing multiple strings
John Kessenichd6c72a42014-08-18 19:42:35 +00001147 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenichb3297152015-07-11 18:01:03 -06001148 int ptr_len = 0;
1149 int i = 0;
1150 while (count > 0) {
1151 return_data[i] = (char*)malloc(len + 2); // freed in FreeFileData()
1152 memcpy(return_data[i], fdata + ptr_len, len);
1153 return_data[i][len] = '\0';
1154 count -= len;
1155 ptr_len += len;
1156 if (count < len) {
1157 if (count == 0) {
1158 NumShaderStrings = i + 1;
John Kessenicha0af4732012-12-12 21:15:54 +00001159 break;
1160 }
John Kessenichb3297152015-07-11 18:01:03 -06001161 len = count;
John Kessenichd6c72a42014-08-18 19:42:35 +00001162 }
1163 ++i;
1164 }
John Kessenichb3297152015-07-11 18:01:03 -06001165
1166 free(fdata);
1167
John Kessenicha0af4732012-12-12 21:15:54 +00001168 return return_data;
1169}
1170
John Kessenich51cdd902014-02-18 23:37:57 +00001171void FreeFileData(char** data)
John Kessenicha0af4732012-12-12 21:15:54 +00001172{
John Kessenichb3297152015-07-11 18:01:03 -06001173 for(int i = 0; i < NumShaderStrings; i++)
John Kessenicha0af4732012-12-12 21:15:54 +00001174 free(data[i]);
John Kessenichb3297152015-07-11 18:01:03 -06001175
1176 free(data);
John Kessenicha0af4732012-12-12 21:15:54 +00001177}
1178
John Kessenich54d8cda2013-02-11 22:36:01 +00001179void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +00001180{
John Kessenichfae38ee2015-06-10 23:23:12 +00001181 if (num >= 0 )
1182 printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
1183 else
1184 printf("#### %s %s INFO LOG ####\n", msg, name);
John Kessenicha0af4732012-12-12 21:15:54 +00001185}