blob: 07e52579f029cec5331ccf440bd6fc92191329a0 [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 Kessenich2b07c7e2013-07-31 18:44:13 +000036#include "Worklist.h"
John Kessenicha0af4732012-12-12 21:15:54 +000037#include "./../glslang/Include/ShHandle.h"
38#include "./../glslang/Public/ShaderLang.h"
39#include <string.h>
John Kessenichcfd643e2013-03-08 23:14:42 +000040#include <stdlib.h>
John Kessenicha0af4732012-12-12 21:15:54 +000041#include <math.h>
42
John Kessenich2b07c7e2013-07-31 18:44:13 +000043#include "osinclude.h"
John Kessenicha0af4732012-12-12 21:15:54 +000044
45extern "C" {
46 SH_IMPORT_EXPORT void ShOutputHtml();
47}
48
John Kessenich94a81fb2013-08-31 02:41:30 +000049// Command-line options
50enum TOptions {
51 EOptionNone = 0x000,
52 EOptionIntermediate = 0x001,
53 EOptionSuppressInfolog = 0x002,
54 EOptionMemoryLeakMode = 0x004,
55 EOptionRelaxedErrors = 0x008,
56 EOptionGiveWarnings = 0x010,
57 EOptionsLinkProgram = 0x020,
58};
59
John Kessenicha0af4732012-12-12 21:15:54 +000060//
61// Return codes from main.
62//
63enum TFailCode {
64 ESuccess = 0,
65 EFailUsage,
66 EFailCompile,
67 EFailLink,
68 EFailCompilerCreate,
John Kessenich2b07c7e2013-07-31 18:44:13 +000069 EFailThreadCreate,
John Kessenicha0af4732012-12-12 21:15:54 +000070 EFailLinkerCreate
71};
72
73//
74// Just placeholders for testing purposes. The stand-alone environment
75// can't actually do a full link without something specifying real
76// attribute bindings.
77//
78ShBinding FixedAttributeBindings[] = {
79 { "gl_Vertex", 15 },
80 { "gl_Color", 10 },
81 { "gl_Normal", 7 },
82};
83
84ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
85
John Kessenichb603f912013-08-29 00:39:25 +000086EShLanguage FindLanguage(const std::string& name);
John Kessenich52ac67e2013-05-05 23:46:22 +000087bool CompileFile(const char *fileName, ShHandle, int options, const TBuiltInResource*);
John Kessenicha0af4732012-12-12 21:15:54 +000088void usage();
89void FreeFileData(char **data);
John Kessenich54d8cda2013-02-11 22:36:01 +000090char** ReadFileData(const char *fileName);
91void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +000092
93// Use to test breaking a single shader file into multiple strings.
94int NumShaderStrings = 1;
John Kessenicha0af4732012-12-12 21:15:54 +000095
96//
97// Set up the per compile resources
98//
99void GenerateResources(TBuiltInResource& resources)
John Kessenichb51f62c2013-04-11 16:31:09 +0000100{
John Kessenicha0af4732012-12-12 21:15:54 +0000101 resources.maxLights = 32;
102 resources.maxClipPlanes = 6;
103 resources.maxTextureUnits = 32;
104 resources.maxTextureCoords = 32;
105 resources.maxVertexAttribs = 64;
106 resources.maxVertexUniformComponents = 4096;
107 resources.maxVaryingFloats = 64;
108 resources.maxVertexTextureImageUnits = 32;
109 resources.maxCombinedTextureImageUnits = 32;
110 resources.maxTextureImageUnits = 32;
111 resources.maxFragmentUniformComponents = 4096;
112 resources.maxDrawBuffers = 32;
John Kessenichbd0747d2013-02-17 06:01:50 +0000113 resources.maxVertexUniformVectors = 128;
114 resources.maxVaryingVectors = 8;
115 resources.maxFragmentUniformVectors = 16;
116 resources.maxVertexOutputVectors = 16;
John Kessenich1f2a36b2013-02-20 04:42:42 +0000117 resources.maxFragmentInputVectors = 15;
John Kessenichbd0747d2013-02-17 06:01:50 +0000118 resources.minProgramTexelOffset = -8;
119 resources.maxProgramTexelOffset = 7;
John Kessenicha0af4732012-12-12 21:15:54 +0000120}
121
John Kessenich2b07c7e2013-07-31 18:44:13 +0000122glslang::TWorklist Worklist;
John Kessenich94a81fb2013-08-31 02:41:30 +0000123int Options = 0;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000124bool Delay = false;
125
126bool ProcessArguments(int argc, char* argv[])
127{
128 argc--;
129 argv++;
130 for (; argc >= 1; argc--, argv++) {
131 if (argv[0][0] == '-') {
132 switch (argv[0][1]) {
133 case 'd':
134 Delay = true;
135 break;
136 case 'i':
John Kessenich94a81fb2013-08-31 02:41:30 +0000137 Options |= EOptionIntermediate;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000138 break;
139 case 'l':
John Kessenich94a81fb2013-08-31 02:41:30 +0000140 Options |= EOptionsLinkProgram;
141 break;
142 case 'm':
143 Options |= EOptionMemoryLeakMode;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000144 break;
145 case 'r':
John Kessenich94a81fb2013-08-31 02:41:30 +0000146 Options |= EOptionRelaxedErrors;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000147 break;
148 case 's':
John Kessenich94a81fb2013-08-31 02:41:30 +0000149 Options |= EOptionSuppressInfolog;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000150 break;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000151 default:
John Kessenich2b07c7e2013-07-31 18:44:13 +0000152 return false;
153 }
154 } else
155 Worklist.add(std::string(argv[0]));
156 }
157
John Kessenich54f6e562013-08-03 00:04:10 +0000158 if (Worklist.empty())
159 return false;
160
John Kessenich2b07c7e2013-07-31 18:44:13 +0000161 return true;
162}
163
164// Thread entry point
John Kessenichee6a9c82013-07-31 23:19:17 +0000165unsigned int
166#ifdef _WIN32
167 __stdcall
168#endif
John Kessenich94a81fb2013-08-31 02:41:30 +0000169CompileShaders(void*)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000170{
171 ShHandle compiler;
172
173 std::string shaderName;
174 while (Worklist.remove(shaderName)) {
John Kessenich94a81fb2013-08-31 02:41:30 +0000175 compiler = ShConstructCompiler(FindLanguage(shaderName), Options);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000176 if (compiler == 0)
177 return false;
178
179 TBuiltInResource resources;
180 GenerateResources(resources);
John Kessenich94a81fb2013-08-31 02:41:30 +0000181 CompileFile(shaderName.c_str(), compiler, Options, &resources);
John Kessenich2b07c7e2013-07-31 18:44:13 +0000182
John Kessenich94a81fb2013-08-31 02:41:30 +0000183 if (! (Options & EOptionSuppressInfolog))
John Kessenich2b07c7e2013-07-31 18:44:13 +0000184 puts(ShGetInfoLog(compiler));
185
186 ShDestruct(compiler);
187 }
188
189 return 0;
190}
191
John Kessenicha0af4732012-12-12 21:15:54 +0000192int C_DECL main(int argc, char* argv[])
193{
John Kessenicha0af4732012-12-12 21:15:54 +0000194 bool compileFailed = false;
195 bool linkFailed = false;
John Kessenicha0af4732012-12-12 21:15:54 +0000196
John Kessenich2b07c7e2013-07-31 18:44:13 +0000197 // Init for front-end proper
John Kessenicha0af4732012-12-12 21:15:54 +0000198 ShInitialize();
199
John Kessenich2b07c7e2013-07-31 18:44:13 +0000200 // Init for for standalone
201 glslang::InitGlobalLock();
John Kessenicha0af4732012-12-12 21:15:54 +0000202
John Kessenich54f6e562013-08-03 00:04:10 +0000203 if (! ProcessArguments(argc, argv)) {
204 usage();
John Kessenich2b07c7e2013-07-31 18:44:13 +0000205 return EFailUsage;
John Kessenich54f6e562013-08-03 00:04:10 +0000206 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000207
208 // TODO: finish threading, allow external control over number of threads
209 const int NumThreads = 1;
210 if (NumThreads > 1) {
211 void* threads[NumThreads];
212 for (int t = 0; t < NumThreads; ++t) {
213 threads[t] = glslang::OS_CreateThread(&CompileShaders);
214 if (! threads[t]) {
215 printf("Failed to create thread\n");
216 return EFailThreadCreate;
John Kessenicha0af4732012-12-12 21:15:54 +0000217 }
218 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000219 glslang::OS_WaitForAllThreads(threads, NumThreads);
220 } else {
221 if (! CompileShaders(0))
222 compileFailed = true;
John Kessenicha0af4732012-12-12 21:15:54 +0000223 }
John Kessenich2b07c7e2013-07-31 18:44:13 +0000224
225 if (Delay)
226 glslang::OS_Sleep(1000000);
John Kessenicha0af4732012-12-12 21:15:54 +0000227
228 if (compileFailed)
229 return EFailCompile;
230 if (linkFailed)
231 return EFailLink;
232
233 return 0;
234}
235
236//
237// Deduce the language from the filename. Files must end in one of the
238// following extensions:
239//
John Kessenich2b07c7e2013-07-31 18:44:13 +0000240// .vert = vertex
241// .tesc = tessellation control
242// .tese = tessellation evaluation
243// .geom = geometry
244// .frag = fragment
John Kessenich94a81fb2013-08-31 02:41:30 +0000245// .comp = compute
John Kessenicha0af4732012-12-12 21:15:54 +0000246//
John Kessenichb603f912013-08-29 00:39:25 +0000247EShLanguage FindLanguage(const std::string& name)
John Kessenicha0af4732012-12-12 21:15:54 +0000248{
John Kessenich2b07c7e2013-07-31 18:44:13 +0000249 size_t ext = name.rfind('.');
250 if (ext == std::string::npos) {
251 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000252 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000253 }
254
John Kessenich2b07c7e2013-07-31 18:44:13 +0000255 std::string suffix = name.substr(ext + 1, std::string::npos);
256 if (suffix == "vert")
257 return EShLangVertex;
258 else if (suffix == "tesc")
259 return EShLangTessControl;
260 else if (suffix == "tese")
261 return EShLangTessEvaluation;
262 else if (suffix == "geom")
263 return EShLangGeometry;
264 else if (suffix == "frag")
265 return EShLangFragment;
John Kessenichc0275792013-08-09 17:14:49 +0000266 else if (suffix == "comp")
267 return EShLangCompute;
John Kessenich2b07c7e2013-07-31 18:44:13 +0000268
269 usage();
John Kesseniche95ecc52012-12-12 21:34:14 +0000270 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000271}
272
John Kessenicha0af4732012-12-12 21:15:54 +0000273//
274// Read a file's data into a string, and compile it using ShCompile
275//
John Kessenich94a81fb2013-08-31 02:41:30 +0000276bool CompileFile(const char *fileName, ShHandle compiler, int Options, const TBuiltInResource *resources)
John Kessenicha0af4732012-12-12 21:15:54 +0000277{
278 int ret;
John Kessenich41cf6b52013-06-25 18:10:05 +0000279 char** shaderStrings = ReadFileData(fileName);
John Kessenichdb4cd542013-06-26 22:42:55 +0000280 if (! shaderStrings) {
281 usage();
282 return false;
283 }
284
John Kessenich41cf6b52013-06-25 18:10:05 +0000285 int* lengths = new int[NumShaderStrings];
286
287 // move to length-based strings, rather than null-terminated strings
288 for (int s = 0; s < NumShaderStrings; ++s)
289 lengths[s] = strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000290
John Kessenich41cf6b52013-06-25 18:10:05 +0000291 if (! shaderStrings)
John Kessenicha0af4732012-12-12 21:15:54 +0000292 return false;
293
John Kessenich52ac67e2013-05-05 23:46:22 +0000294 EShMessages messages = EShMsgDefault;
John Kessenich94a81fb2013-08-31 02:41:30 +0000295 if (Options & EOptionRelaxedErrors)
John Kessenich52ac67e2013-05-05 23:46:22 +0000296 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
John Kessenich94a81fb2013-08-31 02:41:30 +0000297 if (Options & EOptionIntermediate)
298 messages = (EShMessages)(messages | EShMsgAST);
299 for (int i = 0; i < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++i) {
300 for (int j = 0; j < ((Options & EOptionMemoryLeakMode) ? 100 : 1); ++j) {
301 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, resources, Options, 100, false, messages);
302 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000303 //const char* multi[4] = { "# ve", "rsion", " 300 e", "s" };
304 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
John Kessenich94a81fb2013-08-31 02:41:30 +0000305 //ret = ShCompile(compiler, multi, 4, 0, EShOptNone, resources, Options, 100, false, messages);
John Kessenich41cf6b52013-06-25 18:10:05 +0000306 }
John Kessenicha0af4732012-12-12 21:15:54 +0000307
John Kessenich94a81fb2013-08-31 02:41:30 +0000308 if (Options & EOptionMemoryLeakMode)
John Kessenich2b07c7e2013-07-31 18:44:13 +0000309 glslang::OS_DumpMemoryCounters();
John Kessenicha0af4732012-12-12 21:15:54 +0000310 }
John Kessenicha0af4732012-12-12 21:15:54 +0000311
John Kessenich41cf6b52013-06-25 18:10:05 +0000312 delete [] lengths;
313 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000314
315 return ret ? true : false;
316}
317
318
319//
320// print usage to stdout
321//
322void usage()
323{
John Kessenich8df53cc2013-04-14 19:23:50 +0000324 printf("Usage: standalone [ options ] filename\n"
John Kessenichc0275792013-08-09 17:14:49 +0000325 "Where: filename is a name ending in\n"
326 " .vert for a vertex shader\n"
327 " .tesc for a tessellation control shader\n"
328 " .tese for a tessellation evaluation shader\n"
329 " .geom for a geometry shader\n"
330 " .frag for a fragment shader\n"
331 " .comp for a compute shader\n\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000332 "Compilation warnings and errors will be printed to stdout.\n"
333 "To get other information, use one of the following options:\n"
334 "-i: intermediate tree (glslang AST) is printed out\n"
335 "-d: delay exit\n"
John Kessenich94a81fb2013-08-31 02:41:30 +0000336 "-l: link validation of all input files\n"
337 "-m: memory leak mode\n"
John Kessenich4586dbd2013-08-05 15:52:03 +0000338 "-s: silent mode\n"
339 "-r: relaxed semantic error-checking mode\n");
John Kessenicha0af4732012-12-12 21:15:54 +0000340}
341
John Kessenichcfd643e2013-03-08 23:14:42 +0000342#ifndef _WIN32
343
344#include <errno.h>
345
346int fopen_s(
347 FILE** pFile,
348 const char *filename,
349 const char *mode
350)
351{
352 if (!pFile || !filename || !mode) {
353 return EINVAL;
354 }
355
356 FILE* f = fopen(filename, mode);
357 if (! f) {
358 if (errno != 0) {
359 return errno;
360 } else {
361 return ENOENT;
362 }
363 }
364 *pFile = f;
365
366 return 0;
367}
368
369#endif
370
John Kessenicha0af4732012-12-12 21:15:54 +0000371//
372// Malloc a string of sufficient size and read a string into it.
373//
John Kessenich54d8cda2013-02-11 22:36:01 +0000374char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000375{
John Kessenich200b2732012-12-12 21:21:23 +0000376 FILE *in;
377 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000378 char *fdata;
379 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000380 const int maxSourceStrings = 5;
381 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000382
383 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000384 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000385 printf("Error: unable to open input file: %s\n", fileName);
386 return 0;
387 }
388
389 while (fgetc(in) != EOF)
390 count++;
391
392 fseek(in, 0, SEEK_SET);
393
394
395 if (!(fdata = (char *)malloc(count+2))) {
396 printf("Error allocating memory\n");
397 return 0;
398 }
399 if (fread(fdata,1,count, in)!=count) {
400 printf("Error reading input file: %s\n", fileName);
401 return 0;
402 }
403 fdata[count] = '\0';
404 fclose(in);
405 if(count==0){
406 return_data[0]=(char*)malloc(count+2);
407 return_data[0][0]='\0';
John Kessenich41cf6b52013-06-25 18:10:05 +0000408 NumShaderStrings=0;
John Kessenicha0af4732012-12-12 21:15:54 +0000409 return return_data;
410 }
411
John Kessenich41cf6b52013-06-25 18:10:05 +0000412 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000413 int ptr_len=0,i=0;
414 while(count>0){
415 return_data[i]=(char*)malloc(len+2);
416 memcpy(return_data[i],fdata+ptr_len,len);
417 return_data[i][len]='\0';
418 count-=(len);
419 ptr_len+=(len);
420 if(count<len){
421 if(count==0){
John Kessenich41cf6b52013-06-25 18:10:05 +0000422 NumShaderStrings=(i+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000423 break;
424 }
425 len = count;
426 }
427 ++i;
428 }
429 return return_data;
430}
431
432
433
434void FreeFileData(char **data)
435{
John Kessenich41cf6b52013-06-25 18:10:05 +0000436 for(int i=0;i<NumShaderStrings;i++)
John Kessenicha0af4732012-12-12 21:15:54 +0000437 free(data[i]);
438}
439
440
441
John Kessenich54d8cda2013-02-11 22:36:01 +0000442void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000443{
444 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
445 "#### %s %s INFO LOG ####\n", msg, name, num);
446}