blob: e7d0800838d5968a12dc6141fb23fc15969f270b [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
51//#define MEASURE_MEMORY
52
53//
54// Return codes from main.
55//
56enum TFailCode {
57 ESuccess = 0,
58 EFailUsage,
59 EFailCompile,
60 EFailLink,
61 EFailCompilerCreate,
62 EFailLinkerCreate
63};
64
65//
66// Just placeholders for testing purposes. The stand-alone environment
67// can't actually do a full link without something specifying real
68// attribute bindings.
69//
70ShBinding FixedAttributeBindings[] = {
71 { "gl_Vertex", 15 },
72 { "gl_Color", 10 },
73 { "gl_Normal", 7 },
74};
75
76ShBindingTable FixedAttributeTable = { 3, FixedAttributeBindings };
77
78static EShLanguage FindLanguage(char *lang);
John Kessenich54d8cda2013-02-11 22:36:01 +000079bool CompileFile(const char *fileName, ShHandle, int, const TBuiltInResource*);
John Kessenicha0af4732012-12-12 21:15:54 +000080void usage();
81void FreeFileData(char **data);
John Kessenich54d8cda2013-02-11 22:36:01 +000082char** ReadFileData(const char *fileName);
83void InfoLogMsg(const char* msg, const char* name, const int num);
84int ShOutputMultipleStrings(const char *);
John Kessenicha0af4732012-12-12 21:15:54 +000085//Added to accomodate the multiple strings.
86int OutputMultipleStrings = 1;
87
88//
89// Set up the per compile resources
90//
91void GenerateResources(TBuiltInResource& resources)
John Kessenichb51f62c2013-04-11 16:31:09 +000092{
John Kessenicha0af4732012-12-12 21:15:54 +000093 resources.maxLights = 32;
94 resources.maxClipPlanes = 6;
95 resources.maxTextureUnits = 32;
96 resources.maxTextureCoords = 32;
97 resources.maxVertexAttribs = 64;
98 resources.maxVertexUniformComponents = 4096;
99 resources.maxVaryingFloats = 64;
100 resources.maxVertexTextureImageUnits = 32;
101 resources.maxCombinedTextureImageUnits = 32;
102 resources.maxTextureImageUnits = 32;
103 resources.maxFragmentUniformComponents = 4096;
104 resources.maxDrawBuffers = 32;
John Kessenichbd0747d2013-02-17 06:01:50 +0000105 resources.maxVertexUniformVectors = 128;
106 resources.maxVaryingVectors = 8;
107 resources.maxFragmentUniformVectors = 16;
108 resources.maxVertexOutputVectors = 16;
John Kessenich1f2a36b2013-02-20 04:42:42 +0000109 resources.maxFragmentInputVectors = 15;
John Kessenichbd0747d2013-02-17 06:01:50 +0000110 resources.minProgramTexelOffset = -8;
111 resources.maxProgramTexelOffset = 7;
John Kessenicha0af4732012-12-12 21:15:54 +0000112}
113
114int C_DECL main(int argc, char* argv[])
115{
116 bool delay = false;
117 int numCompilers = 0;
118 bool compileFailed = false;
119 bool linkFailed = false;
120 int debugOptions = 0;
121 int i;
122
123 ShHandle linker = 0;
124 ShHandle uniformMap = 0;
125 ShHandle compilers[EShLangCount];
126
127 ShInitialize();
128
129#ifdef _WIN32
130 __try {
131#endif
132 argc--;
133 argv++;
134 for (; argc >= 1; argc--, argv++) {
John Kessenichd7c120f2013-03-12 17:52:59 +0000135 if (argv[0][0] == '-') {
John Kessenicha0af4732012-12-12 21:15:54 +0000136 switch (argv[0][1]) {
137 case 'd': delay = true; break;
138
139#ifdef MEASURE_MEMORY
140 case 'i': break;
141 case 'a': break;
142 case 'h': break;
143#else
144 case 'i': debugOptions |= EDebugOpIntermediate; break;
145 case 'a': debugOptions |= EDebugOpAssembly; break;
146#endif
John Kessenich54d8cda2013-02-11 22:36:01 +0000147 case 'c': if(!ShOutputMultipleStrings((++argv)[0]))
John Kessenicha0af4732012-12-12 21:15:54 +0000148 return EFailUsage;
149 --argc; break;
150 case 'm': debugOptions |= EDebugOpLinkMaps; break;
151 default: usage(); return EFailUsage;
152 }
153 } else {
154 compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), debugOptions);
155 if (compilers[numCompilers] == 0)
156 return EFailCompilerCreate;
157 ++numCompilers;
158
159 TBuiltInResource resources;
160 GenerateResources(resources);
161 if (! CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources))
162 compileFailed = true;
163 }
164 }
165
166 if (!numCompilers) {
167 usage();
168 return EFailUsage;
169 }
170
171 linker = ShConstructLinker(EShExVertexFragment, debugOptions);
172 if (linker == 0)
173 return EFailLinkerCreate;
174
175 uniformMap = ShConstructUniformMap();
176 if (uniformMap == 0)
177 return EFailLinkerCreate;
178
179 if (numCompilers > 0) {
180 ShSetFixedAttributeBindings(linker, &FixedAttributeTable);
181 if (! ShLink(linker, compilers, numCompilers, uniformMap, 0, 0))
182 linkFailed = true;
183 }
184
185 for (i = 0; i < numCompilers; ++i) {
186 InfoLogMsg("BEGIN", "COMPILER", i);
187 puts(ShGetInfoLog(compilers[i]));
188 InfoLogMsg("END", "COMPILER", i);
189 }
190
191 InfoLogMsg("BEGIN", "LINKER", -1);
192 puts(ShGetInfoLog(linker));
193 InfoLogMsg("END", "LINKER", -1);
194
195#ifdef _WIN32
196 } __finally {
197#endif
198 for (i = 0; i < numCompilers; ++i)
199 ShDestruct(compilers[i]);
200
201 ShDestruct(linker);
202 ShDestruct(uniformMap);
203
204#ifdef _WIN32
205 if (delay)
206 Sleep(1000000);
207
208 }
209#endif
210
211 if (compileFailed)
212 return EFailCompile;
213 if (linkFailed)
214 return EFailLink;
215
216 return 0;
217}
218
219//
220// Deduce the language from the filename. Files must end in one of the
221// following extensions:
222//
223// .frag* = fragment programs
224// .vert* = vertex programs
John Kessenicha0af4732012-12-12 21:15:54 +0000225//
226static EShLanguage FindLanguage(char *name)
227{
228 if (!name)
John Kesseniche95ecc52012-12-12 21:34:14 +0000229 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000230
231 char *ext = strrchr(name, '.');
232
233 if (ext && strcmp(ext, ".sl") == 0)
234 for (; ext > name && ext[0] != '.'; ext--);
235
236 if (ext = strrchr(name, '.')) {
237 if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment;
John Kessenicha0af4732012-12-12 21:15:54 +0000238 }
239
John Kesseniche95ecc52012-12-12 21:34:14 +0000240 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000241}
242
243
244//
245// Read a file's data into a string, and compile it using ShCompile
246//
John Kessenich54d8cda2013-02-11 22:36:01 +0000247bool CompileFile(const char *fileName, ShHandle compiler, int debugOptions, const TBuiltInResource *resources)
John Kessenicha0af4732012-12-12 21:15:54 +0000248{
249 int ret;
250 char **data = ReadFileData(fileName);
251
252#ifdef MEASURE_MEMORY
253 PROCESS_MEMORY_COUNTERS counters;
254#endif
255
256 if (!data)
257 return false;
258
259#ifdef MEASURE_MEMORY
260 for (int i = 0; i < 1000; ++i) {
261 for (int j = 0; j < 100; ++j)
262#endif
John Kessenich37827022013-03-08 19:26:11 +0000263 ret = ShCompile(compiler, data, OutputMultipleStrings, EShOptNone, resources, debugOptions, 100, false, EShMsgDefault);
John Kessenicha0af4732012-12-12 21:15:54 +0000264#ifdef MEASURE_MEMORY
265
266 GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters));
John Kessenichdadf9452013-02-11 00:54:44 +0000267 printf("Working set size: %d\n", counters.WorkingSetSize);
John Kessenicha0af4732012-12-12 21:15:54 +0000268 }
269#endif
270
271 FreeFileData(data);
272
273 return ret ? true : false;
274}
275
276
277//
278// print usage to stdout
279//
280void usage()
281{
282 printf("Usage: standalone [-i -a -c -m -d -h] file1 file2 ...\n"
283 "Where: filename = filename ending in .frag* or .vert*\n");
284}
285
286
John Kessenichcfd643e2013-03-08 23:14:42 +0000287#ifndef _WIN32
288
289#include <errno.h>
290
291int fopen_s(
292 FILE** pFile,
293 const char *filename,
294 const char *mode
295)
296{
297 if (!pFile || !filename || !mode) {
298 return EINVAL;
299 }
300
301 FILE* f = fopen(filename, mode);
302 if (! f) {
303 if (errno != 0) {
304 return errno;
305 } else {
306 return ENOENT;
307 }
308 }
309 *pFile = f;
310
311 return 0;
312}
313
314#endif
315
John Kessenicha0af4732012-12-12 21:15:54 +0000316//
317// Malloc a string of sufficient size and read a string into it.
318//
John Kessenich54d8cda2013-02-11 22:36:01 +0000319char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000320{
John Kessenich200b2732012-12-12 21:21:23 +0000321 FILE *in;
322 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000323 char *fdata;
324 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000325 const int maxSourceStrings = 5;
326 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000327
328 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000329 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000330 printf("Error: unable to open input file: %s\n", fileName);
331 return 0;
332 }
333
334 while (fgetc(in) != EOF)
335 count++;
336
337 fseek(in, 0, SEEK_SET);
338
339
340 if (!(fdata = (char *)malloc(count+2))) {
341 printf("Error allocating memory\n");
342 return 0;
343 }
344 if (fread(fdata,1,count, in)!=count) {
345 printf("Error reading input file: %s\n", fileName);
346 return 0;
347 }
348 fdata[count] = '\0';
349 fclose(in);
350 if(count==0){
351 return_data[0]=(char*)malloc(count+2);
352 return_data[0][0]='\0';
353 OutputMultipleStrings=0;
354 return return_data;
355 }
356
357 int len = (int)(ceil)((float)count/(float)OutputMultipleStrings);
358 int ptr_len=0,i=0;
359 while(count>0){
360 return_data[i]=(char*)malloc(len+2);
361 memcpy(return_data[i],fdata+ptr_len,len);
362 return_data[i][len]='\0';
363 count-=(len);
364 ptr_len+=(len);
365 if(count<len){
366 if(count==0){
367 OutputMultipleStrings=(i+1);
368 break;
369 }
370 len = count;
371 }
372 ++i;
373 }
374 return return_data;
375}
376
377
378
379void FreeFileData(char **data)
380{
381 for(int i=0;i<OutputMultipleStrings;i++)
382 free(data[i]);
383}
384
385
386
John Kessenich54d8cda2013-02-11 22:36:01 +0000387void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000388{
389 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
390 "#### %s %s INFO LOG ####\n", msg, name, num);
391}
392
John Kessenich54d8cda2013-02-11 22:36:01 +0000393int ShOutputMultipleStrings(const char *argv)
John Kessenicha0af4732012-12-12 21:15:54 +0000394{
John Kessenich54d8cda2013-02-11 22:36:01 +0000395 if(!(abs(OutputMultipleStrings = atoi(argv)))||((OutputMultipleStrings >5 || OutputMultipleStrings < 1)? 1:0)){
John Kessenicha0af4732012-12-12 21:15:54 +0000396 printf("Invalid Command Line Argument after -c option.\n"
397 "Usage: -c <integer> where integer =[1,5]\n"
398 "This option must be specified before the input file path\n");
399 return 0;
400 }
401 return 1;
402}