blob: 454466407775226776328bc6b12c1fb515a52f18 [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>
39#include <math.h>
40
41#ifdef _WIN32
42 #include <windows.h>
43 #include <psapi.h>
44#endif
45
46extern "C" {
47 SH_IMPORT_EXPORT void ShOutputHtml();
48}
49
50//#define MEASURE_MEMORY
51
52//
53// Return codes from main.
54//
55enum TFailCode {
56 ESuccess = 0,
57 EFailUsage,
58 EFailCompile,
59 EFailLink,
60 EFailCompilerCreate,
61 EFailLinkerCreate
62};
63
64//
65// Just placeholders for testing purposes. The stand-alone environment
66// can't actually do a full link without something specifying real
67// attribute bindings.
68//
69ShBinding FixedAttributeBindings[] = {
70 { "gl_Vertex", 15 },
71 { "gl_Color", 10 },
72 { "gl_Normal", 7 },
73};
74
75ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
76
77static EShLanguage FindLanguage(char *lang);
John Kessenich54d8cda2013-02-11 22:36:01 +000078bool CompileFile(const char *fileName, ShHandle, int, const TBuiltInResource*);
John Kessenicha0af4732012-12-12 21:15:54 +000079void usage();
80void FreeFileData(char **data);
John Kessenich54d8cda2013-02-11 22:36:01 +000081char** ReadFileData(const char *fileName);
82void InfoLogMsg(const char* msg, const char* name, const int num);
83int ShOutputMultipleStrings(const char *);
John Kessenicha0af4732012-12-12 21:15:54 +000084//Added to accomodate the multiple strings.
85int OutputMultipleStrings = 1;
86
87//
88// Set up the per compile resources
89//
90void GenerateResources(TBuiltInResource& resources)
91{
92 resources.maxLights = 32;
93 resources.maxClipPlanes = 6;
94 resources.maxTextureUnits = 32;
95 resources.maxTextureCoords = 32;
96 resources.maxVertexAttribs = 64;
97 resources.maxVertexUniformComponents = 4096;
98 resources.maxVaryingFloats = 64;
99 resources.maxVertexTextureImageUnits = 32;
100 resources.maxCombinedTextureImageUnits = 32;
101 resources.maxTextureImageUnits = 32;
102 resources.maxFragmentUniformComponents = 4096;
103 resources.maxDrawBuffers = 32;
John Kessenichbd0747d2013-02-17 06:01:50 +0000104 resources.maxVertexUniformVectors = 128;
105 resources.maxVaryingVectors = 8;
106 resources.maxFragmentUniformVectors = 16;
107 resources.maxVertexOutputVectors = 16;
John Kessenich1f2a36b2013-02-20 04:42:42 +0000108 resources.maxFragmentInputVectors = 15;
John Kessenichbd0747d2013-02-17 06:01:50 +0000109 resources.minProgramTexelOffset = -8;
110 resources.maxProgramTexelOffset = 7;
John Kessenicha0af4732012-12-12 21:15:54 +0000111}
112
113int C_DECL main(int argc, char* argv[])
114{
115 bool delay = false;
116 int numCompilers = 0;
117 bool compileFailed = false;
118 bool linkFailed = false;
119 int debugOptions = 0;
120 int i;
121
122 ShHandle linker = 0;
123 ShHandle uniformMap = 0;
124 ShHandle compilers[EShLangCount];
125
126 ShInitialize();
127
128#ifdef _WIN32
129 __try {
130#endif
131 argc--;
132 argv++;
133 for (; argc >= 1; argc--, argv++) {
134 if (argv[0][0] == '-' || argv[0][0] == '/') {
135 switch (argv[0][1]) {
136 case 'd': delay = true; break;
137
138#ifdef MEASURE_MEMORY
139 case 'i': break;
140 case 'a': break;
141 case 'h': break;
142#else
143 case 'i': debugOptions |= EDebugOpIntermediate; break;
144 case 'a': debugOptions |= EDebugOpAssembly; break;
145#endif
John Kessenich54d8cda2013-02-11 22:36:01 +0000146 case 'c': if(!ShOutputMultipleStrings((++argv)[0]))
John Kessenicha0af4732012-12-12 21:15:54 +0000147 return EFailUsage;
148 --argc; break;
149 case 'm': debugOptions |= EDebugOpLinkMaps; break;
150 default: usage(); return EFailUsage;
151 }
152 } else {
153 compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), debugOptions);
154 if (compilers[numCompilers] == 0)
155 return EFailCompilerCreate;
156 ++numCompilers;
157
158 TBuiltInResource resources;
159 GenerateResources(resources);
160 if (! CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources))
161 compileFailed = true;
162 }
163 }
164
165 if (!numCompilers) {
166 usage();
167 return EFailUsage;
168 }
169
170 linker = ShConstructLinker(EShExVertexFragment, debugOptions);
171 if (linker == 0)
172 return EFailLinkerCreate;
173
174 uniformMap = ShConstructUniformMap();
175 if (uniformMap == 0)
176 return EFailLinkerCreate;
177
178 if (numCompilers > 0) {
179 ShSetFixedAttributeBindings(linker, &FixedAttributeTable);
180 if (! ShLink(linker, compilers, numCompilers, uniformMap, 0, 0))
181 linkFailed = true;
182 }
183
184 for (i = 0; i < numCompilers; ++i) {
185 InfoLogMsg("BEGIN", "COMPILER", i);
186 puts(ShGetInfoLog(compilers[i]));
187 InfoLogMsg("END", "COMPILER", i);
188 }
189
190 InfoLogMsg("BEGIN", "LINKER", -1);
191 puts(ShGetInfoLog(linker));
192 InfoLogMsg("END", "LINKER", -1);
193
194#ifdef _WIN32
195 } __finally {
196#endif
197 for (i = 0; i < numCompilers; ++i)
198 ShDestruct(compilers[i]);
199
200 ShDestruct(linker);
201 ShDestruct(uniformMap);
202
203#ifdef _WIN32
204 if (delay)
205 Sleep(1000000);
206
207 }
208#endif
209
210 if (compileFailed)
211 return EFailCompile;
212 if (linkFailed)
213 return EFailLink;
214
215 return 0;
216}
217
218//
219// Deduce the language from the filename. Files must end in one of the
220// following extensions:
221//
222// .frag* = fragment programs
223// .vert* = vertex programs
John Kessenicha0af4732012-12-12 21:15:54 +0000224//
225static EShLanguage FindLanguage(char *name)
226{
227 if (!name)
John Kesseniche95ecc52012-12-12 21:34:14 +0000228 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000229
230 char *ext = strrchr(name, '.');
231
232 if (ext && strcmp(ext, ".sl") == 0)
233 for (; ext > name && ext[0] != '.'; ext--);
234
235 if (ext = strrchr(name, '.')) {
236 if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment;
John Kessenicha0af4732012-12-12 21:15:54 +0000237 }
238
John Kesseniche95ecc52012-12-12 21:34:14 +0000239 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000240}
241
242
243//
244// Read a file's data into a string, and compile it using ShCompile
245//
John Kessenich54d8cda2013-02-11 22:36:01 +0000246bool CompileFile(const char *fileName, ShHandle compiler, int debugOptions, const TBuiltInResource *resources)
John Kessenicha0af4732012-12-12 21:15:54 +0000247{
248 int ret;
249 char **data = ReadFileData(fileName);
250
251#ifdef MEASURE_MEMORY
252 PROCESS_MEMORY_COUNTERS counters;
253#endif
254
255 if (!data)
256 return false;
257
258#ifdef MEASURE_MEMORY
259 for (int i = 0; i < 1000; ++i) {
260 for (int j = 0; j < 100; ++j)
261#endif
John Kessenich37827022013-03-08 19:26:11 +0000262 ret = ShCompile(compiler, data, OutputMultipleStrings, EShOptNone, resources, debugOptions, 100, false, EShMsgDefault);
John Kessenicha0af4732012-12-12 21:15:54 +0000263#ifdef MEASURE_MEMORY
264
265 GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters));
John Kessenichdadf9452013-02-11 00:54:44 +0000266 printf("Working set size: %d\n", counters.WorkingSetSize);
John Kessenicha0af4732012-12-12 21:15:54 +0000267 }
268#endif
269
270 FreeFileData(data);
271
272 return ret ? true : false;
273}
274
275
276//
277// print usage to stdout
278//
279void usage()
280{
281 printf("Usage: standalone [-i -a -c -m -d -h] file1 file2 ...\n"
282 "Where: filename = filename ending in .frag* or .vert*\n");
283}
284
285
286//
287// Malloc a string of sufficient size and read a string into it.
288//
289# define MAX_SOURCE_STRINGS 5
John Kessenich54d8cda2013-02-11 22:36:01 +0000290char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000291{
John Kessenich200b2732012-12-12 21:21:23 +0000292 FILE *in;
293 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000294 char *fdata;
295 int count = 0;
296 char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1);
297
298 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000299 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000300 printf("Error: unable to open input file: %s\n", fileName);
301 return 0;
302 }
303
304 while (fgetc(in) != EOF)
305 count++;
306
307 fseek(in, 0, SEEK_SET);
308
309
310 if (!(fdata = (char *)malloc(count+2))) {
311 printf("Error allocating memory\n");
312 return 0;
313 }
314 if (fread(fdata,1,count, in)!=count) {
315 printf("Error reading input file: %s\n", fileName);
316 return 0;
317 }
318 fdata[count] = '\0';
319 fclose(in);
320 if(count==0){
321 return_data[0]=(char*)malloc(count+2);
322 return_data[0][0]='\0';
323 OutputMultipleStrings=0;
324 return return_data;
325 }
326
327 int len = (int)(ceil)((float)count/(float)OutputMultipleStrings);
328 int ptr_len=0,i=0;
329 while(count>0){
330 return_data[i]=(char*)malloc(len+2);
331 memcpy(return_data[i],fdata+ptr_len,len);
332 return_data[i][len]='\0';
333 count-=(len);
334 ptr_len+=(len);
335 if(count<len){
336 if(count==0){
337 OutputMultipleStrings=(i+1);
338 break;
339 }
340 len = count;
341 }
342 ++i;
343 }
344 return return_data;
345}
346
347
348
349void FreeFileData(char **data)
350{
351 for(int i=0;i<OutputMultipleStrings;i++)
352 free(data[i]);
353}
354
355
356
John Kessenich54d8cda2013-02-11 22:36:01 +0000357void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000358{
359 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
360 "#### %s %s INFO LOG ####\n", msg, name, num);
361}
362
John Kessenich54d8cda2013-02-11 22:36:01 +0000363int ShOutputMultipleStrings(const char *argv)
John Kessenicha0af4732012-12-12 21:15:54 +0000364{
John Kessenich54d8cda2013-02-11 22:36:01 +0000365 if(!(abs(OutputMultipleStrings = atoi(argv)))||((OutputMultipleStrings >5 || OutputMultipleStrings < 1)? 1:0)){
John Kessenicha0af4732012-12-12 21:15:54 +0000366 printf("Invalid Command Line Argument after -c option.\n"
367 "Usage: -c <integer> where integer =[1,5]\n"
368 "This option must be specified before the input file path\n");
369 return 0;
370 }
371 return 1;
372}