blob: db9428e9aafbdd96be4f386938b096b548a70641 [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();
95void FreeFileData(char **data);
John Kessenich54d8cda2013-02-11 22:36:01 +000096char** ReadFileData(const char *fileName);
97void 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 Kessenich41cf6b52013-06-25 18:10:05 +0000100int NumShaderStrings = 1;
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 Kessenich05a70632013-09-17 19:26:08 +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"
John Kessenicha5830df2013-10-02 05:10:48 +0000129"MaxProgramTexelOffset 7\n"
130"nonInductiveForLoops 1\n"
131"whileLoops 1\n"
132"doWhileLoops 1\n"
133"generalUniformIndexing 1\n"
134"generalAttributeMatrixVectorIndexing 1\n"
135"generalVaryingIndexing 1\n"
136"generalSamplerIndexing 1\n"
137"generalVariableIndexing 1\n"
138"generalConstantMatrixVectorIndexing 1\n"
John Kessenich05a70632013-09-17 19:26:08 +0000139;
140
141//
142// Parse either a .conf file provided by the user or the default string above.
143//
144void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000145{
John Kessenich05a70632013-09-17 19:26:08 +0000146 char** configStrings = 0;
147 char *config = 0;
148 if (ConfigFile.size() > 0) {
149 char** configStrings = ReadFileData(ConfigFile.c_str());
150 if (configStrings)
151 config = *configStrings;
152 else {
153 printf("Error opening configuration file; will instead use the default configuration\n");
154 usage();
155 }
156 }
157
158 if (config == 0) {
159 config = new char[strlen(DefaultConfig)];
160 strcpy(config, DefaultConfig);
161 }
162
163 const char* delims = " \t\n\r";
164 const char* token = strtok(config, delims);
165 while (token) {
166 const char* valueStr = strtok(0, delims);
167 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
168 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
169 return;
170 }
171 int value = atoi(valueStr);
172
173 if (strcmp(token, "MaxLights") == 0)
174 Resources.maxLights = value;
175 else if (strcmp(token, "MaxClipPlanes") == 0)
176 Resources.maxClipPlanes = value;
177 else if (strcmp(token, "MaxTextureUnits") == 0)
178 Resources.maxTextureUnits = value;
179 else if (strcmp(token, "MaxTextureCoords") == 0)
180 Resources.maxTextureCoords = value;
181 else if (strcmp(token, "MaxVertexAttribs") == 0)
182 Resources.maxVertexAttribs = value;
183 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
184 Resources.maxVertexUniformComponents = value;
185 else if (strcmp(token, "MaxVaryingFloats") == 0)
186 Resources.maxVaryingFloats = value;
187 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
188 Resources.maxVertexTextureImageUnits = value;
189 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
190 Resources.maxCombinedTextureImageUnits = value;
191 else if (strcmp(token, "MaxTextureImageUnits") == 0)
192 Resources.maxTextureImageUnits = value;
193 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
194 Resources.maxFragmentUniformComponents = value;
195 else if (strcmp(token, "MaxDrawBuffers") == 0)
196 Resources.maxDrawBuffers = value;
197 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
198 Resources.maxVertexUniformVectors = value;
199 else if (strcmp(token, "MaxVaryingVectors") == 0)
200 Resources.maxVaryingVectors = value;
201 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
202 Resources.maxFragmentUniformVectors = value;
203 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
204 Resources.maxVertexOutputVectors = value;
205 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
206 Resources.maxFragmentInputVectors = value;
207 else if (strcmp(token, "MinProgramTexelOffset") == 0)
208 Resources.minProgramTexelOffset = value;
209 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
210 Resources.maxProgramTexelOffset = value;
John Kessenicha5830df2013-10-02 05:10:48 +0000211 else if (strcmp(token, "nonInductiveForLoops") == 0)
212 Resources.limits.nonInductiveForLoops = (value != 0);
213 else if (strcmp(token, "whileLoops") == 0)
214 Resources.limits.whileLoops = (value != 0);
215 else if (strcmp(token, "doWhileLoops") == 0)
216 Resources.limits.doWhileLoops = (value != 0);
217 else if (strcmp(token, "generalUniformIndexing") == 0)
218 Resources.limits.generalUniformIndexing = (value != 0);
219 else if (strcmp(token, "generalAttributeMatrixVectorIndexing") == 0)
220 Resources.limits.generalAttributeMatrixVectorIndexing = (value != 0);
221 else if (strcmp(token, "generalVaryingIndexing") == 0)
222 Resources.limits.generalVaryingIndexing = (value != 0);
223 else if (strcmp(token, "generalSamplerIndexing") == 0)
224 Resources.limits.generalSamplerIndexing = (value != 0);
225 else if (strcmp(token, "generalVariableIndexing") == 0)
226 Resources.limits.generalVariableIndexing = (value != 0);
227 else if (strcmp(token, "generalConstantMatrixVectorIndexing") == 0)
228 Resources.limits.generalConstantMatrixVectorIndexing = (value != 0);
John Kessenich05a70632013-09-17 19:26:08 +0000229 else
230 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
231
232 token = strtok(0, delims);
233 }
234 if (configStrings)
235 FreeFileData(configStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000236}
237
John Kessenich38f3b892013-09-06 19:52:57 +0000238// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000239glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000240
241// array of unique places to leave the shader names and infologs for the asynchronous compiles
242glslang::TWorkItem **Work = 0;
243int NumWorkItems = 0;
244
John Kessenich94a81fb2013-08-31 02:41:30 +0000245int Options = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000246bool Delay = false;
John Kessenich38f3b892013-09-06 19:52:57 +0000247const char* ExecutableName;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000248
John Kessenich05a70632013-09-17 19:26:08 +0000249//
250// *.conf => this is a config file that can set limits/resources
251//
252bool SetConfigFile(const std::string& name)
253{
254 if (name.size() < 5)
255 return false;
256
John Kessenich4c706852013-10-11 16:28:43 +0000257 if (name.compare(name.size() - 5, 5, ".conf") == 0) {
John Kessenich05a70632013-09-17 19:26:08 +0000258 ConfigFile = name;
259 return true;
260 }
261
262 return false;
263}
264
John Kessenich2b07c7e2013-07-31 18:44:13 +0000265bool ProcessArguments(int argc, char* argv[])
266{
John Kessenich38f3b892013-09-06 19:52:57 +0000267 ExecutableName = argv[0];
268 NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
269 Work = new glslang::TWorkItem*[NumWorkItems];
270 Work[0] = 0;
271
John Kessenich2b07c7e2013-07-31 18:44:13 +0000272 argc--;
273 argv++;
274 for (; argc >= 1; argc--, argv++) {
John Kessenich05a70632013-09-17 19:26:08 +0000275 Work[argc] = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000276 if (argv[0][0] == '-') {
277 switch (argv[0][1]) {
John Kessenich05a70632013-09-17 19:26:08 +0000278 case 'c':
279 Options |= EOptionDumpConfig;
280 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000281 case 'd':
282 Delay = true;
283 break;
John Kessenich05a70632013-09-17 19:26:08 +0000284 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000285 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000286 break;
287 case 'l':
John Kessenich94a81fb2013-08-31 02:41:30 +0000288 Options |= EOptionsLinkProgram;
289 break;
290 case 'm':
291 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000292 break;
293 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000294 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000295 break;
296 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000297 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000298 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000299 case 't':
300 #ifdef _WIN32
301 Options |= EOptionMultiThreaded;
302 #endif
303 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000304 default:
John Kessenich2b07c7e2013-07-31 18:44:13 +0000305 return false;
306 }
John Kessenich38f3b892013-09-06 19:52:57 +0000307 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000308 std::string name(argv[0]);
309 if (! SetConfigFile(name)) {
310 Work[argc] = new glslang::TWorkItem(name);
311 Worklist.add(Work[argc]);
312 }
John Kessenich38f3b892013-09-06 19:52:57 +0000313 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000314 }
315
316 return true;
317}
318
John Kessenich69f4b512013-09-04 21:19:27 +0000319// Thread entry point, for non-linking asynchronous mode.
John Kessenichee6a9c82013-07-31 23:19:17 +0000320unsigned int
321#ifdef _WIN32
322 __stdcall
323#endif
John Kessenich94a81fb2013-08-31 02:41:30 +0000324CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000325{
John Kessenich38f3b892013-09-06 19:52:57 +0000326 glslang::TWorkItem* workItem;
327 while (Worklist.remove(workItem)) {
328 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000329 if (compiler == 0)
330 return false;
331
John Kessenich05a70632013-09-17 19:26:08 +0000332 CompileFile(workItem->name.c_str(), compiler, Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000333
John Kessenich94a81fb2013-08-31 02:41:30 +0000334 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000335 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000336
337 ShDestruct(compiler);
338 }
339
340 return 0;
341}
342
John Kessenich69f4b512013-09-04 21:19:27 +0000343//
344// For linking mode: Will independently parse each item in the worklist, but then put them
345// in the same program and link them together.
346//
347// Uses the new C++ interface instead of the old handle-based interface.
348//
349void CompileAndLinkShaders()
350{
351 // keep track of what to free
352 std::list<glslang::TShader*> shaders;
353
354 EShMessages messages = EShMsgDefault;
355 if (Options & EOptionRelaxedErrors)
356 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
357 if (Options & EOptionIntermediate)
358 messages = (EShMessages)(messages | EShMsgAST);
359
John Kessenich69f4b512013-09-04 21:19:27 +0000360 //
361 // Per-shader processing...
362 //
363
364 glslang::TProgram program;
John Kessenich38f3b892013-09-06 19:52:57 +0000365 glslang::TWorkItem* workItem;
366 while (Worklist.remove(workItem)) {
367 EShLanguage stage = FindLanguage(workItem->name);
John Kessenich69f4b512013-09-04 21:19:27 +0000368 glslang::TShader* shader = new glslang::TShader(stage);
369 shaders.push_back(shader);
370
John Kessenich38f3b892013-09-06 19:52:57 +0000371 char** shaderStrings = ReadFileData(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000372 if (! shaderStrings) {
373 usage();
374 return;
375 }
376
377 shader->setStrings(shaderStrings, 1);
378
John Kessenich05a70632013-09-17 19:26:08 +0000379 shader->parse(&Resources, 100, false, messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000380
381 program.addShader(shader);
382
383 if (! (Options & EOptionSuppressInfolog)) {
John Kessenich38f3b892013-09-06 19:52:57 +0000384 puts(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000385 puts(shader->getInfoLog());
386 puts(shader->getInfoDebugLog());
387 }
388
389 FreeFileData(shaderStrings);
390 }
391
392 //
393 // Program-level processing...
394 //
395
396 program.link(messages);
397 if (! (Options & EOptionSuppressInfolog)) {
398 puts(program.getInfoLog());
399 puts(program.getInfoDebugLog());
400 }
401
402 // free everything up
403 while (shaders.size() > 0) {
404 delete shaders.back();
405 shaders.pop_back();
406 }
407
408 // TODO: memory: for each compile, need a GetThreadPoolAllocator().pop();
409}
410
John Kessenicha0af4732012-12-12 21:15:54 +0000411int C_DECL main(int argc, char* argv[])
412{
John Kessenicha0af4732012-12-12 21:15:54 +0000413 bool compileFailed = false;
414 bool linkFailed = false;
John Kessenicha0af4732012-12-12 21:15:54 +0000415
John Kessenich2b07c7e2013-07-31 18:44:13 +0000416 // Init for front-end proper
John Kessenicha0af4732012-12-12 21:15:54 +0000417 ShInitialize();
418
John Kessenich38f3b892013-09-06 19:52:57 +0000419 // Init for standalone
John Kessenich2b07c7e2013-07-31 18:44:13 +0000420 glslang::InitGlobalLock();
John Kessenicha0af4732012-12-12 21:15:54 +0000421
John Kessenich54f6e562013-08-03 00:04:10 +0000422 if (! ProcessArguments(argc, argv)) {
423 usage();
John Kessenich2b07c7e2013-07-31 18:44:13 +0000424 return EFailUsage;
John Kessenich54f6e562013-08-03 00:04:10 +0000425 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000426
John Kessenich05a70632013-09-17 19:26:08 +0000427 if (Options & EOptionDumpConfig) {
428 printf("%s", DefaultConfig);
429 if (Worklist.empty())
430 return ESuccess;
431 }
432
433 if (Worklist.empty()) {
434 usage();
435 return EFailUsage;
436 }
437
438 ProcessConfigFile();
439
440
John Kessenich69f4b512013-09-04 21:19:27 +0000441 //
442 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000443 // 1) linking all arguments together, single-threaded, new C++ interface
444 // 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 +0000445 //
John Kessenich38f3b892013-09-06 19:52:57 +0000446 if (Options & EOptionsLinkProgram)
447 CompileAndLinkShaders();
448 else {
449 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000450
John Kessenich38f3b892013-09-06 19:52:57 +0000451 if (Options & EOptionMultiThreaded) {
452 const int NumThreads = 16;
453 void* threads[NumThreads];
454 for (int t = 0; t < NumThreads; ++t) {
455 threads[t] = glslang::OS_CreateThread(&CompileShaders);
456 if (! threads[t]) {
457 printf("Failed to create thread\n");
458 return EFailThreadCreate;
459 }
John Kessenicha0af4732012-12-12 21:15:54 +0000460 }
John Kessenich38f3b892013-09-06 19:52:57 +0000461 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenich69f4b512013-09-04 21:19:27 +0000462 } else {
463 if (! CompileShaders(0))
464 compileFailed = true;
465 }
John Kessenich38f3b892013-09-06 19:52:57 +0000466
467 // Print out all the resulting infologs
468 for (int w = 0; w < NumWorkItems; ++w) {
469 if (Work[w]) {
470 if (printShaderNames)
471 puts(Work[w]->name.c_str());
472 puts(Work[w]->results.c_str());
473 delete Work[w];
474 }
475 }
John Kessenicha0af4732012-12-12 21:15:54 +0000476 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000477
478 if (Delay)
479 glslang::OS_Sleep(1000000);
John Kessenicha0af4732012-12-12 21:15:54 +0000480
481 if (compileFailed)
482 return EFailCompile;
483 if (linkFailed)
484 return EFailLink;
485
486 return 0;
487}
488
489//
490// Deduce the language from the filename. Files must end in one of the
491// following extensions:
492//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000493// .vert = vertex
494// .tesc = tessellation control
495// .tese = tessellation evaluation
496// .geom = geometry
497// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000498// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000499//
John Kessenichb603f912013-08-29 00:39:25 +0000500EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000501{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000502 size_t ext = name.rfind('.');
503 if (ext == std::string::npos) {
504 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000505 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000506 }
507
John Kessenich2b07c7e2013-07-31 18:44:13 +0000508 std::string suffix = name.substr(ext + 1, std::string::npos);
509 if (suffix == "vert")
510 return EShLangVertex;
511 else if (suffix == "tesc")
512 return EShLangTessControl;
513 else if (suffix == "tese")
514 return EShLangTessEvaluation;
515 else if (suffix == "geom")
516 return EShLangGeometry;
517 else if (suffix == "frag")
518 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000519 else if (suffix == "comp")
520 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000521
522 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000523 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000524}
525
John Kessenicha0af4732012-12-12 21:15:54 +0000526//
John Kessenich69f4b512013-09-04 21:19:27 +0000527// Read a file's data into a string, and compile it using the old interface ShCompile,
528// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000529//
John Kessenich05a70632013-09-17 19:26:08 +0000530bool CompileFile(const char *fileName, ShHandle compiler, int Options)
John Kessenicha0af4732012-12-12 21:15:54 +0000531{
532 int ret;
John Kessenich41cf6b52013-06-25 18:10:05 +0000533 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000534 if (! shaderStrings) {
535 usage();
536 return false;
537 }
538
John Kessenich41cf6b52013-06-25 18:10:05 +0000539 int* lengths = new int[NumShaderStrings];
540
541 // move to length-based strings, rather than null-terminated strings
542 for (int s = 0; s < NumShaderStrings; ++s)
543 lengths[s] = strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000544
John Kessenich41cf6b52013-06-25 18:10:05 +0000545 if (! shaderStrings)
John Kessenicha0af4732012-12-12 21:15:54 +0000546 return false;
547
John Kessenich52ac67e2013-05-05 23:46:22 +0000548 EShMessages messages = EShMsgDefault;
John Kessenich94a81fb2013-08-31 02:41:30 +0000549 if (Options & EOptionRelaxedErrors)
John Kessenich52ac67e2013-05-05 23:46:22 +0000550 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
John Kessenich94a81fb2013-08-31 02:41:30 +0000551 if (Options & EOptionIntermediate)
552 messages = (EShMessages)(messages | EShMsgAST);
John Kessenich69f4b512013-09-04 21:19:27 +0000553
John Kessenich94a81fb2013-08-31 02:41:30 +0000554 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
555 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich05a70632013-09-17 19:26:08 +0000556 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages);
557 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000558 //const char* multi[4] = { "# ve", "rsion", " 300 e", "s" };
559 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenich05a70632013-09-17 19:26:08 +0000560 //ret = ShCompile(compiler, multi, 4, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000561 }
John Kessenicha0af4732012-12-12 21:15:54 +0000562
John Kessenich94a81fb2013-08-31 02:41:30 +0000563 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000564 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000565 }
John Kessenicha0af4732012-12-12 21:15:54 +0000566
John Kessenich41cf6b52013-06-25 18:10:05 +0000567 delete [] lengths;
568 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000569
570 return ret ? true : false;
571}
572
John Kessenicha0af4732012-12-12 21:15:54 +0000573//
574// print usage to stdout
575//
576void usage()
577{
John Kessenich38f3b892013-09-06 19:52:57 +0000578 printf("Usage: glslangValidator [ options ] filename\n"
John Kessenichc0275792013-08-09 17:14:49 +0000579 "Where: filename is a name ending in\n"
John Kessenich05a70632013-09-17 19:26:08 +0000580 " .conf provides an optional config file that replaces the default configuration\n"
581 " (see -c option below for generating a template)\n"
John Kessenichc0275792013-08-09 17:14:49 +0000582 " .vert for a vertex shader\n"
583 " .tesc for a tessellation control shader\n"
584 " .tese for a tessellation evaluation shader\n"
585 " .geom for a geometry shader\n"
586 " .frag for a fragment shader\n"
587 " .comp for a compute shader\n\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000588 "Compilation warnings and errors will be printed to stdout.\n"
589 "To get other information, use one of the following options:\n"
John Kessenich05a70632013-09-17 19:26:08 +0000590 "-c: configuration dump; use to create default configuration file (redirect to a .conf file)\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000591 "-i: intermediate tree (glslang AST) is printed out\n"
592 "-d: delay exit\n"
John Kessenich94a81fb2013-08-31 02:41:30 +0000593 "-l: link validation of all input files\n"
594 "-m: memory leak mode\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000595 "-r: relaxed semantic error-checking mode\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000596 "-s: silent mode\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000597 "-t: multi-threaded mode\n");
John Kessenicha0af4732012-12-12 21:15:54 +0000598}
599
John Kessenichcfd643e2013-03-08 23:14:42 +0000600#ifndef _WIN32
601
602#include <errno.h>
603
604int fopen_s(
605 FILE** pFile,
606 const char *filename,
607 const char *mode
608)
609{
610 if (!pFile || !filename || !mode) {
611 return EINVAL;
612 }
613
614 FILE* f = fopen(filename, mode);
615 if (! f) {
616 if (errno != 0) {
617 return errno;
618 } else {
619 return ENOENT;
620 }
621 }
622 *pFile = f;
623
624 return 0;
625}
626
627#endif
628
John Kessenicha0af4732012-12-12 21:15:54 +0000629//
630// Malloc a string of sufficient size and read a string into it.
631//
John Kessenich54d8cda2013-02-11 22:36:01 +0000632char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000633{
John Kessenich200b2732012-12-12 21:21:23 +0000634 FILE *in;
635 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000636 char *fdata;
637 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000638 const int maxSourceStrings = 5;
639 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000640
641 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000642 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000643 printf("Error: unable to open input file: %s\n", fileName);
644 return 0;
645 }
646
647 while (fgetc(in) != EOF)
648 count++;
649
650 fseek(in, 0, SEEK_SET);
651
652
653 if (!(fdata = (char *)malloc(count+2))) {
654 printf("Error allocating memory\n");
655 return 0;
656 }
657 if (fread(fdata,1,count, in)!=count) {
658 printf("Error reading input file: %s\n", fileName);
659 return 0;
660 }
661 fdata[count] = '\0';
662 fclose(in);
663 if(count==0){
664 return_data[0]=(char*)malloc(count+2);
665 return_data[0][0]='\0';
John Kessenich41cf6b52013-06-25 18:10:05 +0000666 NumShaderStrings=0;
John Kessenicha0af4732012-12-12 21:15:54 +0000667 return return_data;
668 }
669
John Kessenich41cf6b52013-06-25 18:10:05 +0000670 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000671 int ptr_len=0,i=0;
672 while(count>0){
673 return_data[i]=(char*)malloc(len+2);
674 memcpy(return_data[i],fdata+ptr_len,len);
675 return_data[i][len]='\0';
676 count-=(len);
677 ptr_len+=(len);
678 if(count<len){
679 if(count==0){
John Kessenich41cf6b52013-06-25 18:10:05 +0000680 NumShaderStrings=(i+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000681 break;
682 }
683 len = count;
684 }
685 ++i;
686 }
687 return return_data;
688}
689
John Kessenicha0af4732012-12-12 21:15:54 +0000690void FreeFileData(char **data)
691{
John Kessenich41cf6b52013-06-25 18:10:05 +0000692 for(int i=0;i<NumShaderStrings;i++)
John Kessenicha0af4732012-12-12 21:15:54 +0000693 free(data[i]);
694}
695
John Kessenich54d8cda2013-02-11 22:36:01 +0000696void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000697{
698 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
699 "#### %s %s INFO LOG ####\n", msg, name, num);
700}