blob: a3c1fafa6cfcd2bed2ab52ac5c5af2e96c8750ca [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"
43#include <string.h>
John Kessenichcfd643e2013-03-08 23:14:42 +000044#include <stdlib.h>
John Kessenicha0af4732012-12-12 21:15:54 +000045#include <math.h>
46
John Kessenich2b07c7e2013-07-31 18:44:13 +000047#include "osinclude.h"
John Kessenicha0af4732012-12-12 21:15:54 +000048
49extern "C" {
50 SH_IMPORT_EXPORT void ShOutputHtml();
51}
52
John Kessenich94a81fb2013-08-31 02:41:30 +000053// Command-line options
54enum TOptions {
55 EOptionNone = 0x000,
56 EOptionIntermediate = 0x001,
57 EOptionSuppressInfolog = 0x002,
58 EOptionMemoryLeakMode = 0x004,
59 EOptionRelaxedErrors = 0x008,
60 EOptionGiveWarnings = 0x010,
61 EOptionsLinkProgram = 0x020,
John Kessenich38f3b892013-09-06 19:52:57 +000062 EOptionMultiThreaded = 0x040,
John Kessenich05a70632013-09-17 19:26:08 +000063 EOptionDumpConfig = 0x080,
John Kessenich11f9fc72013-11-07 01:06:34 +000064 EOptionDumpReflection = 0x100,
John Kessenich94a81fb2013-08-31 02:41:30 +000065};
66
John Kessenicha0af4732012-12-12 21:15:54 +000067//
68// Return codes from main.
69//
70enum TFailCode {
71 ESuccess = 0,
72 EFailUsage,
73 EFailCompile,
74 EFailLink,
75 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000076 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000077 EFailLinkerCreate
78};
79
80//
81// Just placeholders for testing purposes. The stand-alone environment
82// can't actually do a full link without something specifying real
83// attribute bindings.
84//
85ShBinding FixedAttributeBindings[] = {
86 { "gl_Vertex", 15 },
87 { "gl_Color", 10 },
88 { "gl_Normal", 7 },
89};
90
91ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
92
John Kessenichb603f912013-08-29 00:39:25 +000093EShLanguage FindLanguage(const std::string& name);
John Kessenich05a70632013-09-17 19:26:08 +000094bool CompileFile(const char *fileName, ShHandle, int options);
John Kessenicha0af4732012-12-12 21:15:54 +000095void usage();
John Kessenichea869fb2013-10-28 18:12:06 +000096void FreeFileData(char** data);
97char** ReadFileData(const char* fileName);
John Kessenich54d8cda2013-02-11 22:36:01 +000098void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +000099
John Kessenich05a70632013-09-17 19:26:08 +0000100// Use to test breaking up a single shader file into multiple strings.
John Kessenichea869fb2013-10-28 18:12:06 +0000101int NumShaderStrings;
John Kessenicha0af4732012-12-12 21:15:54 +0000102
John Kessenich05a70632013-09-17 19:26:08 +0000103TBuiltInResource Resources;
104std::string ConfigFile;
105
John Kessenicha0af4732012-12-12 21:15:54 +0000106//
John Kessenich05a70632013-09-17 19:26:08 +0000107// These are the default resources for TBuiltInResources, used for both
108// - parsing this string for the case where the user didn't supply one
109// - dumping out a template for user construction of a config file
John Kessenicha0af4732012-12-12 21:15:54 +0000110//
John Kessenich284231c2013-10-22 01:50:39 +0000111const char* DefaultConfig =
112 "MaxLights 32\n"
113 "MaxClipPlanes 6\n"
114 "MaxTextureUnits 32\n"
115 "MaxTextureCoords 32\n"
116 "MaxVertexAttribs 64\n"
117 "MaxVertexUniformComponents 4096\n"
118 "MaxVaryingFloats 64\n"
119 "MaxVertexTextureImageUnits 32\n"
120 "MaxCombinedTextureImageUnits 32\n"
121 "MaxTextureImageUnits 32\n"
122 "MaxFragmentUniformComponents 4096\n"
123 "MaxDrawBuffers 32\n"
124 "MaxVertexUniformVectors 128\n"
125 "MaxVaryingVectors 8\n"
126 "MaxFragmentUniformVectors 16\n"
127 "MaxVertexOutputVectors 16\n"
128 "MaxFragmentInputVectors 15\n"
129 "MinProgramTexelOffset -8\n"
130 "MaxProgramTexelOffset 7\n"
131 "MaxClipDistances 8\n"
132 "MaxComputeWorkGroupCountX 65535\n"
133 "MaxComputeWorkGroupCountY 65535\n"
134 "MaxComputeWorkGroupCountZ 65535\n"
135 "MaxComputeWorkGroupSizeX 1024\n"
136 "MaxComputeWorkGroupSizeX 1024\n"
137 "MaxComputeWorkGroupSizeZ 64\n"
138 "MaxComputeUniformComponents 1024\n"
139 "MaxComputeTextureImageUnits 16\n"
140 "MaxComputeImageUniforms 8\n"
141 "MaxComputeAtomicCounters 8\n"
142 "MaxComputeAtomicCounterBuffers 1\n"
143 "MaxVaryingComponents 60\n"
144 "MaxVertexOutputComponents 64\n"
145 "MaxGeometryInputComponents 64\n"
146 "MaxGeometryOutputComponents 128\n"
147 "MaxFragmentInputComponents 128\n"
148 "MaxImageUnits 8\n"
149 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
150 "MaxImageSamples 0\n"
151 "MaxVertexImageUniforms 0\n"
152 "MaxTessControlImageUniforms 0\n"
153 "MaxTessEvaluationImageUniforms 0\n"
154 "MaxGeometryImageUniforms 0\n"
155 "MaxFragmentImageUniforms 8\n"
156 "MaxCombinedImageUniforms 8\n"
157 "MaxGeometryTextureImageUnits 16\n"
158 "MaxGeometryOutputVertices 256\n"
159 "MaxGeometryTotalOutputComponents 1024\n"
160 "MaxGeometryUniformComponents 1024\n"
161 "MaxGeometryVaryingComponents 64\n"
162 "MaxTessControlInputComponents 128\n"
163 "MaxTessControlOutputComponents 128\n"
164 "MaxTessControlTextureImageUnits 16\n"
165 "MaxTessControlUniformComponents 1024\n"
166 "MaxTessControlTotalOutputComponents 4096\n"
167 "MaxTessEvaluationInputComponents 128\n"
168 "MaxTessEvaluationOutputComponents 128\n"
169 "MaxTessEvaluationTextureImageUnits 16\n"
170 "MaxTessEvaluationUniformComponents 1024\n"
171 "MaxTessPatchComponents 120\n"
172 "MaxPatchVertices 32\n"
173 "MaxTessGenLevel 64\n"
174 "MaxViewports 16\n"
175 "MaxVertexAtomicCounters 0\n"
176 "MaxTessControlAtomicCounters 0\n"
177 "MaxTessEvaluationAtomicCounters 0\n"
178 "MaxGeometryAtomicCounters 0\n"
179 "MaxFragmentAtomicCounters 8\n"
180 "MaxCombinedAtomicCounters 8\n"
181 "MaxAtomicCounterBindings 1\n"
182 "MaxVertexAtomicCounterBuffers 0\n"
183 "MaxTessControlAtomicCounterBuffers 0\n"
184 "MaxTessEvaluationAtomicCounterBuffers 0\n"
185 "MaxGeometryAtomicCounterBuffers 0\n"
186 "MaxFragmentAtomicCounterBuffers 1\n"
187 "MaxCombinedAtomicCounterBuffers 1\n"
188 "MaxAtomicCounterBufferSize 16384\n"
189
190 "nonInductiveForLoops 1\n"
191 "whileLoops 1\n"
192 "doWhileLoops 1\n"
193 "generalUniformIndexing 1\n"
194 "generalAttributeMatrixVectorIndexing 1\n"
195 "generalVaryingIndexing 1\n"
196 "generalSamplerIndexing 1\n"
197 "generalVariableIndexing 1\n"
198 "generalConstantMatrixVectorIndexing 1\n"
199 ;
John Kessenich05a70632013-09-17 19:26:08 +0000200
201//
202// Parse either a .conf file provided by the user or the default string above.
203//
204void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000205{
John Kessenich05a70632013-09-17 19:26:08 +0000206 char** configStrings = 0;
207 char *config = 0;
208 if (ConfigFile.size() > 0) {
John Kessenichea869fb2013-10-28 18:12:06 +0000209 configStrings = ReadFileData(ConfigFile.c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000210 if (configStrings)
211 config = *configStrings;
212 else {
213 printf("Error opening configuration file; will instead use the default configuration\n");
214 usage();
215 }
216 }
217
218 if (config == 0) {
219 config = new char[strlen(DefaultConfig)];
220 strcpy(config, DefaultConfig);
221 }
222
223 const char* delims = " \t\n\r";
224 const char* token = strtok(config, delims);
225 while (token) {
226 const char* valueStr = strtok(0, delims);
227 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
228 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
229 return;
230 }
231 int value = atoi(valueStr);
232
233 if (strcmp(token, "MaxLights") == 0)
234 Resources.maxLights = value;
235 else if (strcmp(token, "MaxClipPlanes") == 0)
236 Resources.maxClipPlanes = value;
237 else if (strcmp(token, "MaxTextureUnits") == 0)
238 Resources.maxTextureUnits = value;
239 else if (strcmp(token, "MaxTextureCoords") == 0)
240 Resources.maxTextureCoords = value;
241 else if (strcmp(token, "MaxVertexAttribs") == 0)
242 Resources.maxVertexAttribs = value;
243 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
244 Resources.maxVertexUniformComponents = value;
245 else if (strcmp(token, "MaxVaryingFloats") == 0)
246 Resources.maxVaryingFloats = value;
247 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
248 Resources.maxVertexTextureImageUnits = value;
249 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
250 Resources.maxCombinedTextureImageUnits = value;
251 else if (strcmp(token, "MaxTextureImageUnits") == 0)
252 Resources.maxTextureImageUnits = value;
253 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
254 Resources.maxFragmentUniformComponents = value;
255 else if (strcmp(token, "MaxDrawBuffers") == 0)
256 Resources.maxDrawBuffers = value;
257 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
258 Resources.maxVertexUniformVectors = value;
259 else if (strcmp(token, "MaxVaryingVectors") == 0)
260 Resources.maxVaryingVectors = value;
261 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
262 Resources.maxFragmentUniformVectors = value;
263 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
264 Resources.maxVertexOutputVectors = value;
265 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
266 Resources.maxFragmentInputVectors = value;
267 else if (strcmp(token, "MinProgramTexelOffset") == 0)
268 Resources.minProgramTexelOffset = value;
269 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
270 Resources.maxProgramTexelOffset = value;
John Kesseniche7c59c12013-10-16 22:28:35 +0000271 else if (strcmp(token, "MaxClipDistances") == 0)
272 Resources.maxClipDistances = value;
John Kessenich284231c2013-10-22 01:50:39 +0000273 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
274 Resources.maxComputeWorkGroupCountX = value;
275 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
276 Resources.maxComputeWorkGroupCountY = value;
277 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
278 Resources.maxComputeWorkGroupCountZ = value;
279 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
280 Resources.maxComputeWorkGroupSizeX = value;
281 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
282 Resources.maxComputeWorkGroupSizeY = value;
283 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
284 Resources.maxComputeWorkGroupSizeZ = value;
285 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
286 Resources.maxComputeUniformComponents = value;
287 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
288 Resources.maxComputeTextureImageUnits = value;
289 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
290 Resources.maxComputeImageUniforms = value;
291 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
292 Resources.maxComputeAtomicCounters = value;
293 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
294 Resources.maxComputeAtomicCounterBuffers = value;
295 else if (strcmp(token, "MaxVaryingComponents") == 0)
296 Resources.maxVaryingComponents = value;
297 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
298 Resources.maxVertexOutputComponents = value;
299 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
300 Resources.maxGeometryInputComponents = value;
301 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
302 Resources.maxGeometryOutputComponents = value;
303 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
304 Resources.maxFragmentInputComponents = value;
305 else if (strcmp(token, "MaxImageUnits") == 0)
306 Resources.maxImageUnits = value;
307 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
308 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
309 else if (strcmp(token, "MaxImageSamples") == 0)
310 Resources.maxImageSamples = value;
311 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
312 Resources.maxVertexImageUniforms = value;
313 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
314 Resources.maxTessControlImageUniforms = value;
315 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
316 Resources.maxTessEvaluationImageUniforms = value;
317 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
318 Resources.maxGeometryImageUniforms = value;
319 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
320 Resources.maxFragmentImageUniforms = value;
321 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
322 Resources.maxCombinedImageUniforms = value;
323 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
324 Resources.maxGeometryTextureImageUnits = value;
325 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
326 Resources.maxGeometryOutputVertices = value;
327 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
328 Resources.maxGeometryTotalOutputComponents = value;
329 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
330 Resources.maxGeometryUniformComponents = value;
331 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
332 Resources.maxGeometryVaryingComponents = value;
333 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
334 Resources.maxTessControlInputComponents = value;
335 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
336 Resources.maxTessControlOutputComponents = value;
337 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
338 Resources.maxTessControlTextureImageUnits = value;
339 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
340 Resources.maxTessControlUniformComponents = value;
341 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
342 Resources.maxTessControlTotalOutputComponents = value;
343 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
344 Resources.maxTessEvaluationInputComponents = value;
345 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
346 Resources.maxTessEvaluationOutputComponents = value;
347 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
348 Resources.maxTessEvaluationTextureImageUnits = value;
349 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
350 Resources.maxTessEvaluationUniformComponents = value;
351 else if (strcmp(token, "MaxTessPatchComponents") == 0)
352 Resources.maxTessPatchComponents = value;
353 else if (strcmp(token, "MaxPatchVertices") == 0)
354 Resources.maxPatchVertices = value;
355 else if (strcmp(token, "MaxTessGenLevel") == 0)
356 Resources.maxTessGenLevel = value;
357 else if (strcmp(token, "MaxViewports") == 0)
358 Resources.maxViewports = value;
359 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
360 Resources.maxVertexAtomicCounters = value;
361 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
362 Resources.maxTessControlAtomicCounters = value;
363 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
364 Resources.maxTessEvaluationAtomicCounters = value;
365 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
366 Resources.maxGeometryAtomicCounters = value;
367 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
368 Resources.maxFragmentAtomicCounters = value;
369 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
370 Resources.maxCombinedAtomicCounters = value;
371 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
372 Resources.maxAtomicCounterBindings = value;
373 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
374 Resources.maxVertexAtomicCounterBuffers = value;
375 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
376 Resources.maxTessControlAtomicCounterBuffers = value;
377 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
378 Resources.maxTessEvaluationAtomicCounterBuffers = value;
379 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
380 Resources.maxGeometryAtomicCounterBuffers = value;
381 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
382 Resources.maxFragmentAtomicCounterBuffers = value;
383 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
384 Resources.maxCombinedAtomicCounterBuffers = value;
385 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
386 Resources.maxAtomicCounterBufferSize = value;
387
John Kessenicha5830df2013-10-02 05:10:48 +0000388 else if (strcmp(token, "nonInductiveForLoops") == 0)
389 Resources.limits.nonInductiveForLoops = (value != 0);
390 else if (strcmp(token, "whileLoops") == 0)
391 Resources.limits.whileLoops = (value != 0);
392 else if (strcmp(token, "doWhileLoops") == 0)
393 Resources.limits.doWhileLoops = (value != 0);
394 else if (strcmp(token, "generalUniformIndexing") == 0)
395 Resources.limits.generalUniformIndexing = (value != 0);
396 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
397 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
398 else if (strcmp(token, "generalVaryingIndexing") == 0)
399 Resources.limits.generalVaryingIndexing = (value != 0);
400 else if (strcmp(token, "generalSamplerIndexing") == 0)
401 Resources.limits.generalSamplerIndexing = (value != 0);
402 else if (strcmp(token, "generalVariableIndexing") == 0)
403 Resources.limits.generalVariableIndexing = (value != 0);
404 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
405 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000406 else
407 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
408
409 token = strtok(0, delims);
410 }
411 if (configStrings)
412 FreeFileData(configStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000413}
414
John Kessenich38f3b892013-09-06 19:52:57 +0000415// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000416glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000417
418// array of unique places to leave the shader names and infologs for the asynchronous compiles
419glslang::TWorkItem **Work = 0;
420int NumWorkItems = 0;
421
John Kessenich94a81fb2013-08-31 02:41:30 +0000422int Options = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000423bool Delay = false;
John Kessenich38f3b892013-09-06 19:52:57 +0000424const char* ExecutableName;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000425
John Kessenich05a70632013-09-17 19:26:08 +0000426//
427// *.conf => this is a config file that can set limits/resources
428//
429bool SetConfigFile(const std::string& name)
430{
431 if (name.size() < 5)
432 return false;
433
John Kessenich4c706852013-10-11 16:28:43 +0000434 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000435 ConfigFile = name;
436 return true;
437 }
438
439 return false;
440}
441
John Kessenich2b07c7e2013-07-31 18:44:13 +0000442bool ProcessArguments(int argc, char* argv[])
443{
John Kessenich38f3b892013-09-06 19:52:57 +0000444 ExecutableName = argv[0];
445 NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
446 Work = new glslang::TWorkItem*[NumWorkItems];
447 Work[0] = 0;
448
John Kessenich2b07c7e2013-07-31 18:44:13 +0000449 argc--;
450 argv++;
451 for (; argc >= 1; argc--, argv++) {
John Kessenich05a70632013-09-17 19:26:08 +0000452 Work[argc] = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000453 if (argv[0][0] == '-') {
454 switch (argv[0][1]) {
John Kessenich05a70632013-09-17 19:26:08 +0000455 case 'c':
456 Options |= EOptionDumpConfig;
457 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000458 case 'd':
459 Delay = true;
460 break;
John Kessenich05a70632013-09-17 19:26:08 +0000461 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000462 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000463 break;
464 case 'l':
John Kessenich94a81fb2013-08-31 02:41:30 +0000465 Options |= EOptionsLinkProgram;
466 break;
467 case 'm':
468 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000469 break;
John Kessenich11f9fc72013-11-07 01:06:34 +0000470 case 'q':
471 Options |= EOptionDumpReflection;
472 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000473 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000474 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000475 break;
476 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000477 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000478 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000479 case 't':
480 #ifdef _WIN32
481 Options |= EOptionMultiThreaded;
482 #endif
483 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000484 default:
John Kessenich2b07c7e2013-07-31 18:44:13 +0000485 return false;
486 }
John Kessenich38f3b892013-09-06 19:52:57 +0000487 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000488 std::string name(argv[0]);
489 if (! SetConfigFile(name)) {
490 Work[argc] = new glslang::TWorkItem(name);
491 Worklist.add(Work[argc]);
492 }
John Kessenich38f3b892013-09-06 19:52:57 +0000493 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000494 }
495
496 return true;
497}
498
John Kessenich69f4b512013-09-04 21:19:27 +0000499// Thread entry point, for non-linking asynchronous mode.
John Kessenichee6a9c82013-07-31 23:19:17 +0000500unsigned int
501#ifdef _WIN32
502 __stdcall
503#endif
John Kessenich94a81fb2013-08-31 02:41:30 +0000504CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000505{
John Kessenich38f3b892013-09-06 19:52:57 +0000506 glslang::TWorkItem* workItem;
507 while (Worklist.remove(workItem)) {
508 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000509 if (compiler == 0)
510 return false;
511
John Kessenich05a70632013-09-17 19:26:08 +0000512 CompileFile(workItem->name.c_str(), compiler, Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000513
John Kessenich94a81fb2013-08-31 02:41:30 +0000514 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000515 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000516
517 ShDestruct(compiler);
518 }
519
520 return 0;
521}
522
John Kessenich69f4b512013-09-04 21:19:27 +0000523//
524// For linking mode: Will independently parse each item in the worklist, but then put them
525// in the same program and link them together.
526//
527// Uses the new C++ interface instead of the old handle-based interface.
528//
529void CompileAndLinkShaders()
530{
531 // keep track of what to free
532 std::list<glslang::TShader*> shaders;
533
534 EShMessages messages = EShMsgDefault;
535 if (Options & EOptionRelaxedErrors)
536 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
537 if (Options & EOptionIntermediate)
538 messages = (EShMessages)(messages | EShMsgAST);
539
John Kessenich69f4b512013-09-04 21:19:27 +0000540 //
541 // Per-shader processing...
542 //
543
John Kessenich5b0f13a2013-11-01 03:08:40 +0000544 glslang::TProgram& program = *new glslang::TProgram;
John Kessenich38f3b892013-09-06 19:52:57 +0000545 glslang::TWorkItem* workItem;
546 while (Worklist.remove(workItem)) {
547 EShLanguage stage = FindLanguage(workItem->name);
John Kessenich69f4b512013-09-04 21:19:27 +0000548 glslang::TShader* shader = new glslang::TShader(stage);
549 shaders.push_back(shader);
550
John Kessenich38f3b892013-09-06 19:52:57 +0000551 char** shaderStrings = ReadFileData(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000552 if (! shaderStrings) {
553 usage();
554 return;
555 }
556
557 shader->setStrings(shaderStrings, 1);
558
John Kessenich05a70632013-09-17 19:26:08 +0000559 shader->parse(&Resources, 100, false, messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000560
561 program.addShader(shader);
562
563 if (! (Options & EOptionSuppressInfolog)) {
John Kessenich38f3b892013-09-06 19:52:57 +0000564 puts(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000565 puts(shader->getInfoLog());
566 puts(shader->getInfoDebugLog());
567 }
568
569 FreeFileData(shaderStrings);
570 }
571
572 //
573 // Program-level processing...
574 //
575
576 program.link(messages);
577 if (! (Options & EOptionSuppressInfolog)) {
578 puts(program.getInfoLog());
579 puts(program.getInfoDebugLog());
580 }
581
John Kessenich11f9fc72013-11-07 01:06:34 +0000582 if (Options & EOptionDumpReflection) {
583 program.buildReflection();
584 program.dumpReflection();
585 }
586
John Kessenich5b0f13a2013-11-01 03:08:40 +0000587 // Free everything up, program has to go before the shaders
588 // because it might have merged stuff from the shaders, and
589 // the stuff from the shaders has to have its destructors called
590 // before the pools holding the memory in the shaders is freed.
591 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000592 while (shaders.size() > 0) {
593 delete shaders.back();
594 shaders.pop_back();
595 }
John Kessenich69f4b512013-09-04 21:19:27 +0000596}
597
John Kessenicha0af4732012-12-12 21:15:54 +0000598int C_DECL main(int argc, char* argv[])
599{
John Kessenicha0af4732012-12-12 21:15:54 +0000600 bool compileFailed = false;
601 bool linkFailed = false;
John Kessenicha0af4732012-12-12 21:15:54 +0000602
John Kessenich54f6e562013-08-03 00:04:10 +0000603 if (! ProcessArguments(argc, argv)) {
604 usage();
John Kessenich2b07c7e2013-07-31 18:44:13 +0000605 return EFailUsage;
John Kessenich54f6e562013-08-03 00:04:10 +0000606 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000607
John Kessenich05a70632013-09-17 19:26:08 +0000608 if (Options & EOptionDumpConfig) {
609 printf("%s", DefaultConfig);
610 if (Worklist.empty())
611 return ESuccess;
612 }
613
614 if (Worklist.empty()) {
615 usage();
616 return EFailUsage;
617 }
618
619 ProcessConfigFile();
620
John Kessenich69f4b512013-09-04 21:19:27 +0000621 //
622 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000623 // 1) linking all arguments together, single-threaded, new C++ interface
624 // 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 +0000625 //
John Kessenichc36e1d82013-11-01 17:41:52 +0000626 if (Options & EOptionsLinkProgram) {
627 glslang::InitializeProcess();
John Kessenich38f3b892013-09-06 19:52:57 +0000628 CompileAndLinkShaders();
John Kessenichc36e1d82013-11-01 17:41:52 +0000629 glslang::FinalizeProcess();
630 } else {
631 ShInitialize();
632
John Kessenich38f3b892013-09-06 19:52:57 +0000633 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000634
John Kessenich38f3b892013-09-06 19:52:57 +0000635 if (Options & EOptionMultiThreaded) {
636 const int NumThreads = 16;
637 void* threads[NumThreads];
638 for (int t = 0; t < NumThreads; ++t) {
639 threads[t] = glslang::OS_CreateThread(&CompileShaders);
640 if (! threads[t]) {
641 printf("Failed to create thread\n");
642 return EFailThreadCreate;
643 }
John Kessenicha0af4732012-12-12 21:15:54 +0000644 }
John Kessenich38f3b892013-09-06 19:52:57 +0000645 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenich69f4b512013-09-04 21:19:27 +0000646 } else {
647 if (! CompileShaders(0))
648 compileFailed = true;
649 }
John Kessenich38f3b892013-09-06 19:52:57 +0000650
651 // Print out all the resulting infologs
652 for (int w = 0; w < NumWorkItems; ++w) {
653 if (Work[w]) {
654 if (printShaderNames)
655 puts(Work[w]->name.c_str());
656 puts(Work[w]->results.c_str());
657 delete Work[w];
658 }
659 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000660
661 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000662 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000663
664 if (Delay)
665 glslang::OS_Sleep(1000000);
John Kessenicha0af4732012-12-12 21:15:54 +0000666
667 if (compileFailed)
668 return EFailCompile;
669 if (linkFailed)
670 return EFailLink;
671
672 return 0;
673}
674
675//
676// Deduce the language from the filename. Files must end in one of the
677// following extensions:
678//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000679// .vert = vertex
680// .tesc = tessellation control
681// .tese = tessellation evaluation
682// .geom = geometry
683// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000684// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000685//
John Kessenichb603f912013-08-29 00:39:25 +0000686EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000687{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000688 size_t ext = name.rfind('.');
689 if (ext == std::string::npos) {
690 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000691 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000692 }
693
John Kessenich2b07c7e2013-07-31 18:44:13 +0000694 std::string suffix = name.substr(ext + 1, std::string::npos);
695 if (suffix == "vert")
696 return EShLangVertex;
697 else if (suffix == "tesc")
698 return EShLangTessControl;
699 else if (suffix == "tese")
700 return EShLangTessEvaluation;
701 else if (suffix == "geom")
702 return EShLangGeometry;
703 else if (suffix == "frag")
704 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000705 else if (suffix == "comp")
706 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000707
708 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000709 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000710}
711
John Kessenicha0af4732012-12-12 21:15:54 +0000712//
John Kessenich69f4b512013-09-04 21:19:27 +0000713// Read a file's data into a string, and compile it using the old interface ShCompile,
714// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000715//
John Kessenich05a70632013-09-17 19:26:08 +0000716bool CompileFile(const char *fileName, ShHandle compiler, int Options)
John Kessenicha0af4732012-12-12 21:15:54 +0000717{
718 int ret;
John Kessenich41cf6b52013-06-25 18:10:05 +0000719 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000720 if (! shaderStrings) {
721 usage();
722 return false;
723 }
724
John Kessenich41cf6b52013-06-25 18:10:05 +0000725 int* lengths = new int[NumShaderStrings];
726
727 // move to length-based strings, rather than null-terminated strings
728 for (int s = 0; s < NumShaderStrings; ++s)
729 lengths[s] = strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000730
John Kessenich41cf6b52013-06-25 18:10:05 +0000731 if (! shaderStrings)
John Kessenicha0af4732012-12-12 21:15:54 +0000732 return false;
733
John Kessenich52ac67e2013-05-05 23:46:22 +0000734 EShMessages messages = EShMsgDefault;
John Kessenich94a81fb2013-08-31 02:41:30 +0000735 if (Options & EOptionRelaxedErrors)
John Kessenich52ac67e2013-05-05 23:46:22 +0000736 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
John Kessenich94a81fb2013-08-31 02:41:30 +0000737 if (Options & EOptionIntermediate)
738 messages = (EShMessages)(messages | EShMsgAST);
John Kessenich69f4b512013-09-04 21:19:27 +0000739
John Kessenich94a81fb2013-08-31 02:41:30 +0000740 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
741 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich05a70632013-09-17 19:26:08 +0000742 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages);
743 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +0000744 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
745 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
746 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +0000747 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichea869fb2013-10-28 18:12:06 +0000748 //ret = ShCompile(compiler, multi, 7, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000749 }
John Kessenicha0af4732012-12-12 21:15:54 +0000750
John Kessenich94a81fb2013-08-31 02:41:30 +0000751 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000752 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000753 }
John Kessenicha0af4732012-12-12 21:15:54 +0000754
John Kessenich41cf6b52013-06-25 18:10:05 +0000755 delete [] lengths;
756 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000757
758 return ret ? true : false;
759}
760
John Kessenicha0af4732012-12-12 21:15:54 +0000761//
762// print usage to stdout
763//
764void usage()
765{
John Kessenich38f3b892013-09-06 19:52:57 +0000766 printf("Usage: glslangValidator [ options ] filename\n"
John Kessenichc0275792013-08-09 17:14:49 +0000767 "Where: filename is a name ending in\n"
John Kessenich05a70632013-09-17 19:26:08 +0000768 " .conf provides an optional config file that replaces the default configuration\n"
769 " (see -c option below for generating a template)\n"
John Kessenichc0275792013-08-09 17:14:49 +0000770 " .vert for a vertex shader\n"
771 " .tesc for a tessellation control shader\n"
772 " .tese for a tessellation evaluation shader\n"
773 " .geom for a geometry shader\n"
774 " .frag for a fragment shader\n"
775 " .comp for a compute shader\n\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000776 "Compilation warnings and errors will be printed to stdout.\n"
777 "To get other information, use one of the following options:\n"
John Kessenich05a70632013-09-17 19:26:08 +0000778 "-c: configuration dump; use to create default configuration file (redirect to a .conf file)\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000779 "-i: intermediate tree (glslang AST) is printed out\n"
780 "-d: delay exit\n"
John Kessenich94a81fb2013-08-31 02:41:30 +0000781 "-l: link validation of all input files\n"
782 "-m: memory leak mode\n"
John Kessenich11f9fc72013-11-07 01:06:34 +0000783 "-q: dump reflection query database\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000784 "-r: relaxed semantic error-checking mode\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000785 "-s: silent mode\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000786 "-t: multi-threaded mode\n");
John Kessenicha0af4732012-12-12 21:15:54 +0000787}
788
John Kessenichcfd643e2013-03-08 23:14:42 +0000789#ifndef _WIN32
790
791#include <errno.h>
792
793int fopen_s(
794 FILE** pFile,
795 const char *filename,
796 const char *mode
797)
798{
799 if (!pFile || !filename || !mode) {
800 return EINVAL;
801 }
802
803 FILE* f = fopen(filename, mode);
804 if (! f) {
805 if (errno != 0) {
806 return errno;
807 } else {
808 return ENOENT;
809 }
810 }
811 *pFile = f;
812
813 return 0;
814}
815
816#endif
817
John Kessenicha0af4732012-12-12 21:15:54 +0000818//
819// Malloc a string of sufficient size and read a string into it.
820//
John Kessenich54d8cda2013-02-11 22:36:01 +0000821char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000822{
John Kessenich200b2732012-12-12 21:21:23 +0000823 FILE *in;
824 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000825 char *fdata;
826 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000827 const int maxSourceStrings = 5;
828 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000829
830 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000831 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000832 printf("Error: unable to open input file: %s\n", fileName);
833 return 0;
834 }
835
836 while (fgetc(in) != EOF)
837 count++;
838
839 fseek(in, 0, SEEK_SET);
840
841
842 if (!(fdata = (char *)malloc(count+2))) {
843 printf("Error allocating memory\n");
844 return 0;
845 }
846 if (fread(fdata,1,count, in)!=count) {
847 printf("Error reading input file: %s\n", fileName);
848 return 0;
849 }
850 fdata[count] = '\0';
851 fclose(in);
John Kessenichea869fb2013-10-28 18:12:06 +0000852 if (count == 0) {
John Kessenicha0af4732012-12-12 21:15:54 +0000853 return_data[0]=(char*)malloc(count+2);
854 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +0000855 NumShaderStrings = 0;
John Kessenicha0af4732012-12-12 21:15:54 +0000856 return return_data;
John Kessenichea869fb2013-10-28 18:12:06 +0000857 } else
858 NumShaderStrings = 1;
John Kessenicha0af4732012-12-12 21:15:54 +0000859
John Kessenich41cf6b52013-06-25 18:10:05 +0000860 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000861 int ptr_len=0,i=0;
862 while(count>0){
863 return_data[i]=(char*)malloc(len+2);
864 memcpy(return_data[i],fdata+ptr_len,len);
865 return_data[i][len]='\0';
866 count-=(len);
867 ptr_len+=(len);
868 if(count<len){
869 if(count==0){
John Kessenich41cf6b52013-06-25 18:10:05 +0000870 NumShaderStrings=(i+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000871 break;
872 }
873 len = count;
874 }
875 ++i;
876 }
877 return return_data;
878}
879
John Kessenicha0af4732012-12-12 21:15:54 +0000880void FreeFileData(char **data)
881{
John Kessenich41cf6b52013-06-25 18:10:05 +0000882 for(int i=0;i<NumShaderStrings;i++)
John Kessenicha0af4732012-12-12 21:15:54 +0000883 free(data[i]);
884}
885
John Kessenich54d8cda2013-02-11 22:36:01 +0000886void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000887{
888 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
889 "#### %s %s INFO LOG ####\n", msg, name, num);
890}