blob: b88d8ad5ef6981187205c7756eb3fe409f24eb75 [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"
42#include "./../glslang/Public/ShaderLang.h"
John Kessenich0df0cde2015-03-03 17:09:43 +000043#include "../SPIRV/GlslangToSpv.h"
44#include "../SPIRV/GLSL450Lib.h"
John Kessenichacba7722015-03-04 03:48:38 +000045#include "../SPIRV/doc.h"
46#include "../SPIRV/disassemble.h"
John Kessenicha0af4732012-12-12 21:15:54 +000047#include <string.h>
John Kessenichcfd643e2013-03-08 23:14:42 +000048#include <stdlib.h>
John Kessenicha0af4732012-12-12 21:15:54 +000049#include <math.h>
50
John Kessenich2b07c7e2013-07-31 18:44:13 +000051#include "osinclude.h"
John Kessenicha0af4732012-12-12 21:15:54 +000052
53extern "C" {
54 SH_IMPORT_EXPORT void ShOutputHtml();
55}
56
John Kessenich94a81fb2013-08-31 02:41:30 +000057// Command-line options
58enum TOptions {
John Kessenichacba7722015-03-04 03:48:38 +000059 EOptionNone = 0x0000,
60 EOptionIntermediate = 0x0001,
61 EOptionSuppressInfolog = 0x0002,
62 EOptionMemoryLeakMode = 0x0004,
63 EOptionRelaxedErrors = 0x0008,
64 EOptionGiveWarnings = 0x0010,
65 EOptionLinkProgram = 0x0020,
66 EOptionMultiThreaded = 0x0040,
67 EOptionDumpConfig = 0x0080,
68 EOptionDumpReflection = 0x0100,
69 EOptionSuppressWarnings = 0x0200,
70 EOptionDumpVersions = 0x0400,
71 EOptionSpv = 0x0800,
72 EOptionHumanReadableSpv = 0x1000,
John Kessenich68d78fd2015-07-12 19:28:10 -060073 EOptionVulkanRules = 0x2000,
74 EOptionDefaultDesktop = 0x4000,
75 EOptionOutputPreprocessed = 0x8000,
John Kessenich94a81fb2013-08-31 02:41:30 +000076};
77
John Kessenicha0af4732012-12-12 21:15:54 +000078//
John Kessenich68d78fd2015-07-12 19:28:10 -060079// Return codes from main/exit().
John Kessenicha0af4732012-12-12 21:15:54 +000080//
81enum TFailCode {
82 ESuccess = 0,
83 EFailUsage,
84 EFailCompile,
85 EFailLink,
86 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000087 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000088 EFailLinkerCreate
89};
90
91//
John Kessenich68d78fd2015-07-12 19:28:10 -060092// Forward declarations.
John Kessenicha0af4732012-12-12 21:15:54 +000093//
John Kessenichb603f912013-08-29 00:39:25 +000094EShLanguage FindLanguage(const std::string& name);
John Kessenich51cdd902014-02-18 23:37:57 +000095void CompileFile(const char* fileName, ShHandle);
John Kessenicha0af4732012-12-12 21:15:54 +000096void usage();
John Kessenichea869fb2013-10-28 18:12:06 +000097void FreeFileData(char** data);
98char** ReadFileData(const char* fileName);
John Kessenich54d8cda2013-02-11 22:36:01 +000099void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +0000100
John Kessenichc999ba22013-11-07 23:33:24 +0000101// Globally track if any compile or link failure.
102bool CompileFailed = false;
103bool LinkFailed = false;
104
John Kessenich05a70632013-09-17 19:26:08 +0000105// Use to test breaking up a single shader file into multiple strings.
John Kessenich68d78fd2015-07-12 19:28:10 -0600106// Set in ReadFileData().
John Kessenichea869fb2013-10-28 18:12:06 +0000107int NumShaderStrings;
John Kessenicha0af4732012-12-12 21:15:54 +0000108
John Kessenich05a70632013-09-17 19:26:08 +0000109TBuiltInResource Resources;
110std::string ConfigFile;
111
John Kessenicha0af4732012-12-12 21:15:54 +0000112//
John Kessenich05a70632013-09-17 19:26:08 +0000113// These are the default resources for TBuiltInResources, used for both
114// - parsing this string for the case where the user didn't supply one
115// - dumping out a template for user construction of a config file
John Kessenicha0af4732012-12-12 21:15:54 +0000116//
John Kessenich284231c2013-10-22 01:50:39 +0000117const char* DefaultConfig =
118 "MaxLights 32\n"
119 "MaxClipPlanes 6\n"
120 "MaxTextureUnits 32\n"
121 "MaxTextureCoords 32\n"
122 "MaxVertexAttribs 64\n"
123 "MaxVertexUniformComponents 4096\n"
124 "MaxVaryingFloats 64\n"
125 "MaxVertexTextureImageUnits 32\n"
John Kessenich623833f2013-12-11 18:57:40 +0000126 "MaxCombinedTextureImageUnits 80\n"
John Kessenich284231c2013-10-22 01:50:39 +0000127 "MaxTextureImageUnits 32\n"
128 "MaxFragmentUniformComponents 4096\n"
129 "MaxDrawBuffers 32\n"
130 "MaxVertexUniformVectors 128\n"
131 "MaxVaryingVectors 8\n"
132 "MaxFragmentUniformVectors 16\n"
133 "MaxVertexOutputVectors 16\n"
134 "MaxFragmentInputVectors 15\n"
135 "MinProgramTexelOffset -8\n"
136 "MaxProgramTexelOffset 7\n"
137 "MaxClipDistances 8\n"
138 "MaxComputeWorkGroupCountX 65535\n"
139 "MaxComputeWorkGroupCountY 65535\n"
140 "MaxComputeWorkGroupCountZ 65535\n"
141 "MaxComputeWorkGroupSizeX 1024\n"
John Kessenichda66bc72014-08-19 20:32:48 +0000142 "MaxComputeWorkGroupSizeY 1024\n"
John Kessenich284231c2013-10-22 01:50:39 +0000143 "MaxComputeWorkGroupSizeZ 64\n"
144 "MaxComputeUniformComponents 1024\n"
145 "MaxComputeTextureImageUnits 16\n"
146 "MaxComputeImageUniforms 8\n"
147 "MaxComputeAtomicCounters 8\n"
148 "MaxComputeAtomicCounterBuffers 1\n"
149 "MaxVaryingComponents 60\n"
150 "MaxVertexOutputComponents 64\n"
151 "MaxGeometryInputComponents 64\n"
152 "MaxGeometryOutputComponents 128\n"
153 "MaxFragmentInputComponents 128\n"
154 "MaxImageUnits 8\n"
155 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
John Kessenichddea6782014-08-10 18:19:36 +0000156 "MaxCombinedShaderOutputResources 8\n"
John Kessenich284231c2013-10-22 01:50:39 +0000157 "MaxImageSamples 0\n"
158 "MaxVertexImageUniforms 0\n"
159 "MaxTessControlImageUniforms 0\n"
160 "MaxTessEvaluationImageUniforms 0\n"
161 "MaxGeometryImageUniforms 0\n"
162 "MaxFragmentImageUniforms 8\n"
163 "MaxCombinedImageUniforms 8\n"
164 "MaxGeometryTextureImageUnits 16\n"
165 "MaxGeometryOutputVertices 256\n"
166 "MaxGeometryTotalOutputComponents 1024\n"
167 "MaxGeometryUniformComponents 1024\n"
168 "MaxGeometryVaryingComponents 64\n"
169 "MaxTessControlInputComponents 128\n"
170 "MaxTessControlOutputComponents 128\n"
171 "MaxTessControlTextureImageUnits 16\n"
172 "MaxTessControlUniformComponents 1024\n"
173 "MaxTessControlTotalOutputComponents 4096\n"
174 "MaxTessEvaluationInputComponents 128\n"
175 "MaxTessEvaluationOutputComponents 128\n"
176 "MaxTessEvaluationTextureImageUnits 16\n"
177 "MaxTessEvaluationUniformComponents 1024\n"
178 "MaxTessPatchComponents 120\n"
179 "MaxPatchVertices 32\n"
180 "MaxTessGenLevel 64\n"
181 "MaxViewports 16\n"
182 "MaxVertexAtomicCounters 0\n"
183 "MaxTessControlAtomicCounters 0\n"
184 "MaxTessEvaluationAtomicCounters 0\n"
185 "MaxGeometryAtomicCounters 0\n"
186 "MaxFragmentAtomicCounters 8\n"
187 "MaxCombinedAtomicCounters 8\n"
188 "MaxAtomicCounterBindings 1\n"
189 "MaxVertexAtomicCounterBuffers 0\n"
190 "MaxTessControlAtomicCounterBuffers 0\n"
191 "MaxTessEvaluationAtomicCounterBuffers 0\n"
192 "MaxGeometryAtomicCounterBuffers 0\n"
193 "MaxFragmentAtomicCounterBuffers 1\n"
194 "MaxCombinedAtomicCounterBuffers 1\n"
195 "MaxAtomicCounterBufferSize 16384\n"
John Kessenichc7776ec2014-01-26 01:37:13 +0000196 "MaxTransformFeedbackBuffers 4\n"
197 "MaxTransformFeedbackInterleavedComponents 64\n"
John Kessenich69968412014-08-13 06:37:59 +0000198 "MaxCullDistances 8\n"
199 "MaxCombinedClipAndCullDistances 8\n"
John Kessenichcd77f8e2014-08-13 16:54:02 +0000200 "MaxSamples 4\n"
John Kessenich284231c2013-10-22 01:50:39 +0000201
202 "nonInductiveForLoops 1\n"
203 "whileLoops 1\n"
204 "doWhileLoops 1\n"
205 "generalUniformIndexing 1\n"
206 "generalAttributeMatrixVectorIndexing 1\n"
207 "generalVaryingIndexing 1\n"
208 "generalSamplerIndexing 1\n"
209 "generalVariableIndexing 1\n"
210 "generalConstantMatrixVectorIndexing 1\n"
211 ;
John Kessenich05a70632013-09-17 19:26:08 +0000212
213//
214// Parse either a .conf file provided by the user or the default string above.
215//
216void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000217{
John Kessenich05a70632013-09-17 19:26:08 +0000218 char** configStrings = 0;
John Kessenich51cdd902014-02-18 23:37:57 +0000219 char* config = 0;
John Kessenich05a70632013-09-17 19:26:08 +0000220 if (ConfigFile.size() > 0) {
John Kessenichea869fb2013-10-28 18:12:06 +0000221 configStrings = ReadFileData(ConfigFile.c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000222 if (configStrings)
223 config = *configStrings;
224 else {
225 printf("Error opening configuration file; will instead use the default configuration\n");
226 usage();
227 }
228 }
229
230 if (config == 0) {
John Kessenich6494baf2014-02-19 00:08:59 +0000231 config = new char[strlen(DefaultConfig) + 1];
John Kessenich05a70632013-09-17 19:26:08 +0000232 strcpy(config, DefaultConfig);
233 }
234
235 const char* delims = " \t\n\r";
236 const char* token = strtok(config, delims);
237 while (token) {
238 const char* valueStr = strtok(0, delims);
239 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
240 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
241 return;
242 }
243 int value = atoi(valueStr);
244
245 if (strcmp(token, "MaxLights") == 0)
246 Resources.maxLights = value;
247 else if (strcmp(token, "MaxClipPlanes") == 0)
248 Resources.maxClipPlanes = value;
249 else if (strcmp(token, "MaxTextureUnits") == 0)
250 Resources.maxTextureUnits = value;
251 else if (strcmp(token, "MaxTextureCoords") == 0)
252 Resources.maxTextureCoords = value;
253 else if (strcmp(token, "MaxVertexAttribs") == 0)
254 Resources.maxVertexAttribs = value;
255 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
256 Resources.maxVertexUniformComponents = value;
257 else if (strcmp(token, "MaxVaryingFloats") == 0)
258 Resources.maxVaryingFloats = value;
259 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
260 Resources.maxVertexTextureImageUnits = value;
261 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
262 Resources.maxCombinedTextureImageUnits = value;
263 else if (strcmp(token, "MaxTextureImageUnits") == 0)
264 Resources.maxTextureImageUnits = value;
265 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
266 Resources.maxFragmentUniformComponents = value;
267 else if (strcmp(token, "MaxDrawBuffers") == 0)
268 Resources.maxDrawBuffers = value;
269 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
270 Resources.maxVertexUniformVectors = value;
271 else if (strcmp(token, "MaxVaryingVectors") == 0)
272 Resources.maxVaryingVectors = value;
273 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
274 Resources.maxFragmentUniformVectors = value;
275 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
276 Resources.maxVertexOutputVectors = value;
277 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
278 Resources.maxFragmentInputVectors = value;
279 else if (strcmp(token, "MinProgramTexelOffset") == 0)
280 Resources.minProgramTexelOffset = value;
281 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
282 Resources.maxProgramTexelOffset = value;
John Kesseniche7c59c12013-10-16 22:28:35 +0000283 else if (strcmp(token, "MaxClipDistances") == 0)
284 Resources.maxClipDistances = value;
John Kessenich284231c2013-10-22 01:50:39 +0000285 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
286 Resources.maxComputeWorkGroupCountX = value;
287 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
288 Resources.maxComputeWorkGroupCountY = value;
289 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
290 Resources.maxComputeWorkGroupCountZ = value;
291 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
292 Resources.maxComputeWorkGroupSizeX = value;
293 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
294 Resources.maxComputeWorkGroupSizeY = value;
295 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
296 Resources.maxComputeWorkGroupSizeZ = value;
297 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
298 Resources.maxComputeUniformComponents = value;
299 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
300 Resources.maxComputeTextureImageUnits = value;
301 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
302 Resources.maxComputeImageUniforms = value;
303 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
304 Resources.maxComputeAtomicCounters = value;
305 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
306 Resources.maxComputeAtomicCounterBuffers = value;
307 else if (strcmp(token, "MaxVaryingComponents") == 0)
308 Resources.maxVaryingComponents = value;
309 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
310 Resources.maxVertexOutputComponents = value;
311 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
312 Resources.maxGeometryInputComponents = value;
313 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
314 Resources.maxGeometryOutputComponents = value;
315 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
316 Resources.maxFragmentInputComponents = value;
317 else if (strcmp(token, "MaxImageUnits") == 0)
318 Resources.maxImageUnits = value;
319 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
320 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
John Kessenichddea6782014-08-10 18:19:36 +0000321 else if (strcmp(token, "MaxCombinedShaderOutputResources") == 0)
322 Resources.maxCombinedShaderOutputResources = value;
John Kessenich284231c2013-10-22 01:50:39 +0000323 else if (strcmp(token, "MaxImageSamples") == 0)
324 Resources.maxImageSamples = value;
325 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
326 Resources.maxVertexImageUniforms = value;
327 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
328 Resources.maxTessControlImageUniforms = value;
329 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
330 Resources.maxTessEvaluationImageUniforms = value;
331 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
332 Resources.maxGeometryImageUniforms = value;
333 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
334 Resources.maxFragmentImageUniforms = value;
335 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
336 Resources.maxCombinedImageUniforms = value;
337 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
338 Resources.maxGeometryTextureImageUnits = value;
339 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
340 Resources.maxGeometryOutputVertices = value;
341 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
342 Resources.maxGeometryTotalOutputComponents = value;
343 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
344 Resources.maxGeometryUniformComponents = value;
345 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
346 Resources.maxGeometryVaryingComponents = value;
347 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
348 Resources.maxTessControlInputComponents = value;
349 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
350 Resources.maxTessControlOutputComponents = value;
351 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
352 Resources.maxTessControlTextureImageUnits = value;
353 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
354 Resources.maxTessControlUniformComponents = value;
355 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
356 Resources.maxTessControlTotalOutputComponents = value;
357 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
358 Resources.maxTessEvaluationInputComponents = value;
359 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
360 Resources.maxTessEvaluationOutputComponents = value;
361 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
362 Resources.maxTessEvaluationTextureImageUnits = value;
363 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
364 Resources.maxTessEvaluationUniformComponents = value;
365 else if (strcmp(token, "MaxTessPatchComponents") == 0)
366 Resources.maxTessPatchComponents = value;
367 else if (strcmp(token, "MaxPatchVertices") == 0)
368 Resources.maxPatchVertices = value;
369 else if (strcmp(token, "MaxTessGenLevel") == 0)
370 Resources.maxTessGenLevel = value;
371 else if (strcmp(token, "MaxViewports") == 0)
372 Resources.maxViewports = value;
373 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
374 Resources.maxVertexAtomicCounters = value;
375 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
376 Resources.maxTessControlAtomicCounters = value;
377 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
378 Resources.maxTessEvaluationAtomicCounters = value;
379 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
380 Resources.maxGeometryAtomicCounters = value;
381 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
382 Resources.maxFragmentAtomicCounters = value;
383 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
384 Resources.maxCombinedAtomicCounters = value;
385 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
386 Resources.maxAtomicCounterBindings = value;
387 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
388 Resources.maxVertexAtomicCounterBuffers = value;
389 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
390 Resources.maxTessControlAtomicCounterBuffers = value;
391 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
392 Resources.maxTessEvaluationAtomicCounterBuffers = value;
393 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
394 Resources.maxGeometryAtomicCounterBuffers = value;
395 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
396 Resources.maxFragmentAtomicCounterBuffers = value;
397 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
398 Resources.maxCombinedAtomicCounterBuffers = value;
399 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
400 Resources.maxAtomicCounterBufferSize = value;
John Kessenichc7776ec2014-01-26 01:37:13 +0000401 else if (strcmp(token, "MaxTransformFeedbackBuffers") == 0)
402 Resources.maxTransformFeedbackBuffers = value;
403 else if (strcmp(token, "MaxTransformFeedbackInterleavedComponents") == 0)
404 Resources.maxTransformFeedbackInterleavedComponents = value;
John Kessenich69968412014-08-13 06:37:59 +0000405 else if (strcmp(token, "MaxCullDistances") == 0)
406 Resources.maxCullDistances = value;
407 else if (strcmp(token, "MaxCombinedClipAndCullDistances") == 0)
408 Resources.maxCombinedClipAndCullDistances = value;
John Kessenichcd77f8e2014-08-13 16:54:02 +0000409 else if (strcmp(token, "MaxSamples") == 0)
410 Resources.maxSamples = value;
John Kessenich284231c2013-10-22 01:50:39 +0000411
John Kessenicha5830df2013-10-02 05:10:48 +0000412 else if (strcmp(token, "nonInductiveForLoops") == 0)
413 Resources.limits.nonInductiveForLoops = (value != 0);
414 else if (strcmp(token, "whileLoops") == 0)
415 Resources.limits.whileLoops = (value != 0);
416 else if (strcmp(token, "doWhileLoops") == 0)
417 Resources.limits.doWhileLoops = (value != 0);
418 else if (strcmp(token, "generalUniformIndexing") == 0)
419 Resources.limits.generalUniformIndexing = (value != 0);
420 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
421 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
422 else if (strcmp(token, "generalVaryingIndexing") == 0)
423 Resources.limits.generalVaryingIndexing = (value != 0);
424 else if (strcmp(token, "generalSamplerIndexing") == 0)
425 Resources.limits.generalSamplerIndexing = (value != 0);
426 else if (strcmp(token, "generalVariableIndexing") == 0)
427 Resources.limits.generalVariableIndexing = (value != 0);
428 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
429 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000430 else
431 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
432
433 token = strtok(0, delims);
434 }
435 if (configStrings)
436 FreeFileData(configStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000437}
438
John Kessenich38f3b892013-09-06 19:52:57 +0000439// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000440glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000441
442// array of unique places to leave the shader names and infologs for the asynchronous compiles
John Kessenichfd305422014-06-05 16:30:53 +0000443glslang::TWorkItem** Work = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000444int NumWorkItems = 0;
445
John Kessenich94a81fb2013-08-31 02:41:30 +0000446int Options = 0;
John Kessenich68d78fd2015-07-12 19:28:10 -0600447const char* ExecutableName = nullptr;
448const char* binaryFileName = nullptr;
449
450//
451// Create the default name for saving a binary if -o is not provided.
452//
453const char* GetBinaryName(EShLanguage stage)
454{
455 const char* name;
456 if (binaryFileName == nullptr) {
457 switch (stage) {
458 case EShLangVertex: name = "vert.spv"; break;
459 case EShLangTessControl: name = "tesc.spv"; break;
460 case EShLangTessEvaluation: name = "tese.spv"; break;
461 case EShLangGeometry: name = "geom.spv"; break;
462 case EShLangFragment: name = "frag.spv"; break;
463 case EShLangCompute: name = "comp.spv"; break;
464 default: name = "unknown"; break;
465 }
466 } else
467 name = binaryFileName;
468
469 return name;
470}
John Kessenich2b07c7e2013-07-31 18:44:13 +0000471
John Kessenich05a70632013-09-17 19:26:08 +0000472//
473// *.conf => this is a config file that can set limits/resources
474//
475bool SetConfigFile(const std::string& name)
476{
477 if (name.size() < 5)
478 return false;
479
John Kessenich4c706852013-10-11 16:28:43 +0000480 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000481 ConfigFile = name;
482 return true;
483 }
484
485 return false;
486}
487
John Kessenich68d78fd2015-07-12 19:28:10 -0600488//
489// Give error and exit with failure code.
490//
491void Error(const char* message)
492{
493 printf("%s: Error %s (use -h for usage)\n", ExecutableName, message);
494 exit(EFailUsage);
495}
496
497//
498// Do all command-line argument parsing. This includes building up the work-items
499// to be processed later, and saving all the command-line options.
500//
501// Does not return (it exits) if command-line is fatally flawed.
502//
503void ProcessArguments(int argc, char* argv[])
John Kessenich2b07c7e2013-07-31 18:44:13 +0000504{
John Kessenich38f3b892013-09-06 19:52:57 +0000505 ExecutableName = argv[0];
506 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 +0000507 Work = new glslang::TWorkItem*[NumWorkItems];
John Kessenich68d78fd2015-07-12 19:28:10 -0600508 for (int w = 0; w < NumWorkItems; ++w)
509 Work[w] = 0;
John Kessenich38f3b892013-09-06 19:52:57 +0000510
John Kessenich2b07c7e2013-07-31 18:44:13 +0000511 argc--;
512 argv++;
513 for (; argc >= 1; argc--, argv++) {
514 if (argv[0][0] == '-') {
John Kessenich2aa7f3a2015-05-15 16:02:07 +0000515 switch (argv[0][1]) {
516 case 'H':
517 Options |= EOptionHumanReadableSpv;
518 // fall through to -V
John Kessenich0df0cde2015-03-03 17:09:43 +0000519 case 'V':
520 Options |= EOptionSpv;
John Kessenich68d78fd2015-07-12 19:28:10 -0600521 Options |= EOptionVulkanRules;
522 Options |= EOptionLinkProgram;
523 break;
524 case 'G':
525 Options |= EOptionSpv;
John Kessenichd78e3512014-08-25 20:07:55 +0000526 Options |= EOptionLinkProgram;
John Kessenich92f90382014-07-28 04:21:04 +0000527 break;
John Kessenichc555ddd2015-06-17 02:38:44 +0000528 case 'E':
529 Options |= EOptionOutputPreprocessed;
530 break;
John Kessenich05a70632013-09-17 19:26:08 +0000531 case 'c':
532 Options |= EOptionDumpConfig;
533 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000534 case 'd':
John Kessenich26ad2682014-08-13 20:17:19 +0000535 Options |= EOptionDefaultDesktop;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000536 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600537 case 'h':
538 usage();
539 break;
John Kessenich05a70632013-09-17 19:26:08 +0000540 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000541 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000542 break;
543 case 'l':
John Kessenichd78e3512014-08-25 20:07:55 +0000544 Options |= EOptionLinkProgram;
John Kessenich94a81fb2013-08-31 02:41:30 +0000545 break;
546 case 'm':
547 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000548 break;
John Kessenich68d78fd2015-07-12 19:28:10 -0600549 case 'o':
550 binaryFileName = argv[1];
551 if (argc > 0) {
552 argc--;
553 argv++;
554 } else
555 Error("no <file> provided for -o");
556 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000557 case 'q':
558 Options |= EOptionDumpReflection;
559 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000560 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000561 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000562 break;
563 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000564 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000565 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000566 case 't':
567 #ifdef _WIN32
John Kessenichb0a7eb52013-11-07 17:44:20 +0000568 Options |= EOptionMultiThreaded;
John Kessenich38f3b892013-09-06 19:52:57 +0000569 #endif
570 break;
John Kessenich319de232013-12-04 04:43:40 +0000571 case 'v':
572 Options |= EOptionDumpVersions;
573 break;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000574 case 'w':
575 Options |= EOptionSuppressWarnings;
576 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000577 default:
John Kessenich68d78fd2015-07-12 19:28:10 -0600578 usage();
579 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000580 }
John Kessenich38f3b892013-09-06 19:52:57 +0000581 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000582 std::string name(argv[0]);
583 if (! SetConfigFile(name)) {
584 Work[argc] = new glslang::TWorkItem(name);
585 Worklist.add(Work[argc]);
586 }
John Kessenich38f3b892013-09-06 19:52:57 +0000587 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000588 }
589
John Kessenich68d78fd2015-07-12 19:28:10 -0600590 // Make sure that -E is not specified alongside linking (which includes SPV generation)
591 if ((Options & EOptionOutputPreprocessed) && (Options & EOptionLinkProgram))
592 Error("can't use -E when linking is selected");
John Kessenichc555ddd2015-06-17 02:38:44 +0000593
John Kessenich68d78fd2015-07-12 19:28:10 -0600594 // -o makes no sense if there is no target binary
595 if (binaryFileName && (Options & EOptionSpv) == 0)
596 Error("no binary generation requested (e.g., -V)");
John Kessenich2b07c7e2013-07-31 18:44:13 +0000597}
598
John Kessenich68d78fd2015-07-12 19:28:10 -0600599//
600// Translate the meaningful subset of command-line options to parser-behavior options.
601//
John Kessenichb0a7eb52013-11-07 17:44:20 +0000602void SetMessageOptions(EShMessages& messages)
603{
604 if (Options & EOptionRelaxedErrors)
605 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
606 if (Options & EOptionIntermediate)
607 messages = (EShMessages)(messages | EShMsgAST);
608 if (Options & EOptionSuppressWarnings)
609 messages = (EShMessages)(messages | EShMsgSuppressWarnings);
John Kessenich68d78fd2015-07-12 19:28:10 -0600610 if (Options & EOptionSpv)
611 messages = (EShMessages)(messages | EShMsgSpvRules);
612 if (Options & EOptionVulkanRules)
613 messages = (EShMessages)(messages | EShMsgVulkanRules);
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400614 if (Options & EOptionOutputPreprocessed)
615 messages = (EShMessages)(messages | EShMsgOnlyPreprocessor);
John Kessenichb0a7eb52013-11-07 17:44:20 +0000616}
617
John Kessenich68d78fd2015-07-12 19:28:10 -0600618//
John Kessenich69f4b512013-09-04 21:19:27 +0000619// Thread entry point, for non-linking asynchronous mode.
John Kessenichc999ba22013-11-07 23:33:24 +0000620//
621// Return 0 for failure, 1 for success.
622//
John Kessenichee6a9c82013-07-31 23:19:17 +0000623unsigned int
624#ifdef _WIN32
625 __stdcall
626#endif
John Kessenich94a81fb2013-08-31 02:41:30 +0000627CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000628{
John Kessenich38f3b892013-09-06 19:52:57 +0000629 glslang::TWorkItem* workItem;
630 while (Worklist.remove(workItem)) {
631 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000632 if (compiler == 0)
John Kessenichc999ba22013-11-07 23:33:24 +0000633 return 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000634
John Kessenichb0a7eb52013-11-07 17:44:20 +0000635 CompileFile(workItem->name.c_str(), compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000636
John Kessenich94a81fb2013-08-31 02:41:30 +0000637 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000638 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000639
640 ShDestruct(compiler);
641 }
642
643 return 0;
644}
645
John Kessenichacba7722015-03-04 03:48:38 +0000646const char* GlslStd450DebugNames[GLSL_STD_450::Count];
647
John Kessenich6626cad2015-06-19 05:14:19 +0000648// Outputs the given string, but only if it is non-null and non-empty.
649// This prevents erroneous newlines from appearing.
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400650void PutsIfNonEmpty(const char* str)
John Kessenich6626cad2015-06-19 05:14:19 +0000651{
652 if (str && str[0]) {
653 puts(str);
654 }
655}
656
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400657// Outputs the given string to stderr, but only if it is non-null and non-empty.
658// This prevents erroneous newlines from appearing.
659void StderrIfNonEmpty(const char* str)
660{
661 if (str && str[0]) {
662 fprintf(stderr, "%s\n", str);
663 }
664}
665
John Kessenich69f4b512013-09-04 21:19:27 +0000666//
667// For linking mode: Will independently parse each item in the worklist, but then put them
668// in the same program and link them together.
669//
670// Uses the new C++ interface instead of the old handle-based interface.
671//
672void CompileAndLinkShaders()
673{
674 // keep track of what to free
675 std::list<glslang::TShader*> shaders;
John Kessenichbf63ef02013-11-14 00:16:43 +0000676
John Kessenich69f4b512013-09-04 21:19:27 +0000677 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000678 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000679
John Kessenich69f4b512013-09-04 21:19:27 +0000680 //
681 // Per-shader processing...
682 //
683
John Kessenich5b0f13a2013-11-01 03:08:40 +0000684 glslang::TProgram& program = *new glslang::TProgram;
John Kessenich38f3b892013-09-06 19:52:57 +0000685 glslang::TWorkItem* workItem;
686 while (Worklist.remove(workItem)) {
687 EShLanguage stage = FindLanguage(workItem->name);
John Kessenich69f4b512013-09-04 21:19:27 +0000688 glslang::TShader* shader = new glslang::TShader(stage);
689 shaders.push_back(shader);
690
John Kessenich38f3b892013-09-06 19:52:57 +0000691 char** shaderStrings = ReadFileData(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000692 if (! shaderStrings) {
693 usage();
John Kessenichb3297152015-07-11 18:01:03 -0600694 delete &program;
695
John Kessenich69f4b512013-09-04 21:19:27 +0000696 return;
697 }
John Kessenichc555ddd2015-06-17 02:38:44 +0000698 const int defaultVersion = Options & EOptionDefaultDesktop? 110: 100;
John Kessenich69f4b512013-09-04 21:19:27 +0000699
700 shader->setStrings(shaderStrings, 1);
John Kessenichc555ddd2015-06-17 02:38:44 +0000701 if (Options & EOptionOutputPreprocessed) {
702 std::string str;
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400703 if (shader->preprocess(&Resources, defaultVersion, ENoProfile,
704 false, false, messages, &str)) {
705 PutsIfNonEmpty(str.c_str());
706 } else {
707 CompileFailed = true;
708 }
709 StderrIfNonEmpty(shader->getInfoLog());
710 StderrIfNonEmpty(shader->getInfoDebugLog());
John Kessenichc555ddd2015-06-17 02:38:44 +0000711 FreeFileData(shaderStrings);
712 continue;
713 }
714 if (! shader->parse(&Resources, defaultVersion, false, messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000715 CompileFailed = true;
John Kessenichc555ddd2015-06-17 02:38:44 +0000716
John Kessenich69f4b512013-09-04 21:19:27 +0000717 program.addShader(shader);
718
719 if (! (Options & EOptionSuppressInfolog)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400720 PutsIfNonEmpty(workItem->name.c_str());
721 PutsIfNonEmpty(shader->getInfoLog());
722 PutsIfNonEmpty(shader->getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000723 }
724
725 FreeFileData(shaderStrings);
726 }
727
728 //
729 // Program-level processing...
730 //
731
John Kessenich68d78fd2015-07-12 19:28:10 -0600732 if (! (Options & EOptionOutputPreprocessed) && ! program.link(messages))
John Kessenichc999ba22013-11-07 23:33:24 +0000733 LinkFailed = true;
734
John Kessenich69f4b512013-09-04 21:19:27 +0000735 if (! (Options & EOptionSuppressInfolog)) {
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400736 PutsIfNonEmpty(program.getInfoLog());
737 PutsIfNonEmpty(program.getInfoDebugLog());
John Kessenich69f4b512013-09-04 21:19:27 +0000738 }
739
John Kessenich11f9fc72013-11-07 01:06:34 +0000740 if (Options & EOptionDumpReflection) {
741 program.buildReflection();
742 program.dumpReflection();
743 }
744
John Kessenich0df0cde2015-03-03 17:09:43 +0000745 if (Options & EOptionSpv) {
John Kessenich92f90382014-07-28 04:21:04 +0000746 if (CompileFailed || LinkFailed)
John Kessenich68d78fd2015-07-12 19:28:10 -0600747 printf("SPIR-V is not generated for failed compile or link\n");
John Kessenich92f90382014-07-28 04:21:04 +0000748 else {
749 for (int stage = 0; stage < EShLangCount; ++stage) {
John Kessenicha7a68a92014-08-24 18:21:00 +0000750 if (program.getIntermediate((EShLanguage)stage)) {
John Kessenich0df0cde2015-03-03 17:09:43 +0000751 std::vector<unsigned int> spirv;
752 glslang::GlslangToSpv(*program.getIntermediate((EShLanguage)stage), spirv);
John Kessenich68d78fd2015-07-12 19:28:10 -0600753 glslang::OutputSpv(spirv, GetBinaryName((EShLanguage)stage));
John Kessenichacba7722015-03-04 03:48:38 +0000754 if (Options & EOptionHumanReadableSpv) {
755 spv::Parameterize();
756 GLSL_STD_450::GetDebugNames(GlslStd450DebugNames);
757 spv::Disassemble(std::cout, spirv);
758 }
John Kessenicha7a68a92014-08-24 18:21:00 +0000759 }
John Kessenich92f90382014-07-28 04:21:04 +0000760 }
761 }
762 }
763
John Kessenich5b0f13a2013-11-01 03:08:40 +0000764 // Free everything up, program has to go before the shaders
765 // because it might have merged stuff from the shaders, and
766 // the stuff from the shaders has to have its destructors called
767 // before the pools holding the memory in the shaders is freed.
768 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000769 while (shaders.size() > 0) {
770 delete shaders.back();
771 shaders.pop_back();
772 }
John Kessenich69f4b512013-09-04 21:19:27 +0000773}
774
John Kessenicha0af4732012-12-12 21:15:54 +0000775int C_DECL main(int argc, char* argv[])
776{
John Kessenich68d78fd2015-07-12 19:28:10 -0600777 ProcessArguments(argc, argv);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000778
John Kessenich05a70632013-09-17 19:26:08 +0000779 if (Options & EOptionDumpConfig) {
780 printf("%s", DefaultConfig);
781 if (Worklist.empty())
782 return ESuccess;
783 }
784
John Kessenich319de232013-12-04 04:43:40 +0000785 if (Options & EOptionDumpVersions) {
786 printf("ESSL Version: %s\n", glslang::GetEsslVersionString());
787 printf("GLSL Version: %s\n", glslang::GetGlslVersionString());
John Kessenich68d78fd2015-07-12 19:28:10 -0600788 std::string spirvVersion;
789 glslang::GetSpirvVersion(spirvVersion);
790 printf("SPIR-V Version %s\n", spirvVersion.c_str()); // TODO: move to consume source-generated data
John Kessenich319de232013-12-04 04:43:40 +0000791 if (Worklist.empty())
792 return ESuccess;
793 }
794
John Kessenich05a70632013-09-17 19:26:08 +0000795 if (Worklist.empty()) {
796 usage();
John Kessenich05a70632013-09-17 19:26:08 +0000797 }
798
799 ProcessConfigFile();
800
John Kessenich69f4b512013-09-04 21:19:27 +0000801 //
802 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000803 // 1) linking all arguments together, single-threaded, new C++ interface
804 // 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 +0000805 //
John Kessenichc555ddd2015-06-17 02:38:44 +0000806 if (Options & EOptionLinkProgram ||
807 Options & EOptionOutputPreprocessed) {
John Kessenichc36e1d82013-11-01 17:41:52 +0000808 glslang::InitializeProcess();
John Kessenich38f3b892013-09-06 19:52:57 +0000809 CompileAndLinkShaders();
John Kessenichc36e1d82013-11-01 17:41:52 +0000810 glslang::FinalizeProcess();
811 } else {
812 ShInitialize();
813
John Kessenich38f3b892013-09-06 19:52:57 +0000814 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000815
John Kessenich38f3b892013-09-06 19:52:57 +0000816 if (Options & EOptionMultiThreaded) {
817 const int NumThreads = 16;
818 void* threads[NumThreads];
819 for (int t = 0; t < NumThreads; ++t) {
820 threads[t] = glslang::OS_CreateThread(&CompileShaders);
821 if (! threads[t]) {
822 printf("Failed to create thread\n");
823 return EFailThreadCreate;
824 }
John Kessenicha0af4732012-12-12 21:15:54 +0000825 }
John Kessenich38f3b892013-09-06 19:52:57 +0000826 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenichc999ba22013-11-07 23:33:24 +0000827 } else
828 CompileShaders(0);
John Kessenich38f3b892013-09-06 19:52:57 +0000829
830 // Print out all the resulting infologs
831 for (int w = 0; w < NumWorkItems; ++w) {
832 if (Work[w]) {
833 if (printShaderNames)
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400834 PutsIfNonEmpty(Work[w]->name.c_str());
835 PutsIfNonEmpty(Work[w]->results.c_str());
John Kessenich38f3b892013-09-06 19:52:57 +0000836 delete Work[w];
837 }
838 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000839
840 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000841 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000842
John Kessenichc999ba22013-11-07 23:33:24 +0000843 if (CompileFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000844 return EFailCompile;
John Kessenichc999ba22013-11-07 23:33:24 +0000845 if (LinkFailed)
John Kessenicha0af4732012-12-12 21:15:54 +0000846 return EFailLink;
847
848 return 0;
849}
850
851//
852// Deduce the language from the filename. Files must end in one of the
853// following extensions:
854//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000855// .vert = vertex
856// .tesc = tessellation control
857// .tese = tessellation evaluation
858// .geom = geometry
859// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000860// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000861//
John Kessenichb603f912013-08-29 00:39:25 +0000862EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000863{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000864 size_t ext = name.rfind('.');
865 if (ext == std::string::npos) {
866 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000867 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000868 }
869
John Kessenich2b07c7e2013-07-31 18:44:13 +0000870 std::string suffix = name.substr(ext + 1, std::string::npos);
871 if (suffix == "vert")
872 return EShLangVertex;
873 else if (suffix == "tesc")
874 return EShLangTessControl;
875 else if (suffix == "tese")
876 return EShLangTessEvaluation;
877 else if (suffix == "geom")
878 return EShLangGeometry;
879 else if (suffix == "frag")
880 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000881 else if (suffix == "comp")
882 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000883
884 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000885 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000886}
887
John Kessenicha0af4732012-12-12 21:15:54 +0000888//
John Kessenich69f4b512013-09-04 21:19:27 +0000889// Read a file's data into a string, and compile it using the old interface ShCompile,
890// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000891//
John Kessenich51cdd902014-02-18 23:37:57 +0000892void CompileFile(const char* fileName, ShHandle compiler)
John Kessenicha0af4732012-12-12 21:15:54 +0000893{
John Kessenichca3457f2015-05-18 01:59:45 +0000894 int ret = 0;
John Kessenich41cf6b52013-06-25 18:10:05 +0000895 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000896 if (! shaderStrings) {
897 usage();
John Kessenichdb4cd542013-06-26 22:42:55 +0000898 }
899
John Kessenich41cf6b52013-06-25 18:10:05 +0000900 int* lengths = new int[NumShaderStrings];
901
902 // move to length-based strings, rather than null-terminated strings
903 for (int s = 0; s < NumShaderStrings; ++s)
John Kessenich35f04bd2014-02-19 02:47:20 +0000904 lengths[s] = (int)strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000905
John Kessenichc999ba22013-11-07 23:33:24 +0000906 if (! shaderStrings) {
907 CompileFailed = true;
908 return;
909 }
John Kessenicha0af4732012-12-12 21:15:54 +0000910
John Kessenich52ac67e2013-05-05 23:46:22 +0000911 EShMessages messages = EShMsgDefault;
John Kessenichb0a7eb52013-11-07 17:44:20 +0000912 SetMessageOptions(messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000913
John Kessenich94a81fb2013-08-31 02:41:30 +0000914 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
915 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich26ad2682014-08-13 20:17:19 +0000916 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichca3457f2015-05-18 01:59:45 +0000917 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +0000918 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
919 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
920 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +0000921 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichca3457f2015-05-18 01:59:45 +0000922 //ret = ShCompile(compiler, multi, 7, nullptr, EShOptNone, &Resources, Options, (Options & EOptionDefaultDesktop) ? 110 : 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000923 }
John Kessenicha0af4732012-12-12 21:15:54 +0000924
John Kessenich94a81fb2013-08-31 02:41:30 +0000925 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000926 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000927 }
John Kessenicha0af4732012-12-12 21:15:54 +0000928
John Kessenich41cf6b52013-06-25 18:10:05 +0000929 delete [] lengths;
930 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000931
John Kessenichc999ba22013-11-07 23:33:24 +0000932 if (ret == 0)
933 CompileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +0000934}
935
John Kessenicha0af4732012-12-12 21:15:54 +0000936//
937// print usage to stdout
938//
939void usage()
940{
John Kessenich319de232013-12-04 04:43:40 +0000941 printf("Usage: glslangValidator [option]... [file]...\n"
942 "\n"
John Kessenich0df0cde2015-03-03 17:09:43 +0000943 "Where: each 'file' ends in .<stage>, where <stage> is one of\n"
John Kessenich68d78fd2015-07-12 19:28:10 -0600944 " .conf to provide an optional config file that replaces the default configuration\n"
945 " (see -c option below for generating a template)\n"
946 " .vert for a vertex shader\n"
947 " .tesc for a tessellation control shader\n"
948 " .tese for a tessellation evaluation shader\n"
949 " .geom for a geometry shader\n"
950 " .frag for a fragment shader\n"
951 " .comp for a compute shader\n"
John Kessenich319de232013-12-04 04:43:40 +0000952 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000953 "Compilation warnings and errors will be printed to stdout.\n"
John Kessenich319de232013-12-04 04:43:40 +0000954 "\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000955 "To get other information, use one of the following options:\n"
John Kessenich68d78fd2015-07-12 19:28:10 -0600956 "Each option must be specified separately.\n"
957 " -V create SPIR-V binary, under Vulkan semantics; turns on -l;\n"
958 " default file name is <stage>.spv (-o overrides this)\n"
959 " (unless -o is specified, which overrides the default file name)\n"
960 " -G create SPIR-V binary, under OpenGL semantics; turns on -l;\n"
961 " default file name is <stage>.spv (-o overrides this)\n"
962 " -H print human readable form of SPIR-V; turns on -V\n"
Andrew Woloszynaae1ad82015-06-24 17:00:46 -0400963 " -E print pre-processed GLSL; cannot be used with -l;\n"
964 " errors will appear on stderr.\n"
John Kessenich68d78fd2015-07-12 19:28:10 -0600965 " -c configuration dump;\n"
966 " creates the default configuration file (redirect to a .conf file)\n"
967 " -d default to desktop (#version 110) when there is no shader #version\n"
968 " (default is ES version 100)\n"
969 " -h print this usage message\n"
970 " -i intermediate tree (glslang AST) is printed out\n"
971 " -l link all input files together to form a single module\n"
972 " -m memory leak mode\n"
973 " -o <file> save binary into <file>, requires a binary option (e.g., -V)\n"
974 " -q dump reflection query database\n"
975 " -r relaxed semantic error-checking mode\n"
976 " -s silent mode\n"
977 " -t multi-threaded mode\n"
978 " -v print version strings\n"
979 " -w suppress warnings (except as required by #extension : warn)\n"
John Kessenichb0a7eb52013-11-07 17:44:20 +0000980 );
John Kessenich68d78fd2015-07-12 19:28:10 -0600981
982 exit(EFailUsage);
John Kessenicha0af4732012-12-12 21:15:54 +0000983}
984
John Kessenich3ce4e592014-10-06 19:57:34 +0000985#if !defined _MSC_VER && !defined MINGW_HAS_SECURE_API
John Kessenichcfd643e2013-03-08 23:14:42 +0000986
987#include <errno.h>
988
989int fopen_s(
990 FILE** pFile,
John Kessenich51cdd902014-02-18 23:37:57 +0000991 const char* filename,
992 const char* mode
John Kessenichcfd643e2013-03-08 23:14:42 +0000993)
994{
995 if (!pFile || !filename || !mode) {
996 return EINVAL;
997 }
998
999 FILE* f = fopen(filename, mode);
1000 if (! f) {
1001 if (errno != 0) {
1002 return errno;
1003 } else {
1004 return ENOENT;
1005 }
1006 }
1007 *pFile = f;
1008
1009 return 0;
1010}
1011
1012#endif
1013
John Kessenicha0af4732012-12-12 21:15:54 +00001014//
1015// Malloc a string of sufficient size and read a string into it.
1016//
John Kessenich51cdd902014-02-18 23:37:57 +00001017char** ReadFileData(const char* fileName)
John Kessenicha0af4732012-12-12 21:15:54 +00001018{
John Kessenichb3297152015-07-11 18:01:03 -06001019 FILE *in = nullptr;
John Kessenich3ce4e592014-10-06 19:57:34 +00001020 int errorCode = fopen_s(&in, fileName, "r");
John Kessenichd6c72a42014-08-18 19:42:35 +00001021
John Kessenicha0af4732012-12-12 21:15:54 +00001022 int count = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001023 const int maxSourceStrings = 5; // for testing splitting shader/tokens across multiple strings
1024 char** return_data = (char**)malloc(sizeof(char *) * (maxSourceStrings+1)); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001025
John Kessenich68d78fd2015-07-12 19:28:10 -06001026 if (errorCode || in == nullptr)
1027 Error("unable to open input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001028
1029 while (fgetc(in) != EOF)
1030 count++;
1031
John Kessenichd6c72a42014-08-18 19:42:35 +00001032 fseek(in, 0, SEEK_SET);
John Kessenichca3457f2015-05-18 01:59:45 +00001033
John Kessenichb3297152015-07-11 18:01:03 -06001034 char *fdata = (char*)malloc(count+2); // freed before return of this function
John Kessenich68d78fd2015-07-12 19:28:10 -06001035 if (! fdata)
1036 Error("can't allocate memory");
1037
John Kessenichb3297152015-07-11 18:01:03 -06001038 if ((int)fread(fdata, 1, count, in) != count) {
John Kessenichb3297152015-07-11 18:01:03 -06001039 free(fdata);
John Kessenich68d78fd2015-07-12 19:28:10 -06001040 Error("can't read input file");
John Kessenicha0af4732012-12-12 21:15:54 +00001041 }
John Kessenich68d78fd2015-07-12 19:28:10 -06001042
John Kessenicha0af4732012-12-12 21:15:54 +00001043 fdata[count] = '\0';
1044 fclose(in);
John Kessenichb3297152015-07-11 18:01:03 -06001045
John Kessenichea869fb2013-10-28 18:12:06 +00001046 if (count == 0) {
John Kessenichb3297152015-07-11 18:01:03 -06001047 // recover from empty file
1048 return_data[0] = (char*)malloc(count+2); // freed in FreeFileData()
John Kessenicha0af4732012-12-12 21:15:54 +00001049 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +00001050 NumShaderStrings = 0;
John Kessenichb3297152015-07-11 18:01:03 -06001051 free(fdata);
John Kessenicha0af4732012-12-12 21:15:54 +00001052
John Kessenichb3297152015-07-11 18:01:03 -06001053 return return_data;
1054 } else
1055 NumShaderStrings = 1; // Set to larger than 1 for testing multiple strings
1056
1057 // compute how to split up the file into multiple strings, for testing multiple strings
John Kessenichd6c72a42014-08-18 19:42:35 +00001058 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenichb3297152015-07-11 18:01:03 -06001059 int ptr_len = 0;
1060 int i = 0;
1061 while (count > 0) {
1062 return_data[i] = (char*)malloc(len + 2); // freed in FreeFileData()
1063 memcpy(return_data[i], fdata + ptr_len, len);
1064 return_data[i][len] = '\0';
1065 count -= len;
1066 ptr_len += len;
1067 if (count < len) {
1068 if (count == 0) {
1069 NumShaderStrings = i + 1;
John Kessenicha0af4732012-12-12 21:15:54 +00001070 break;
1071 }
John Kessenichb3297152015-07-11 18:01:03 -06001072 len = count;
John Kessenichd6c72a42014-08-18 19:42:35 +00001073 }
1074 ++i;
1075 }
John Kessenichb3297152015-07-11 18:01:03 -06001076
1077 free(fdata);
1078
John Kessenicha0af4732012-12-12 21:15:54 +00001079 return return_data;
1080}
1081
John Kessenich51cdd902014-02-18 23:37:57 +00001082void FreeFileData(char** data)
John Kessenicha0af4732012-12-12 21:15:54 +00001083{
John Kessenichb3297152015-07-11 18:01:03 -06001084 for(int i = 0; i < NumShaderStrings; i++)
John Kessenicha0af4732012-12-12 21:15:54 +00001085 free(data[i]);
John Kessenichb3297152015-07-11 18:01:03 -06001086
1087 free(data);
John Kessenicha0af4732012-12-12 21:15:54 +00001088}
1089
John Kessenich54d8cda2013-02-11 22:36:01 +00001090void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +00001091{
John Kessenichfae38ee2015-06-10 23:23:12 +00001092 if (num >= 0 )
1093 printf("#### %s %s %d INFO LOG ####\n", msg, name, num);
1094 else
1095 printf("#### %s %s INFO LOG ####\n", msg, name);
John Kessenicha0af4732012-12-12 21:15:54 +00001096}