blob: e0915af14965902aa157e57e908d9e162cb18f95 [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//
36#include "./../glslang/Include/ShHandle.h"
37#include "./../glslang/Public/ShaderLang.h"
38#include <string.h>
John Kessenichcfd643e2013-03-08 23:14:42 +000039#include <stdlib.h>
John Kessenicha0af4732012-12-12 21:15:54 +000040#include <math.h>
41
42#ifdef _WIN32
43 #include <windows.h>
44 #include <psapi.h>
45#endif
46
47extern "C" {
48 SH_IMPORT_EXPORT void ShOutputHtml();
49}
50
John Kessenicha0af4732012-12-12 21:15:54 +000051//
52// Return codes from main.
53//
54enum TFailCode {
55 ESuccess = 0,
56 EFailUsage,
57 EFailCompile,
58 EFailLink,
59 EFailCompilerCreate,
60 EFailLinkerCreate
61};
62
63//
64// Just placeholders for testing purposes. The stand-alone environment
65// can't actually do a full link without something specifying real
66// attribute bindings.
67//
68ShBinding FixedAttributeBindings[] = {
69 { "gl_Vertex", 15 },
70 { "gl_Color", 10 },
71 { "gl_Normal", 7 },
72};
73
74ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
75
76static EShLanguage FindLanguage(char *lang);
John Kessenich52ac67e2013-05-05 23:46:22 +000077bool CompileFile(const char *fileName, ShHandle, int options, const TBuiltInResource*);
John Kessenicha0af4732012-12-12 21:15:54 +000078void usage();
79void FreeFileData(char **data);
John Kessenich54d8cda2013-02-11 22:36:01 +000080char** ReadFileData(const char *fileName);
81void InfoLogMsg(const char* msg, const char* name, const int num);
John Kessenich41cf6b52013-06-25 18:10:05 +000082
83// Use to test breaking a single shader file into multiple strings.
84int NumShaderStrings = 1;
John Kessenicha0af4732012-12-12 21:15:54 +000085
86//
87// Set up the per compile resources
88//
89void GenerateResources(TBuiltInResource& resources)
John Kessenichb51f62c2013-04-11 16:31:09 +000090{
John Kessenicha0af4732012-12-12 21:15:54 +000091 resources.maxLights = 32;
92 resources.maxClipPlanes = 6;
93 resources.maxTextureUnits = 32;
94 resources.maxTextureCoords = 32;
95 resources.maxVertexAttribs = 64;
96 resources.maxVertexUniformComponents = 4096;
97 resources.maxVaryingFloats = 64;
98 resources.maxVertexTextureImageUnits = 32;
99 resources.maxCombinedTextureImageUnits = 32;
100 resources.maxTextureImageUnits = 32;
101 resources.maxFragmentUniformComponents = 4096;
102 resources.maxDrawBuffers = 32;
John Kessenichbd0747d2013-02-17 06:01:50 +0000103 resources.maxVertexUniformVectors = 128;
104 resources.maxVaryingVectors = 8;
105 resources.maxFragmentUniformVectors = 16;
106 resources.maxVertexOutputVectors = 16;
John Kessenich1f2a36b2013-02-20 04:42:42 +0000107 resources.maxFragmentInputVectors = 15;
John Kessenichbd0747d2013-02-17 06:01:50 +0000108 resources.minProgramTexelOffset = -8;
109 resources.maxProgramTexelOffset = 7;
John Kessenicha0af4732012-12-12 21:15:54 +0000110}
111
112int C_DECL main(int argc, char* argv[])
113{
114 bool delay = false;
115 int numCompilers = 0;
116 bool compileFailed = false;
117 bool linkFailed = false;
118 int debugOptions = 0;
119 int i;
120
121 ShHandle linker = 0;
122 ShHandle uniformMap = 0;
123 ShHandle compilers[EShLangCount];
124
125 ShInitialize();
126
127#ifdef _WIN32
128 __try {
129#endif
130 argc--;
131 argv++;
132 for (; argc >= 1; argc--, argv++) {
John Kessenichd7c120f2013-03-12 17:52:59 +0000133 if (argv[0][0] == '-') {
John Kessenicha0af4732012-12-12 21:15:54 +0000134 switch (argv[0][1]) {
John Kessenich8df53cc2013-04-14 19:23:50 +0000135 case 'd':
136 delay = true;
137 break;
138 case 'i':
139 debugOptions |= EDebugOpIntermediate;
140 break;
141 case 'a':
142 debugOptions |= EDebugOpAssembly;
143 break;
144 case 'l':
145 debugOptions |= EDebugOpMemoryLeakMode;
146 break;
John Kessenich52ac67e2013-05-05 23:46:22 +0000147 case 'r':
148 debugOptions |= EDebugOpRelaxedErrors;
149 break;
John Kessenich8df53cc2013-04-14 19:23:50 +0000150 case 's':
151 debugOptions |= EDebugOpSuppressInfolog;
152 break;
153 case 't':
154 debugOptions |= EDebugOpTexturePrototypes;
155 break;
156 default:
157 usage();
158 return EFailUsage;
John Kessenicha0af4732012-12-12 21:15:54 +0000159 }
160 } else {
161 compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), debugOptions);
162 if (compilers[numCompilers] == 0)
163 return EFailCompilerCreate;
164 ++numCompilers;
165
166 TBuiltInResource resources;
167 GenerateResources(resources);
168 if (! CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources))
169 compileFailed = true;
170 }
171 }
172
173 if (!numCompilers) {
174 usage();
175 return EFailUsage;
176 }
177
178 linker = ShConstructLinker(EShExVertexFragment, debugOptions);
179 if (linker == 0)
180 return EFailLinkerCreate;
181
182 uniformMap = ShConstructUniformMap();
183 if (uniformMap == 0)
184 return EFailLinkerCreate;
185
186 if (numCompilers > 0) {
187 ShSetFixedAttributeBindings(linker, &FixedAttributeTable);
188 if (! ShLink(linker, compilers, numCompilers, uniformMap, 0, 0))
189 linkFailed = true;
190 }
191
John Kessenich8df53cc2013-04-14 19:23:50 +0000192 if (! (debugOptions & EDebugOpSuppressInfolog)) {
193 for (i = 0; i < numCompilers; ++i) {
194 InfoLogMsg("BEGIN", "COMPILER", i);
195 puts(ShGetInfoLog(compilers[i]));
196 InfoLogMsg("END", "COMPILER", i);
197 }
John Kessenicha0af4732012-12-12 21:15:54 +0000198
John Kessenich8df53cc2013-04-14 19:23:50 +0000199 InfoLogMsg("BEGIN", "LINKER", -1);
200 puts(ShGetInfoLog(linker));
201 InfoLogMsg("END", "LINKER", -1);
202 }
John Kessenicha0af4732012-12-12 21:15:54 +0000203
204#ifdef _WIN32
205 } __finally {
206#endif
207 for (i = 0; i < numCompilers; ++i)
208 ShDestruct(compilers[i]);
209
210 ShDestruct(linker);
211 ShDestruct(uniformMap);
212
213#ifdef _WIN32
214 if (delay)
215 Sleep(1000000);
216
217 }
218#endif
219
220 if (compileFailed)
221 return EFailCompile;
222 if (linkFailed)
223 return EFailLink;
224
225 return 0;
226}
227
228//
229// Deduce the language from the filename. Files must end in one of the
230// following extensions:
231//
232// .frag* = fragment programs
233// .vert* = vertex programs
John Kessenicha0af4732012-12-12 21:15:54 +0000234//
235static EShLanguage FindLanguage(char *name)
236{
237 if (!name)
John Kesseniche95ecc52012-12-12 21:34:14 +0000238 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000239
240 char *ext = strrchr(name, '.');
241
242 if (ext && strcmp(ext, ".sl") == 0)
243 for (; ext > name && ext[0] != '.'; ext--);
244
245 if (ext = strrchr(name, '.')) {
246 if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment;
John Kessenicha0af4732012-12-12 21:15:54 +0000247 }
248
John Kesseniche95ecc52012-12-12 21:34:14 +0000249 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000250}
251
252
253//
254// Read a file's data into a string, and compile it using ShCompile
255//
John Kessenich54d8cda2013-02-11 22:36:01 +0000256bool CompileFile(const char *fileName, ShHandle compiler, int debugOptions, const TBuiltInResource *resources)
John Kessenicha0af4732012-12-12 21:15:54 +0000257{
258 int ret;
John Kessenich41cf6b52013-06-25 18:10:05 +0000259 char** shaderStrings = ReadFileData(fileName);
260 int* lengths = new int[NumShaderStrings];
261
262 // move to length-based strings, rather than null-terminated strings
263 for (int s = 0; s < NumShaderStrings; ++s)
264 lengths[s] = strlen(shaderStrings[s]);
John Kessenich09da79e2013-04-17 19:34:23 +0000265
266#ifdef _WIN32
John Kessenich8df53cc2013-04-14 19:23:50 +0000267 PROCESS_MEMORY_COUNTERS counters; // just for memory leak testing
John Kessenich09da79e2013-04-17 19:34:23 +0000268#endif
John Kessenicha0af4732012-12-12 21:15:54 +0000269
John Kessenich41cf6b52013-06-25 18:10:05 +0000270 if (! shaderStrings)
John Kessenicha0af4732012-12-12 21:15:54 +0000271 return false;
272
John Kessenich52ac67e2013-05-05 23:46:22 +0000273 EShMessages messages = EShMsgDefault;
274 if (debugOptions & EDebugOpRelaxedErrors)
275 messages = (EShMessages)(messages | EShMsgRelaxedErrors);
John Kessenich8df53cc2013-04-14 19:23:50 +0000276 for (int i = 0; i < ((debugOptions & EDebugOpMemoryLeakMode) ? 100 : 1); ++i) {
John Kessenich41cf6b52013-06-25 18:10:05 +0000277 for (int j = 0; j < ((debugOptions & EDebugOpMemoryLeakMode) ? 100 : 1); ++j) {
278 //ret = ShCompile(compiler, shaderStrings, NumShaderStrings, lengths, EShOptNone, resources, debugOptions, 100, false, messages);
279 ret = ShCompile(compiler, shaderStrings, NumShaderStrings, 0, EShOptNone, resources, debugOptions, 100, false, messages);
280 //const char* multi[4] = { "# ve", "rsion", " 300 e", "s" };
281 //const char* multi[7] = { "/", "/", "\\", "\n", "\n", "#", "version 300 es" };
282 //ret = ShCompile(compiler, multi, 4, 0, EShOptNone, resources, debugOptions, 100, false, messages);
283 }
John Kessenicha0af4732012-12-12 21:15:54 +0000284
John Kessenich09da79e2013-04-17 19:34:23 +0000285#ifdef _WIN32
John Kessenich8df53cc2013-04-14 19:23:50 +0000286 if (debugOptions & EDebugOpMemoryLeakMode) {
287 GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters));
288 printf("Working set size: %d\n", counters.WorkingSetSize);
289 }
John Kessenich09da79e2013-04-17 19:34:23 +0000290#endif
John Kessenicha0af4732012-12-12 21:15:54 +0000291 }
John Kessenicha0af4732012-12-12 21:15:54 +0000292
John Kessenich41cf6b52013-06-25 18:10:05 +0000293 delete [] lengths;
294 FreeFileData(shaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000295
296 return ret ? true : false;
297}
298
299
300//
301// print usage to stdout
302//
303void usage()
304{
John Kessenich8df53cc2013-04-14 19:23:50 +0000305 printf("Usage: standalone [ options ] filename\n"
306 "Where: filename = filename ending in .frag* or .vert*\n"
307 "-i: intermediate (glslang AST)\n"
308 "-a: assembly dump (LLVM IR)\n"
309 "-d: delay end (keeps output up in debugger, WIN32)\n"
310 "-l: memory leak mode\n"
John Kessenich52ac67e2013-05-05 23:46:22 +0000311 "-s: silent mode (no info log)\n"
312 "-r: relaxed semantic error checking mode\n");
John Kessenicha0af4732012-12-12 21:15:54 +0000313}
314
John Kessenichcfd643e2013-03-08 23:14:42 +0000315#ifndef _WIN32
316
317#include <errno.h>
318
319int fopen_s(
320 FILE** pFile,
321 const char *filename,
322 const char *mode
323)
324{
325 if (!pFile || !filename || !mode) {
326 return EINVAL;
327 }
328
329 FILE* f = fopen(filename, mode);
330 if (! f) {
331 if (errno != 0) {
332 return errno;
333 } else {
334 return ENOENT;
335 }
336 }
337 *pFile = f;
338
339 return 0;
340}
341
342#endif
343
John Kessenicha0af4732012-12-12 21:15:54 +0000344//
345// Malloc a string of sufficient size and read a string into it.
346//
John Kessenich54d8cda2013-02-11 22:36:01 +0000347char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000348{
John Kessenich200b2732012-12-12 21:21:23 +0000349 FILE *in;
350 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000351 char *fdata;
352 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000353 const int maxSourceStrings = 5;
354 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000355
356 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000357 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000358 printf("Error: unable to open input file: %s\n", fileName);
359 return 0;
360 }
361
362 while (fgetc(in) != EOF)
363 count++;
364
365 fseek(in, 0, SEEK_SET);
366
367
368 if (!(fdata = (char *)malloc(count+2))) {
369 printf("Error allocating memory\n");
370 return 0;
371 }
372 if (fread(fdata,1,count, in)!=count) {
373 printf("Error reading input file: %s\n", fileName);
374 return 0;
375 }
376 fdata[count] = '\0';
377 fclose(in);
378 if(count==0){
379 return_data[0]=(char*)malloc(count+2);
380 return_data[0][0]='\0';
John Kessenich41cf6b52013-06-25 18:10:05 +0000381 NumShaderStrings=0;
John Kessenicha0af4732012-12-12 21:15:54 +0000382 return return_data;
383 }
384
John Kessenich41cf6b52013-06-25 18:10:05 +0000385 int len = (int)(ceil)((float)count/(float)NumShaderStrings);
John Kessenicha0af4732012-12-12 21:15:54 +0000386 int ptr_len=0,i=0;
387 while(count>0){
388 return_data[i]=(char*)malloc(len+2);
389 memcpy(return_data[i],fdata+ptr_len,len);
390 return_data[i][len]='\0';
391 count-=(len);
392 ptr_len+=(len);
393 if(count<len){
394 if(count==0){
John Kessenich41cf6b52013-06-25 18:10:05 +0000395 NumShaderStrings=(i+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000396 break;
397 }
398 len = count;
399 }
400 ++i;
401 }
402 return return_data;
403}
404
405
406
407void FreeFileData(char **data)
408{
John Kessenich41cf6b52013-06-25 18:10:05 +0000409 for(int i=0;i<NumShaderStrings;i++)
John Kessenicha0af4732012-12-12 21:15:54 +0000410 free(data[i]);
411}
412
413
414
John Kessenich54d8cda2013-02-11 22:36:01 +0000415void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000416{
417 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
418 "#### %s %s INFO LOG ####\n", msg, name, num);
419}