blob: b3a37dc4a27d168c0b3f773f196b3ce04021246a [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 Kessenich94a81fb2013-08-31 02:41:30 +000064};
65
John Kessenicha0af4732012-12-12 21:15:54 +000066//
67// Return codes from main.
68//
69enum TFailCode {
70 ESuccess = 0,
71 EFailUsage,
72 EFailCompile,
73 EFailLink,
74 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000075 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000076 EFailLinkerCreate
77};
78
79//
80// Just placeholders for testing purposes. The stand-alone environment
81// can't actually do a full link without something specifying real
82// attribute bindings.
83//
84ShBinding FixedAttributeBindings[] = {
85 { "gl_Vertex", 15 },
86 { "gl_Color", 10 },
87 { "gl_Normal", 7 },
88};
89
90ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
91
John Kessenichb603f912013-08-29 00:39:25 +000092EShLanguage FindLanguage(const std::string& name);
John Kessenich05a70632013-09-17 19:26:08 +000093bool CompileFile(const char *fileName, ShHandle, int options);
John Kessenicha0af4732012-12-12 21:15:54 +000094void usage();
John Kessenichea869fb2013-10-28 18:12:06 +000095void FreeFileData(char** data);
96char** ReadFileData(const char* fileName);
John Kessenich54d8cda2013-02-11 22:36:01 +000097void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +000098
John Kessenich05a70632013-09-17 19:26:08 +000099// Use to test breaking up a single shader file into multiple strings.
John Kessenichea869fb2013-10-28 18:12:06 +0000100int NumShaderStrings;
John Kessenicha0af4732012-12-12 21:15:54 +0000101
John Kessenich05a70632013-09-17 19:26:08 +0000102TBuiltInResource Resources;
103std::string ConfigFile;
104
John Kessenicha0af4732012-12-12 21:15:54 +0000105//
John Kessenich05a70632013-09-17 19:26:08 +0000106// These are the default resources for TBuiltInResources, used for both
107// - parsing this string for the case where the user didn't supply one
108// - dumping out a template for user construction of a config file
John Kessenicha0af4732012-12-12 21:15:54 +0000109//
John Kessenich284231c2013-10-22 01:50:39 +0000110const char* DefaultConfig =
111 "MaxLights 32\n"
112 "MaxClipPlanes 6\n"
113 "MaxTextureUnits 32\n"
114 "MaxTextureCoords 32\n"
115 "MaxVertexAttribs 64\n"
116 "MaxVertexUniformComponents 4096\n"
117 "MaxVaryingFloats 64\n"
118 "MaxVertexTextureImageUnits 32\n"
119 "MaxCombinedTextureImageUnits 32\n"
120 "MaxTextureImageUnits 32\n"
121 "MaxFragmentUniformComponents 4096\n"
122 "MaxDrawBuffers 32\n"
123 "MaxVertexUniformVectors 128\n"
124 "MaxVaryingVectors 8\n"
125 "MaxFragmentUniformVectors 16\n"
126 "MaxVertexOutputVectors 16\n"
127 "MaxFragmentInputVectors 15\n"
128 "MinProgramTexelOffset -8\n"
129 "MaxProgramTexelOffset 7\n"
130 "MaxClipDistances 8\n"
131 "MaxComputeWorkGroupCountX 65535\n"
132 "MaxComputeWorkGroupCountY 65535\n"
133 "MaxComputeWorkGroupCountZ 65535\n"
134 "MaxComputeWorkGroupSizeX 1024\n"
135 "MaxComputeWorkGroupSizeX 1024\n"
136 "MaxComputeWorkGroupSizeZ 64\n"
137 "MaxComputeUniformComponents 1024\n"
138 "MaxComputeTextureImageUnits 16\n"
139 "MaxComputeImageUniforms 8\n"
140 "MaxComputeAtomicCounters 8\n"
141 "MaxComputeAtomicCounterBuffers 1\n"
142 "MaxVaryingComponents 60\n"
143 "MaxVertexOutputComponents 64\n"
144 "MaxGeometryInputComponents 64\n"
145 "MaxGeometryOutputComponents 128\n"
146 "MaxFragmentInputComponents 128\n"
147 "MaxImageUnits 8\n"
148 "MaxCombinedImageUnitsAndFragmentOutputs 8\n"
149 "MaxImageSamples 0\n"
150 "MaxVertexImageUniforms 0\n"
151 "MaxTessControlImageUniforms 0\n"
152 "MaxTessEvaluationImageUniforms 0\n"
153 "MaxGeometryImageUniforms 0\n"
154 "MaxFragmentImageUniforms 8\n"
155 "MaxCombinedImageUniforms 8\n"
156 "MaxGeometryTextureImageUnits 16\n"
157 "MaxGeometryOutputVertices 256\n"
158 "MaxGeometryTotalOutputComponents 1024\n"
159 "MaxGeometryUniformComponents 1024\n"
160 "MaxGeometryVaryingComponents 64\n"
161 "MaxTessControlInputComponents 128\n"
162 "MaxTessControlOutputComponents 128\n"
163 "MaxTessControlTextureImageUnits 16\n"
164 "MaxTessControlUniformComponents 1024\n"
165 "MaxTessControlTotalOutputComponents 4096\n"
166 "MaxTessEvaluationInputComponents 128\n"
167 "MaxTessEvaluationOutputComponents 128\n"
168 "MaxTessEvaluationTextureImageUnits 16\n"
169 "MaxTessEvaluationUniformComponents 1024\n"
170 "MaxTessPatchComponents 120\n"
171 "MaxPatchVertices 32\n"
172 "MaxTessGenLevel 64\n"
173 "MaxViewports 16\n"
174 "MaxVertexAtomicCounters 0\n"
175 "MaxTessControlAtomicCounters 0\n"
176 "MaxTessEvaluationAtomicCounters 0\n"
177 "MaxGeometryAtomicCounters 0\n"
178 "MaxFragmentAtomicCounters 8\n"
179 "MaxCombinedAtomicCounters 8\n"
180 "MaxAtomicCounterBindings 1\n"
181 "MaxVertexAtomicCounterBuffers 0\n"
182 "MaxTessControlAtomicCounterBuffers 0\n"
183 "MaxTessEvaluationAtomicCounterBuffers 0\n"
184 "MaxGeometryAtomicCounterBuffers 0\n"
185 "MaxFragmentAtomicCounterBuffers 1\n"
186 "MaxCombinedAtomicCounterBuffers 1\n"
187 "MaxAtomicCounterBufferSize 16384\n"
188
189 "nonInductiveForLoops 1\n"
190 "whileLoops 1\n"
191 "doWhileLoops 1\n"
192 "generalUniformIndexing 1\n"
193 "generalAttributeMatrixVectorIndexing 1\n"
194 "generalVaryingIndexing 1\n"
195 "generalSamplerIndexing 1\n"
196 "generalVariableIndexing 1\n"
197 "generalConstantMatrixVectorIndexing 1\n"
198 ;
John Kessenich05a70632013-09-17 19:26:08 +0000199
200//
201// Parse either a .conf file provided by the user or the default string above.
202//
203void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000204{
John Kessenich05a70632013-09-17 19:26:08 +0000205 char** configStrings = 0;
206 char *config = 0;
207 if (ConfigFile.size() > 0) {
John Kessenichea869fb2013-10-28 18:12:06 +0000208 configStrings = ReadFileData(ConfigFile.c_str());
John Kessenich05a70632013-09-17 19:26:08 +0000209 if (configStrings)
210 config = *configStrings;
211 else {
212 printf("Error opening configuration file; will instead use the default configuration\n");
213 usage();
214 }
215 }
216
217 if (config == 0) {
218 config = new char[strlen(DefaultConfig)];
219 strcpy(config, DefaultConfig);
220 }
221
222 const char* delims = " \t\n\r";
223 const char* token = strtok(config, delims);
224 while (token) {
225 const char* valueStr = strtok(0, delims);
226 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
227 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
228 return;
229 }
230 int value = atoi(valueStr);
231
232 if (strcmp(token, "MaxLights") == 0)
233 Resources.maxLights = value;
234 else if (strcmp(token, "MaxClipPlanes") == 0)
235 Resources.maxClipPlanes = value;
236 else if (strcmp(token, "MaxTextureUnits") == 0)
237 Resources.maxTextureUnits = value;
238 else if (strcmp(token, "MaxTextureCoords") == 0)
239 Resources.maxTextureCoords = value;
240 else if (strcmp(token, "MaxVertexAttribs") == 0)
241 Resources.maxVertexAttribs = value;
242 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
243 Resources.maxVertexUniformComponents = value;
244 else if (strcmp(token, "MaxVaryingFloats") == 0)
245 Resources.maxVaryingFloats = value;
246 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
247 Resources.maxVertexTextureImageUnits = value;
248 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
249 Resources.maxCombinedTextureImageUnits = value;
250 else if (strcmp(token, "MaxTextureImageUnits") == 0)
251 Resources.maxTextureImageUnits = value;
252 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
253 Resources.maxFragmentUniformComponents = value;
254 else if (strcmp(token, "MaxDrawBuffers") == 0)
255 Resources.maxDrawBuffers = value;
256 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
257 Resources.maxVertexUniformVectors = value;
258 else if (strcmp(token, "MaxVaryingVectors") == 0)
259 Resources.maxVaryingVectors = value;
260 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
261 Resources.maxFragmentUniformVectors = value;
262 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
263 Resources.maxVertexOutputVectors = value;
264 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
265 Resources.maxFragmentInputVectors = value;
266 else if (strcmp(token, "MinProgramTexelOffset") == 0)
267 Resources.minProgramTexelOffset = value;
268 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
269 Resources.maxProgramTexelOffset = value;
John Kesseniche7c59c12013-10-16 22:28:35 +0000270 else if (strcmp(token, "MaxClipDistances") == 0)
271 Resources.maxClipDistances = value;
John Kessenich284231c2013-10-22 01:50:39 +0000272 else if (strcmp(token, "MaxComputeWorkGroupCountX") == 0)
273 Resources.maxComputeWorkGroupCountX = value;
274 else if (strcmp(token, "MaxComputeWorkGroupCountY") == 0)
275 Resources.maxComputeWorkGroupCountY = value;
276 else if (strcmp(token, "MaxComputeWorkGroupCountZ") == 0)
277 Resources.maxComputeWorkGroupCountZ = value;
278 else if (strcmp(token, "MaxComputeWorkGroupSizeX") == 0)
279 Resources.maxComputeWorkGroupSizeX = value;
280 else if (strcmp(token, "MaxComputeWorkGroupSizeY") == 0)
281 Resources.maxComputeWorkGroupSizeY = value;
282 else if (strcmp(token, "MaxComputeWorkGroupSizeZ") == 0)
283 Resources.maxComputeWorkGroupSizeZ = value;
284 else if (strcmp(token, "MaxComputeUniformComponents") == 0)
285 Resources.maxComputeUniformComponents = value;
286 else if (strcmp(token, "MaxComputeTextureImageUnits") == 0)
287 Resources.maxComputeTextureImageUnits = value;
288 else if (strcmp(token, "MaxComputeImageUniforms") == 0)
289 Resources.maxComputeImageUniforms = value;
290 else if (strcmp(token, "MaxComputeAtomicCounters") == 0)
291 Resources.maxComputeAtomicCounters = value;
292 else if (strcmp(token, "MaxComputeAtomicCounterBuffers") == 0)
293 Resources.maxComputeAtomicCounterBuffers = value;
294 else if (strcmp(token, "MaxVaryingComponents") == 0)
295 Resources.maxVaryingComponents = value;
296 else if (strcmp(token, "MaxVertexOutputComponents") == 0)
297 Resources.maxVertexOutputComponents = value;
298 else if (strcmp(token, "MaxGeometryInputComponents") == 0)
299 Resources.maxGeometryInputComponents = value;
300 else if (strcmp(token, "MaxGeometryOutputComponents") == 0)
301 Resources.maxGeometryOutputComponents = value;
302 else if (strcmp(token, "MaxFragmentInputComponents") == 0)
303 Resources.maxFragmentInputComponents = value;
304 else if (strcmp(token, "MaxImageUnits") == 0)
305 Resources.maxImageUnits = value;
306 else if (strcmp(token, "MaxCombinedImageUnitsAndFragmentOutputs") == 0)
307 Resources.maxCombinedImageUnitsAndFragmentOutputs = value;
308 else if (strcmp(token, "MaxImageSamples") == 0)
309 Resources.maxImageSamples = value;
310 else if (strcmp(token, "MaxVertexImageUniforms") == 0)
311 Resources.maxVertexImageUniforms = value;
312 else if (strcmp(token, "MaxTessControlImageUniforms") == 0)
313 Resources.maxTessControlImageUniforms = value;
314 else if (strcmp(token, "MaxTessEvaluationImageUniforms") == 0)
315 Resources.maxTessEvaluationImageUniforms = value;
316 else if (strcmp(token, "MaxGeometryImageUniforms") == 0)
317 Resources.maxGeometryImageUniforms = value;
318 else if (strcmp(token, "MaxFragmentImageUniforms") == 0)
319 Resources.maxFragmentImageUniforms = value;
320 else if (strcmp(token, "MaxCombinedImageUniforms") == 0)
321 Resources.maxCombinedImageUniforms = value;
322 else if (strcmp(token, "MaxGeometryTextureImageUnits") == 0)
323 Resources.maxGeometryTextureImageUnits = value;
324 else if (strcmp(token, "MaxGeometryOutputVertices") == 0)
325 Resources.maxGeometryOutputVertices = value;
326 else if (strcmp(token, "MaxGeometryTotalOutputComponents") == 0)
327 Resources.maxGeometryTotalOutputComponents = value;
328 else if (strcmp(token, "MaxGeometryUniformComponents") == 0)
329 Resources.maxGeometryUniformComponents = value;
330 else if (strcmp(token, "MaxGeometryVaryingComponents") == 0)
331 Resources.maxGeometryVaryingComponents = value;
332 else if (strcmp(token, "MaxTessControlInputComponents") == 0)
333 Resources.maxTessControlInputComponents = value;
334 else if (strcmp(token, "MaxTessControlOutputComponents") == 0)
335 Resources.maxTessControlOutputComponents = value;
336 else if (strcmp(token, "MaxTessControlTextureImageUnits") == 0)
337 Resources.maxTessControlTextureImageUnits = value;
338 else if (strcmp(token, "MaxTessControlUniformComponents") == 0)
339 Resources.maxTessControlUniformComponents = value;
340 else if (strcmp(token, "MaxTessControlTotalOutputComponents") == 0)
341 Resources.maxTessControlTotalOutputComponents = value;
342 else if (strcmp(token, "MaxTessEvaluationInputComponents") == 0)
343 Resources.maxTessEvaluationInputComponents = value;
344 else if (strcmp(token, "MaxTessEvaluationOutputComponents") == 0)
345 Resources.maxTessEvaluationOutputComponents = value;
346 else if (strcmp(token, "MaxTessEvaluationTextureImageUnits") == 0)
347 Resources.maxTessEvaluationTextureImageUnits = value;
348 else if (strcmp(token, "MaxTessEvaluationUniformComponents") == 0)
349 Resources.maxTessEvaluationUniformComponents = value;
350 else if (strcmp(token, "MaxTessPatchComponents") == 0)
351 Resources.maxTessPatchComponents = value;
352 else if (strcmp(token, "MaxPatchVertices") == 0)
353 Resources.maxPatchVertices = value;
354 else if (strcmp(token, "MaxTessGenLevel") == 0)
355 Resources.maxTessGenLevel = value;
356 else if (strcmp(token, "MaxViewports") == 0)
357 Resources.maxViewports = value;
358 else if (strcmp(token, "MaxVertexAtomicCounters") == 0)
359 Resources.maxVertexAtomicCounters = value;
360 else if (strcmp(token, "MaxTessControlAtomicCounters") == 0)
361 Resources.maxTessControlAtomicCounters = value;
362 else if (strcmp(token, "MaxTessEvaluationAtomicCounters") == 0)
363 Resources.maxTessEvaluationAtomicCounters = value;
364 else if (strcmp(token, "MaxGeometryAtomicCounters") == 0)
365 Resources.maxGeometryAtomicCounters = value;
366 else if (strcmp(token, "MaxFragmentAtomicCounters") == 0)
367 Resources.maxFragmentAtomicCounters = value;
368 else if (strcmp(token, "MaxCombinedAtomicCounters") == 0)
369 Resources.maxCombinedAtomicCounters = value;
370 else if (strcmp(token, "MaxAtomicCounterBindings") == 0)
371 Resources.maxAtomicCounterBindings = value;
372 else if (strcmp(token, "MaxVertexAtomicCounterBuffers") == 0)
373 Resources.maxVertexAtomicCounterBuffers = value;
374 else if (strcmp(token, "MaxTessControlAtomicCounterBuffers") == 0)
375 Resources.maxTessControlAtomicCounterBuffers = value;
376 else if (strcmp(token, "MaxTessEvaluationAtomicCounterBuffers") == 0)
377 Resources.maxTessEvaluationAtomicCounterBuffers = value;
378 else if (strcmp(token, "MaxGeometryAtomicCounterBuffers") == 0)
379 Resources.maxGeometryAtomicCounterBuffers = value;
380 else if (strcmp(token, "MaxFragmentAtomicCounterBuffers") == 0)
381 Resources.maxFragmentAtomicCounterBuffers = value;
382 else if (strcmp(token, "MaxCombinedAtomicCounterBuffers") == 0)
383 Resources.maxCombinedAtomicCounterBuffers = value;
384 else if (strcmp(token, "MaxAtomicCounterBufferSize") == 0)
385 Resources.maxAtomicCounterBufferSize = value;
386
John Kessenicha5830df2013-10-02 05:10:48 +0000387 else if (strcmp(token, "nonInductiveForLoops") == 0)
388 Resources.limits.nonInductiveForLoops = (value != 0);
389 else if (strcmp(token, "whileLoops") == 0)
390 Resources.limits.whileLoops = (value != 0);
391 else if (strcmp(token, "doWhileLoops") == 0)
392 Resources.limits.doWhileLoops = (value != 0);
393 else if (strcmp(token, "generalUniformIndexing") == 0)
394 Resources.limits.generalUniformIndexing = (value != 0);
395 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
396 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
397 else if (strcmp(token, "generalVaryingIndexing") == 0)
398 Resources.limits.generalVaryingIndexing = (value != 0);
399 else if (strcmp(token, "generalSamplerIndexing") == 0)
400 Resources.limits.generalSamplerIndexing = (value != 0);
401 else if (strcmp(token, "generalVariableIndexing") == 0)
402 Resources.limits.generalVariableIndexing = (value != 0);
403 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
404 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000405 else
406 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
407
408 token = strtok(0, delims);
409 }
410 if (configStrings)
411 FreeFileData(configStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000412}
413
John Kessenich38f3b892013-09-06 19:52:57 +0000414// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000415glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000416
417// array of unique places to leave the shader names and infologs for the asynchronous compiles
418glslang::TWorkItem **Work = 0;
419int NumWorkItems = 0;
420
John Kessenich94a81fb2013-08-31 02:41:30 +0000421int Options = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000422bool Delay = false;
John Kessenich38f3b892013-09-06 19:52:57 +0000423const char* ExecutableName;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000424
John Kessenich05a70632013-09-17 19:26:08 +0000425//
426// *.conf => this is a config file that can set limits/resources
427//
428bool SetConfigFile(const std::string& name)
429{
430 if (name.size() < 5)
431 return false;
432
John Kessenich4c706852013-10-11 16:28:43 +0000433 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000434 ConfigFile = name;
435 return true;
436 }
437
438 return false;
439}
440
John Kessenich2b07c7e2013-07-31 18:44:13 +0000441bool ProcessArguments(int argc, char* argv[])
442{
John Kessenich38f3b892013-09-06 19:52:57 +0000443 ExecutableName = argv[0];
444 NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
445 Work = new glslang::TWorkItem*[NumWorkItems];
446 Work[0] = 0;
447
John Kessenich2b07c7e2013-07-31 18:44:13 +0000448 argc--;
449 argv++;
450 for (; argc >= 1; argc--, argv++) {
John Kessenich05a70632013-09-17 19:26:08 +0000451 Work[argc] = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000452 if (argv[0][0] == '-') {
453 switch (argv[0][1]) {
John Kessenich05a70632013-09-17 19:26:08 +0000454 case 'c':
455 Options |= EOptionDumpConfig;
456 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000457 case 'd':
458 Delay = true;
459 break;
John Kessenich05a70632013-09-17 19:26:08 +0000460 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000461 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000462 break;
463 case 'l':
John Kessenich94a81fb2013-08-31 02:41:30 +0000464 Options |= EOptionsLinkProgram;
465 break;
466 case 'm':
467 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000468 break;
469 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000470 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000471 break;
472 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000473 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000474 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000475 case 't':
476 #ifdef _WIN32
477 Options |= EOptionMultiThreaded;
478 #endif
479 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000480 default:
John Kessenich2b07c7e2013-07-31 18:44:13 +0000481 return false;
482 }
John Kessenich38f3b892013-09-06 19:52:57 +0000483 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000484 std::string name(argv[0]);
485 if (! SetConfigFile(name)) {
486 Work[argc] = new glslang::TWorkItem(name);
487 Worklist.add(Work[argc]);
488 }
John Kessenich38f3b892013-09-06 19:52:57 +0000489 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000490 }
491
492 return true;
493}
494
John Kessenich69f4b512013-09-04 21:19:27 +0000495// Thread entry point, for non-linking asynchronous mode.
John Kessenichee6a9c82013-07-31 23:19:17 +0000496unsigned int
497#ifdef _WIN32
498 __stdcall
499#endif
John Kessenich94a81fb2013-08-31 02:41:30 +0000500CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000501{
John Kessenich38f3b892013-09-06 19:52:57 +0000502 glslang::TWorkItem* workItem;
503 while (Worklist.remove(workItem)) {
504 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000505 if (compiler == 0)
506 return false;
507
John Kessenich05a70632013-09-17 19:26:08 +0000508 CompileFile(workItem->name.c_str(), compiler, Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000509
John Kessenich94a81fb2013-08-31 02:41:30 +0000510 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000511 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000512
513 ShDestruct(compiler);
514 }
515
516 return 0;
517}
518
John Kessenich69f4b512013-09-04 21:19:27 +0000519//
520// For linking mode: Will independently parse each item in the worklist, but then put them
521// in the same program and link them together.
522//
523// Uses the new C++ interface instead of the old handle-based interface.
524//
525void CompileAndLinkShaders()
526{
527 // keep track of what to free
528 std::list<glslang::TShader*> shaders;
529
530 EShMessages messages = EShMsgDefault;
531 if (Options & EOptionRelaxedErrors)
532 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
533 if (Options & EOptionIntermediate)
534 messages = (EShMessages)(messages | EShMsgAST);
535
John Kessenich69f4b512013-09-04 21:19:27 +0000536 //
537 // Per-shader processing...
538 //
539
John Kessenich5b0f13a2013-11-01 03:08:40 +0000540 glslang::TProgram& program = *new glslang::TProgram;
John Kessenich38f3b892013-09-06 19:52:57 +0000541 glslang::TWorkItem* workItem;
542 while (Worklist.remove(workItem)) {
543 EShLanguage stage = FindLanguage(workItem->name);
John Kessenich69f4b512013-09-04 21:19:27 +0000544 glslang::TShader* shader = new glslang::TShader(stage);
545 shaders.push_back(shader);
546
John Kessenich38f3b892013-09-06 19:52:57 +0000547 char** shaderStrings = ReadFileData(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000548 if (! shaderStrings) {
549 usage();
550 return;
551 }
552
553 shader->setStrings(shaderStrings, 1);
554
John Kessenich05a70632013-09-17 19:26:08 +0000555 shader->parse(&Resources, 100, false, messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000556
557 program.addShader(shader);
558
559 if (! (Options & EOptionSuppressInfolog)) {
John Kessenich38f3b892013-09-06 19:52:57 +0000560 puts(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000561 puts(shader->getInfoLog());
562 puts(shader->getInfoDebugLog());
563 }
564
565 FreeFileData(shaderStrings);
566 }
567
568 //
569 // Program-level processing...
570 //
571
572 program.link(messages);
573 if (! (Options & EOptionSuppressInfolog)) {
574 puts(program.getInfoLog());
575 puts(program.getInfoDebugLog());
576 }
577
John Kessenich5b0f13a2013-11-01 03:08:40 +0000578 // Free everything up, program has to go before the shaders
579 // because it might have merged stuff from the shaders, and
580 // the stuff from the shaders has to have its destructors called
581 // before the pools holding the memory in the shaders is freed.
582 delete &program;
John Kessenich69f4b512013-09-04 21:19:27 +0000583 while (shaders.size() > 0) {
584 delete shaders.back();
585 shaders.pop_back();
586 }
John Kessenich69f4b512013-09-04 21:19:27 +0000587}
588
John Kessenicha0af4732012-12-12 21:15:54 +0000589int C_DECL main(int argc, char* argv[])
590{
John Kessenicha0af4732012-12-12 21:15:54 +0000591 bool compileFailed = false;
592 bool linkFailed = false;
John Kessenicha0af4732012-12-12 21:15:54 +0000593
John Kessenich54f6e562013-08-03 00:04:10 +0000594 if (! ProcessArguments(argc, argv)) {
595 usage();
John Kessenich2b07c7e2013-07-31 18:44:13 +0000596 return EFailUsage;
John Kessenich54f6e562013-08-03 00:04:10 +0000597 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000598
John Kessenich05a70632013-09-17 19:26:08 +0000599 if (Options & EOptionDumpConfig) {
600 printf("%s", DefaultConfig);
601 if (Worklist.empty())
602 return ESuccess;
603 }
604
605 if (Worklist.empty()) {
606 usage();
607 return EFailUsage;
608 }
609
610 ProcessConfigFile();
611
John Kessenich69f4b512013-09-04 21:19:27 +0000612 //
613 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000614 // 1) linking all arguments together, single-threaded, new C++ interface
615 // 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 +0000616 //
John Kessenichc36e1d82013-11-01 17:41:52 +0000617 if (Options & EOptionsLinkProgram) {
618 glslang::InitializeProcess();
John Kessenich38f3b892013-09-06 19:52:57 +0000619 CompileAndLinkShaders();
John Kessenichc36e1d82013-11-01 17:41:52 +0000620 glslang::FinalizeProcess();
621 } else {
622 ShInitialize();
623
John Kessenich38f3b892013-09-06 19:52:57 +0000624 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000625
John Kessenich38f3b892013-09-06 19:52:57 +0000626 if (Options & EOptionMultiThreaded) {
627 const int NumThreads = 16;
628 void* threads[NumThreads];
629 for (int t = 0; t < NumThreads; ++t) {
630 threads[t] = glslang::OS_CreateThread(&CompileShaders);
631 if (! threads[t]) {
632 printf("Failed to create thread\n");
633 return EFailThreadCreate;
634 }
John Kessenicha0af4732012-12-12 21:15:54 +0000635 }
John Kessenich38f3b892013-09-06 19:52:57 +0000636 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenich69f4b512013-09-04 21:19:27 +0000637 } else {
638 if (! CompileShaders(0))
639 compileFailed = true;
640 }
John Kessenich38f3b892013-09-06 19:52:57 +0000641
642 // Print out all the resulting infologs
643 for (int w = 0; w < NumWorkItems; ++w) {
644 if (Work[w]) {
645 if (printShaderNames)
646 puts(Work[w]->name.c_str());
647 puts(Work[w]->results.c_str());
648 delete Work[w];
649 }
650 }
John Kessenichc36e1d82013-11-01 17:41:52 +0000651
652 ShFinalize();
John Kessenicha0af4732012-12-12 21:15:54 +0000653 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000654
655 if (Delay)
656 glslang::OS_Sleep(1000000);
John Kessenicha0af4732012-12-12 21:15:54 +0000657
658 if (compileFailed)
659 return EFailCompile;
660 if (linkFailed)
661 return EFailLink;
662
663 return 0;
664}
665
666//
667// Deduce the language from the filename. Files must end in one of the
668// following extensions:
669//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000670// .vert = vertex
671// .tesc = tessellation control
672// .tese = tessellation evaluation
673// .geom = geometry
674// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000675// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000676//
John Kessenichb603f912013-08-29 00:39:25 +0000677EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000678{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000679 size_t ext = name.rfind('.');
680 if (ext == std::string::npos) {
681 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000682 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000683 }
684
John Kessenich2b07c7e2013-07-31 18:44:13 +0000685 std::string suffix = name.substr(ext + 1, std::string::npos);
686 if (suffix == "vert")
687 return EShLangVertex;
688 else if (suffix == "tesc")
689 return EShLangTessControl;
690 else if (suffix == "tese")
691 return EShLangTessEvaluation;
692 else if (suffix == "geom")
693 return EShLangGeometry;
694 else if (suffix == "frag")
695 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000696 else if (suffix == "comp")
697 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000698
699 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000700 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000701}
702
John Kessenicha0af4732012-12-12 21:15:54 +0000703//
John Kessenich69f4b512013-09-04 21:19:27 +0000704// Read a file's data into a string, and compile it using the old interface ShCompile,
705// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000706//
John Kessenich05a70632013-09-17 19:26:08 +0000707bool CompileFile(const char *fileName, ShHandle compiler, int Options)
John Kessenicha0af4732012-12-12 21:15:54 +0000708{
709 int ret;
John Kessenich41cf6b52013-06-25 18:10:05 +0000710 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000711 if (! shaderStrings) {
712 usage();
713 return false;
714 }
715
John Kessenich41cf6b52013-06-25 18:10:05 +0000716 int* lengths = new int[NumShaderStrings];
717
718 // move to length-based strings, rather than null-terminated strings
719 for (int s = 0; s < NumShaderStrings; ++s)
720 lengths[s] = strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000721
John Kessenich41cf6b52013-06-25 18:10:05 +0000722 if (! shaderStrings)
John Kessenicha0af4732012-12-12 21:15:54 +0000723 return false;
724
John Kessenich52ac67e2013-05-05 23:46:22 +0000725 EShMessages messages = EShMsgDefault;
John Kessenich94a81fb2013-08-31 02:41:30 +0000726 if (Options & EOptionRelaxedErrors)
John Kessenich52ac67e2013-05-05 23:46:22 +0000727 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
John Kessenich94a81fb2013-08-31 02:41:30 +0000728 if (Options & EOptionIntermediate)
729 messages = (EShMessages)(messages | EShMsgAST);
John Kessenich69f4b512013-09-04 21:19:27 +0000730
John Kessenich94a81fb2013-08-31 02:41:30 +0000731 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
732 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich05a70632013-09-17 19:26:08 +0000733 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages);
734 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenichea869fb2013-10-28 18:12:06 +0000735 //const char* multi[12] = { "# ve", "rsion", " 300 e", "s", "\n#err",
736 // "or should be l", "ine 1", "string 5\n", "float glo", "bal",
737 // ";\n#error should be line 2\n void main() {", "global = 2.3;}" };
John Kessenich41cf6b52013-06-25 18:10:05 +0000738 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenichea869fb2013-10-28 18:12:06 +0000739 //ret = ShCompile(compiler, multi, 7, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000740 }
John Kessenicha0af4732012-12-12 21:15:54 +0000741
John Kessenich94a81fb2013-08-31 02:41:30 +0000742 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000743 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000744 }
John Kessenicha0af4732012-12-12 21:15:54 +0000745
John Kessenich41cf6b52013-06-25 18:10:05 +0000746 delete [] lengths;
747 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000748
749 return ret ? true : false;
750}
751
John Kessenicha0af4732012-12-12 21:15:54 +0000752//
753// print usage to stdout
754//
755void usage()
756{
John Kessenich38f3b892013-09-06 19:52:57 +0000757 printf("Usage: glslangValidator [ options ] filename\n"
John Kessenichc0275792013-08-09 17:14:49 +0000758 "Where: filename is a name ending in\n"
John Kessenich05a70632013-09-17 19:26:08 +0000759 " .conf provides an optional config file that replaces the default configuration\n"
760 " (see -c option below for generating a template)\n"
John Kessenichc0275792013-08-09 17:14:49 +0000761 " .vert for a vertex shader\n"
762 " .tesc for a tessellation control shader\n"
763 " .tese for a tessellation evaluation shader\n"
764 " .geom for a geometry shader\n"
765 " .frag for a fragment shader\n"
766 " .comp for a compute shader\n\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000767 "Compilation warnings and errors will be printed to stdout.\n"
768 "To get other information, use one of the following options:\n"
John Kessenich05a70632013-09-17 19:26:08 +0000769 "-c: configuration dump; use to create default configuration file (redirect to a .conf file)\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000770 "-i: intermediate tree (glslang AST) is printed out\n"
771 "-d: delay exit\n"
John Kessenich94a81fb2013-08-31 02:41:30 +0000772 "-l: link validation of all input files\n"
773 "-m: memory leak mode\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000774 "-r: relaxed semantic error-checking mode\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000775 "-s: silent mode\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000776 "-t: multi-threaded mode\n");
John Kessenicha0af4732012-12-12 21:15:54 +0000777}
778
John Kessenichcfd643e2013-03-08 23:14:42 +0000779#ifndef _WIN32
780
781#include <errno.h>
782
783int fopen_s(
784 FILE** pFile,
785 const char *filename,
786 const char *mode
787)
788{
789 if (!pFile || !filename || !mode) {
790 return EINVAL;
791 }
792
793 FILE* f = fopen(filename, mode);
794 if (! f) {
795 if (errno != 0) {
796 return errno;
797 } else {
798 return ENOENT;
799 }
800 }
801 *pFile = f;
802
803 return 0;
804}
805
806#endif
807
John Kessenicha0af4732012-12-12 21:15:54 +0000808//
809// Malloc a string of sufficient size and read a string into it.
810//
John Kessenich54d8cda2013-02-11 22:36:01 +0000811char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000812{
John Kessenich200b2732012-12-12 21:21:23 +0000813 FILE *in;
814 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000815 char *fdata;
816 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000817 const int maxSourceStrings = 5;
818 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000819
820 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000821 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000822 printf("Error: unable to open input file: %s\n", fileName);
823 return 0;
824 }
825
826 while (fgetc(in) != EOF)
827 count++;
828
829 fseek(in, 0, SEEK_SET);
830
831
832 if (!(fdata = (char *)malloc(count+2))) {
833 printf("Error allocating memory\n");
834 return 0;
835 }
836 if (fread(fdata,1,count, in)!=count) {
837 printf("Error reading input file: %s\n", fileName);
838 return 0;
839 }
840 fdata[count] = '\0';
841 fclose(in);
John Kessenichea869fb2013-10-28 18:12:06 +0000842 if (count == 0) {
John Kessenicha0af4732012-12-12 21:15:54 +0000843 return_data[0]=(char*)malloc(count+2);
844 return_data[0][0]='\0';
John Kessenichea869fb2013-10-28 18:12:06 +0000845 NumShaderStrings = 0;
John Kessenicha0af4732012-12-12 21:15:54 +0000846 return return_data;
John Kessenichea869fb2013-10-28 18:12:06 +0000847 } else
848 NumShaderStrings = 1;
John Kessenicha0af4732012-12-12 21:15:54 +0000849
John Kessenich41cf6b52013-06-25 18:10:05 +0000850 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000851 int ptr_len=0,i=0;
852 while(count>0){
853 return_data[i]=(char*)malloc(len+2);
854 memcpy(return_data[i],fdata+ptr_len,len);
855 return_data[i][len]='\0';
856 count-=(len);
857 ptr_len+=(len);
858 if(count<len){
859 if(count==0){
John Kessenich41cf6b52013-06-25 18:10:05 +0000860 NumShaderStrings=(i+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000861 break;
862 }
863 len = count;
864 }
865 ++i;
866 }
867 return return_data;
868}
869
John Kessenicha0af4732012-12-12 21:15:54 +0000870void FreeFileData(char **data)
871{
John Kessenich41cf6b52013-06-25 18:10:05 +0000872 for(int i=0;i<NumShaderStrings;i++)
John Kessenicha0af4732012-12-12 21:15:54 +0000873 free(data[i]);
874}
875
John Kessenich54d8cda2013-02-11 22:36:01 +0000876void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000877{
878 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
879 "#### %s %s INFO LOG ####\n", msg, name, num);
880}