blob: bd04bea6301d9ceea31f55a075df07207868ccaf [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"
129"MaxProgramTexelOffset 7\n"
130;
131
132//
133// Parse either a .conf file provided by the user or the default string above.
134//
135void ProcessConfigFile()
John Kessenichb51f62c2013-04-11 16:31:09 +0000136{
John Kessenich05a70632013-09-17 19:26:08 +0000137 char** configStrings = 0;
138 char *config = 0;
139 if (ConfigFile.size() > 0) {
140 char** configStrings = ReadFileData(ConfigFile.c_str());
141 if (configStrings)
142 config = *configStrings;
143 else {
144 printf("Error opening configuration file; will instead use the default configuration\n");
145 usage();
146 }
147 }
148
149 if (config == 0) {
150 config = new char[strlen(DefaultConfig)];
151 strcpy(config, DefaultConfig);
152 }
153
154 const char* delims = " \t\n\r";
155 const char* token = strtok(config, delims);
156 while (token) {
157 const char* valueStr = strtok(0, delims);
158 if (valueStr == 0 || ! (valueStr[0] == '-' || (valueStr[0] >= '0' && valueStr[0] <= '9'))) {
159 printf("Error: '%s' bad .conf file. Each name must be followed by one number.\n", valueStr ? valueStr : "");
160 return;
161 }
162 int value = atoi(valueStr);
163
164 if (strcmp(token, "MaxLights") == 0)
165 Resources.maxLights = value;
166 else if (strcmp(token, "MaxClipPlanes") == 0)
167 Resources.maxClipPlanes = value;
168 else if (strcmp(token, "MaxTextureUnits") == 0)
169 Resources.maxTextureUnits = value;
170 else if (strcmp(token, "MaxTextureCoords") == 0)
171 Resources.maxTextureCoords = value;
172 else if (strcmp(token, "MaxVertexAttribs") == 0)
173 Resources.maxVertexAttribs = value;
174 else if (strcmp(token, "MaxVertexUniformComponents") == 0)
175 Resources.maxVertexUniformComponents = value;
176 else if (strcmp(token, "MaxVaryingFloats") == 0)
177 Resources.maxVaryingFloats = value;
178 else if (strcmp(token, "MaxVertexTextureImageUnits") == 0)
179 Resources.maxVertexTextureImageUnits = value;
180 else if (strcmp(token, "MaxCombinedTextureImageUnits") == 0)
181 Resources.maxCombinedTextureImageUnits = value;
182 else if (strcmp(token, "MaxTextureImageUnits") == 0)
183 Resources.maxTextureImageUnits = value;
184 else if (strcmp(token, "MaxFragmentUniformComponents") == 0)
185 Resources.maxFragmentUniformComponents = value;
186 else if (strcmp(token, "MaxDrawBuffers") == 0)
187 Resources.maxDrawBuffers = value;
188 else if (strcmp(token, "MaxVertexUniformVectors") == 0)
189 Resources.maxVertexUniformVectors = value;
190 else if (strcmp(token, "MaxVaryingVectors") == 0)
191 Resources.maxVaryingVectors = value;
192 else if (strcmp(token, "MaxFragmentUniformVectors") == 0)
193 Resources.maxFragmentUniformVectors = value;
194 else if (strcmp(token, "MaxVertexOutputVectors") == 0)
195 Resources.maxVertexOutputVectors = value;
196 else if (strcmp(token, "MaxFragmentInputVectors") == 0)
197 Resources.maxFragmentInputVectors = value;
198 else if (strcmp(token, "MinProgramTexelOffset") == 0)
199 Resources.minProgramTexelOffset = value;
200 else if (strcmp(token, "MaxProgramTexelOffset") == 0)
201 Resources.maxProgramTexelOffset = value;
202 else
203 printf("Warning: unrecognized limit (%s) in configuration file.\n", token);
204
205 token = strtok(0, delims);
206 }
207 if (configStrings)
208 FreeFileData(configStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000209}
210
John Kessenich38f3b892013-09-06 19:52:57 +0000211// thread-safe list of shaders to asynchronously grab and compile
John Kessenich2b07c7e2013-07-31 18:44:13 +0000212glslang::TWorklist Worklist;
John Kessenich38f3b892013-09-06 19:52:57 +0000213
214// array of unique places to leave the shader names and infologs for the asynchronous compiles
215glslang::TWorkItem **Work = 0;
216int NumWorkItems = 0;
217
John Kessenich94a81fb2013-08-31 02:41:30 +0000218int Options = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000219bool Delay = false;
John Kessenich38f3b892013-09-06 19:52:57 +0000220const char* ExecutableName;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000221
John Kessenich05a70632013-09-17 19:26:08 +0000222//
223// *.conf => this is a config file that can set limits/resources
224//
225bool SetConfigFile(const std::string& name)
226{
227 if (name.size() < 5)
228 return false;
229
230 if (name.substr(name.size() - 5, std::string::npos) == ".conf") {
231 ConfigFile = name;
232 return true;
233 }
234
235 return false;
236}
237
John Kessenich2b07c7e2013-07-31 18:44:13 +0000238bool ProcessArguments(int argc, char* argv[])
239{
John Kessenich38f3b892013-09-06 19:52:57 +0000240 ExecutableName = argv[0];
241 NumWorkItems = argc; // will include some empties where the '-' options were, but it doesn't matter, they'll be 0
242 Work = new glslang::TWorkItem*[NumWorkItems];
243 Work[0] = 0;
244
John Kessenich2b07c7e2013-07-31 18:44:13 +0000245 argc--;
246 argv++;
247 for (; argc >= 1; argc--, argv++) {
John Kessenich05a70632013-09-17 19:26:08 +0000248 Work[argc] = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000249 if (argv[0][0] == '-') {
250 switch (argv[0][1]) {
John Kessenich05a70632013-09-17 19:26:08 +0000251 case 'c':
252 Options |= EOptionDumpConfig;
253 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000254 case 'd':
255 Delay = true;
256 break;
John Kessenich05a70632013-09-17 19:26:08 +0000257 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000258 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000259 break;
260 case 'l':
John Kessenich94a81fb2013-08-31 02:41:30 +0000261 Options |= EOptionsLinkProgram;
262 break;
263 case 'm':
264 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000265 break;
266 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000267 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000268 break;
269 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000270 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000271 break;
John Kessenich38f3b892013-09-06 19:52:57 +0000272 case 't':
273 #ifdef _WIN32
274 Options |= EOptionMultiThreaded;
275 #endif
276 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000277 default:
John Kessenich2b07c7e2013-07-31 18:44:13 +0000278 return false;
279 }
John Kessenich38f3b892013-09-06 19:52:57 +0000280 } else {
John Kessenich05a70632013-09-17 19:26:08 +0000281 std::string name(argv[0]);
282 if (! SetConfigFile(name)) {
283 Work[argc] = new glslang::TWorkItem(name);
284 Worklist.add(Work[argc]);
285 }
John Kessenich38f3b892013-09-06 19:52:57 +0000286 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000287 }
288
289 return true;
290}
291
John Kessenich69f4b512013-09-04 21:19:27 +0000292// Thread entry point, for non-linking asynchronous mode.
John Kessenichee6a9c82013-07-31 23:19:17 +0000293unsigned int
294#ifdef _WIN32
295 __stdcall
296#endif
John Kessenich94a81fb2013-08-31 02:41:30 +0000297CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000298{
John Kessenich38f3b892013-09-06 19:52:57 +0000299 glslang::TWorkItem* workItem;
300 while (Worklist.remove(workItem)) {
301 ShHandle compiler = ShConstructCompiler(FindLanguage(workItem->name), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000302 if (compiler == 0)
303 return false;
304
John Kessenich05a70632013-09-17 19:26:08 +0000305 CompileFile(workItem->name.c_str(), compiler, Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000306
John Kessenich94a81fb2013-08-31 02:41:30 +0000307 if (! (Options & EOptionSuppressInfolog))
John Kessenich38f3b892013-09-06 19:52:57 +0000308 workItem->results = ShGetInfoLog(compiler);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000309
310 ShDestruct(compiler);
311 }
312
313 return 0;
314}
315
John Kessenich69f4b512013-09-04 21:19:27 +0000316//
317// For linking mode: Will independently parse each item in the worklist, but then put them
318// in the same program and link them together.
319//
320// Uses the new C++ interface instead of the old handle-based interface.
321//
322void CompileAndLinkShaders()
323{
324 // keep track of what to free
325 std::list<glslang::TShader*> shaders;
326
327 EShMessages messages = EShMsgDefault;
328 if (Options & EOptionRelaxedErrors)
329 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
330 if (Options & EOptionIntermediate)
331 messages = (EShMessages)(messages | EShMsgAST);
332
John Kessenich69f4b512013-09-04 21:19:27 +0000333 //
334 // Per-shader processing...
335 //
336
337 glslang::TProgram program;
John Kessenich38f3b892013-09-06 19:52:57 +0000338 glslang::TWorkItem* workItem;
339 while (Worklist.remove(workItem)) {
340 EShLanguage stage = FindLanguage(workItem->name);
John Kessenich69f4b512013-09-04 21:19:27 +0000341 glslang::TShader* shader = new glslang::TShader(stage);
342 shaders.push_back(shader);
343
John Kessenich38f3b892013-09-06 19:52:57 +0000344 char** shaderStrings = ReadFileData(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000345 if (! shaderStrings) {
346 usage();
347 return;
348 }
349
350 shader->setStrings(shaderStrings, 1);
351
John Kessenich05a70632013-09-17 19:26:08 +0000352 shader->parse(&Resources, 100, false, messages);
John Kessenich69f4b512013-09-04 21:19:27 +0000353
354 program.addShader(shader);
355
356 if (! (Options & EOptionSuppressInfolog)) {
John Kessenich38f3b892013-09-06 19:52:57 +0000357 puts(workItem->name.c_str());
John Kessenich69f4b512013-09-04 21:19:27 +0000358 puts(shader->getInfoLog());
359 puts(shader->getInfoDebugLog());
360 }
361
362 FreeFileData(shaderStrings);
363 }
364
365 //
366 // Program-level processing...
367 //
368
369 program.link(messages);
370 if (! (Options & EOptionSuppressInfolog)) {
371 puts(program.getInfoLog());
372 puts(program.getInfoDebugLog());
373 }
374
375 // free everything up
376 while (shaders.size() > 0) {
377 delete shaders.back();
378 shaders.pop_back();
379 }
380
381 // TODO: memory: for each compile, need a GetThreadPoolAllocator().pop();
382}
383
John Kessenicha0af4732012-12-12 21:15:54 +0000384int C_DECL main(int argc, char* argv[])
385{
John Kessenicha0af4732012-12-12 21:15:54 +0000386 bool compileFailed = false;
387 bool linkFailed = false;
John Kessenicha0af4732012-12-12 21:15:54 +0000388
John Kessenich2b07c7e2013-07-31 18:44:13 +0000389 // Init for front-end proper
John Kessenicha0af4732012-12-12 21:15:54 +0000390 ShInitialize();
391
John Kessenich38f3b892013-09-06 19:52:57 +0000392 // Init for standalone
John Kessenich2b07c7e2013-07-31 18:44:13 +0000393 glslang::InitGlobalLock();
John Kessenicha0af4732012-12-12 21:15:54 +0000394
John Kessenich54f6e562013-08-03 00:04:10 +0000395 if (! ProcessArguments(argc, argv)) {
396 usage();
John Kessenich2b07c7e2013-07-31 18:44:13 +0000397 return EFailUsage;
John Kessenich54f6e562013-08-03 00:04:10 +0000398 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000399
John Kessenich05a70632013-09-17 19:26:08 +0000400 if (Options & EOptionDumpConfig) {
401 printf("%s", DefaultConfig);
402 if (Worklist.empty())
403 return ESuccess;
404 }
405
406 if (Worklist.empty()) {
407 usage();
408 return EFailUsage;
409 }
410
411 ProcessConfigFile();
412
413
John Kessenich69f4b512013-09-04 21:19:27 +0000414 //
415 // Two modes:
John Kessenich38f3b892013-09-06 19:52:57 +0000416 // 1) linking all arguments together, single-threaded, new C++ interface
417 // 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 +0000418 //
John Kessenich38f3b892013-09-06 19:52:57 +0000419 if (Options & EOptionsLinkProgram)
420 CompileAndLinkShaders();
421 else {
422 bool printShaderNames = Worklist.size() > 1;
John Kessenich69f4b512013-09-04 21:19:27 +0000423
John Kessenich38f3b892013-09-06 19:52:57 +0000424 if (Options & EOptionMultiThreaded) {
425 const int NumThreads = 16;
426 void* threads[NumThreads];
427 for (int t = 0; t < NumThreads; ++t) {
428 threads[t] = glslang::OS_CreateThread(&CompileShaders);
429 if (! threads[t]) {
430 printf("Failed to create thread\n");
431 return EFailThreadCreate;
432 }
John Kessenicha0af4732012-12-12 21:15:54 +0000433 }
John Kessenich38f3b892013-09-06 19:52:57 +0000434 glslang::OS_WaitForAllThreads(threads, NumThreads);
John Kessenich69f4b512013-09-04 21:19:27 +0000435 } else {
436 if (! CompileShaders(0))
437 compileFailed = true;
438 }
John Kessenich38f3b892013-09-06 19:52:57 +0000439
440 // Print out all the resulting infologs
441 for (int w = 0; w < NumWorkItems; ++w) {
442 if (Work[w]) {
443 if (printShaderNames)
444 puts(Work[w]->name.c_str());
445 puts(Work[w]->results.c_str());
446 delete Work[w];
447 }
448 }
John Kessenicha0af4732012-12-12 21:15:54 +0000449 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000450
451 if (Delay)
452 glslang::OS_Sleep(1000000);
John Kessenicha0af4732012-12-12 21:15:54 +0000453
454 if (compileFailed)
455 return EFailCompile;
456 if (linkFailed)
457 return EFailLink;
458
459 return 0;
460}
461
462//
463// Deduce the language from the filename. Files must end in one of the
464// following extensions:
465//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000466// .vert = vertex
467// .tesc = tessellation control
468// .tese = tessellation evaluation
469// .geom = geometry
470// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000471// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000472//
John Kessenichb603f912013-08-29 00:39:25 +0000473EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000474{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000475 size_t ext = name.rfind('.');
476 if (ext == std::string::npos) {
477 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000478 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000479 }
480
John Kessenich2b07c7e2013-07-31 18:44:13 +0000481 std::string suffix = name.substr(ext + 1, std::string::npos);
482 if (suffix == "vert")
483 return EShLangVertex;
484 else if (suffix == "tesc")
485 return EShLangTessControl;
486 else if (suffix == "tese")
487 return EShLangTessEvaluation;
488 else if (suffix == "geom")
489 return EShLangGeometry;
490 else if (suffix == "frag")
491 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000492 else if (suffix == "comp")
493 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000494
495 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000496 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000497}
498
John Kessenicha0af4732012-12-12 21:15:54 +0000499//
John Kessenich69f4b512013-09-04 21:19:27 +0000500// Read a file's data into a string, and compile it using the old interface ShCompile,
501// for non-linkable results.
John Kessenicha0af4732012-12-12 21:15:54 +0000502//
John Kessenich05a70632013-09-17 19:26:08 +0000503bool CompileFile(const char *fileName, ShHandle compiler, int Options)
John Kessenicha0af4732012-12-12 21:15:54 +0000504{
505 int ret;
John Kessenich41cf6b52013-06-25 18:10:05 +0000506 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000507 if (! shaderStrings) {
508 usage();
509 return false;
510 }
511
John Kessenich41cf6b52013-06-25 18:10:05 +0000512 int* lengths = new int[NumShaderStrings];
513
514 // move to length-based strings, rather than null-terminated strings
515 for (int s = 0; s < NumShaderStrings; ++s)
516 lengths[s] = strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000517
John Kessenich41cf6b52013-06-25 18:10:05 +0000518 if (! shaderStrings)
John Kessenicha0af4732012-12-12 21:15:54 +0000519 return false;
520
John Kessenich52ac67e2013-05-05 23:46:22 +0000521 EShMessages messages = EShMsgDefault;
John Kessenich94a81fb2013-08-31 02:41:30 +0000522 if (Options & EOptionRelaxedErrors)
John Kessenich52ac67e2013-05-05 23:46:22 +0000523 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
John Kessenich94a81fb2013-08-31 02:41:30 +0000524 if (Options & EOptionIntermediate)
525 messages = (EShMessages)(messages | EShMsgAST);
John Kessenich69f4b512013-09-04 21:19:27 +0000526
John Kessenich94a81fb2013-08-31 02:41:30 +0000527 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
528 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
John Kessenich05a70632013-09-17 19:26:08 +0000529 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, &Resources, Options, 100, false, messages);
530 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000531 //const char* multi[4] = { "# ve", "rsion", " 300 e", "s" };
532 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenich05a70632013-09-17 19:26:08 +0000533 //ret = ShCompile(compiler, multi, 4, 0, EShOptNone, &Resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000534 }
John Kessenicha0af4732012-12-12 21:15:54 +0000535
John Kessenich94a81fb2013-08-31 02:41:30 +0000536 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000537 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000538 }
John Kessenicha0af4732012-12-12 21:15:54 +0000539
John Kessenich41cf6b52013-06-25 18:10:05 +0000540 delete [] lengths;
541 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000542
543 return ret ? true : false;
544}
545
John Kessenicha0af4732012-12-12 21:15:54 +0000546//
547// print usage to stdout
548//
549void usage()
550{
John Kessenich38f3b892013-09-06 19:52:57 +0000551 printf("Usage: glslangValidator [ options ] filename\n"
John Kessenichc0275792013-08-09 17:14:49 +0000552 "Where: filename is a name ending in\n"
John Kessenich05a70632013-09-17 19:26:08 +0000553 " .conf provides an optional config file that replaces the default configuration\n"
554 " (see -c option below for generating a template)\n"
John Kessenichc0275792013-08-09 17:14:49 +0000555 " .vert for a vertex shader\n"
556 " .tesc for a tessellation control shader\n"
557 " .tese for a tessellation evaluation shader\n"
558 " .geom for a geometry shader\n"
559 " .frag for a fragment shader\n"
560 " .comp for a compute shader\n\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000561 "Compilation warnings and errors will be printed to stdout.\n"
562 "To get other information, use one of the following options:\n"
John Kessenich05a70632013-09-17 19:26:08 +0000563 "-c: configuration dump; use to create default configuration file (redirect to a .conf file)\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000564 "-i: intermediate tree (glslang AST) is printed out\n"
565 "-d: delay exit\n"
John Kessenich94a81fb2013-08-31 02:41:30 +0000566 "-l: link validation of all input files\n"
567 "-m: memory leak mode\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000568 "-r: relaxed semantic error-checking mode\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000569 "-s: silent mode\n"
John Kessenich38f3b892013-09-06 19:52:57 +0000570 "-t: multi-threaded mode\n");
John Kessenicha0af4732012-12-12 21:15:54 +0000571}
572
John Kessenichcfd643e2013-03-08 23:14:42 +0000573#ifndef _WIN32
574
575#include <errno.h>
576
577int fopen_s(
578 FILE** pFile,
579 const char *filename,
580 const char *mode
581)
582{
583 if (!pFile || !filename || !mode) {
584 return EINVAL;
585 }
586
587 FILE* f = fopen(filename, mode);
588 if (! f) {
589 if (errno != 0) {
590 return errno;
591 } else {
592 return ENOENT;
593 }
594 }
595 *pFile = f;
596
597 return 0;
598}
599
600#endif
601
John Kessenicha0af4732012-12-12 21:15:54 +0000602//
603// Malloc a string of sufficient size and read a string into it.
604//
John Kessenich54d8cda2013-02-11 22:36:01 +0000605char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000606{
John Kessenich200b2732012-12-12 21:21:23 +0000607 FILE *in;
608 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000609 char *fdata;
610 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000611 const int maxSourceStrings = 5;
612 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000613
614 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000615 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000616 printf("Error: unable to open input file: %s\n", fileName);
617 return 0;
618 }
619
620 while (fgetc(in) != EOF)
621 count++;
622
623 fseek(in, 0, SEEK_SET);
624
625
626 if (!(fdata = (char *)malloc(count+2))) {
627 printf("Error allocating memory\n");
628 return 0;
629 }
630 if (fread(fdata,1,count, in)!=count) {
631 printf("Error reading input file: %s\n", fileName);
632 return 0;
633 }
634 fdata[count] = '\0';
635 fclose(in);
636 if(count==0){
637 return_data[0]=(char*)malloc(count+2);
638 return_data[0][0]='\0';
John Kessenich41cf6b52013-06-25 18:10:05 +0000639 NumShaderStrings=0;
John Kessenicha0af4732012-12-12 21:15:54 +0000640 return return_data;
641 }
642
John Kessenich41cf6b52013-06-25 18:10:05 +0000643 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000644 int ptr_len=0,i=0;
645 while(count>0){
646 return_data[i]=(char*)malloc(len+2);
647 memcpy(return_data[i],fdata+ptr_len,len);
648 return_data[i][len]='\0';
649 count-=(len);
650 ptr_len+=(len);
651 if(count<len){
652 if(count==0){
John Kessenich41cf6b52013-06-25 18:10:05 +0000653 NumShaderStrings=(i+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000654 break;
655 }
656 len = count;
657 }
658 ++i;
659 }
660 return return_data;
661}
662
John Kessenicha0af4732012-12-12 21:15:54 +0000663void FreeFileData(char **data)
664{
John Kessenich41cf6b52013-06-25 18:10:05 +0000665 for(int i=0;i<NumShaderStrings;i++)
John Kessenicha0af4732012-12-12 21:15:54 +0000666 free(data[i]);
667}
668
John Kessenich54d8cda2013-02-11 22:36:01 +0000669void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000670{
671 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
672 "#### %s %s INFO LOG ####\n", msg, name, num);
673}