blob: e66a315b63f02d8dbcc8238ccdb4b7fe614aff2f [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 Kessenich54d8cda2013-02-11 22:36:01 +000077bool CompileFile(const char *fileName, ShHandle, int, 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 Kessenicha0af4732012-12-12 21:15:54 +000082//Added to accomodate the multiple strings.
83int OutputMultipleStrings = 1;
84
85//
86// Set up the per compile resources
87//
88void GenerateResources(TBuiltInResource& resources)
John Kessenichb51f62c2013-04-11 16:31:09 +000089{
John Kessenicha0af4732012-12-12 21:15:54 +000090 resources.maxLights = 32;
91 resources.maxClipPlanes = 6;
92 resources.maxTextureUnits = 32;
93 resources.maxTextureCoords = 32;
94 resources.maxVertexAttribs = 64;
95 resources.maxVertexUniformComponents = 4096;
96 resources.maxVaryingFloats = 64;
97 resources.maxVertexTextureImageUnits = 32;
98 resources.maxCombinedTextureImageUnits = 32;
99 resources.maxTextureImageUnits = 32;
100 resources.maxFragmentUniformComponents = 4096;
101 resources.maxDrawBuffers = 32;
John Kessenichbd0747d2013-02-17 06:01:50 +0000102 resources.maxVertexUniformVectors = 128;
103 resources.maxVaryingVectors = 8;
104 resources.maxFragmentUniformVectors = 16;
105 resources.maxVertexOutputVectors = 16;
John Kessenich1f2a36b2013-02-20 04:42:42 +0000106 resources.maxFragmentInputVectors = 15;
John Kessenichbd0747d2013-02-17 06:01:50 +0000107 resources.minProgramTexelOffset = -8;
108 resources.maxProgramTexelOffset = 7;
John Kessenicha0af4732012-12-12 21:15:54 +0000109}
110
111int C_DECL main(int argc, char* argv[])
112{
113 bool delay = false;
114 int numCompilers = 0;
115 bool compileFailed = false;
116 bool linkFailed = false;
117 int debugOptions = 0;
118 int i;
119
120 ShHandle linker = 0;
121 ShHandle uniformMap = 0;
122 ShHandle compilers[EShLangCount];
123
124 ShInitialize();
125
126#ifdef _WIN32
127 __try {
128#endif
129 argc--;
130 argv++;
131 for (; argc >= 1; argc--, argv++) {
John Kessenichd7c120f2013-03-12 17:52:59 +0000132 if (argv[0][0] == '-') {
John Kessenicha0af4732012-12-12 21:15:54 +0000133 switch (argv[0][1]) {
John Kessenich8df53cc2013-04-14 19:23:50 +0000134 case 'd':
135 delay = true;
136 break;
137 case 'i':
138 debugOptions |= EDebugOpIntermediate;
139 break;
140 case 'a':
141 debugOptions |= EDebugOpAssembly;
142 break;
143 case 'l':
144 debugOptions |= EDebugOpMemoryLeakMode;
145 break;
146 case 's':
147 debugOptions |= EDebugOpSuppressInfolog;
148 break;
149 case 't':
150 debugOptions |= EDebugOpTexturePrototypes;
151 break;
152 default:
153 usage();
154 return EFailUsage;
John Kessenicha0af4732012-12-12 21:15:54 +0000155 }
156 } else {
157 compilers[numCompilers] = ShConstructCompiler(FindLanguage(argv[0]), debugOptions);
158 if (compilers[numCompilers] == 0)
159 return EFailCompilerCreate;
160 ++numCompilers;
161
162 TBuiltInResource resources;
163 GenerateResources(resources);
164 if (! CompileFile(argv[0], compilers[numCompilers-1], debugOptions, &resources))
165 compileFailed = true;
166 }
167 }
168
169 if (!numCompilers) {
170 usage();
171 return EFailUsage;
172 }
173
174 linker = ShConstructLinker(EShExVertexFragment, debugOptions);
175 if (linker == 0)
176 return EFailLinkerCreate;
177
178 uniformMap = ShConstructUniformMap();
179 if (uniformMap == 0)
180 return EFailLinkerCreate;
181
182 if (numCompilers > 0) {
183 ShSetFixedAttributeBindings(linker, &FixedAttributeTable);
184 if (! ShLink(linker, compilers, numCompilers, uniformMap, 0, 0))
185 linkFailed = true;
186 }
187
John Kessenich8df53cc2013-04-14 19:23:50 +0000188 if (! (debugOptions & EDebugOpSuppressInfolog)) {
189 for (i = 0; i < numCompilers; ++i) {
190 InfoLogMsg("BEGIN", "COMPILER", i);
191 puts(ShGetInfoLog(compilers[i]));
192 InfoLogMsg("END", "COMPILER", i);
193 }
John Kessenicha0af4732012-12-12 21:15:54 +0000194
John Kessenich8df53cc2013-04-14 19:23:50 +0000195 InfoLogMsg("BEGIN", "LINKER", -1);
196 puts(ShGetInfoLog(linker));
197 InfoLogMsg("END", "LINKER", -1);
198 }
John Kessenicha0af4732012-12-12 21:15:54 +0000199
200#ifdef _WIN32
201 } __finally {
202#endif
203 for (i = 0; i < numCompilers; ++i)
204 ShDestruct(compilers[i]);
205
206 ShDestruct(linker);
207 ShDestruct(uniformMap);
208
209#ifdef _WIN32
210 if (delay)
211 Sleep(1000000);
212
213 }
214#endif
215
216 if (compileFailed)
217 return EFailCompile;
218 if (linkFailed)
219 return EFailLink;
220
221 return 0;
222}
223
224//
225// Deduce the language from the filename. Files must end in one of the
226// following extensions:
227//
228// .frag* = fragment programs
229// .vert* = vertex programs
John Kessenicha0af4732012-12-12 21:15:54 +0000230//
231static EShLanguage FindLanguage(char *name)
232{
233 if (!name)
John Kesseniche95ecc52012-12-12 21:34:14 +0000234 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000235
236 char *ext = strrchr(name, '.');
237
238 if (ext && strcmp(ext, ".sl") == 0)
239 for (; ext > name && ext[0] != '.'; ext--);
240
241 if (ext = strrchr(name, '.')) {
242 if (strncmp(ext, ".frag", 4) == 0) return EShLangFragment;
John Kessenicha0af4732012-12-12 21:15:54 +0000243 }
244
John Kesseniche95ecc52012-12-12 21:34:14 +0000245 return EShLangVertex;
John Kessenicha0af4732012-12-12 21:15:54 +0000246}
247
248
249//
250// Read a file's data into a string, and compile it using ShCompile
251//
John Kessenich54d8cda2013-02-11 22:36:01 +0000252bool CompileFile(const char *fileName, ShHandle compiler, int debugOptions, const TBuiltInResource *resources)
John Kessenicha0af4732012-12-12 21:15:54 +0000253{
254 int ret;
255 char **data = ReadFileData(fileName);
John Kessenich09da79e2013-04-17 19:34:23 +0000256
257#ifdef _WIN32
John Kessenich8df53cc2013-04-14 19:23:50 +0000258 PROCESS_MEMORY_COUNTERS counters; // just for memory leak testing
John Kessenich09da79e2013-04-17 19:34:23 +0000259#endif
John Kessenicha0af4732012-12-12 21:15:54 +0000260
261 if (!data)
262 return false;
263
John Kessenich8df53cc2013-04-14 19:23:50 +0000264 for (int i = 0; i < ((debugOptions & EDebugOpMemoryLeakMode) ? 100 : 1); ++i) {
265 for (int j = 0; j < ((debugOptions & EDebugOpMemoryLeakMode) ? 100 : 1); ++j)
John Kessenich37827022013-03-08 19:26:11 +0000266 ret = ShCompile(compiler, data, OutputMultipleStrings, EShOptNone, resources, debugOptions, 100, false, EShMsgDefault);
John Kessenicha0af4732012-12-12 21:15:54 +0000267
John Kessenich09da79e2013-04-17 19:34:23 +0000268#ifdef _WIN32
John Kessenich8df53cc2013-04-14 19:23:50 +0000269 if (debugOptions & EDebugOpMemoryLeakMode) {
270 GetProcessMemoryInfo(GetCurrentProcess(), &counters, sizeof(counters));
271 printf("Working set size: %d\n", counters.WorkingSetSize);
272 }
John Kessenich09da79e2013-04-17 19:34:23 +0000273#endif
John Kessenicha0af4732012-12-12 21:15:54 +0000274 }
John Kessenicha0af4732012-12-12 21:15:54 +0000275
276 FreeFileData(data);
277
278 return ret ? true : false;
279}
280
281
282//
283// print usage to stdout
284//
285void usage()
286{
John Kessenich8df53cc2013-04-14 19:23:50 +0000287 printf("Usage: standalone [ options ] filename\n"
288 "Where: filename = filename ending in .frag* or .vert*\n"
289 "-i: intermediate (glslang AST)\n"
290 "-a: assembly dump (LLVM IR)\n"
291 "-d: delay end (keeps output up in debugger, WIN32)\n"
292 "-l: memory leak mode\n"
293 "-s: silent mode (no info log)\n");
John Kessenicha0af4732012-12-12 21:15:54 +0000294}
295
John Kessenichcfd643e2013-03-08 23:14:42 +0000296#ifndef _WIN32
297
298#include <errno.h>
299
300int fopen_s(
301 FILE** pFile,
302 const char *filename,
303 const char *mode
304)
305{
306 if (!pFile || !filename || !mode) {
307 return EINVAL;
308 }
309
310 FILE* f = fopen(filename, mode);
311 if (! f) {
312 if (errno != 0) {
313 return errno;
314 } else {
315 return ENOENT;
316 }
317 }
318 *pFile = f;
319
320 return 0;
321}
322
323#endif
324
John Kessenicha0af4732012-12-12 21:15:54 +0000325//
326// Malloc a string of sufficient size and read a string into it.
327//
John Kessenich54d8cda2013-02-11 22:36:01 +0000328char** ReadFileData(const char *fileName)
John Kessenicha0af4732012-12-12 21:15:54 +0000329{
John Kessenich200b2732012-12-12 21:21:23 +0000330 FILE *in;
331 int errorCode = fopen_s(&in, fileName, "r");
John Kessenicha0af4732012-12-12 21:15:54 +0000332 char *fdata;
333 int count = 0;
John Kessenichcfd643e2013-03-08 23:14:42 +0000334 const int maxSourceStrings = 5;
335 char** return_data = (char**)malloc(maxSourceStrings+1);
John Kessenicha0af4732012-12-12 21:15:54 +0000336
337 //return_data[MAX_SOURCE_STRINGS]=NULL;
John Kessenich200b2732012-12-12 21:21:23 +0000338 if (errorCode) {
John Kessenicha0af4732012-12-12 21:15:54 +0000339 printf("Error: unable to open input file: %s\n", fileName);
340 return 0;
341 }
342
343 while (fgetc(in) != EOF)
344 count++;
345
346 fseek(in, 0, SEEK_SET);
347
348
349 if (!(fdata = (char *)malloc(count+2))) {
350 printf("Error allocating memory\n");
351 return 0;
352 }
353 if (fread(fdata,1,count, in)!=count) {
354 printf("Error reading input file: %s\n", fileName);
355 return 0;
356 }
357 fdata[count] = '\0';
358 fclose(in);
359 if(count==0){
360 return_data[0]=(char*)malloc(count+2);
361 return_data[0][0]='\0';
362 OutputMultipleStrings=0;
363 return return_data;
364 }
365
366 int len = (int)(ceil)((float)count/(float)OutputMultipleStrings);
367 int ptr_len=0,i=0;
368 while(count>0){
369 return_data[i]=(char*)malloc(len+2);
370 memcpy(return_data[i],fdata+ptr_len,len);
371 return_data[i][len]='\0';
372 count-=(len);
373 ptr_len+=(len);
374 if(count<len){
375 if(count==0){
376 OutputMultipleStrings=(i+1);
377 break;
378 }
379 len = count;
380 }
381 ++i;
382 }
383 return return_data;
384}
385
386
387
388void FreeFileData(char **data)
389{
390 for(int i=0;i<OutputMultipleStrings;i++)
391 free(data[i]);
392}
393
394
395
John Kessenich54d8cda2013-02-11 22:36:01 +0000396void InfoLogMsg(const char* msg, const char* name, const int num)
John Kessenicha0af4732012-12-12 21:15:54 +0000397{
398 printf(num >= 0 ? "#### %s %s %d INFO LOG ####\n" :
399 "#### %s %s INFO LOG ####\n", msg, name, num);
400}