blob: 4fce3ed2be90e26e87e178082fd33a1e5f0603f8 [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;
108 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++) {
133 if (argv[0][0] == '-' || argv[0][0] == '/') {
134 switch (argv[0][1]) {
135 case 'd': delay = true; break;
136
137#ifdef MEASURE_MEMORY
138 case 'i': break;
139 case 'a': break;
140 case 'h': break;
141#else
142 case 'i': debugOptions |= EDebugOpIntermediate; break;
143 case 'a': debugOptions |= EDebugOpAssembly; break;
144#endif
John Kessenich54d8cda2013-02-11 22:36:01 +0000145 case 'c': if(!ShOutputMultipleStrings((++argv)[0]))
John Kessenicha0af4732012-12-12 21:15:54 +0000146 return EFailUsage;
147 --argc; break;
148 case 'm': debugOptions |= EDebugOpLinkMaps; break;
149 default: usage(); return EFailUsage;
150 }
151 } else {
152 compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), debugOptions);
153 if (compilers[numCompilers] == 0)
154 return EFailCompilerCreate;
155 ++numCompilers;
156
157 TBuiltInResource resources;
158 GenerateResources(resources);
159 if (! CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources))
160 compileFailed = true;
161 }
162 }
163
164 if (!numCompilers) {
165 usage();
166 return EFailUsage;
167 }
168
169 linker = ShConstructLinker(EShExVertexFragment, debugOptions);
170 if (linker == 0)
171 return EFailLinkerCreate;
172
173 uniformMap = ShConstructUniformMap();
174 if (uniformMap == 0)
175 return EFailLinkerCreate;
176
177 if (numCompilers > 0) {
178 ShSetFixedAttributeBindings(linker, &FixedAttributeTable);
179 if (! ShLink(linker, compilers, numCompilers, uniformMap, 0, 0))
180 linkFailed = true;
181 }
182
183 for (i = 0; i < numCompilers; ++i) {
184 InfoLogMsg("BEGIN", "COMPILER", i);
185 puts(ShGetInfoLog(compilers[i]));
186 InfoLogMsg("END", "COMPILER", i);
187 }
188
189 InfoLogMsg("BEGIN", "LINKER", -1);
190 puts(ShGetInfoLog(linker));
191 InfoLogMsg("END", "LINKER", -1);
192
193#ifdef _WIN32
194 } __finally {
195#endif
196 for (i = 0; i < numCompilers; ++i)
197 ShDestruct(compilers[i]);
198
199 ShDestruct(linker);
200 ShDestruct(uniformMap);
201
202#ifdef _WIN32
203 if (delay)
204 Sleep(1000000);
205
206 }
207#endif
208
209 if (compileFailed)
210 return EFailCompile;
211 if (linkFailed)
212 return EFailLink;
213
214 return 0;
215}
216
217//
218// Deduce the language from the filename. Files must end in one of the
219// following extensions:
220//
221// .frag* = fragment programs
222// .vert* = vertex programs
John Kessenicha0af4732012-12-12 21:15:54 +0000223//
224static EShLanguage FindLanguage(char *name)
225{
226 if (!name)
John Kesseniche95ecc52012-12-12 21:34:14 +0000227 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000228
229 char *ext = strrchr(name, '.');
230
231 if (ext && strcmp(ext, ".sl") == 0)
232 for (; ext > name && ext[0] != '.'; ext--);
233
234 if (ext = strrchr(name, '.')) {
235 if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment;
John Kessenicha0af4732012-12-12 21:15:54 +0000236 }
237
John Kesseniche95ecc52012-12-12 21:34:14 +0000238 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000239}
240
241
242//
243// Read a file's data into a string, and compile it using ShCompile
244//
John Kessenich54d8cda2013-02-11 22:36:01 +0000245bool CompileFile(const char *fileName, ShHandle compiler, int debugOptions, const TBuiltInResource *resources)
John Kessenicha0af4732012-12-12 21:15:54 +0000246{
247 int ret;
248 char **data = ReadFileData(fileName);
249
250#ifdef MEASURE_MEMORY
251 PROCESS_MEMORY_COUNTERS counters;
252#endif
253
254 if (!data)
255 return false;
256
257#ifdef MEASURE_MEMORY
258 for (int i = 0; i < 1000; ++i) {
259 for (int j = 0; j < 100; ++j)
260#endif
John Kessenich38c507e2013-02-08 18:56:56 +0000261 ret = ShCompile(compiler, data, OutputMultipleStrings, EShOptNone, resources, debugOptions, 100);
John Kessenicha0af4732012-12-12 21:15:54 +0000262#ifdef MEASURE_MEMORY
263
264 GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters));
John Kessenichdadf9452013-02-11 00:54:44 +0000265 printf("Working set size: %d\n", counters.WorkingSetSize);
John Kessenicha0af4732012-12-12 21:15:54 +0000266 }
267#endif
268
269 FreeFileData(data);
270
271 return ret ? true : false;
272}
273
274
275//
276// print usage to stdout
277//
278void usage()
279{
280 printf("Usage: standalone [-i -a -c -m -d -h] file1 file2 ...\n"
281 "Where: filename = filename ending in .frag* or .vert*\n");
282}
283
284
285//
286// Malloc a string of sufficient size and read a string into it.
287//
288# define MAX_SOURCE_STRINGS 5
John Kessenich54d8cda2013-02-11 22:36:01 +0000289char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000290{
John Kessenich200b2732012-12-12 21:21:23 +0000291 FILE *in;
292 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000293 char *fdata;
294 int count = 0;
295 char**return_data=(char**)malloc(MAX_SOURCE_STRINGS+1);
296
297 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000298 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000299 printf("Error: unable to open input file: %s\n", fileName);
300 return 0;
301 }
302
303 while (fgetc(in) != EOF)
304 count++;
305
306 fseek(in, 0, SEEK_SET);
307
308
309 if (!(fdata = (char *)malloc(count+2))) {
310 printf("Error allocating memory\n");
311 return 0;
312 }
313 if (fread(fdata,1,count, in)!=count) {
314 printf("Error reading input file: %s\n", fileName);
315 return 0;
316 }
317 fdata[count] = '\0';
318 fclose(in);
319 if(count==0){
320 return_data[0]=(char*)malloc(count+2);
321 return_data[0][0]='\0';
322 OutputMultipleStrings=0;
323 return return_data;
324 }
325
326 int len = (int)(ceil)((float)count/(float)OutputMultipleStrings);
327 int ptr_len=0,i=0;
328 while(count>0){
329 return_data[i]=(char*)malloc(len+2);
330 memcpy(return_data[i],fdata+ptr_len,len);
331 return_data[i][len]='\0';
332 count-=(len);
333 ptr_len+=(len);
334 if(count<len){
335 if(count==0){
336 OutputMultipleStrings=(i+1);
337 break;
338 }
339 len = count;
340 }
341 ++i;
342 }
343 return return_data;
344}
345
346
347
348void FreeFileData(char **data)
349{
350 for(int i=0;i<OutputMultipleStrings;i++)
351 free(data[i]);
352}
353
354
355
John Kessenich54d8cda2013-02-11 22:36:01 +0000356void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000357{
358 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
359 "#### %s %s INFO LOG ####\n", msg, name, num);
360}
361
John Kessenich54d8cda2013-02-11 22:36:01 +0000362int ShOutputMultipleStrings(const char *argv)
John Kessenicha0af4732012-12-12 21:15:54 +0000363{
John Kessenich54d8cda2013-02-11 22:36:01 +0000364 if(!(abs(OutputMultipleStrings = atoi(argv)))||((OutputMultipleStrings >5 || OutputMultipleStrings < 1)? 1:0)){
John Kessenicha0af4732012-12-12 21:15:54 +0000365 printf("Invalid Command Line Argument after -c option.\n"
366 "Usage: -c <integer> where integer =[1,5]\n"
367 "This option must be specified before the input file path\n");
368 return 0;
369 }
370 return 1;
371}